feat(web): declare the remaining context forms on every shipped producer
Four values complete the vocabulary, so the opaque body is reached only by producers that genuinely promise no shape. `snapshot` — current state a later snapshot supersedes. system-prompt now exposes `renderContextSections()`, the named contributions `renderContextSnapshot()` already joins for the model, so the body attributes each part to the subsystem that produced it instead of re-splitting joined prose. The runtime snapshot, time-context, and tmux-context declare it. `notice` — a one-off account of what just happened, declared by tool-tasks, goal state changes, tool-goal wrap-up, plan-mode switches, and repeat-tool-guard. Its `summary` rides the COLLAPSED row: these five are the majority of shipped producers and none of them needs expanding to be read. The task summary bounds itself because its inputs are unbounded caller text. `relay` — a message another agent addressed to this one; both subagent sources declare it and the body names the sender above what it said. `recall` — material lifted from another session's log. session-reference needed no new field: its references already record retained and omitted counts and the truncation flag, which the body shows first, because recalled context is bounded on the way in. `ContextFormed` is now discriminated by `form`, so a producer cannot declare a shape without the facts that shape is presented from — a notice without its summary, or a snapshot without its sections, fails to compile. Only the two hook bridges stay opaque, by design: their content is whatever an external program printed, so no shape can be promised for it. Unknown kinds and unreadable records land there too.
This commit is contained in:
@@ -46,10 +46,12 @@ import {
|
||||
llmRetryPolicyOf,
|
||||
markAgentLoopRequest,
|
||||
} from '@deepseek-ai/dsh-llm'
|
||||
import type { GenerateOptions, LlmCallConfig, LlmFailure, Message, PreparedLlmCall, ResolvedRetryPolicy } from '@deepseek-ai/dsh-llm'
|
||||
import type {
|
||||
ContextSnapshotSection, GenerateOptions, LlmCallConfig, LlmFailure, Message, PreparedLlmCall, ResolvedRetryPolicy,
|
||||
} from '@deepseek-ai/dsh-llm'
|
||||
import { canonicalHeader, headerEquals } from '@deepseek-ai/dsh-session'
|
||||
import type { AssistantMessage, EpochHeader, RequestContext, Session, SessionId, TurnEndReason, TurnTrigger, UserMessage } from '@deepseek-ai/dsh-session'
|
||||
import { renderContextSnapshot, renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import { renderContextSections, renderContextSnapshot, renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import type {} from '@deepseek-ai/dsh-tools'
|
||||
import { executeToolCalls } from './tool-calls.ts'
|
||||
|
||||
@@ -105,7 +107,11 @@ function retainedRuntimeContext(session: Session): { found: boolean; text: strin
|
||||
}
|
||||
|
||||
/** Append a full current snapshot only when it changed or compaction removed it. */
|
||||
function materializeRuntimeContext(session: Session, current: string): void {
|
||||
function materializeRuntimeContext(
|
||||
session: Session,
|
||||
current: string,
|
||||
sections: readonly ContextSnapshotSection[],
|
||||
): void {
|
||||
const previous = retainedRuntimeContext(session)
|
||||
if (!previous.found && current.length === 0) {
|
||||
const compactedPriorSnapshot = session.surface.replaceGeneration > 0
|
||||
@@ -116,7 +122,10 @@ function materializeRuntimeContext(session: Session, current: string): void {
|
||||
if (previous.text === snapshot) return
|
||||
session.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: snapshot }],
|
||||
source: { kind: 'plugin', plugin: RUNTIME_CONTEXT_SOURCE },
|
||||
// The cleared marker has no contributions left to attribute.
|
||||
source: sections.length === 0
|
||||
? { kind: 'plugin', plugin: RUNTIME_CONTEXT_SOURCE }
|
||||
: { kind: 'plugin', plugin: RUNTIME_CONTEXT_SOURCE, form: 'snapshot', sections },
|
||||
}), { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
@@ -691,7 +700,7 @@ export class ReactLoopAgent implements Agent {
|
||||
const assembly = await this.loopCtx.systemPrompt.assemble(assembleContextFor(this, signal))
|
||||
signal.throwIfAborted()
|
||||
const system = renderPrompt(assembly)
|
||||
materializeRuntimeContext(session, renderContextSnapshot(assembly))
|
||||
materializeRuntimeContext(session, renderContextSnapshot(assembly), renderContextSections(assembly))
|
||||
|
||||
// Commit the exact pending batch only after every asynchronous
|
||||
// pre-request contribution succeeded. Input accepted after this splice
|
||||
|
||||
Reference in New Issue
Block a user