mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
chore(examples): make todo_write opt-in for the tui-agent example
Make todo_write opt-in for the tui-agent example (disabled by default; TUI still renders plans when the tool is loaded). Both enabled and disabled cases covered by tests.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
2026-07-21-tui-todo-write-opt-in.md: 30797568f2b37180f8a9c837cb4ae7f10b6125eb
|
||||
2026-07-21-tui-todo-write-opt-in.zh.md: 29a779bbd765a42a12e8561c87375d742dd8bd4b
|
||||
@@ -0,0 +1,27 @@
|
||||
# Agent Note: Ship the TUI without `todo_write`; keep it a one-line opt-in
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-07-21-tui-todo-write-opt-in.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The shipped tui-agent `cordis.yml` loaded `@deepseek-ai/dsh-tool-todo`, exposing `todo_write` by default. The tool is a task-tracking convenience, not a core coding affordance like `bash` or the `read`/`write`/`edit` fs tools; most TUI sessions never call it, yet shipping it enlarges the wire tool list and system prompt for every turn. Meanwhile the TUI's plan rendering is event-driven: `packages/ui/tui/src/index.ts` listens for the `todo/write` session event and `TodoComponent.render` returns nothing when the list is empty, so the front door already tolerates the tool being absent or present with no runtime coupling to the plugin.
|
||||
|
||||
## Decision
|
||||
|
||||
The tui-agent `cordis.yml` no longer loads `tool-todo`; `todo_write` is opt-in. The `code-mode.cordis.yml` overlay inherits the base composition, so its generated SDK drops `todo_write` too. Enabling it is one entry — add `@deepseek-ai/dsh-tool-todo` to `cordis.yml` (or a `~/.config/dsh` personal overlay) — after which the model logs the whole-list `todo/write` snapshot and the TUI renders the plan, unchanged. The `TodoItem` type and the `todo/write` event stay in `@deepseek-ai/dsh-session` and the TUI's plan rendering stays wired, so both the default (disabled) and opt-in (enabled) paths are first-class. The sibling acp-agent, headless-agent, and jsonrpc-agent examples still ship the tool.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep `todo_write` in the shipped TUI default** — rejected: it is an opt-in convenience, not a core tool, and shipping it spends every turn's tool-list and prompt budget on a feature most sessions ignore. The examples that still ship it retain the plugin's real-composition coverage.
|
||||
|
||||
**Drop the TUI's plan rendering and todo tests along with the default entry** — rejected: the requirement is to support both the enabled and disabled cases, and the event-driven `TodoComponent` already renders plans with zero plugin coupling, so deleting it would discard a working capability for no gain. The enabled path keeps dedicated coverage instead.
|
||||
|
||||
## Testing
|
||||
|
||||
`examples/tui-agent/tests/tui.snapshot.ts` mounts `ToolTodo` only when a scenario sets `enableTodo`: only the `todo-plan` scenario does (the enabled-path proof, whose `session.jsonl`/`terminal.expected.txt` pin the rendered plan), while every other scenario runs the default todo-free composition. `tests/harness.ts` makes `ToolTodo` a `todo` opt-in that only `tests/todo-write.e2e.ts` sets, so the with-key todo e2e still drives the real tool while the other suites match the shipped stack. The keyless `tests/tui-keyless-smoke.e2e.ts` boots the real `cordis.yml` and asserts nothing about todo, so the default boot is unaffected.
|
||||
|
||||
## Consequences
|
||||
|
||||
The default TUI wire tool list and system prompt shrink by one tool; a session that wants task tracking adds one plugin entry. `examples/tui-agent/composition.md` (regenerated) and its leaf-entry table no longer list `tool-todo`, and the curated summary in `scripts/gen-doc-graphs.ts` drops it. The `@deepseek-ai/dsh-tool-todo` package is unchanged and still shipped by the acp/headless/jsonrpc examples, so its coverage requirement is met there. Restoring the default would re-add the one `cordis.yml` entry and flip the snapshot/harness opt-in flags back on.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Agent Note: Ship the TUI without `todo_write`; keep it a one-line opt-in
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-07-21-tui-todo-write-opt-in.md) | 中文
|
||||
|
||||
## Problem
|
||||
|
||||
出厂的 tui-agent `cordis.yml` 加载了 `@deepseek-ai/dsh-tool-todo`,默认向模型暴露 `todo_write`。这个工具是一项任务追踪的便利功能,而非像 `bash` 或 `read`/`write`/`edit` 文件系统工具那样的核心编码能力;多数 TUI 会话从不调用它,但出厂加载它会让每一轮的协议工具列表和系统提示词都随之变大。而 TUI 的计划渲染是事件驱动的:`packages/ui/tui/src/index.ts` 监听 `todo/write` 会话事件,`TodoComponent.render` 在列表为空时不返回任何内容,因此这个入口本就能容忍该工具的缺席或存在,与该插件没有任何运行时耦合。
|
||||
|
||||
## Decision
|
||||
|
||||
tui-agent `cordis.yml` 不再加载 `tool-todo`;`todo_write` 改为可选启用。`code-mode.cordis.yml` 覆盖配置继承基础组合,因此它生成的 SDK 同样不再包含 `todo_write`。启用它只需一条配置项——把 `@deepseek-ai/dsh-tool-todo` 加入 `cordis.yml`(或 `~/.config/dsh` 的个人覆盖配置)——此后模型照旧记录整份清单的 `todo/write` 快照,TUI 照旧渲染该计划。`TodoItem` 类型与 `todo/write` 事件仍留在 `@deepseek-ai/dsh-session`,TUI 的计划渲染也保持接线,因此默认(禁用)与可选启用(启用)两条路径都是一等公民。同类的 acp-agent、headless-agent、jsonrpc-agent 示例仍然出厂携带该工具。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**在出厂的 TUI 默认配置中保留 `todo_write`。** 否决:它是一项可选启用的便利功能,而非核心工具,出厂加载它会为多数会话都忽略的功能花掉每一轮的工具列表与提示词预算。仍然携带它的示例保留了该插件的真实组合覆盖。
|
||||
|
||||
**连同默认配置项一起删掉 TUI 的计划渲染与 todo 测试。** 否决:需求是同时支持启用与禁用两种情形,而事件驱动的 `TodoComponent` 本就在零插件耦合下渲染计划,删掉它等于白白丢弃一项可用能力。取而代之,启用路径保留专门的覆盖。
|
||||
|
||||
## Testing
|
||||
|
||||
`examples/tui-agent/tests/tui.snapshot.ts` 根据逐场景的 `enableTodo` 开关决定是否挂载 `ToolTodo`:只有 `todo-plan` 场景挂载它(启用路径的证明,其 `session.jsonl`/`terminal.expected.txt` 固定了渲染出的计划),其余每个场景都运行默认的无 todo 组合。`tests/harness.ts` 把 `ToolTodo` 做成一个 `todo` 可选项,只有 `tests/todo-write.e2e.ts` 会开启它,因此带密钥的 todo e2e 仍然驱动真实工具,而其余套件与出厂技术栈保持一致。无密钥的 `tests/tui-keyless-smoke.e2e.ts` 启动真实的 `cordis.yml`,且不对 todo 作任何断言,因此默认启动不受影响。
|
||||
|
||||
## Consequences
|
||||
|
||||
默认 TUI 的协议工具列表和系统提示词少了一个工具;想要任务追踪的会话加一条插件配置项即可。`examples/tui-agent/composition.md`(已重新生成)及其叶子条目表不再列出 `tool-todo`,`scripts/gen-doc-graphs.ts` 中人工维护的摘要也去掉了它。`@deepseek-ai/dsh-tool-todo` 包本身没有变动,仍由 acp/headless/jsonrpc 示例出厂携带,因此它的覆盖需求在那里得到满足。若要恢复默认,只需重新加入那一条 `cordis.yml` 配置项,并把快照/harness 的可选开关重新打开。
|
||||
@@ -47,6 +47,12 @@ interface Scenario {
|
||||
childSessions?: number
|
||||
recorded: boolean
|
||||
seedWorkspace?: boolean
|
||||
/**
|
||||
* Load the opt-in `todo_write` tool for this scenario. The shipped tui-agent
|
||||
* config omits it, so only the todo-plan scenario (the enabled-path proof)
|
||||
* mounts it; the rest cover the default, todo-free composition.
|
||||
*/
|
||||
enableTodo?: boolean
|
||||
}
|
||||
|
||||
const SCENARIOS: Scenario[] = [
|
||||
@@ -62,6 +68,7 @@ const SCENARIOS: Scenario[] = [
|
||||
expectedTools: ['todo_write'],
|
||||
expectedEventCounts: { 'todo/write': 1 },
|
||||
recorded: true,
|
||||
enableTodo: true,
|
||||
},
|
||||
{
|
||||
name: 'bash-terminal-card',
|
||||
@@ -196,7 +203,9 @@ async function mountScenarioContext(
|
||||
await ctx.plugin(FsPolicy)
|
||||
await ctx.plugin(ToolFs)
|
||||
await ctx.plugin(UserInteractionService)
|
||||
await ctx.plugin(ToolTodo)
|
||||
// todo_write is opt-in: only the todo-plan scenario mounts it, matching the shipped
|
||||
// config that omits it. The other scenarios prove the default todo-free composition.
|
||||
if (scenario.enableTodo === true) await ctx.plugin(ToolTodo)
|
||||
await ctx.plugin(SubagentService)
|
||||
await ctx.plugin(SubagentSpawn, { providerName: 'spawn' })
|
||||
await ctx.plugin(ToolSubagent, { provider: 'spawn', toolName: 'subagent', enableRunInBackground: false })
|
||||
|
||||
Reference in New Issue
Block a user