# Conflicts: # docs/config-catalog.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.md # docs/event-producer-consumer.md # docs/persistence-catalog.md # docs/rfc/implemented/feature/2026-06-15-code-mode.md # docs/rfc/implemented/feature/2026-06-30-interception-seams.md # docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md # docs/tool-execution-pipeline.md # packages/cordis/tool-cordis/src/api-catalog.ts # packages/core/agent-core/tests/agent-core.spec.ts # packages/core/agent-loop/src/agent.ts # packages/core/agent/README.md # packages/core/session/src/index.ts # packages/core/tools/README.md # packages/core/tools/src/index.ts # pnpm-lock.yaml # scripts/gen-doc-graphs.ts # scripts/type-equiv.manifest.json
echo-agent
Runnable demo: stdin chat with a scripted mock model and an echo tool. The all-mock skeleton — "swap the backend, keep the app".
What it shows
This example is just a leaf cordis.yml: it loads the @deepseek-ai/dsh-stdio-agent app (which bundles the whole @deepseek-ai/dsh-agent-core spine, the console logger, JSONL persistence, the readline UI, and a pre-created main agent), and swaps in two example-local backends plus hmr:
mock-llm.ts— a mockLlmAdapterthat streams scripted responses and calls theechotool when the user types "echo ". Registered withctx.llm.registerAdapter(['mock-echo'], …).echo-tool.ts— a tool registered viactx.tools.register(defineTool(…))with typedexecuteargs; echoes text back uppercased.
Swapping mock-llm for the real llm-deepseek adapter is all that separates this from coding-agent — the same app, a different backend.
Plugin files
| File | Role | Key patterns demonstrated |
|---|---|---|
src/mock-llm.ts |
LlmAdapter registration |
ctx.llm.registerAdapter(['mock-echo'], …), streaming chunks with the proper block-start/block-end protocol |
src/echo-tool.ts |
Tool registration | ctx.tools.register(defineTool(…)) with typed execute args, returning ContentBlock[] |
cordis.yml |
Leaf wiring | the two backends + hmr + one @deepseek-ai/dsh-stdio-agent entry carrying the app config |
The spine, UI, persistence, and boot glue all live in @deepseek-ai/dsh-stdio-agent and the bundle it loads — this folder holds only the demo-specific mocks and the leaf wiring.
Run
pnpm run demo:echo
# or:
node --expose-internals --import tsx packages/ui/stdio-agent/src/bin.ts examples/echo-agent/cordis.yml
Type a message and press Enter. "echo " triggers a tool call round-trip (the mock model requests the echo tool, which echoes the text uppercased, and the next model step acknowledges it).
The session is persisted under .sessions/ relative to the directory you launch the demo from. pnpm run demo:echo runs from the repo root, so the logs land in <repo-root>/.sessions/cwd-<hash>/ (one .jsonl log per session). Clean up with: rm -rf .sessions