Merge latest origin/master into parallel-tool-call

# Conflicts:
#	docs/architecture.md
#	examples/acp-agent/tests/snapshots/bash-spill/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	packages/core/agent-loop/src/loop.ts
This commit is contained in:
Tianyi Cui
2026-07-18 15:09:39 +08:00
198 changed files with 6086 additions and 4036 deletions

View File

@@ -24,6 +24,7 @@ A harness is one [Cordis](cordis-primer.md) context. Packages contribute service
| ctx key | Package family | Role |
|---|---|---|
| `ctx.llm` | [`llm/`](../packages/llm/README.md) | adapter registry and streaming model calls |
| `ctx.tokenMeter` | [`llm/token-meter`](../packages/llm/token-meter/README.md) | singleton replay-aware request/surface pressure |
| `ctx.bash` | [`bash/`](../packages/bash/README.md) | foreground/background command execution |
| `ctx.sandbox` | [`sandbox/`](../packages/sandbox/README.md) | same-world process confinement (argv wrapping, per-call policy) |
| `ctx.codeRuntime` | [`code-runtime/`](../packages/code-runtime/README.md) | model-written program execution |
@@ -81,13 +82,13 @@ forever:
agent/request (config only) -> log request/header -> llm/stream (frozen)
'assistant/chunk'
agent/step-result
'assistant/message'
'assistant/message' (transformed content or empty success anchor after step-result rejection)
schedule tool calls by ctx.tools.executionMode:
exclusive -> one-call barrier
parallel -> rolling pool, <= maxParallelToolCalls in flight; reclassify before start
each start -> 'tool/call' -> ordered tools/pre-execute -> concurrent tools/execute
each model-order result -> ordered tools/post-execute -> 'tool/result'
append post-tool context (model order) and steering
append accepted tool-batch context after all recorded results, then steering
'step/end'
agent/turn-continuation
agent/turn-stop (terminal policy)
@@ -98,7 +99,7 @@ forever:
Each step assembles ordered prompt sections, tool schemas, and `{{name}}` variables; unknown or valueless references fail the turn. `dsh-system-prompt` owns the harness identity and default persona, which an agent scope may shadow. The loop supplies `model` and `cwd` ([prompt-ownership RFC](rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)).
Post-tool context lands after all tool results so tool-call/result adjacency stays stable. Steering drains between steps; leftover ordinary steering becomes queued input. Terminal `agent/turn-stop` runs after continuation and steering folding, stays authoritative through turn close/flush, and discards later steering while preserving queued prompts.
Context accepted during tool execution—including async `agent.inject()` notices and post-tool `additionalContexts`—waits for settlement, then follows every recorded result. Successful batches preserve call/result adjacency; interrupted batches drain that context before turn closure. Steering drains between steps; ordinary leftover steering becomes queued input. Terminal `agent/turn-stop` runs after continuation and steering folding, stays authoritative through turn close and flush, and discards later steering while preserving queued prompts.
### Failure Boundaries
@@ -126,7 +127,7 @@ Durability is a plugin concern. Persistence backends buffer synchronous `session
### Model Content
Messages contain typed blocks (`text`, `reasoning`, `tool-call`, `tool-result`) derived from merge-extensible `ContentBlockMap`; the same pattern types `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`. New block types coordinate adapters, UI bridges, compaction pricing, and persistence as one repo-wide contract.
Messages contain typed blocks (`text`, `reasoning`, `tool-call`, `tool-result`) derived from merge-extensible `ContentBlockMap`; the same pattern types `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`. New block types coordinate adapters, UI bridges, compaction pricing, token metering, and persistence as one repo-wide contract; replay measurement types live in [token-meter.md](core-data-structures/token-meter.md).
Streaming uses raw chunks (`block-start` through `finish`) and `BlockAssembler`. The loop logs and assembles chunks, storing provider/model provenance plus replay state. An `LlmAdapter` implements `stream()`, registers provider routes, and may expose selector metadata; it resolves and validates model ids. Replay state reaches targets only when both routes map to one adapter instance, which owns validation and conversion. The contract lives in [llm-streaming.md](core-data-structures/llm-streaming.md).