Files
deepseek-harness/packages/cordis/tool-cordis
Tianyi Cui bed03449ee Merge current master into PR #251
Master advanced from 5143fac7f to be363166e with the Cordis and loader vendor update after the previous PR merge was validated. GitHub therefore tested a new synthetic merge where packages/util/home still selected Cordis rc.6 with loader rc.4 while the updated workspace graph requires Cordis rc.7 with loader rc.5.

That stale importer made pnpm-lock.yaml semantically incomplete even though Git merged it without a textual conflict, so every Node, sandbox, and real-API job failed during immutable install before running tests. Merge the exact current master tip and regenerate the lockfile so the home package resolves the same peer graph as the updated workspace.

Verified the repaired merge with pnpm install --frozen-lockfile; the full pre-push gate runs on the committed merge before it is published.
2026-07-15 12:50:03 +08:00
..
2026-07-15 11:28:45 +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 globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as ctx.fs, ctx.web, and ctx.bash, and writes to globalThis stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Treat this toolset like bash access; see the design and trust stance.

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).

Model Experience

Tool schemas

What the model sees: The conversation model sees the generated cordis_inspect, cordis_mount, and cordis_unmount schemas whenever this plugin is visible.

Token effect: Fixed schema cost on every request in that tool view.

Tool-call history and results

What the model sees: Inspect joins selected sections exactly as ## <section> then a newline and the data-dependent body, with one blank line between sections. Mount returns mounted <id> (plugin "<name>", state: <state>), optionally inserting — waiting for service(s): <names> (activates when provided) before the closing parenthesis. Unmount returns unmounted <id> (plugin "<name>"); an unknown id becomes Error: no dynamic plugin with id "<id>" (list mounts with cordis_inspect what:"dynamic"). The submitted mount program remains in the assistant tool-call history.

Token effect: Inspect output and mount code are data-dependent and resent until compaction; lifecycle acknowledgements are small.

Later requests after a mount

What the model sees: A mounted plugin may register tools, prompt contributions, or listeners that change later requests for the scopes it targets; unmount removes those contributions after quiescence.

Token effect: Indirect token impact equals the mounted plugin's contributions and lasts only for the mount lifetime.

Known Limitations and Deferred Work

  • The sandbox is containment for honest code, not a security boundary — host-realm helpers on the sandbox global are reachable, so mount code can reach Node; load this plugin as deliberately as you would grant a bash tool (see § Trust stance).
  • The ctx façade exposes no effect() — mount code cannot register a bespoke disposer; on/provide/tools.register cover every mount seen so far, and a guarded effect waits on a real need (FIXME(sandbox-effect)).
  • vmTimeoutMs bounds only synchronous evaluation — an async mount body escapes it; there is no async budget on mount code.