Merge branch 'codex/simp-unify-agent-session-id' into codex/simp-ui-identity-residue

# Conflicts:
#	docs/config-catalog.md
#	docs/event-producer-consumer.md
#	docs/rfc/implemented/feature/2026-07-06-approval-seam.md
#	packages/ui/acp/README.md
#	packages/ui/acp/src/index.ts
#	packages/ui/jsonrpc/README.md
#	packages/ui/jsonrpc/src/server.ts
This commit is contained in:
Tianyi Cui
2026-07-14 18:55:51 +08:00
508 changed files with 3487 additions and 9370 deletions

View File

@@ -1,11 +1,5 @@
/**
* Pure translation between harness vocabulary and ACP wire types. No I/O, no
* Cordis context — every function here is total and unit-testable in isolation.
* Keeping the mapping pure is deliberate: the SDK rejects an unknown
* `stopReason`, so the {@link turnEndToStopReason} total function (with its
* exhaustive test over every `TurnEndReason` kind) is the guard that a turn
* always settles to a legal wire value.
*
* Pure, total translation between harness vocabulary and ACP wire types.
* @module @deepseek-ai/dsh-acp/codec
*/
@@ -16,29 +10,11 @@ import type { ContentBlock as AcpContentBlock, StopReason } from '@agentclientpr
/**
* Map a harness {@link TurnEndReason} to the ACP `StopReason` wire enum.
*
* The mapping is total over the kinds the loop actually produces today
* (`completed`/`aborted`/`error`/`disposed`/`max-tokens`/`rejected`).
* `TurnEndReason` is
* merge-extensible, so an unknown future kind falls through to `end_turn` —
* the safest default (the turn DID end; we just lack a more specific wire
* reason) — rather than throwing into the SDK, which would reject an unknown
* `stopReason` and break the prompt RPC. When a new kind gains a dedicated ACP
* reason (e.g. a future `refusal` → `refusal`), add an explicit case here.
*
* - `completed` → `end_turn` (the model chose to stop)
* - `max-tokens` → `max_tokens` (cut off at the output-token ceiling)
* - `aborted` → `cancelled` (a step abort or a queue-aware `agent.cancel()`, e.g. from `session/cancel`)
* - `error` → `end_turn` (defensive fallback only: the bridge REJECTS the
* `session/prompt` RPC on an error turn BEFORE calling this, so
* a client sees a JSON-RPC error, not a stop reason — see
* `rejectPrompt` in index.ts. This case keeps the function total
* for any non-bridge caller / property test.)
* - `disposed` → `cancelled` (the agent was torn down mid-turn — closest to a
* cancellation from the client's perspective)
* - `rejected` → `cancelled` (the prompt was blocked by an `agent/prompt-submit`
* hook before any step ran — ACP has no "rejected" reason, and a
* blocked prompt is, from the client's view, the prompt not being
* carried out; `cancelled` is the closest legal wire reason)
* `completed` and the defensive `error` case map to `end_turn`;
* `max-tokens` maps to `max_tokens`; `aborted`, `disposed`, and `rejected` map
* to `cancelled`. The bridge rejects error turns before this mapping. Unknown
* merge-extensible kinds use legal fallback `end_turn` rather than breaking
* the prompt RPC.
* @param reason - the harness turn-end reason to translate.
* @returns the legal ACP wire value per the mapping above.
*/
@@ -56,23 +32,17 @@ export function turnEndToStopReason(reason: TurnEndReason): StopReason {
return 'cancelled'
case 'error':
return 'end_turn'
// Merge-extensible: an unknown future TurnEndReason kind still has to
// produce a legal wire value (the SDK rejects unknown stopReason), so
// default to end_turn rather than assertNever. Add an explicit case when a
// new kind gains a dedicated ACP reason.
// Merge-extensible: an unknown future TurnEndReason kind still has to produce a legal wire
// value (the SDK rejects unknown stopReason), so default to end_turn rather than
// assertNever.
default:
return 'end_turn'
}
}
/**
* Translate a harness {@link ContentBlock} from a prompt into ACP content for
* replay, or `undefined` for block kinds the bridge does not surface to the
* client as message content. Today only `text` maps; `resource_link` is an
* ACP prompt-only input rendered into text by {@link acpPromptToText};
* `reasoning` is surfaced via `agent_thought_chunk`
* streaming rather than as a message block, and `tool-call`/`tool-result`
* are handled by the tool-call update path.
* Map replayable text to ACP message content. Other block kinds use their
* prompt, thought-stream, or tool-update paths.
* @param block - the harness content block to translate.
* @returns the ACP block, or `undefined` for a kind with no message-content mapping.
*/