fix(web): address the review round on the remaining context forms

- `relay` resolves its sender in `contextBody` like every other form. It was
  the one shape whose marker could claim a form the body did not render: an
  unreadable sender fell back inside the body while the row still said relay,
  contradicting the contract this PR's own note states.
- `recall` requires the retained, omitted, and truncated fields. Completeness
  is what the card exists to report, so a reference that cannot state it is
  not a readable recall — showing the label alone presents a confident card
  over unknown loss.
- The snapshot body states the supersession its producer framing line carries.
  That line is the one part of the model-facing text no section contains, and
  unlike an instruction context's `<system-reminder>` it states the form's own
  semantics rather than wrapping content.
- `GoalMessageSource` is a discriminated pair, so `{ form: 'notice' }` without
  its account no longer compiles. The guarantee this PR claims now holds at
  that seam too, not only through `ContextFormed` on plugin sources.
- Goal and tool-goal summaries are bounded by a shared `boundContextSummary`,
  which tool-tasks now uses as well. A goal objective is unbounded caller text
  in exactly the way a task label is.
- The runtime snapshot interpolates once per request: agent-loop renders the
  sections and joins them through `joinContextSections`.
- Every form's fallback branch is pinned, not only the notice one.
This commit is contained in:
creatixchu
2026-08-05 17:39:50 +08:00
parent bb59526598
commit e7f2005ec7
16 changed files with 160 additions and 84 deletions
+3 -14
View File
@@ -8,7 +8,7 @@
import type { Context } from 'cordis'
import z from 'schemastery'
import { createUserMessage, type ContentBlock } from '@deepseek-ai/dsh-llm'
import { boundContextSummary, createUserMessage, type ContentBlock } from '@deepseek-ai/dsh-llm'
import { TextRetainer } from '@deepseek-ai/dsh-retention'
import { defineTool } from '@deepseek-ai/dsh-tools'
import type { GenericCallView, ToolDefinition, ToolExecution } from '@deepseek-ai/dsh-tools'
@@ -114,24 +114,13 @@ function fitWithSuffix(
return `${retainTail(content, maxBytes - fixedBytes)}${fixed}`
}
/**
* Bound for the durable one-line account. A notice summary rides a collapsed
* transcript row, and both the task label and its status detail are caller
* text with no length of their own, so the summary caps itself rather than
* committing unbounded prose to the log.
*/
const SUMMARY_MAX_CHARS = 120
/**
* One-line account of a settled task for the `notice` form's collapsed row.
* @param snapshot - the settled task.
* @returns its kind, label, and status, bounded to {@link SUMMARY_MAX_CHARS}.
* @returns its kind, label, and status, bounded like every notice summary.
*/
function completionSummary(snapshot: TaskSnapshot): string {
const summary = `${snapshot.kind} ${snapshot.label} ${statusLine(snapshot)}`
return summary.length <= SUMMARY_MAX_CHARS
? summary
: `${summary.slice(0, SUMMARY_MAX_CHARS - 1)}…`
return boundContextSummary(`${snapshot.kind} ${snapshot.label} ${statusLine(snapshot)}`)
}
function fitCompletionNotice(snapshot: TaskSnapshot): string {