# DSH TUI · Harness 兼容性契约 本项目是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的原生终端 projection layer,不是独立 Agent runtime。TUI 可以自主管理终端渲染和即时交互;所有可影响 Agent、会话、工具或持久化配置的功能,必须以 Harness 官方服务和 durable event 为真相源。 ## 规则 1. Agent 业务状态不在 TUI 复制:会话、运行状态、权限、模型、任务、技能与配置均从 Harness 读取。 2. 业务写入走官方 API:不要由 TUI 直接篡改 session log、权限状态、模型状态或 Harness 配置文件。 3. durable event 是可重放状态的依据:恢复会话时,应由事件重建 UI,而不是使用未持久化的内存缓存猜测状态。 4. 可选服务须 capability-detect:服务未挂载时显示明确提示或关闭该入口,不能静默伪造结果。 5. Harness 仍为 developer preview:依赖基线为 [`@deepseek-ai/dsh@0.1.5-rc.1`](https://www.npmjs.com/package/@deepseek-ai/dsh)。该版本的 V3 会话格式由 Harness 负责迁移,TUI 只经 `snapshotEvents()` 和 `sessionQuery` 投影;持久化生命周期由 `ctx.agents.create/resume()` 返回的 handle 管理。每次升级后,仍须复核 patch、注入服务、命令签名、事件 payload,并运行真实 Profile 的图片与 PTY 回归。 ## 已适配的 Harness 能力 | TUI 功能 | Harness 适配 | 状态来源 / 写路径 | | --- | --- | --- | | 创建、恢复和提交对话 | `ctx.agents`、`ctx.sessions`、`sessionQuery` | `agents.create/resume`、`agent.followup`、durable `session/event`;读取优先使用 rc.1 `snapshotEvents()`,不直接持有 persistence service | | 流式输出、reasoning、工具调用、usage | `session/event`、`agent/status` | durable 消息/工具/usage 事件与 agent 状态 | | 模型与 effort | `ctx.llm`、`agentDefaultModel` | `inputModalities` 视觉能力、动态 reasoning efforts、request override、通过 `saveSelection()` 持久化完整默认模型与 effort 选择 | | Agent preset 与 plan/build | `agentPresets`、`planMode`、`subagentModelSelection` | preset mount/recompose 与 durable preset/plan 事件;Host 挂载官方 subagent model-selection settings 服务 | | 权限审批 | `permissionPresets`、`approval/request` | rc.1 `current(session)` / `set(session, name)`、审批回调、durable permission 事件 | | Slash 命令 | `ctx.commands` | 官方 command registry 的 find/list/execute | | 上下文压缩 | `ctx.compaction`(`compaction-basic`)与官方 `/compact` | 阈值压力压缩在 `agent/pre-step` 内自动执行并继续当前回合(`thresholdRatio` 默认 0.8,保留原文尾部);TUI 只投影 `compaction/start`、`compaction/summary`、`compaction/end`,不自行改写会话历史 | | Skills | `ctx.skills` | 官方 skill registry;技能选择仅回填输入,由 Harness tool 注入 | | 图片附件 | `ctx.attachments` | 粘贴时 `validateImage`;普通消息提交时批量 `saveImages`,命令图片由 registry admission 负责;durable ref 不携带 base64/本地路径 | | 问卷 | `ctx.userQuestions` + `dsh-tool-ask-user` | TUI 注册 provider,支持选项、`custom` 自由文本和多行回答 | | 后台任务 | `ctx.jobs` | list/read/kill/onJobsChanged;归一化 bash、subagent、workflow 等任务快照,不自行制造百分比进度 | | 图片命令 | `ctx.commands` + `ctx.attachments` | 以新版 `execute(agent, line, images, signal)` 传递 `/goal`、官方 `/plan` 等命令图片附件;准入失败保留 composer draft | | TUI 设置 | `ctx.settings` / settings-file | `dsh-omc-tui` namespace,主题与输入历史偏好持久化到 `$DSH_HOME/settings.yaml` | Reasoning effort 必须来自具体模型的 `reasoning.efforts` 元数据。官方适配器可直接提供能力;第三方中转或本地反向代理无法暴露该元数据时,由用户在 `models[].reasoningEfforts` 中声明选择 ID 到网关值的映射。元数据缺失时使用 Provider 默认行为,TUI 显示 `PROVIDER`,不生成或发送猜测档位;能力查询本身失败时则显示真实诊断。 用户确认 effort 后,TUI 将当前 provider、model 与规范化 effort ID 作为一份完整选择交给 `agentDefaultModel.saveSelection()`。内存状态只在 Harness 设置写入成功后更新,因此新会话可通过 `currentSelection()` 恢复相同档位,写入失败也不会造成界面状态与持久化配置分叉。直接命令输入必须先匹配当前模型声明的 effort;无效值不会持久化。选择不支持 reasoning effort 的模型时,通过省略 `reasoningEffort` 的完整保存清除旧覆盖值。 ## 允许保留在 TUI 本地的内容 - ANSI 主题渲染、终端尺寸、光标、选区、滚动位置、动画和当前面板选中项。 - 输入框的即时编辑状态:未提交文本、换行、历史搜索 query、文件菜单筛选与待发送附件列表。 - 仅供展示的折叠状态,例如 reasoning/tool 结果是否展开。 - 本地输入历史缓存文件;它不等同于 Harness 会话,也不影响模型上下文。 这些本地状态不得被表述为 Agent 的真实状态;重启或恢复会话后可丢失或重新计算。 ## 目前的边界与待验证项 - `/settings` 只保存 TUI 偏好;模型、权限和 preset 均继续由各自的官方服务持久化,不应移入 TUI namespace。 - 压缩阈值由 profile 的 `compaction-basic.thresholdRatio` 决定(本插件 patch 显式设为 0.8),TUI 的 `contextCriticalAt` 只控制状态栏告警配色;`autoCompact` 仅是未挂载官方压缩引擎时的回退开关。 - `/jobs` 的流式输出读取会消费官方单一游标,因此只在用户显式选中任务后读取。 - 插件市场/安装目前**未适配**:TUI 没有 `ctx.plugins` 或 catalog 服务,也不会直接修改 profile manifest。计划中的 `/plugins` 应只做市场发现与确认,并把安装/移除委托给官方 `dsh plugin --profile tui add/remove`;profile 重组后需重启 TUI。 - `/fork`、`/rewind`、会话内全文检索等功能,只有在 Harness 提供稳定 session/checkpoint 合约后才能实现;不能通过截断 durable log 模拟。 - Windows、真实 provider 下的技能发送与长任务生产者仍须做独立 E2E 验证。 ## 发布前检查 ```sh dsh --profile tui --dump-config DSH_HOME= python3 test/pty-e2e.py DSH_HOME= python3 test/pty-interaction.py DSH_HOME= python3 test/pty-resume.py ``` 任何新增的 Agent-facing 功能都应先在本表新增对应的官方服务、事件和验证项,再实现 UI。