mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
core-data-structures 18 篇(core.md 因超长仍在产出、随后补)、 postmortem 3 篇与 RFC 前门 README 配对;流水线 + 二遍校验产出。 生成文件 docs/rfc/INDEX.md(gen-rfc-index 产物)列入排除。中文侧 页内锚点统一指向英文侧锚名,满足配对门禁的链接目标一致规则。
100 lines
3.3 KiB
Markdown
100 lines
3.3 KiB
Markdown
# 用户交互
|
||
|
||
[English](user-interaction.md) | 中文
|
||
|
||
[dsh-user-interaction](../../packages/ui/user-interaction) 的用户交互 seam。它是工具或权限插件在需要人类回答后 agent 才能继续时所使用的提供方无关词汇。UI 表面提供活跃的 `UserInteractionProvider`:`dsh-stdio-demo` 在 readline 中渲染问题,`dsh-acp` 将其映射为 ACP 表单引出。
|
||
|
||
源码:[`packages/ui/user-interaction/src/index.ts`](../../packages/ui/user-interaction/src/index.ts)
|
||
|
||
## 问题选项
|
||
|
||
`AskUserQuestionOption` 是可选择项的形状。`label` 是面向用户的选项文字,同时也是模型侧选中后的值;`description` 是可选的 UI 辅助文字。
|
||
|
||
```ts type-equiv
|
||
interface AskUserQuestionOption {
|
||
/** User-facing label. */
|
||
label: string
|
||
/** Optional extra context rendered by capable UIs. */
|
||
description?: string
|
||
}
|
||
```
|
||
|
||
## 问题条目
|
||
|
||
`AskUserQuestionItem` 是请求中的一个问题。模型提供一个稳定的 `id`,回答时原样回传,使批量问题可路由。
|
||
|
||
```ts type-equiv
|
||
interface AskUserQuestionItem {
|
||
/** Stable model-provided question id, echoed in the answer. */
|
||
id: string
|
||
/** The question to display. */
|
||
question: string
|
||
/** Optional short heading/group label. */
|
||
header?: string
|
||
/** Optional choices the UI can render as a menu. */
|
||
options?: AskUserQuestionOption[]
|
||
/** Whether more than one option may be selected. Defaults to single-select. */
|
||
multiSelect?: boolean
|
||
}
|
||
```
|
||
|
||
## 提问请求
|
||
|
||
`AskUserQuestionRequest` 是跨包请求。`questions` 是数组,这样 UI 可以在一次流程中展示相关问题,同时为每个回答保留稳定的 id。
|
||
|
||
```ts type-equiv
|
||
interface AskUserQuestionRequest {
|
||
/** Questions to display. */
|
||
questions: AskUserQuestionItem[]
|
||
/** Calling agent, when the request came from an agent tool call. */
|
||
agent?: Agent
|
||
/** Abort signal for the owning tool/step. */
|
||
signal?: AbortSignal
|
||
}
|
||
```
|
||
|
||
## 回答
|
||
|
||
提供方为每个已回答的问题 id 返回一条回答。`selected` 包含选中的选项 label,`custom` 在用户输入了自由文本"其他"答案时携带该内容。当 `custom` 存在时,`selected` 为空;自定义文本是对选中项的覆盖,而非补充。
|
||
|
||
```ts type-equiv
|
||
interface AskUserQuestionAnswerItem {
|
||
/** The answered question id. */
|
||
id: string
|
||
/** Selected option labels. Empty when the answer is purely custom text. */
|
||
selected: string[]
|
||
/** Optional free-text "Other" answer. */
|
||
custom?: string
|
||
}
|
||
```
|
||
|
||
```ts type-equiv
|
||
interface AskUserQuestionAnswer {
|
||
/** Structured answers keyed by question id. */
|
||
answers: AskUserQuestionAnswerItem[]
|
||
}
|
||
```
|
||
|
||
## 提供方
|
||
|
||
同一上下文中只能有一个活跃的提供方。提供方注册与 effect 绑定,因此 HMR(热模块替换)或 dispose(资源释放)会移除活跃的 UI。
|
||
|
||
```ts type-equiv
|
||
interface UserInteractionProvider {
|
||
ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
|
||
}
|
||
```
|
||
|
||
## 错误
|
||
|
||
`UserInteractionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会为面向模型的工具失败保留 `{ name, code }`,例如 `EMPTY_QUESTIONS`、`NO_PROVIDER`、`ASK_ABORTED` 或 ACP 侧的取消。
|
||
|
||
```ts type-equiv
|
||
class UserInteractionError extends HarnessError {
|
||
constructor(message: string, code: string, options?: ErrorOptions) {
|
||
super(message, code, options)
|
||
this.name = 'UserInteractionError'
|
||
}
|
||
}
|
||
```
|