2026-06-16 21:00:24 +08:00
<!-- Generated by scripts/gen - module - graph.ts — do not edit by hand.
Run `pnpm run gen-module-graph` to regenerate. -->
# Module dependency graph
2026-06-16 21:21:21 +08:00
Inter-package dependencies among the `@deepseek-ai/dsh-*` harness packages, derived from each package's `peerDependencies` (the canonical runtime-dependency signal). An edge `a --> b` means package `a` depends on package `b` . Names have the `@deepseek-ai/dsh-` prefix stripped.
2026-06-16 21:00:24 +08:00
```mermaid
graph TD
2026-06-16 21:11:09 +08:00
bash-local --> bash
llm-deepseek --> llm
llm-pi-ai --> llm
session --> llm
system-prompt --> llm
2026-06-16 21:00:24 +08:00
agent --> llm
agent --> session
2026-06-16 23:16:59 +08:00
session-persistence --> session
2026-06-16 21:11:09 +08:00
invariants --> agent
invariants --> llm
invariants --> session
2026-06-16 23:16:59 +08:00
session-persistence-jsonl --> session
session-persistence-jsonl --> session-persistence
2026-06-16 23:19:45 +08:00
session-persistence-sqlite --> session
session-persistence-sqlite --> session-persistence
2026-06-16 21:11:09 +08:00
tools --> agent
tools --> llm
tools --> system-prompt
feat(acp): tool-owned tool-call UI presentation (title/command/output)
In Zed the tool-call card showed only "bash" — the bare tool name — instead
of what the command does. Fix it by letting each TOOL own how its calls render,
rather than the bridge special-casing names.
dsh-tools: add an optional two-state presentation seam to ToolDefinition /
defineTool — `presentCall(args)` (pending: title, kind, rawInput) and
`presentResult(args, result)` (completed: title?, content?). Provider-neutral
`ToolCallKind`/`ToolCallPresentation`/`ToolResultPresentation` vocabulary so
tools never depend on ACP. defineTool soft-validates args (display runs on log
replay, so a malformed/old shape returns undefined instead of throwing).
dsh-tool-bash: bash declares presentCall (model `description` → title, exact
`command` → rawInput, kind execute) and presentResult (wrap output in a fenced
```console block — a UI-only affordance kept out of the model-facing result);
bash_output/bash_kill present task-scoped titles.
dsh-acp: inject `tools`; a per-session `ToolPresenter` looks the tool up by name
and maps its neutral presentation to the ACP tool_call/tool_call_update wire
shape, with a generic fallback (title = name) for tools that declare nothing.
Because the `tool/result` event carries only {callId, content, isError}, the
presenter keeps a small bridge-local map of ONLY in-flight calls' (name, args),
keyed by callId and removed as each result is presented — no event-schema or
core change. Replay uses a throwaway presenter so loaded sessions render
identically to live ones.
Tests: dsh-tools defineTool presenters (typed args, soft-validate), tool-bash
bash/bash_output/bash_kill presenters, acp ToolPresenter (tool-owned mapping,
unknown-callId fallback, in-flight-only map), and an end-to-end turn through the
bridge. The key-gated e2e now asserts a real bash call's title is the model
description (not "bash") and rawInput is the command — verified against the real
DeepSeek model. The test harness derives its inject from the bridge's exported
`inject` so it can't drift again.
2026-06-18 09:01:36 +08:00
acp --> agent
acp --> llm
acp --> session
acp --> session-persistence
acp --> tools
2026-06-16 21:00:24 +08:00
agent-loop --> agent
agent-loop --> llm
agent-loop --> session
2026-06-16 23:18:31 +08:00
agent-loop --> session-persistence
2026-06-16 21:00:24 +08:00
agent-loop --> system-prompt
agent-loop --> tools
tool-bash --> agent
tool-bash --> bash
tool-bash --> llm
tool-bash --> tools
```
| Package | Depends on |
| --- | --- |
| `bash` | — |
| `llm` | — |
2026-06-16 21:11:09 +08:00
| `bash-local` | `bash` |
2026-06-16 21:00:24 +08:00
| `llm-deepseek` | `llm` |
| `llm-pi-ai` | `llm` |
| `session` | `llm` |
| `system-prompt` | `llm` |
2026-06-16 21:11:09 +08:00
| `agent` | `llm` , `session` |
2026-06-16 23:16:59 +08:00
| `session-persistence` | `session` |
2026-06-16 21:11:09 +08:00
| `invariants` | `agent` , `llm` , `session` |
2026-06-16 23:16:59 +08:00
| `session-persistence-jsonl` | `session` , `session-persistence` |
2026-06-16 23:19:45 +08:00
| `session-persistence-sqlite` | `session` , `session-persistence` |
2026-06-16 21:00:24 +08:00
| `tools` | `agent` , `llm` , `system-prompt` |
feat(acp): tool-owned tool-call UI presentation (title/command/output)
In Zed the tool-call card showed only "bash" — the bare tool name — instead
of what the command does. Fix it by letting each TOOL own how its calls render,
rather than the bridge special-casing names.
dsh-tools: add an optional two-state presentation seam to ToolDefinition /
defineTool — `presentCall(args)` (pending: title, kind, rawInput) and
`presentResult(args, result)` (completed: title?, content?). Provider-neutral
`ToolCallKind`/`ToolCallPresentation`/`ToolResultPresentation` vocabulary so
tools never depend on ACP. defineTool soft-validates args (display runs on log
replay, so a malformed/old shape returns undefined instead of throwing).
dsh-tool-bash: bash declares presentCall (model `description` → title, exact
`command` → rawInput, kind execute) and presentResult (wrap output in a fenced
```console block — a UI-only affordance kept out of the model-facing result);
bash_output/bash_kill present task-scoped titles.
dsh-acp: inject `tools`; a per-session `ToolPresenter` looks the tool up by name
and maps its neutral presentation to the ACP tool_call/tool_call_update wire
shape, with a generic fallback (title = name) for tools that declare nothing.
Because the `tool/result` event carries only {callId, content, isError}, the
presenter keeps a small bridge-local map of ONLY in-flight calls' (name, args),
keyed by callId and removed as each result is presented — no event-schema or
core change. Replay uses a throwaway presenter so loaded sessions render
identically to live ones.
Tests: dsh-tools defineTool presenters (typed args, soft-validate), tool-bash
bash/bash_output/bash_kill presenters, acp ToolPresenter (tool-owned mapping,
unknown-callId fallback, in-flight-only map), and an end-to-end turn through the
bridge. The key-gated e2e now asserts a real bash call's title is the model
description (not "bash") and rawInput is the command — verified against the real
DeepSeek model. The test harness derives its inject from the bridge's exported
`inject` so it can't drift again.
2026-06-18 09:01:36 +08:00
| `acp` | `agent` , `llm` , `session` , `session-persistence` , `tools` |
2026-06-16 23:18:31 +08:00
| `agent-loop` | `agent` , `llm` , `session` , `session-persistence` , `system-prompt` , `tools` |
2026-06-16 21:11:09 +08:00
| `tool-bash` | `agent` , `bash` , `llm` , `tools` |