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

View File

@@ -567,7 +567,7 @@ Goal mutation accepted by one live agent. The matching context event is already
Types: [Agent](../core-data-structures/core.md) · [GoalChanged](../core-data-structures/goal.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/goal/goal/src/domain.ts:142`](../../packages/goal/goal/src/domain.ts)
Source: [`packages/goal/goal/src/domain.ts:140`](../../packages/goal/goal/src/domain.ts)
## `llm/*`

View File

@@ -2163,7 +2163,7 @@ async assemble(context: AssembleContext = {}): Promise<PromptAssembly>
Types: [AssembleContext](../core-data-structures/system-prompt.md) · [PromptContext](../core-data-structures/system-prompt.md) · [PromptSection](../core-data-structures/system-prompt.md) · [ToolProviderResult](../core-data-structures/system-prompt.md)
Source: [`packages/core/system-prompt/src/index.ts:310`](../../packages/core/system-prompt/src/index.ts)
Source: [`packages/core/system-prompt/src/index.ts:322`](../../packages/core/system-prompt/src/index.ts)
## `ctx.tasks` — `TaskService` (abstract seam)

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/core-data-structures/goal.md
goal.md: 8627b927fcff1c32faac0e76356f576bdbb29ba8
goal.zh.md: f1c3a2e4d65d1efe849aab565e8beb79e0284aae
goal.md: 5b9b751d734a98d5fc7b0333eeb52febadbca22a
goal.zh.md: 0ce1a2166abc234225309bfb9a513bdf9ed30d4a

View File

@@ -101,22 +101,20 @@ Goal state changes use round `0`. A continuation consumer attributes each admitt
```ts type-equiv
/** Message attribution for durable goal state and continuation rounds. */
interface GoalMessageSource {
type GoalMessageSource = {
readonly kind: 'goal'
/**
* Round-zero state changes are `notice`-form contexts; a continuation round
* carries the objective forward as ordinary context and declares no form.
*/
readonly form?: 'notice'
/** Present with `form`: one-line account of the mutation. */
readonly summary?: string
readonly goalId: GoalId
readonly revision: number
/** Zero for state changes; positive for admitted continuation rounds. */
readonly round: number
/** Complete durable mutation carried only by round-zero state-change messages. */
readonly change?: GoalChangeMeta
}
/**
* Round-zero state changes are `notice`-form contexts; a continuation round
* carries the objective forward as ordinary context and declares no form.
* Discriminated so the account cannot be omitted when the form is declared.
*/
} & ({ readonly form: 'notice'; readonly summary: string } | { readonly form?: never; readonly summary?: never })
```
## Requests and notifications

View File

@@ -101,22 +101,20 @@ interface GoalClearChangeMeta {
```ts type-equiv
/** Message attribution for durable goal state and continuation rounds. */
interface GoalMessageSource {
type GoalMessageSource = {
readonly kind: 'goal'
/**
* Round-zero state changes are `notice`-form contexts; a continuation round
* carries the objective forward as ordinary context and declares no form.
*/
readonly form?: 'notice'
/** Present with `form`: one-line account of the mutation. */
readonly summary?: string
readonly goalId: GoalId
readonly revision: number
/** Zero for state changes; positive for admitted continuation rounds. */
readonly round: number
/** Complete durable mutation carried only by round-zero state-change messages. */
readonly change?: GoalChangeMeta
}
/**
* Round-zero state changes are `notice`-form contexts; a continuation round
* carries the objective forward as ordinary context and declares no form.
* Discriminated so the account cannot be omitted when the form is declared.
*/
} & ({ readonly form: 'notice'; readonly summary: string } | { readonly form?: never; readonly summary?: never })
```
## 请求与通知

View File

@@ -31,7 +31,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:62`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-policy`](../packages/fs/fs-policy) |
| `fs/observed` | `emit` | [`packages/fs/fs/src/index.ts:71`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`emit`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`emit`) | [`fs-policy`](../packages/fs/fs-policy), [`skill-local`](../packages/skill/skill-local) |
| `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:54`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-policy`](../packages/fs/fs-policy) |
| `goal/changed` | `emit` | [`packages/goal/goal/src/domain.ts:142`](../packages/goal/goal/src/domain.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-session`](../packages/goal/goal-session) |
| `goal/changed` | `emit` | [`packages/goal/goal/src/domain.ts:140`](../packages/goal/goal/src/domain.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-session`](../packages/goal/goal-session) |
| `llm/adapters-updated` | `emit` | [`packages/llm/llm/src/index.ts:71`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`events.dispatch`) | `apiproxy`, [`llm`](../packages/llm/llm) |
| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:60`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`waterfall`) | [`agent-loop`](../packages/core/agent-loop), [`llm`](../packages/llm/llm), [`llm-replay`](../packages/support/llm-replay), [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`session-title`](../packages/session-title/session-title) |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:71`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | `apiproxy`, [`compact`](../packages/compact/compact), [`goal`](../packages/goal/goal), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`plan-mode`](../packages/plan/plan-mode), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-telemetry`](../packages/telemetry/session-telemetry), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval) |