Summary
Preserve the structured context that plugins add to a turn so the same content
can be rendered into the model prompt and inspected from the triggering user
message in the dashboard.
Memory recall is the first use case. A recalled-memory contribution should keep
the selected memory ids, content, timestamps, scope, and kind instead of
discarding that structure after producing prompt text.
Current behavior
packages/junior-memory/src/recall.ts selects memories and immediately renders
them into a text-only PromptMessage.
packages/junior-plugin-api/src/prompt.ts defines PromptMessage as a strict
{ text } object.
- Core inserts that text through
getPluginUserPromptContributions(), but it
cannot persist or report which records produced it.
- The dashboard can only see an opaque memory block inside the model-facing
prompt.
Product behavior
- Show a subtle context indicator on a user transcript message when a plugin
contributed context to that turn.
- Opening it shows the context used for the turn. Memory recall gets a focused
view with one row per recalled memory.
- The memory view includes the exact selected content plus memory id, observed
timestamp, scope/kind when available, and the time the snapshot was loaded.
- Later memory edits, expiry, or deletion do not change the historical snapshot.
- Context remains searchable in the transcript and has a compact transcript
export representation.
- Existing conversation payload authorization and redaction rules apply to all
context content.
This is turn context, not a complete dump of every provider request. System
instructions, prior agent history, tool definitions, and later tool results are
outside this issue.
Proposed extension
Add one small, typed context contribution alongside the existing plugin prompt
hook. Follow the existing defineJuniorPlugin / definePluginTool style: plain
objects, a strict Zod schema, and at most one small inference helper.
Conceptually, a context definition owns:
{
kind: "recall",
version: 1,
schema: memoryRecallSchema,
renderPrompt(content) {
return renderMemoryPrompt(content.memories);
},
}
The memory hook creates a contribution from structured content:
{
kind: "recall",
version: 1,
content: {
memories: [
{
id,
content,
observedAtMs,
scope,
kind,
},
],
},
}
Core validates the content, calls the plugin-owned prompt renderer, and inserts
the resulting text through the existing user-prompt path. The prompt renderer
is not persisted.
Core also appends a bounded turn_context conversation event anchored by the
core-owned turn id:
{
type: "turn_context",
turnId,
pluginName: "memory",
kind: "recall",
version: 1,
loadedAtMs,
content: {
memories: [...],
},
}
The event contains facts only. Do not persist field labels, icons, layout,
rendered prompt text, or other presentation instructions. Core supplies
pluginName, turnId, and loadedAtMs; the plugin cannot spoof them.
kind and version form the stored plugin context contract. Changing the
persisted shape or model-visible interpretation requires a new version.
Historical events are not rewritten. Unknown context kinds or versions may use
a safe generic structured view.
Dashboard
The reporting API projects authorized turn_context events and associates them
with the user message that started the turn.
The dashboard provides a safe generic structured-content view. It may also use
an optional specialized renderer keyed by plugin name, kind, and version. The
memory renderer consumes the stored memory structure; it does not query the
memory database or control authorization.
Presentation stays in dashboard code and can change without changing stored
events. A missing specialized renderer falls back to the generic view.
Limits and privacy
- Apply strict per-contribution and aggregate serialized-size limits.
- Limit nesting, collection length, and string length.
- Memory persists only records actually selected for the prompt, not every
search result or full database rows.
- Treat strings as text; do not accept HTML or executable UI content.
- Do not project context content when the caller cannot view conversation
payloads.
- Search and export operate only on the already-authorized report.
The schema can prevent executable or unbounded content. Secret handling remains
the responsibility of the contributing plugin and the conversation payload
authorization boundary.
Acceptance criteria
- Memory recall produces one typed, versioned context contribution derived from
the same selected records used to render the model prompt.
- Core renders the plugin contribution into the existing model-visible user
prompt without changing current recall wording.
- Core durably stores the structured, presentation-free context against the
turn.
- No context event is emitted when recall returns no memories.
- Rich transcript view shows a context indicator on the triggering user
message and a memory-specific detail view.
- The detail view includes memory id, selected content, observed time,
scope/kind, and load time.
- Later changes to memory storage do not alter historical context.
- Unknown kinds or versions render safely without executing plugin UI code.
- Redacted conversations do not expose context through the report, transcript
search, or export.
- Tests cover schema validation and budgets, prompt rendering, durable event
projection, authorization, memory rendering, transcript search, and export.
Requested by David Cramer via Junior.
--
View Junior Session in Sentry
Summary
Preserve the structured context that plugins add to a turn so the same content
can be rendered into the model prompt and inspected from the triggering user
message in the dashboard.
Memory recall is the first use case. A recalled-memory contribution should keep
the selected memory ids, content, timestamps, scope, and kind instead of
discarding that structure after producing prompt text.
Current behavior
packages/junior-memory/src/recall.tsselects memories and immediately rendersthem into a text-only
PromptMessage.packages/junior-plugin-api/src/prompt.tsdefinesPromptMessageas a strict{ text }object.getPluginUserPromptContributions(), but itcannot persist or report which records produced it.
prompt.
Product behavior
contributed context to that turn.
view with one row per recalled memory.
timestamp, scope/kind when available, and the time the snapshot was loaded.
export representation.
context content.
This is turn context, not a complete dump of every provider request. System
instructions, prior agent history, tool definitions, and later tool results are
outside this issue.
Proposed extension
Add one small, typed context contribution alongside the existing plugin prompt
hook. Follow the existing
defineJuniorPlugin/definePluginToolstyle: plainobjects, a strict Zod schema, and at most one small inference helper.
Conceptually, a context definition owns:
The memory hook creates a contribution from structured content:
Core validates the content, calls the plugin-owned prompt renderer, and inserts
the resulting text through the existing user-prompt path. The prompt renderer
is not persisted.
Core also appends a bounded
turn_contextconversation event anchored by thecore-owned turn id:
The event contains facts only. Do not persist field labels, icons, layout,
rendered prompt text, or other presentation instructions. Core supplies
pluginName,turnId, andloadedAtMs; the plugin cannot spoof them.kindandversionform the stored plugin context contract. Changing thepersisted shape or model-visible interpretation requires a new version.
Historical events are not rewritten. Unknown context kinds or versions may use
a safe generic structured view.
Dashboard
The reporting API projects authorized
turn_contextevents and associates themwith the user message that started the turn.
The dashboard provides a safe generic structured-content view. It may also use
an optional specialized renderer keyed by plugin name, kind, and version. The
memory renderer consumes the stored memory structure; it does not query the
memory database or control authorization.
Presentation stays in dashboard code and can change without changing stored
events. A missing specialized renderer falls back to the generic view.
Limits and privacy
search result or full database rows.
payloads.
The schema can prevent executable or unbounded content. Secret handling remains
the responsibility of the contributing plugin and the conversation payload
authorization boundary.
Acceptance criteria
the same selected records used to render the model prompt.
prompt without changing current recall wording.
turn.
message and a memory-specific detail view.
scope/kind, and load time.
search, or export.
projection, authorization, memory rendering, transcript search, and export.
Requested by David Cramer via Junior.
--
View Junior Session in Sentry