feat(web): split context injection into producer-declared forms
Injected context reached the transcript as one anonymous shape whose expanded body was the whole message serialized as inline JSON, so the escaping collapsed the only readable part — the model-facing prose — into a single line. `MessageSource` gains an optional producer-declared `form`, a small semantic vocabulary of information shapes independent of `kind`: kind says who produced the context, form says what shape it is, so several producers may share one presentation. Two values ship. `instructions` (workspace-context) lists the reconciled files above their text and keeps the `<system-reminder>` framing verbatim, because the framing is part of what the model read. `catalog` moves dsh-tool-skill off the shared plugin kind onto a `skill-catalog` source carrying the published name/description entries, and the body lists those instead of re-parsing `<available_skills>` out of the prose. Catalog identity moves with it: the republish digest now covers the durable entries, deleting the text-slicing that recovered them from a logged message. Everything else renders the opaque body — the model-facing text with its real line breaks, then the remaining provenance as fields. That is the documented default, not a leftover: a resumed, forked, or foreign log must render whether or not its producer is mounted here, which is why the classification lives in the durable source rather than a client-side table keyed by producer.
This commit is contained in:
@@ -126,6 +126,7 @@ export function apply(ctx: Context, config: Config): void {
|
||||
content: baselineMessage.content,
|
||||
source: {
|
||||
kind: 'workspace-instructions',
|
||||
form: 'instructions',
|
||||
baseline: true,
|
||||
changes: [...baseline.changes.values()],
|
||||
},
|
||||
|
||||
@@ -39,6 +39,8 @@ const FILE_TOUCH_TOOL_NAMES = new Set(['read', 'write', 'edit'])
|
||||
/** Durable provenance and reconciliation facts for one workspace context. */
|
||||
export interface WorkspaceInstructionSource {
|
||||
kind: 'workspace-instructions'
|
||||
/** Every workspace context carries instructions read out of a file (the `instructions` context form). */
|
||||
form: 'instructions'
|
||||
/** Marks the complete startup/resume baseline rather than a later delta. */
|
||||
baseline?: true
|
||||
changes: WorkspaceInstructionChange[]
|
||||
@@ -87,7 +89,7 @@ export interface ReconciledInstructionContext {
|
||||
function workspaceContextHook(text: string, changes: WorkspaceInstructionChange[]): UserMessage {
|
||||
return createUserMessage({
|
||||
content: [{ type: 'text', text }],
|
||||
source: { kind: 'workspace-instructions', changes },
|
||||
source: { kind: 'workspace-instructions', form: 'instructions', changes },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user