- fromRequest placeholder: the last two braces of a consecutive } run now
terminate the placeholder, so patterns may end with a brace quantifier
(bot warning; the truncated pattern could even silently mis-match since
an unclosed { is literal in JS regexes)
- document that derived JSONL entries pass through the same resolution
- widen ToolRunContext/deferContext seam docs beyond composite-only usage
(source JSDoc, README pair, core-data-structures type-equiv blocks)
- pin direct-human blocked as uninstructed, completing the
goal-round/direct-human x complete/blocked test quadrant
An empty read window (byte cap below the first selected line: `lines: []`
with `totalLines > 0`) dropped `offset` from the persisted presentation
meta, so a replayed read card could not report where the window starts or
where a continuation resumes. Carry `offset` on `FsReadMeta`,
`ReadResultView`, and the `presentationMeta` projection, and validate it in
`readMetaFromMeta` (1-based integer; the first line number may not fall
below it). Re-record the ACP fixtures and the cordis api catalog.
Also correct the Note's `parallel-file-reads` golden path
(examples/tui-agent -> apps/cli) and record the pre-card replay-degradation
tradeoff in the Decision section.
Address the review of the search render card:
- The search result view carries no `content`: it was a no-op for every
consumer and serialized the whole search text twice. A UI without a search
card falls back to the raw tool/result content; the TUI stays byte-identical
to the pre-search-card generic fallback.
- Bound the serialized presentationMeta with a configurable searchMetaMaxBytes
(default 64 KiB): the inline item cap does not bound bytes, and spill-policy
only shrinks content, never meta. capMetaBytes drops trailing groups/paths.
- Share one retention pass (retainGrepMatches/retainGlobPaths in search-core)
between the model-facing render and the meta projection; remove the second
cap/preview implementation and the presentation<->grep module cycle by
moving GrepMatch/previewLine to search-core.
- Rename the result-view discriminant kind -> shape so it no longer collides
with GenericCallView.kind (ToolCallKind, whose values include 'search').
- Narrow the entry export surface to consumed symbols.
- Sync the three bilingual ToolResultView doc pairs and the Agent Note pair;
document the deliberate empty-card acceptance vs diffsFromMeta.
- Regenerate config/tool/cordis catalogs for the new config field.
Address the code-review bot findings on the web result card:
- web_fetch's card truncated now derives from the shared renderFetchOutput
helper, matching the effective truncation the model-facing text reflects
(provider cap, source cut, or output cap), instead of the provider-only flag.
- Drop the redundant content copy from both web result views; a UI without the
web capability falls back to the raw tool/result content. Narrow the TUI
transcript view.content access accordingly.
- Set the result-state title from the call args (query/url) so a window-
truncated replay keeps a title.
- Project meta from the seam result types rather than hand-rolled value types.
- Sync the card vocabulary across core tools README, docs/core-data-structures,
the adding-a-tool cookbook, and the tool-web package README (both languages,
re-recorded pairings); regenerate the cordis api-catalog and cordis-inspect
snapshot; revise the Agent Note.
readMetaFromMeta narrows the opaque persisted meta boundary, so beyond
shape it now rejects replayed JSON that is well-typed but semantically
invalid: line numbers must be 1-based integers, totalLines a non-negative
integer, and line numbers must strictly increase without exceeding
totalLines. Any violation declines to the generic fallback.
Sync the public ToolResultView contract across the core/tools and
tool-fs READMEs and docs/core-data-structures/tools for the fourth
result-view member and the ReadFileLine vocabulary, and expand the
Agent Note Testing section with the new rejection paths and the snapshot
evidence this PR carries.
Conflict resolution: scripts/type-equiv.manifest.json takes master's new
paired-derivative format (one primary entry per pair) and re-adds this
stack's CodeDispatchLog entry in that format. zh README pairs brought
along for the dispatch-log arm (spill-policy behavior/limitations bullets,
tools limitation bullet now pointing at the shipped bounding).
New tools/code-dispatch-log waterfall (run via registry.shapeDispatchLog,
contained — a throwing listener falls back to the unshaped content) lets
listeners reshape the tool/code-dispatch event's content before the
bridge appends it. dsh-spill-policy registers a second arm sharing the
model-facing arm's exact replacement pipeline (same maxInlineBytes cap,
preview + locator, within-cap invariant, best-effort fallbacks), with
artifacts labeled dispatch under the sub-call id. The program's value is
untouched; read sub-calls ARE bounded (a log copy is not model context,
and read produces the biggest logs). Resolves the tools README's
uncapped-dispatch-log Known Limitation.
The bridge replaces its serialization queue with a pool that reuses the
native concurrency contract: submissions classify through
registry.executionMode (fail-closed isConcurrencySafe), start strictly in
submission order, overlap up to the validated maxParallelSubCalls config
(default 10; 1 restores serial), and exclusive calls drain the pool, run
alone, and bar later calls. Each started sub-call logs a
tool/code-dispatch-start event at pool entry; the existing
tool/code-dispatch settles the pair (started ⇔ settles exactly once;
abandoned queued calls log neither). SDK prompt guidance now states the
true Promise.all contract — re-recorded across every code/both-mode
snapshot (plus the stale cordis-dynamic-toolchain fixture gaining the
required description arg).
Client: CodeSubCall widens to RunningToolCall | ToolResultNode — starts
land the running shape (rows wear the native running ring), settles
replace in place preserving start order, callTime pairs to the start
time. Fixture emits start/settle pairs; jsdom pins the running sub-row;
runtime specs pin in-place settlement and out-of-order completion.
run_code gains a required bash-style description parameter: presentCall
titles the card with it and moves the program to rawInput, so every
surface gets a readable label. tool/code-dispatch now logs each
sub-call's complete content/isError (the tool/result vocabulary),
replacing the bounded resultSummary and deleting the summarize/cwd
machinery — a UI renders sub-calls through the identical path as native
results. The dsh config tree mounts the worker code runtime and reads
DSH_TOOLS_MODE (temporary seam until per-session mode selection lands).
Session format stays v0 (pre-release churn). Code-mode ACP/TUI fixtures
re-recorded; TUI presenter pin refreshed; catalogs regenerated. Keyless
web smoke pins the code-mode wire contract (tools=[run_code] + SDK
prompt section).
context/message previously defaulted to a <context source="…">…</context>
wrapper. No model is trained on a <context> tag either, and message
framing does not belong on the session surface: the surface projects the
durable log, and a caller that wants a frame formats its own content —
which the one heavy producer (workspace-context) already does with its own
<system-reminder> frame, opting out via 'raw'. The tag only added
machinery — ContextEnvelope plus an envelope field threaded through
InjectOptions, HookContext, the context/message event, and the agent-loop
inject/additionalContexts plumbing.
context/message now projects its content verbatim as a user-role message,
sharing one deriveEventMessage case with user/message and steering/message.
ContextEnvelope and every envelope field are removed; context/message.meta
still carries durable, model-hidden JSON state. Regenerated catalogs and
website API; refreshed the three affected keyless snapshots (envelope field
only; timestamps unchanged).
Broadens and renames the steering Agent Note to cover both envelope
removals as one decision.
Agent Note: .agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md