From bea6a74ea0f44d1d9e0f0b5dde331a23f4c552ff Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sun, 19 Jul 2026 01:09:20 +0800 Subject: [PATCH] refactor(examples): give TUI its own agent leaf --- docs/graph-atlas.md | 1 + examples/README.md | 8 ++++- examples/coding-agent/README.md | 8 ++--- examples/coding-agent/code-mode.cordis.yml | 2 ++ examples/coding-agent/composition.md | 2 +- examples/coding-agent/cordis.yml | 12 +++----- examples/tui-agent/README.md | 19 ++++++++++++ examples/tui-agent/code-mode.cordis.yml | 30 +++++++++++++++++++ examples/tui-agent/composition.md | 28 +++++++++++++++++ examples/tui-agent/cordis.yml | 28 +++++++++++++++++ examples/tui-agent/package.json | 7 +++++ .../tests/fixtures/tui-scripted-llm.ts | 0 .../tests/fixtures/tui-scripted.cordis.yml | 0 .../tests/tui-keyless-smoke.e2e.ts | 8 ++--- knip.json | 2 +- package.json | 1 + scripts/demo-code-mode.mjs | 7 +++-- scripts/gen-doc-graphs.ts | 21 +++++++++++-- 18 files changed, 159 insertions(+), 25 deletions(-) create mode 100644 examples/tui-agent/README.md create mode 100644 examples/tui-agent/code-mode.cordis.yml create mode 100644 examples/tui-agent/composition.md create mode 100644 examples/tui-agent/cordis.yml create mode 100644 examples/tui-agent/package.json rename examples/{coding-agent => tui-agent}/tests/fixtures/tui-scripted-llm.ts (100%) rename examples/{coding-agent => tui-agent}/tests/fixtures/tui-scripted.cordis.yml (100%) rename examples/{coding-agent => tui-agent}/tests/tui-keyless-smoke.e2e.ts (95%) diff --git a/docs/graph-atlas.md b/docs/graph-atlas.md index 60de01ef81..5220cfa81f 100644 --- a/docs/graph-atlas.md +++ b/docs/graph-atlas.md @@ -14,6 +14,7 @@ The process decision behind this index is recorded in [the documentation graph R | [capability seams and core services](capability-seams.md) | `hybrid generated` | | [echo-agent app composition](../examples/echo-agent/composition.md) | `hybrid generated` | | [coding-agent app composition](../examples/coding-agent/composition.md) | `hybrid generated` | +| [tui-agent app composition](../examples/tui-agent/composition.md) | `hybrid generated` | | [cordis-agent app composition](../examples/cordis-agent/composition.md) | `hybrid generated` | | [acp-agent app composition](../examples/acp-agent/composition.md) | `hybrid generated` | | [event producer/consumer matrix](event-producer-consumer.md) | `hybrid generated` | diff --git a/examples/README.md b/examples/README.md index 25c017824f..03b798e164 100644 --- a/examples/README.md +++ b/examples/README.md @@ -15,12 +15,18 @@ Run with: `pnpm run demo:echo`. When prompted, type "echo " to trigge ## coding-agent -A coding-agent demo: DeepSeek V4 + the `read`/`write`/`edit` filesystem tools + the bash tool suite, `subagent` delegation, and the `todo_write` task tracker on the same `@deepseek-ai/dsh-stdio-demo` app. Interactive runs use the pi-tui coding interface; pipes use readline. +A coding-agent REPL: DeepSeek V4 + the `read`/`write`/`edit` filesystem tools + the bash tool suite, `subagent` delegation, and the `todo_write` task tracker on the `@deepseek-ai/dsh-stdio-demo` app's readline front door. Run with: `pnpm run demo:repl` (needs `DEEPSEEK_API_KEY` in the environment or a gitignored repo-root `.env`). See [coding-agent/README.md](coding-agent/README.md) for details. Run the Code Mode overlay with `pnpm run demo:code-mode`, or pass `acp` for the ACP example. See the [Code Mode example](coding-agent/README.md#code-mode) for its composition and a sample task. +## tui-agent + +The full-screen terminal sibling of `coding-agent`: it reuses the same coding backends and tools while forcing the shared terminal app to `dsh-tui`. It is the home of TUI PTY and snapshot scenarios. + +Run with: `pnpm run demo:tui` (needs `DEEPSEEK_API_KEY`). See [tui-agent/README.md](tui-agent/README.md) for controls and composition. + ## cordis-agent The **self-referential** demo: the coding spine plus [`@deepseek-ai/dsh-tool-cordis`](../packages/cordis/tool-cordis), whose three tools (`cordis_inspect` / `cordis_mount` / `cordis_unmount`) let the agent inspect the live cordis runtime it runs inside, mount model-written plugins into it (an event listener, a brand-new tool for itself, or a service another mount injects), and dispose them again — all dynamic mounts grouped under one `cordis-dynamic` fiber subtree. The `ctx.fs`/`ctx.web` services ride along provider-only, as the capabilities those plugins build on. diff --git a/examples/coding-agent/README.md b/examples/coding-agent/README.md index 9fdadf809d..f94cd31adb 100644 --- a/examples/coding-agent/README.md +++ b/examples/coding-agent/README.md @@ -1,6 +1,6 @@ # coding-agent -The coding-agent demo wiring: DeepSeek V4 + the `read`/`write`/`edit` filesystem tools + the bash tool suite + subagent delegation + `todo_write` + terminal chat + JSONL persistence, loaded from `cordis.yml`. Interactive runs use the pi-tui coding interface; piped runs use readline. +The coding-agent REPL wiring: DeepSeek V4 + the `read`/`write`/`edit` filesystem tools + the bash tool suite + subagent delegation + `todo_write` + readline chat + JSONL persistence, loaded from `cordis.yml`. The sibling [`tui-agent`](../tui-agent/README.md) fixes the same agent composition to the full-screen terminal front door. ## Run it @@ -13,7 +13,7 @@ pnpm run demo:repl Type a coding task. The agent works through the `read`/`write`/`edit` filesystem tools for ordinary file operations and `bash` (+ the generic `task_output` / `task_list` / `task_kill` for background tasks) for shell commands, searches, and test runs, each in a fresh `bash -c` (the system prompt tells the model to pass `workdir` instead of `cd`). Both the fs tools and bash resolve relative paths against the session workspace. It can also delegate with `subagent`/`subagent_fork` and track multi-step work with `todo_write`. -The TUI renders resumed Markdown history, reasoning, tool-owned terminal/diff/generic cards, token totals, and the latest todo list. Enter submits or steers while the agent is running; Ctrl+O expands cards, Ctrl+R toggles reasoning, Escape cancels, and `/help` lists commands. `ask_user_question` opens a keyboard-driven overlay rather than taking over the editor. +The REPL renders reasoning, tool calls/results, and the latest todo list as line-oriented output suitable for terminals and pipes. Use `pnpm run demo:tui` for the interactive Markdown/card interface. ### Resuming a prior session @@ -42,14 +42,14 @@ and watch the transcript: one `run_code` call, a program looping over tools, and ## What each leaf entry demonstrates -This example is a thin leaf `cordis.yml`: it picks the swappable backends, loads one app package, and adds product tools that are intentionally outside the shared spine. The spine (sessions, system-prompt, tools, agents, invariants, `agent-loop`) and the front-door cluster (JSONL persistence, TTY-selected `dsh-tui`/`dsh-stdio` channels, the pre-created `main` agent) live inside the [`@deepseek-ai/dsh-stdio-demo`](../../packages/examples/stdio-demo) app and the [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) bundle it loads; the leaf wires the backends and model-facing optional tools: +This example is a thin leaf `cordis.yml`: it picks the swappable backends, loads one app package, and adds product tools that are intentionally outside the shared spine. The spine (sessions, system-prompt, tools, agents, invariants, `agent-loop`) and the front-door cluster (JSONL persistence, the selected terminal channel, the pre-created `main` agent) live inside the [`@deepseek-ai/dsh-stdio-demo`](../../packages/examples/stdio-demo) app and the [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) bundle it loads; the leaf wires the backends and model-facing optional tools: | Entry | Demonstrates | |---|---| | `hmr` (`@cordisjs/plugin-hmr`) | the dev/demo edit-reload loop — a **leaf** entry (not baked into the app) because it is Loader-only and needs `node --expose-internals`, which `demo:repl` passes | | `llm-deepseek` | real `LlmAdapter` via config (`!!js process.env.…` secrets); swap one line to `@deepseek-ai/dsh-llm-pi-ai` for the library-backed twin | | `bash` (`dsh-bash-local`) | the executor implementation — the swappable half of the bash seam. The model-facing `bash` schema (`tool-bash`) and generic `task_*` controls (`tool-tasks`) come from `dsh-agent-spine-demo`, so only the executor is a leaf choice | -| `stdio-agent` (`@deepseek-ai/dsh-stdio-demo`) | the app bundle: the agent-spine demo + JSONL persistence + TTY-selected `dsh-tui`/`dsh-stdio` channels + a pre-created `main` agent. Its config carries the model, system prompt, `persistenceRoot` (`./.sessions`), `resumeSessionId`, and optional `ui` presentation settings | +| `stdio-agent` (`@deepseek-ai/dsh-stdio-demo`) | the app bundle: the agent-spine demo + JSONL persistence + the configured terminal channel + a pre-created `main` agent. This leaf fixes `ui.mode` to `readline`; `tui-agent` owns the corresponding TUI leaf | | `subagent`, `subagent-spawn`, `subagent-fork` | the subagent provider registry plus the two in-process backends: a fresh child and a child seeded with the parent's completed-turn prefix | | `tool-subagent`, `tool-subagent-fork` | two model-facing `dsh-tool-subagent` loads, each bound to a different provider and exposed under a distinct tool name (`subagent`, `subagent_fork`) | | `tool-todo` | the model-facing `todo_write` tool; writes the whole task list to the session log and renders as a persistent TUI plan or readline checklist | diff --git a/examples/coding-agent/code-mode.cordis.yml b/examples/coding-agent/code-mode.cordis.yml index 3fec40e0f3..b1f62829bc 100644 --- a/examples/coding-agent/code-mode.cordis.yml +++ b/examples/coding-agent/code-mode.cordis.yml @@ -20,6 +20,8 @@ tools: mode: code welcome: 'code-mode agent ready. Give it a multi-tool task.' + ui: + mode: readline persona: | You are coding-agent, a coding assistant powered by the {{model}} model. diff --git a/examples/coding-agent/composition.md b/examples/coding-agent/composition.md index d0411e43d9..2956291dc8 100644 --- a/examples/coding-agent/composition.md +++ b/examples/coding-agent/composition.md @@ -18,7 +18,7 @@ flowchart LR cfg --> plugin_coding_stdio_agent plugin_coding_stdio_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"] plugin_coding_stdio_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"] - plugin_coding_stdio_agent --> frontdoor_stdio["dsh-tui (TTY) / dsh-stdio (pipes)
pre-created main agent"] + plugin_coding_stdio_agent --> frontdoor_stdio["@deepseek-ai/dsh-stdio
pre-created main agent"] bundle_agent_core --> spine_llm["ctx.llm"] bundle_agent_core --> spine_sessions["ctx.sessions"] bundle_agent_core --> spine_tools["ctx.tools + tool-bash"] diff --git a/examples/coding-agent/cordis.yml b/examples/coding-agent/cordis.yml index d3da67ce29..497e2a80c8 100644 --- a/examples/coding-agent/cordis.yml +++ b/examples/coding-agent/cordis.yml @@ -1,7 +1,6 @@ -# Coding agent with swappable DeepSeek and local-bash backends. `dsh-stdio-demo` -# supplies the agent spine, workspace instructions, generic task controls, -# JSONL persistence, TTY-selected `dsh-tui`/`dsh-stdio` terminal front doors, -# readline logging, and `main` agent. +# Readline coding REPL with swappable DeepSeek and local-bash backends. +# `dsh-stdio-demo` supplies the agent spine, workspace instructions, generic +# task controls, JSONL persistence, the line-oriented front door, and `main`. # HMR remains a leaf because it requires Loader internals; `demo:repl` passes # `--expose-internals`. The app bin loads the gitignored root `.env`; this file # reads `DEEPSEEK_API_KEY` and optional `DEEPSEEK_BASE_URL` through `!!js`. @@ -39,10 +38,7 @@ maxBytes: 65536 welcome: 'agent REPL ready. Give it a coding task.' ui: - mode: auto - tui: - showReasoning: true - maxToolOutputLines: 12 + mode: readline # Keep the persona to identity and behavior; tool plugins own tool guidance. # The loop resolves {{model}} from this agent's configuration. persona: | diff --git a/examples/tui-agent/README.md b/examples/tui-agent/README.md new file mode 100644 index 0000000000..909ccf700d --- /dev/null +++ b/examples/tui-agent/README.md @@ -0,0 +1,19 @@ +# tui-agent + +The full-screen terminal counterpart to the [`coding-agent`](../coding-agent/README.md) readline REPL and [`acp-agent`](../acp-agent/README.md) server. It reuses the coding agent's backends and tool composition, then fixes the shared terminal app to the `dsh-tui` front door. + +## Run it + +```sh +pnpm run demo:tui +``` + +The command needs `DEEPSEEK_API_KEY` in the environment or the gitignored repository-root `.env`. Set `RESUME_SESSION_ID` to reopen a persisted conversation under `./.sessions`. + +The TUI renders Markdown history, reasoning, tool-owned terminal/diff/generic cards, token totals, and the latest todo list. Enter submits or steers while the agent is running; Ctrl+O expands cards, Ctrl+R toggles reasoning, Escape cancels, and `/help` lists commands. `ask_user_question` opens a keyboard-driven overlay. + +Run `pnpm run demo:code-mode tui` for the sibling Code Mode overlay. + +## Composition + +[`cordis.yml`](cordis.yml) includes the readline coding-agent leaf so the LLM, bash, filesystem, compaction, subagent, workflow, todo, timeout, and spill choices have one owner. Its asserted patch replaces only the terminal app config and forces `ui.mode: tui`; [`code-mode.cordis.yml`](code-mode.cordis.yml) applies the same front-door patch to the coding agent's Code Mode overlay. diff --git a/examples/tui-agent/code-mode.cordis.yml b/examples/tui-agent/code-mode.cordis.yml new file mode 100644 index 0000000000..7bb7932ba0 --- /dev/null +++ b/examples/tui-agent/code-mode.cordis.yml @@ -0,0 +1,30 @@ +# Code Mode keeps the TUI front door while reusing the coding-agent overlay's +# worker runtime and one-tool registry composition. +- id: base + name: '@cordisjs/plugin-include' + config: + path: ../coding-agent/code-mode.cordis.yml + patches: + - id: stdio-agent + name: '@deepseek-ai/dsh-stdio-demo' + config: + provider: deepseek + model: deepseek-v4-flash + resumeSessionId: !!js process.env.RESUME_SESSION_ID + persistenceRoot: './.sessions' + workspaceContext: + maxBytes: 65536 + tools: + mode: code + welcome: 'TUI Code Mode ready. Give it a multi-tool task.' + ui: + mode: tui + tui: + showReasoning: true + maxToolOutputLines: 12 + persona: | + You are coding-agent, a coding assistant powered by the {{model}} model. + + You work by writing TypeScript programs for run_code: batch related + tool work into one program, loop and branch where it helps, and print + or return ONLY the findings that matter. diff --git a/examples/tui-agent/composition.md b/examples/tui-agent/composition.md new file mode 100644 index 0000000000..511f76d41e --- /dev/null +++ b/examples/tui-agent/composition.md @@ -0,0 +1,28 @@ + + +# TUI Agent App Composition + +The TUI agent reuses the coding-agent backend and tool composition while fixing the shared terminal app to the full-screen dsh-tui front door. + +```mermaid +flowchart LR + cfg["examples/tui-agent
cordis.yml"] + plugin_tui_base["base
@deepseek-ai/dsh-stdio-demo"] + cfg --> plugin_tui_base + plugin_tui_base --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"] + plugin_tui_base --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"] + plugin_tui_base --> frontdoor_stdio["@deepseek-ai/dsh-tui
pre-created main agent"] + bundle_agent_core --> spine_llm["ctx.llm"] + bundle_agent_core --> spine_sessions["ctx.sessions"] + bundle_agent_core --> spine_tools["ctx.tools + tool-bash"] + bundle_agent_core --> spine_loop["ctx.agents + ctx.agentLoop"] +``` + +| Plugin id | Package / module | +| --- | --- | +| `base` | `@deepseek-ai/dsh-stdio-demo` | + +Source config: [`examples/tui-agent/cordis.yml`](cordis.yml). + +Maintenance mode: hybrid: the leaf plugin list is parsed from its `cordis.yml`; app package expansion is curated from package source. diff --git a/examples/tui-agent/cordis.yml b/examples/tui-agent/cordis.yml new file mode 100644 index 0000000000..0f329c38e2 --- /dev/null +++ b/examples/tui-agent/cordis.yml @@ -0,0 +1,28 @@ +# Full-screen TUI front door over the same coding-agent composition used by the +# readline REPL. The include keeps backends and optional tools aligned; the +# patch owns only the terminal-specific app config. +- id: base + name: '@cordisjs/plugin-include' + config: + path: ../coding-agent/cordis.yml + patches: + - id: stdio-agent + name: '@deepseek-ai/dsh-stdio-demo' + config: + provider: deepseek + model: deepseek-v4-flash + resumeSessionId: !!js process.env.RESUME_SESSION_ID + persistenceRoot: './.sessions' + workspaceContext: + maxBytes: 65536 + welcome: 'TUI agent ready. Give it a coding task.' + ui: + mode: tui + tui: + showReasoning: true + maxToolOutputLines: 12 + persona: | + You are coding-agent, a coding assistant powered by the {{model}} model. + + Verify your work by running the code or tests. Keep answers brief and + factual. diff --git a/examples/tui-agent/package.json b/examples/tui-agent/package.json new file mode 100644 index 0000000000..f45e6746a3 --- /dev/null +++ b/examples/tui-agent/package.json @@ -0,0 +1,7 @@ +{ + "name": "tui-agent-example", + "private": true, + "version": "0.0.1", + "type": "module", + "description": "Runnable demo: the coding agent through the full-screen terminal UI" +} diff --git a/examples/coding-agent/tests/fixtures/tui-scripted-llm.ts b/examples/tui-agent/tests/fixtures/tui-scripted-llm.ts similarity index 100% rename from examples/coding-agent/tests/fixtures/tui-scripted-llm.ts rename to examples/tui-agent/tests/fixtures/tui-scripted-llm.ts diff --git a/examples/coding-agent/tests/fixtures/tui-scripted.cordis.yml b/examples/tui-agent/tests/fixtures/tui-scripted.cordis.yml similarity index 100% rename from examples/coding-agent/tests/fixtures/tui-scripted.cordis.yml rename to examples/tui-agent/tests/fixtures/tui-scripted.cordis.yml diff --git a/examples/coding-agent/tests/tui-keyless-smoke.e2e.ts b/examples/tui-agent/tests/tui-keyless-smoke.e2e.ts similarity index 95% rename from examples/coding-agent/tests/tui-keyless-smoke.e2e.ts rename to examples/tui-agent/tests/tui-keyless-smoke.e2e.ts index cc2397c069..26cee8aea2 100644 --- a/examples/coding-agent/tests/tui-keyless-smoke.e2e.ts +++ b/examples/tui-agent/tests/tui-keyless-smoke.e2e.ts @@ -53,7 +53,7 @@ while time.monotonic() < deadline: if scenario == "conversation" and answered_question and not sent_exit and b"Decision received. Scripted TUI run complete." in output: os.write(fd, b"/exit\r") sent_exit = True - if scenario == "boot" and not sent_exit and b"agent REPL ready." in output: + if scenario == "boot" and not sent_exit and b"TUI agent ready." in output: os.write(fd, b"/exit\r") sent_exit = True waited, candidate = os.waitpid(pid, os.WNOHANG) @@ -101,7 +101,7 @@ interface TuiLoaderSmokeOptions { } async function runTuiLoaderSmoke(options: TuiLoaderSmokeOptions = {}): Promise { - const cwd = await mkdtemp(join(tmpdir(), 'coding-tui-smoke-')) + const cwd = await mkdtemp(join(tmpdir(), 'tui-agent-smoke-')) try { const launch = resolveExampleLaunch({ srcBin: binScript, @@ -142,11 +142,11 @@ async function runTuiLoaderSmoke(options: TuiLoaderSmokeOptions = {}): Promise { +describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => { it('boots pi-tui, renders the configured banner, accepts /exit, and restores the terminal', async () => { const output = await runTuiLoaderSmoke() expect(output).toContain('DEEPSEEK') - expect(output).toContain('agent REPL ready.') + expect(output).toContain('TUI agent ready.') expect(output).toContain('\u001B[?2004l') }, LOADER_SMOKE_TEST_TIMEOUT_MS) diff --git a/knip.json b/knip.json index 03fae14896..db77587b48 100644 --- a/knip.json +++ b/knip.json @@ -10,7 +10,7 @@ "examples": { "entry": [ "echo-agent/src/*.ts", - "coding-agent/tests/fixtures/tui-scripted-llm.ts", + "tui-agent/tests/fixtures/tui-scripted-llm.ts", "*/tests/**/*.e2e.ts", "*/tests/**/*.snapshot.ts" ], diff --git a/package.json b/package.json index 39d6a53161..ca85fd32d2 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "hygiene": "pnpm run knip && pnpm run publint && pnpm run constraints && pnpm run verify-cordis-config && pnpm run verify-node-next-types && pnpm run verify-runtime-closure", "demo:echo": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/echo-agent/cordis.yml", "demo:repl": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/coding-agent/cordis.yml", + "demo:tui": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/tui-agent/cordis.yml", "demo:code-mode": "node scripts/demo-code-mode.mjs", "demo:cordis": "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/cordis-agent/cordis.yml", "demo:acp": "node --import tsx packages/examples/acp-demo/src/bin.ts --config examples/acp-agent/cordis.yml", diff --git a/scripts/demo-code-mode.mjs b/scripts/demo-code-mode.mjs index edfc26b4d5..7a5e054cc0 100644 --- a/scripts/demo-code-mode.mjs +++ b/scripts/demo-code-mode.mjs @@ -1,7 +1,7 @@ /** - * Boot the REPL or ACP Code Mode overlay, defaulting to REPL. Each overlay + * Boot the REPL, TUI, or ACP Code Mode overlay, defaulting to REPL. Each overlay * includes its base example, selects Code Mode, and adds the worker runtime. - * Both require a DeepSeek API key; unsupported arguments fail with usage. + * All require a DeepSeek API key; unsupported arguments fail with usage. */ import { spawn } from 'node:child_process' @@ -10,13 +10,14 @@ import { spawn } from 'node:child_process' // Loader's HMR path). const UIS = new Map([ ['repl', ['--expose-internals', '--import', 'tsx', 'packages/examples/stdio-demo/src/bin.ts', 'examples/coding-agent/code-mode.cordis.yml']], + ['tui', ['--expose-internals', '--import', 'tsx', 'packages/examples/stdio-demo/src/bin.ts', 'examples/tui-agent/code-mode.cordis.yml']], ['acp', ['--import', 'tsx', 'packages/examples/acp-demo/src/bin.ts', '--config', 'examples/acp-agent/code-mode.cordis.yml']], ]) const ui = process.argv[2] ?? 'repl' const args = UIS.get(ui) if (!args || process.argv.length > 3) { - console.error('usage: pnpm run demo:code-mode [repl|acp]') + console.error('usage: pnpm run demo:code-mode [repl|tui|acp]') process.exit(2) } diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index 5bf0a9456c..29cea3f9a0 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -434,6 +434,14 @@ const APP_EXAMPLES = [ config: 'examples/coding-agent/cordis.yml', summary: 'The coding-agent demo adds the real DeepSeek adapter, filesystem tools, todo_write, compaction, and both subagent transports on top of the stdio app package.', }, + { + id: 'tui', + rel: 'examples/tui-agent/composition.md', + title: 'TUI Agent App Composition', + label: 'examples/tui-agent', + config: 'examples/tui-agent/cordis.yml', + summary: 'The TUI agent reuses the coding-agent backend and tool composition while fixing the shared terminal app to the full-screen dsh-tui front door.', + }, { id: 'cordis', rel: 'examples/cordis-agent/composition.md', @@ -454,13 +462,18 @@ const APP_EXAMPLES = [ type AppExample = typeof APP_EXAMPLES[number] -function renderAppExpansion(lines: string[], appNode: string, pluginName: string): void { +function renderAppExpansion(lines: string[], appNode: string, pluginName: string, exampleId: string): void { const agentCore = nodeId('bundle', 'agent_core') const jsonl = nodeId('bundle', 'jsonl') lines.push(` ${appNode} --> ${agentCore}["@deepseek-ai/dsh-agent-spine-demo"]`) lines.push(` ${appNode} --> ${jsonl}["@deepseek-ai/dsh-session-persistence-jsonl"]`) if (pluginName === '@deepseek-ai/dsh-stdio-demo') { - lines.push(` ${appNode} --> ${nodeId('frontdoor', 'stdio')}["dsh-tui (TTY) / dsh-stdio (pipes)
pre-created main agent"]`) + const frontDoor = exampleId === 'tui' + ? '@deepseek-ai/dsh-tui
pre-created main agent' + : exampleId === 'coding' + ? '@deepseek-ai/dsh-stdio
pre-created main agent' + : 'dsh-tui (TTY) / dsh-stdio (pipes)
pre-created main agent' + lines.push(` ${appNode} --> ${nodeId('frontdoor', 'stdio')}["${frontDoor}"]`) } else if (pluginName === '@deepseek-ai/dsh-acp-demo') { lines.push(` ${appNode} --> ${nodeId('frontdoor', 'acp')}["@deepseek-ai/dsh-acp
JSON-RPC stdio bridge
sessions created by client"]`) } @@ -488,7 +501,7 @@ function renderAppComposition(example: AppExample): string { lines.push(` ${pluginNode}["${escLabel(plugin.id)}
${escLabel(plugin.name)}"]`) lines.push(` cfg --> ${pluginNode}`) if (plugin.name === '@deepseek-ai/dsh-stdio-demo' || plugin.name === '@deepseek-ai/dsh-acp-demo') { - renderAppExpansion(lines, pluginNode, plugin.name) + renderAppExpansion(lines, pluginNode, plugin.name, example.id) } } lines.push( @@ -978,6 +991,7 @@ function renderIndex(docs: GraphDoc[]): string { 'docs/capability-seams.md': 'capability seams and core services', 'examples/echo-agent/composition.md': 'echo-agent app composition', 'examples/coding-agent/composition.md': 'coding-agent app composition', + 'examples/tui-agent/composition.md': 'tui-agent app composition', 'examples/cordis-agent/composition.md': 'cordis-agent app composition', 'examples/acp-agent/composition.md': 'acp-agent app composition', 'docs/event-producer-consumer.md': 'event producer/consumer matrix', @@ -989,6 +1003,7 @@ function renderIndex(docs: GraphDoc[]): string { 'docs/capability-seams.md': 'hybrid generated', 'examples/echo-agent/composition.md': 'hybrid generated', 'examples/coding-agent/composition.md': 'hybrid generated', + 'examples/tui-agent/composition.md': 'hybrid generated', 'examples/cordis-agent/composition.md': 'hybrid generated', 'examples/acp-agent/composition.md': 'hybrid generated', 'docs/event-producer-consumer.md': 'hybrid generated',