Tool changes previously forced prompt consolidation even when the prepared
route could activate new tools through history. Rewriting the first system
message, or clearing an earlier appended prompt, reset the declaration
series and turned additions into immediate declarations.
Only routes without toolUpdate need that tool-triggered consolidation.
Capable routes append the full changed prompt and keep existing messages.
Explicit series starts, surface replacements, and unsupported prompt
routes still consolidate; retained-name definition changes still rebuild
tool declarations in Session.
Cover both update modes and reset paths, and pin the combined prompt/tool
transition through the shipped headless profile with shared schema goldens.
Log tool changes as developer messages independently of model capability,
fold committed headers and updates into Session.toolHistory(), and let the
LLM runtime construct deferred and retained declarations for routes that
declare a toolUpdate mode. DeepSeek serializes updates as system-role
tool_addition/tool_removal blocks with defer_loading and the tool-changes
beta header. An unchanged restored tool continues the series and is
re-offered through its recorded blocks instead of rewriting declarations.
Replace the obsolete rejection tests with wire assertions and add coverage
for the session fold, loop emission, route projection, config validation,
and the beta header. Chat and Trajectory changes land separately.
The 2026-07-16 explicit-turn-cancellation note still described a frozen,
detached signal reason and a two-variant cause union. The README paragraph
added here points readers at that note as the owner of the signal
lifecycle, so the stale mechanism was load-bearing.
It now records why freezing the caller's cause is not an alternative:
undici assigns `stack` from strict-mode code, so a frozen reason makes
fetch reject with `TypeError: Cannot add property stack` in place of the
abort reason.
Also names `turn/end`'s declared `TurnEndCancelCause` in the README and
takes the reviewer's helper-doc wording.
Node's fetch assigns an enumerable `stack` string onto the abort reason
object it receives, and the loop logged that same object into `turn/end`.
The undici trace became durable session data under a field no reader
declares. A transport adding a property JSON discards instead made
`Session.append` reject the ending, leaving a turn with no close.
`abortedCancelCause()` narrows the untyped `AbortSignal.reason` once and
copies the declared fields, replacing the three `as AgentCancelCause`
assertions at the two read sites and the log write.
Preserve the V3 system-prompt projection while adopting master’s per-agent frozen-message provenance and frontend performance gates. Keep benchmark workload admission and diagnostics fixes intact, and retain both migration and first-open/reopen lifecycle guarantees.
Seed the request surface watermark from the attached session so a replacement before the first resumed request consolidates retained prompt versions. An unchanged resume still continues the series. Actual-loop replacement regression fails before the fix; 53 focused tests and the agent-loop project typecheck pass.
Every same-step attempt resolves its bound route and reconciles the accepted rendered prompt against the current surface before deriving history. Preserve assembly, pre-step admission and entered users exactly once; compaction retries must not resurrect an older surviving prompt.
Normalize a broken request series to the current head plus dormant empty later system nodes, even if later versions survive or the effective text is unchanged. This removes the later-survivor exception without a delete operation and avoids appending instructions after already-admitted users on retry. Capture surface generation after reconciliation so subsequent ordinary retries do not emit phantom series headers.
Tests: both compaction cases fail before the fix (stale head, or stale later survivor), then pass with real loop/MockAdapter, pi-ai conversion and source-event reconstruction. Assert two retries keep one assembly/pre-step/user admission, preserve rendered text across section changes, and log one series boundary. Add unchanged-text explicit/tool series regressions. 391 loop tests with exact agent.ts/runtime-context.ts coverage pass at 100%; final admission spec has 11 passing cases. Source tsc and focused lint pass. Update EN/ZH implementation and owning rationale plus lifecycle retry documentation.
Resolve agent/request and prepareCall inside the accepted open step before committing system and user input. Preserve prompt-assembly model selection, bind capability and dispatch to the same prepared adapter, then log the envelope and derive the request synchronously. Preparation cancellation leaves a balanced empty step with no admitted input.
Normalize incapable-route retained prompt versions with logged per-node empty replacements and a current head, including unchanged rendering and resumed history. Dormant empty tails do not override the effective prompt. No new event or delete operation.
Tests: 389 agent-loop cases pass with exact agent.ts/runtime-context.ts coverage at 100% for all metrics; tsc -b packages/core/agent-loop/tsconfig.json passes. Seven actual-loop MockAdapter cases exercise pi-ai conversion, source-event reconstruction, both route transitions, resume, cancellation barriers, and bound selection. Stale-capability negative control fails all three transition regressions. Update EN/ZH request visibility, lifecycle generator, and owning rationale. Broad catalogs, recorded SDK/GUI and aggregate gates remain parent-owned.
Consolidate the existing in-history capability, loop, UI and artifacts into one baseline. Preserve the reviewed tree so each independently verified correction has a subsequent rationale-rich commit.
Consolidate the representation-change PR and its rebase reconciliations into one baseline. Preserve the exact tree and keep the in-history feature in the dependent PR. Follow-up fixes remain separate.