Files
deepseek-harness/packages/ui/user-interaction/README.zh.md
creatixchu 89d30b0ef7 feat(user-interaction): declare a plan-review presentation intent on questions
A question may now carry `intent`, a tagged declaration that it IS a decision
of a known shape, so a UI that recognises the tag can present it as such
instead of as a generic option list. The one member is
`{ kind: 'plan-review', approve }`, which plan-mode sets on the exit_plan_mode
review.

An intent shapes presentation only: a UI honouring it answers with the same
option labels a generic UI would send, so the tool reads one answer shape
either way, and a UI that does not know the tag renders the generic flow.
`approve` names the affirmative option rather than relying on option order;
since no type can tie that label to the question's own option list, `ask()`
rejects a mismatch as BAD_INTENT, and the wire schema rejects an unknown tag
outright rather than silently rendering generic.

plan-mode also stops reporting a dismissed review as "the user cancelled
ask_user_question" — a tool it never called. A dismissal now tells the model
the user took the turn back to speak, and to stay in plan mode and wait; every
other ask failure keeps its own message.
2026-07-30 19:09:19 +08:00

3.4 KiB
Raw Blame History

@deepseek-ai/dsh-user-interaction

English | 中文

抽象用户交互 seam。它定义 ctx.userInteraction,供面向模型的工具或权限插件在需要暂停工作并询问人类决定时使用。

服务:UserInteractionService(ctx 键:userInteraction)

公开 API

  • ctx.userInteraction.registerProvider(provider): () => void 注册 UI 侧提供方。同一上下文中只能有一个活跃提供方;dispose(资源释放)会将其注销。
  • ctx.userInteraction.ask(request): Promise<AskUserQuestionAnswer> 向活跃提供方提问并等待回答。

关键类型

  • AskUserQuestionRequest:{ questions: [{ id, question, detail?, header?, options?, multiSelect?, intent? }], agent?, signal? };detail 提供辅助文本,提供方会将其随问题一起渲染,而不会将其变成选项标签。
  • AskUserQuestionOption:{ label, description? }。
  • AskUserQuestionIntent:{ kind: 'plan-review', approve };即下文的带标签呈现意图。
  • AskUserQuestionAnswer:{ answers: [{ id, selected, custom? }] }。
  • UserInteractionProvider:包含 ask(request) 的 UI 实现。
  • UserInteractionError:HarnessError 的子类,包含 EMPTY_QUESTIONS、BAD_INTENT、NO_PROVIDER、DUPLICATE_PROVIDER 和 ASK_ABORTED 等代码。

当回答包含 custom 时,selected 为空;自定义文本是所选选项的替代,而不是补充。UI 可以把跳过的条目保留为 { id, selected: [] },既维持现有回答形态,也保留该批次中的其他回答。

呈现意图

intent 声明某个问题本身就是一次已知形状的决定,因此认识该标签的 UI 可以照此呈现 —— plan-review 表示 detail 是一份待审阅的计划,dsh-plan-mode 会在 exit_plan_mode 的问题上设置它。意图只塑造呈现:遵循它的 UI 回答的仍是通用 UI 会发送的那些选项标签,不认识该标签的 UI 渲染通用选项列表,因此调用方两种情况下读到的都是同一种回答形态。approve 指名表示批准的标签,而不依赖选项顺序;由于没有类型能把两者绑定起来,ask() 会以 BAD_INTENT 拒绝 approve 未命中该问题自身任一选项的意图。

职责

这是接口包(package)。@deepseek-ai/dsh-tool-ask-user 等面向模型的消费方依赖此 seam;dsh-tui 和宿主运行时提供交互式实现。循环保持不变:工具调用等待 Promise,工具结果随后恢复正常的 agent loop(智能体循环)。

模型体验

间接地,通过 dsh-tool-ask-user:它会将成功的提供方回答保留为紧凑 JSON,或返回以下失败之一:Error: ask_user_question was aborted before the user answered、Error: ask_user_question requires at least one question、Error: no user-interaction provider is registered 或 Error: <message>。等待人类回答不会增加 token。

KV Cache 影响

不会直接使 KV Cache 失效;请求前缀的任何变更均由上述消费方负责。

已知限制与暂缓事项

  • 每个上下文只能有一个提供方:不支持路由或扇出到多个 UI;第二次注册会抛出 DUPLICATE_PROVIDER,未注册任何提供方时,ask() 会抛出 NO_PROVIDER,而不会降级。
  • 词汇仅包含问题表单形态:可供选择的选项加可选的自定义文本;更丰富的交互形态(文件选择器、diff 预览确认)尚无 seam 词汇。