Files
deepseek-harness/packages/cordis/tool-cordis
kingwl edc065666f feat(mode): exit_plan_mode + the ACP session-mode picker + scriptable review answers
Plan mode's stage 2 (RFC 2026-07-07-plan-mode). The exit tool: one
required plan argument (the durable log artifact), execute re-checks the
folded mode, then conducts the review over the user-interaction seam —
one single-select question (Approve / Keep planning) with free text open
— so an approval appends mode/set back to default in-turn and every
other outcome (keep-planning feedback verbatim, aborted, no provider)
returns the corrective isError with the mode unchanged. presentCall is a
generic card titled by the plan's first heading carrying the plan
markdown; over ACP the review rides the ask_user elicitation flow, in
the terminal the stdio prompt queue — no approval-seam dependency.

The ACP bridge maps the picker 1:1 onto ctx.modes (opportunistic, a
type-only peer edge): session/new + session/load advertise
availableModes/currentModeId, session/set_mode validates through set()
and echoes an optimistic current_mode_update (the pending mode IS the
selection; the logged mode/set lands at the boundary and, matching, is
not re-sent), and a session/event listener re-notifies on each logged
flip that differs from the last sent — the tool-driven exit updates the
picker. The feature matrix rows move from 'not modeled' to the
picker-to-modes / knobs-to-config-options division, with the ACP v2
removal direction recorded as a mechanical-migration risk.

The snapshot harness gains the setMode/setModeExpectError ops and a
scripted elicitationAnswers FIFO (cancel on exhaustion; a stray choice
string reaches the agent verbatim as a non-consenting custom answer, so
a scenario bug fails safe). The suite factory's header-pin requirement
now applies only to model-turn scenarios — a protocol-only suite has no
header content to anchor. examples/plan-acp-agent is the live
composition; its keyless modes-advertise scenario pins the wire surface
(advertisement, both set_mode round-trips, unknown-id rejection). The
recorded plan-mode approve/reject arc awaits a with-key recording
session; its texts are pinned at the unit tier meanwhile.

examples/AGENTS.md ceiling 653 → 680: the new example's required smoke
row does not fit the old budget.
2026-07-10 02:57:40 +08:00
..

@deepseek-ai/dsh-tool-cordis

The self-referential cordis toolset: three model-facing tools over the live runtime the agent runs inside. Design home — sandbox semantics, mount lifecycle, cross-mount composition, the generated API catalog, standing decisions: the toolset RFC.

What it does

  • cordis_inspect — read-only report over the runtime: services, the loaded-plugin list, registered tools, the dynamic-mount table, and the catalog-backed api / events references.
  • cordis_mount — evaluates model-written JavaScript (the body of an async function) in a node:vm sandbox; the code must return a cordis plugin, which is mounted under the cordis-dynamic group fiber and tracked as dyn-<n>.
  • cordis_unmount — disposes one mount by id, returning only after quiescence.

Exact model-facing schemas: the generated tool catalog.

Trust stance

The sandbox isolates the global context only — it is not a security boundary. No Node API is provided: require, the timers, and fetch are callable traps that throw a redirect to the cordis alternative (ctx.fs / ctx.web / ctx.bash / inject: ['timer'] + ctx.setTimeout); process and Buffer are undefined; globalThis writes stay inside. These traps steer honest code onto the cordis services; they do not contain a mount that goes looking — the host-realm helpers on the sandbox global (harness, console, btoa) are reachable functions, so mount code can reach the host realm and Node through one of them, which is fine because ctx is fully privileged anyway. The ctx a mounted plugin's apply receives is a whitelist façade — register tools, observe events, provide/consume services, use timers; framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld — but the capabilities it does expose reach the real runtime, so load this plugin as deliberately as you would grant a bash tool.

Config

Field Default Meaning
vmTimeoutMs 5000 Bound on the SYNCHRONOUS portion of mount-code evaluation; an async body escapes it

The generated API catalog

src/api-catalog.ts is generated by scripts/gen-cordis-api.ts from the same AST walk as docs/cordis-catalog and freshness-gated by pnpm run verify-cordis-api (in doc-sync) — never edit it by hand. cordis_inspect intersects it with the live service store at call time.

Rendering

All three tools render generic cards (read / execute / delete); cordis_mount carries the mount code as rawInput. Presenters are pure functions of the args; results keep the default text rendering.

Export shape

Namespace plugin: named exports name / inject / Config / apply, no default export (docs/postmortem/0001).