@fishwithcat/dsh-tool-ask-user 0.0.0-stage → 0.2.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,76 @@
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/interaction/tool-ask-user/README.md
5
+ /:
6
+ en: fd744e4beac0ee66
7
+ zh: 27288856740f5dbf
8
+ /deepseek-ai-dsh-tool-ask-user:
9
+ en: 2a561a70c4a900d7
10
+ zh: 3d12372992cf2634
11
+ /deepseek-ai-dsh-tool-ask-user/summary:
12
+ en: 1a9a38698a6cb1f3
13
+ zh: 35540765df5648e7
14
+ /deepseek-ai-dsh-tool-ask-user/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /deepseek-ai-dsh-tool-ask-user/use-this-package:
18
+ en: 547a3ea61708bc3e
19
+ zh: 5e251ea392940c1a
20
+ /deepseek-ai-dsh-tool-ask-user/use-this-package/when-to-call-the-tool:
21
+ en: 7c70d43d4cd9aa19
22
+ zh: 7597e972067ec5fe
23
+ /deepseek-ai-dsh-tool-ask-user/use-this-package/what-the-model-gets-back:
24
+ en: a81de874c72ebabb
25
+ zh: 5f6e0bd719ee7123
26
+ /deepseek-ai-dsh-tool-ask-user/use-this-package/when-the-call-fails:
27
+ en: c4ac3c584f900230
28
+ zh: bd8d227f0637b8f1
29
+ /deepseek-ai-dsh-tool-ask-user/understand-the-implementation:
30
+ en: e9b9d46be0b45ca2
31
+ zh: c02403486473cd80
32
+ /deepseek-ai-dsh-tool-ask-user/understand-the-implementation/source-map:
33
+ en: d3b5b1515b9aa2f9
34
+ zh: 0b74abcb4da857aa
35
+ /deepseek-ai-dsh-tool-ask-user/understand-the-implementation/consumer-role:
36
+ en: 7de88d25287b969f
37
+ zh: be36dc5a39aeac3b
38
+ /deepseek-ai-dsh-tool-ask-user/understand-the-implementation/result-rendering:
39
+ en: 361ec8067ee6a6e6
40
+ zh: 4ea4dab0da7f79f9
41
+ /deepseek-ai-dsh-tool-ask-user/further-exploration:
42
+ en: d66802e3991ece30
43
+ zh: fcd59f390f2ee690
44
+ /deepseek-ai-dsh-tool-ask-user/model-experience:
45
+ en: 215e7ba838619b7b
46
+ zh: a311da3843709f90
47
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-schema:
48
+ en: e4c7376d4f29dbd5
49
+ zh: 6b7a9eaf69c9ea53
50
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-schema/what-the-model-sees:
51
+ en: 577c8609a8bb915d
52
+ zh: 8607e0d39be0e492
53
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-schema/token-effect:
54
+ en: 97cce067584eadff
55
+ zh: c376cab39ea9df68
56
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-schema/kv-cache-effect:
57
+ en: b385b04c94496e5b
58
+ zh: 6bd8f2bc39e6f8c0
59
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-call-history-and-result:
60
+ en: 9717b983b6a857e3
61
+ zh: 611a2dadf7c0c706
62
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-call-history-and-result/what-the-model-sees:
63
+ en: c2ceed515656e10b
64
+ zh: 4e9b6768e4914718
65
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-call-history-and-result/token-effect:
66
+ en: 3092d4afd4ba8678
67
+ zh: cb7a7bbefdbc3a1e
68
+ /deepseek-ai-dsh-tool-ask-user/model-experience/tool-call-history-and-result/kv-cache-effect:
69
+ en: f5d5f97a153f7c70
70
+ zh: 4db81881ebdcfcc4
71
+ /deepseek-ai-dsh-tool-ask-user/known-limitations-and-deferred-work:
72
+ en: c8df1368c2959465
73
+ zh: b14fb07a60e75ebf
74
+ /deepseek-ai-dsh-tool-ask-user/known-limitations-and-deferred-work/dev-note:
75
+ en: 0b06d843322610c1
76
+ zh: a1e7cadd4f03c384
package/README.md CHANGED
@@ -1,3 +1,169 @@
1
- # Temporary Holding Version
1
+ ---
2
+ description: "The model-facing ask_user_question tool over the user-questions seam, for users and maintainers composing or debugging interactive agent surfaces."
3
+ kind: "package-reference"
4
+ ---
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ # @deepseek-ai/dsh-tool-ask-user
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ `ask_user_question` asks the user for confirmation, a choice, or missing information. It waits for an answer by default. With `mode: timed`, a deadline can release the model to continue independent work while the question stays answerable; `timeout: -1` waits indefinitely. A live child agent cannot call the tool. Callers provide the answer UI.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ Compose this plugin with `ctx.userQuestions` when the model needs a user decision. Without an answerer, blocking calls fail; finite timed calls return pending at their deadline.
29
+
30
+ Shipped presets use blocking mode. To enable timed mode, set `mode: timed` on the `tool-ask-user` row in the active preset's `config.plugins` list:
31
+
32
+ ```yaml
33
+ - id: tool-ask-user
34
+ name: '@deepseek-ai/dsh-tool-ask-user'
35
+ config:
36
+ mode: timed
37
+ timeout: 120
38
+ ```
39
+
40
+ This is a plugin row, not a top-level `--patch` entry. In the Web profile, change the `preset-standard` plugin list or use the Agent Preset editor. `mode: legacy` or omitted config keeps the blocking schema. The row's `timeout` applies to each timed call by default; `-1` waits indefinitely unless the model supplies a positive timeout. A model-supplied `-1` applies only to that call, including all its questions.
41
+
42
+ ### When to call the tool
43
+
44
+ Send one or more questions with ids unique within the call; the answer echoes those ids. Put a recommended option first and append `(Recommended)` to its label. The optional per-call `timeout` is in seconds; use `-1` when work cannot safely continue without an answer. A timeout is never approval. In the Web card, editing or choosing Take time also holds that Client's wait until submission or cancellation.
45
+
46
+ ```json
47
+ {
48
+ "questions": [
49
+ {
50
+ "id": "cleanup",
51
+ "question": "Proceed with the destructive cleanup?",
52
+ "header": "Confirm",
53
+ "options": [
54
+ { "label": "Yes, delete them (Recommended)", "description": "Removes the three stale files." },
55
+ { "label": "No, keep them", "description": "Aborts the cleanup." }
56
+ ]
57
+ }
58
+ ]
59
+ }
60
+ ```
61
+
62
+ ### What the model gets back
63
+
64
+ An answer returns one item per question. `selected` holds option labels; `custom` supplements a multi-select answer or replaces a single-select choice. A skipped item has empty `selected` and no `custom`; both tool descriptions tell the model how to handle it.
65
+
66
+ For a finite timed call, `{ "pending": true, "callId": "…" }` means the foreground wait ended without an answer. The question remains answerable, and the model may continue independent work. A later answer arrives as a user message identified by `kind`, `tool`, and `callId`. Web chat and the tool's presentation view pair its questions and answers; consumers that render the raw result receive compact JSON text.
67
+
68
+ ```json
69
+ { "answers": [{ "id": "cleanup", "selected": ["Yes, delete them (Recommended)"] }] }
70
+ ```
71
+
72
+ ### When the call fails
73
+
74
+ Legacy and `timeout: -1` calls wait for an answer or cancellation; without an accepting answerer, they return an error. A finite timed call without an answerer returns pending at its deadline. Cancellation and a caller that is not the exact live runtime root also return errors. A live child agent is rejected with `DELEGATED_CALLER` and must include the unresolved decision in its final result.
75
+
76
+ -----
77
+
78
+ <a id="understand-the-implementation"></a>
79
+ ## Understand the implementation
80
+
81
+ <details>
82
+ <summary>Implementation internals — click to expand</summary>
83
+
84
+ The observable behavior is covered in [Use this package](#use-this-package); this section explains the tool definition and its relationship to the seam.
85
+
86
+ ### Source map
87
+
88
+ | File | Role |
89
+ |---|---|
90
+ | [`src/index.ts`](src/index.ts) | Default blocking tool definition and mode selection |
91
+ | [`src/timed.ts`](src/timed.ts) | Opt-in timed tool definition and result rendering |
92
+ | [`src/presentation.ts`](src/presentation.ts) | Question-and-answer views for a host's call and result rows |
93
+
94
+ ### Consumer role
95
+
96
+ The plugin registers one tool definition. Legacy mode calls `ask()`; timed mode calls `askTimed()` for positive timeouts and `ask()` for `-1`. Both forward the calling agent and turn signal to `ctx.userQuestions`. Timed requests include the tool call id in `wait`, so a Client can reopen their card. The projection identifies timed native calls from the `timeout` field in the recorded tool schema, even when a call omits that argument.
97
+
98
+ ### Result rendering
99
+
100
+ The `render` output projects the structured value to a single text block via `JSON.stringify`, which is why the model-facing result is compact JSON rather than a richer content-block vocabulary. `presentCall` and `presentResult` separately declare Host views that list each question with the labels the user chose, or with a skip marker, so a terminal or editor row never has to show the answer JSON to its reader.
101
+
102
+ </details>
103
+
104
+ -----
105
+
106
+ <a id="further-exploration"></a>
107
+ ## Further Exploration
108
+
109
+ Read these pages when the package-level contract is not enough. They move from the tool surface to the seam contract and its answerer waterfall.
110
+
111
+ - [User interaction subsystem reference](../../../docs/subsystems/user-questions.md) — the service contract, question vocabulary, and answerer waterfall behind this tool.
112
+ - [Tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-tool-ask-user) — the generated `ask_user_question` schema.
113
+ - [user-questions package](../user-questions/README.md) — the seam this tool consumes.
114
+ - [Interaction group map](../README.md) — adjacent approval and command surfaces.
115
+
116
+ -----
117
+
118
+ <a id="model-experience"></a>
119
+ ## Model Experience
120
+
121
+ ### Tool schema
122
+
123
+ #### What the model sees
124
+
125
+ The shipped presets expose the original blocking [`ask_user_question` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-ask-user). A custom Cordis row with `mode: timed` switches to the alternate schema, including question ids, prompts, headings, options, multi-select flags, `timeout`, and the pending result; the model sees only the selected definition.
126
+
127
+ #### Token effect
128
+
129
+ Fixed schema cost on every request where the tool is visible.
130
+
131
+ #### KV Cache effect
132
+
133
+ Prefix-stable while the definition and visibility are unchanged. Plugin lifecycle or scoped restrictions may invalidate reuse from this schema.
134
+
135
+ ### Tool-call history and result
136
+
137
+ #### What the model sees
138
+
139
+ The assistant tool call retains the questions. An answer during the wait appears in the next step as compact `{"answers":[{"id":"<id>","selected":["<label>"],"custom":"<text>"}]}` JSON; unused `custom` is omitted. A timed-out call returns `{"pending":true,"callId":"<pending-call-id>","message":"<instruction>"}`. A later answer arrives as a user message with `kind: "answer_to_pending_question"`, `tool: "ask_user_question"`, the call id, the original questions, and the answers. UI activity before submission is not model context.
140
+
141
+ #### Token effect
142
+
143
+ Arguments and answer JSON are data-dependent retained tokens; there is no token cost while waiting for the human.
144
+
145
+ #### KV Cache effect
146
+
147
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
148
+
149
+ ## Known Limitations and Deferred Work
150
+
151
+ <a id="known-limitations-and-deferred-work"></a>
152
+
153
+
154
+ These limits define when the tool is a poor fit. They are current package constraints, not a UI backlog.
155
+
156
+ - **The legacy tool never reports pending** — it returns an answer or an error. Native legacy calls do not enter the `userQuestions` projection, and interrupted calls cannot take late answers.
157
+ - **An interrupted PTC wait may lose its question** — if the `run_code` process ends before an `ask_user_question` sub-call records its `tool/ptc-dispatch` result, the projection cannot reconstruct that sub-call for a late answer.
158
+ - **Runtime-owned subagents cannot ask the user** — `ask_user_question` rejects a live child owned by another agent with `DELEGATED_CALLER`; the child must include the unresolved question or decision in its final result. Durable lineage does not decide this boundary, so a lineage-bearing session resumed as a runtime root may ask normally.
159
+ - **Native answers render as JSON text** — the canonical value remains structured, but the model-facing result uses compact JSON rather than a richer content-block vocabulary.
160
+
161
+ <a id="dev-note"></a>
162
+ ### Dev Note
163
+
164
+ <details>
165
+ <summary>Working context for maintainers — click to expand</summary>
166
+
167
+ The [`userQuestions` projection](../user-questions/src/projection.ts) reads each recorded tool schema rather than the call arguments: timed calls may omit `timeout`, and timed `-1` calls still use the timed schema. Changes to the projection fold require a `stateVersion` bump so stored caches refold from the log.
168
+
169
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,169 @@
1
+ ---
2
+ description: "基于 user-questions seam 的模型侧 ask_user_question 工具;供组合或排查交互式 agent(智能体)表面的用户与维护者阅读。"
3
+ kind: "package-reference"
4
+ ---
5
+
6
+ # @deepseek-ai/dsh-tool-ask-user
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## 概述
11
+
12
+ `ask_user_question` 向用户请求确认、选择或缺失的信息。默认情况下,它会等待回答。设置 `mode: timed` 后,期限到达时模型可以继续独立工作,而问题仍可回答;`timeout: -1` 则无限期等待。存活的子 agent 不能调用此工具。调用方需提供回答界面。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 当模型需要用户决定时,将此插件与 `ctx.userQuestions` 组合。没有 answerer 时,阻塞式调用返回错误;有限时长的 timed 调用到期后返回 pending。
29
+
30
+ 随附 preset 使用阻塞模式。要启用 timed 模式,请在当前 preset 的 `config.plugins` 列表中,将 `tool-ask-user` 条目设为 `mode: timed`:
31
+
32
+ ```yaml
33
+ - id: tool-ask-user
34
+ name: '@deepseek-ai/dsh-tool-ask-user'
35
+ config:
36
+ mode: timed
37
+ timeout: 120
38
+ ```
39
+
40
+ 以上片段是插件条目,不是顶层 `--patch` 条目。在 Web profile 中,请修改 `preset-standard` 的插件列表,或使用 Agent Preset 编辑器。`mode: legacy` 或省略配置会保留阻塞式 schema。条目中的 `timeout` 默认适用于每次 timed 调用;设为 `-1` 时会无限期等待,除非模型传入正数期限。模型传入的 `-1` 只适用于该次调用,包括其中的所有问题。
41
+
42
+ ### 何时调用该工具
43
+
44
+ 发送一个或多个问题,每个问题的 `id` 在本次调用内必须唯一;回答会带回这些 id。推荐选项放在首位,并在标签末尾追加 `(Recommended)`。可选的单次调用 `timeout` 以秒为单位;如果没有回答就无法安全继续,请使用 `-1`。超时绝不表示批准。在 Web 卡片中,开始编辑或选择“慢慢回答”也会让该 Client 的等待持续到提交或取消。
45
+
46
+ ```json
47
+ {
48
+ "questions": [
49
+ {
50
+ "id": "cleanup",
51
+ "question": "Proceed with the destructive cleanup?",
52
+ "header": "Confirm",
53
+ "options": [
54
+ { "label": "Yes, delete them (Recommended)", "description": "Removes the three stale files." },
55
+ { "label": "No, keep them", "description": "Aborts the cleanup." }
56
+ ]
57
+ }
58
+ ]
59
+ }
60
+ ```
61
+
62
+ ### 模型得到什么
63
+
64
+ 收到回答时,工具为每个问题返回一项。`selected` 保存选项标签;`custom` 可以补充多选答案,或替代单选选项。跳过的回答项具有空 `selected`,且没有 `custom`;两种工具描述都告诉模型如何处理这种回答项。
65
+
66
+ 对于有限时长的 timed 调用,`{ "pending": true, "callId": "…" }` 表示前台等待结束时仍没有回答。问题仍可回答,模型可以继续独立工作。之后的回答以用户消息送达,由 `kind`、`tool` 和 `callId` 标识。Web 对话与工具声明的呈现视图会配对展示问题与回答;直接渲染原始结果的消费方收到紧凑 JSON 文本。
67
+
68
+ ```json
69
+ { "answers": [{ "id": "cleanup", "selected": ["Yes, delete them (Recommended)"] }] }
70
+ ```
71
+
72
+ ### 调用何时失败
73
+
74
+ Legacy 调用和 `timeout: -1` 调用会等待回答或取消;没有 answerer 接受时返回错误。有限时长的 timed 调用若没有 answerer,则在到期后返回 pending。取消调用,或调用方不是确切的存活运行时根时,也会返回错误。存活的子 agent 会以 `DELEGATED_CALLER` 被拒绝,必须在最终结果中包含尚未解决的决定。
75
+
76
+ -----
77
+
78
+ <a id="understand-the-implementation"></a>
79
+ ## 理解实现
80
+
81
+ <details>
82
+ <summary>实现细节——点击展开</summary>
83
+
84
+ 可观察行为已在[使用本包](#use-this-package)中说明;本节解释工具定义及其与 seam 的关系。
85
+
86
+ ### 源码地图
87
+
88
+ | 文件 | 职责 |
89
+ |---|---|
90
+ | [`src/index.ts`](src/index.ts) | 默认阻塞式工具定义与模式选择 |
91
+ | [`src/timed.ts`](src/timed.ts) | 显式启用的计时工具定义与结果渲染 |
92
+ | [`src/presentation.ts`](src/presentation.ts) | 供宿主调用行与结果行使用的问题与回答视图 |
93
+
94
+ ### 消费方角色
95
+
96
+ 插件只注册一个工具定义。Legacy 模式调用 `ask()`;timed 模式对正数期限调用 `askTimed()`,对 `-1` 调用 `ask()`。两者都向 `ctx.userQuestions` 传递调用方 agent 和轮次信号。Timed 请求在 `wait` 中包含工具调用 id,Client 因此可以重新打开对应卡片。投影从记录的工具 schema 的 `timeout` 字段识别 timed 原生调用,即使某次调用省略该参数也一样。
97
+
98
+ ### 结果渲染
99
+
100
+ `render` 输出把结构化值经 `JSON.stringify` 投影为单个文本块,因此模型侧结果是紧凑 JSON,而非更丰富的内容块词汇。
101
+
102
+ </details>
103
+
104
+ -----
105
+
106
+ <a id="further-exploration"></a>
107
+ ## 进一步探索
108
+
109
+ 当包级约定不够用时阅读以下页面。它们从工具表面逐步进入 seam 约定及其 answerer waterfall。
110
+
111
+ - [用户交互子系统参考](../../../docs/subsystems/user-questions.zh.md)——此工具背后的服务约定、问题词汇与 answerer waterfall。
112
+ - [工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-tool-ask-user)——生成的 `ask_user_question` schema。
113
+ - [user-questions 包](../user-questions/README.zh.md)——本工具消费的 seam。
114
+ - [交互组映射](../README.zh.md)——相邻的审批与命令表面。
115
+
116
+ -----
117
+
118
+ <a id="model-experience"></a>
119
+ ## 模型体验
120
+
121
+ ### 工具 schema
122
+
123
+ #### 模型看到的内容
124
+
125
+ 随附 preset 会公开原有的阻塞式 [`ask_user_question` schema](../../../docs/tool-catalog.zh.md#deepseek-aidsh-tool-ask-user)。自定义 Cordis 行设置 `mode: timed` 后,会切换到包含问题 id、提示语、标题、选项、多选标志、`timeout` 与待处理结果的异步 schema;模型只会看到被选中的定义。
126
+
127
+ #### Token 影响
128
+
129
+ 工具可见时,每个请求都会产生固定的 schema token 开销。
130
+
131
+ #### KV Cache 影响
132
+
133
+ 只要定义和可见性保持不变,前缀即可稳定复用。插件生命周期变化或作用域限制可能会使从此 schema 起的缓存复用失效。
134
+
135
+ ### 工具调用历史与结果
136
+
137
+ #### 模型看到的内容
138
+
139
+ assistant 工具调用保留问题。等待期间收到的回答会在下一步显示为紧凑的 `{"answers":[{"id":"<id>","selected":["<label>"],"custom":"<text>"}]}` JSON;未使用的 `custom` 会省略。计时到期的调用返回 `{"pending":true,"callId":"<pending-call-id>","message":"<instruction>"}`。之后的回答以用户消息送达,包含 `kind: "answer_to_pending_question"`、`tool: "ask_user_question"`、调用 id、原问题和答案。提交之前的 UI 活动不属于模型上下文。
140
+
141
+ #### Token 影响
142
+
143
+ 参数和回答 JSON 是依数据而定的保留 token;等待用户时不会产生 token 开销。
144
+
145
+ #### KV Cache 影响
146
+
147
+ 仅追加;新出现的可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
148
+
149
+ ## 已知限制与延期工作
150
+
151
+ <a id="known-limitations-and-deferred-work"></a>
152
+
153
+
154
+ 这些限制说明该工具何时不合适。它们是当前包约束,不是 UI 积压事项。
155
+
156
+ - **Legacy 工具不会报告 pending**:它只返回回答或错误。原生 legacy 调用不进入 `userQuestions` 投影;中断的调用不能接受迟到回答。
157
+ - **中断的 PTC 等待可能丢失问题**:若 `run_code` 进程在 `ask_user_question` 子调用记录 `tool/ptc-dispatch` 结果前结束,投影无法重建该子调用以接受迟到回答。
158
+ - **运行时中归属于其他 agent 的 subagent 不能向用户提问**:`ask_user_question` 会以 `DELEGATED_CALLER` 拒绝归属于另一个 agent 的存活子级;该子级必须在最终结果中包含尚未解决的问题或决定。持久谱系不能决定这一边界,因此带有谱系的会话恢复为运行时根后可以正常提问。
159
+ - **Native 回答渲染为 JSON 文本**:规范值仍为结构化数据,但模型侧结果使用紧凑 JSON,而非更丰富的内容块词汇。
160
+
161
+ <a id="dev-note"></a>
162
+ ### 开发备注
163
+
164
+ <details>
165
+ <summary>维护者的工作上下文——点击展开</summary>
166
+
167
+ [`userQuestions` 投影](../user-questions/src/projection.ts)读取记录的工具 schema,而不是调用参数:timed 调用可以省略 `timeout`,timed `-1` 调用也仍使用 timed schema。改变投影折叠语义时必须提高 `stateVersion`,让持久化缓存从日志重新折叠。
168
+
169
+ </details>
package/lib/index.js ADDED
@@ -0,0 +1,468 @@
1
+ import { defineTool } from "@deepseek-ai/dsh-tools";
2
+ import z from "@deepseek-ai/schemastery";
3
+ import { TIMED_WAIT_PARAMETER } from "@deepseek-ai/dsh-user-questions";
4
+ //#region lib/types/presentation.js
5
+ /**
6
+ * Host presentation for `ask_user_question`: the question batch and its answer
7
+ * batch as readable lines, instead of the model-facing JSON arguments and
8
+ * result. A host that renders tool presentation views shows the questions and
9
+ * what the user chose; the model-facing result stays compact JSON.
10
+ * @module @deepseek-ai/dsh-tool-ask-user/presentation
11
+ */
12
+ /** Marker that names a question the user moved past without answering. */
13
+ const SKIPPED = " → (skipped)";
14
+ /**
15
+ * One question's display label: its header when it has one, then its text.
16
+ * @param question - the question to label.
17
+ * @returns the label on one line.
18
+ */
19
+ function questionLabel(question) {
20
+ return question.header === void 0 ? question.question : `${question.header} · ${question.question}`;
21
+ }
22
+ /**
23
+ * The questions as one text block, one question per line.
24
+ * @param questions - the questions to list.
25
+ * @returns the view content.
26
+ */
27
+ function questionContent(questions) {
28
+ return [{
29
+ type: "text",
30
+ text: questions.map(questionLabel).join("\n")
31
+ }];
32
+ }
33
+ /**
34
+ * Concatenate one tool result's text blocks.
35
+ * @param blocks - the result content.
36
+ * @returns the visible text.
37
+ */
38
+ function resultText(blocks) {
39
+ let text = "";
40
+ for (const block of blocks)
41
+ /* v8 ignore next -- the tool's render declares exactly one text block */
42
+ if (block.type === "text") text += block.text;
43
+ return text;
44
+ }
45
+ /**
46
+ * Whether a decoded JSON value is a non-null, non-array object.
47
+ * @param value - the decoded value.
48
+ * @returns true when named fields can be read from it.
49
+ */
50
+ function isRecord(value) {
51
+ return typeof value === "object" && value !== null && !Array.isArray(value);
52
+ }
53
+ /**
54
+ * Read the answer entries out of a successful result's JSON object.
55
+ *
56
+ * The result is a durable payload, so every field is checked before the row can
57
+ * present it as a choice the user made.
58
+ * @param parsed - the decoded result object.
59
+ * @returns the answer entries, or undefined when the payload is not one.
60
+ */
61
+ function answerEntries(parsed) {
62
+ if (!Array.isArray(parsed.answers)) return void 0;
63
+ const answers = [];
64
+ for (const answer of parsed.answers) {
65
+ if (!isRecord(answer) || typeof answer.id !== "string" || !Array.isArray(answer.selected)) return void 0;
66
+ if (!answer.selected.every((label) => typeof label === "string")) return void 0;
67
+ if (answer.custom !== void 0 && typeof answer.custom !== "string") return void 0;
68
+ answers.push({
69
+ id: answer.id,
70
+ selected: answer.selected,
71
+ ...answer.custom === void 0 ? {} : { custom: answer.custom }
72
+ });
73
+ }
74
+ return answers;
75
+ }
76
+ /**
77
+ * The presentation view for a pending `ask_user_question` call.
78
+ *
79
+ * A batch renders as its questions, one per line, no matter how many arrived;
80
+ * the title stays the same so a reader recognizes the Tool across states.
81
+ * @param questions - the questions the call asks.
82
+ * @returns the generic call view.
83
+ */
84
+ function presentAskCall(questions) {
85
+ return {
86
+ card: "generic",
87
+ title: "Ask user question",
88
+ content: questionContent(questions)
89
+ };
90
+ }
91
+ /**
92
+ * The presentation view for a settled `ask_user_question` call.
93
+ *
94
+ * Each question is followed by the labels the user chose, or by a skip marker.
95
+ * A timed call whose window closed without an answer shows that it is still
96
+ * waiting; a failed call declares no view so the ordinary error row remains.
97
+ * @param questions - the questions the call asked.
98
+ * @param result - the settled result projection.
99
+ * @returns the generic result view, or undefined when the result is an error or
100
+ * carries no readable batch.
101
+ */
102
+ function presentAskResult(questions, result) {
103
+ if (result.isError) return void 0;
104
+ const text = resultText(result.content);
105
+ let parsed;
106
+ try {
107
+ parsed = JSON.parse(text);
108
+ } catch {
109
+ return;
110
+ }
111
+ if (!isRecord(parsed)) return void 0;
112
+ if (parsed.pending === true) return {
113
+ card: "generic",
114
+ title: "Ask user question · waiting for an answer",
115
+ content: questionContent(questions)
116
+ };
117
+ const answers = answerEntries(parsed);
118
+ if (answers === void 0) return void 0;
119
+ const byId = new Map(answers.map((answer) => [answer.id, answer]));
120
+ const lines = [];
121
+ let answered = 0;
122
+ for (const question of questions) {
123
+ const answer = byId.get(question.id);
124
+ if (answer === void 0) return void 0;
125
+ const chosen = [...answer.selected, ...answer.custom === void 0 || answer.custom === "" ? [] : [answer.custom]];
126
+ if (chosen.length > 0) answered += 1;
127
+ lines.push(questionLabel(question), chosen.length === 0 ? SKIPPED : ` → ${chosen.join(", ")}`);
128
+ }
129
+ return {
130
+ card: "generic",
131
+ title: `Ask user question · ${String(answered)} of ${String(questions.length)} answered`,
132
+ content: [{
133
+ type: "text",
134
+ text: lines.join("\n")
135
+ }]
136
+ };
137
+ }
138
+ //#endregion
139
+ //#region lib/types/timed.js
140
+ /**
141
+ * Opt-in timed `ask_user_question` tool definition.
142
+ */
143
+ function validateTimeout(timeout) {
144
+ if (timeout !== -1 && (!Number.isInteger(timeout) || timeout < 1 || timeout > 2147483)) throw new Error("timeout must be -1 or a positive integer up to 2147483 seconds");
145
+ return timeout;
146
+ }
147
+ function validateQuestionIds(questions) {
148
+ const ids = /* @__PURE__ */ new Set();
149
+ for (const question of questions) {
150
+ if (ids.has(question.id)) throw new Error(`question id ${JSON.stringify(question.id)} must be unique within this call`);
151
+ ids.add(question.id);
152
+ }
153
+ }
154
+ const description$1 = `Ask brief, direct, self-contained questions about missing information, preferences, or decisions. Use user-facing terms; assume no knowledge of background work or internal names. Use distinct stable question IDs. An answer item with empty selected and no custom means the user skipped that question: continue without it, do not ask it again, and do not treat the skip as permission. A pending result instead means no answer batch arrived before the timeout and the user can still answer.`;
155
+ /**
156
+ * Instruction the pending result carries in its `message` field. It is a field
157
+ * of the result value rather than prose beside it because the recorded result
158
+ * text is read back as one JSON object: the `userQuestions` projection decides
159
+ * from it that the call stays answerable, and the Client question row decides
160
+ * from it that the recorded result is the timeout, not an answer batch.
161
+ */
162
+ const pendingNotice = "No answer batch arrived before the timeout. This is pending, not a skipped answer. Continue useful independent work. The user can still answer; their reply will be a user message identified as answer_to_pending_question with this callId and the original questions. Do not treat this as permission.";
163
+ /**
164
+ * Translate the model schema into the service request without changing ownership.
165
+ * @param questions - Model-supplied questions in tool-schema form.
166
+ * @param exec - Execution context that owns the agent and cancellation signal.
167
+ * @returns The corresponding user-question service request.
168
+ */
169
+ function questionRequest(questions, exec) {
170
+ return {
171
+ questions: questions.map((question) => ({
172
+ id: question.id,
173
+ question: question.question,
174
+ ...question.header !== void 0 ? { header: question.header } : {},
175
+ ...question.options !== void 0 ? { options: question.options.map((option) => ({ ...option })) } : {},
176
+ ...question.multi_select !== void 0 ? { multiSelect: question.multi_select } : {}
177
+ })),
178
+ ...exec.agent !== void 0 ? { agent: exec.agent } : {},
179
+ signal: exec.signal
180
+ };
181
+ }
182
+ /**
183
+ * Copy service-owned answer arrays into the model-facing result.
184
+ * @param result - Answer returned by the user-question service.
185
+ * @returns A detached model-facing answer payload.
186
+ */
187
+ function answerResult(result) {
188
+ return { answers: result.answers.map((answer) => ({
189
+ id: answer.id,
190
+ selected: [...answer.selected],
191
+ ...answer.custom !== void 0 ? { custom: answer.custom } : {}
192
+ })) };
193
+ }
194
+ /**
195
+ * Register the opt-in timed tool definition.
196
+ * @param ctx - Agent-scoped context receiving the tool.
197
+ * @param timeout - Default foreground wait in seconds.
198
+ */
199
+ function registerTimedAskUser(ctx, timeout = 120) {
200
+ const defaultTimeout = validateTimeout(timeout);
201
+ ctx.tools.register(defineTool({
202
+ name: "ask_user_question",
203
+ description: description$1,
204
+ parameters: {
205
+ questions: {
206
+ type: "array",
207
+ required: true,
208
+ description: "Questions to ask the user.",
209
+ items: {
210
+ type: "object",
211
+ additionalProperties: true,
212
+ properties: {
213
+ id: {
214
+ type: "string",
215
+ required: true,
216
+ description: "Stable id for this question; echoed in the answer."
217
+ },
218
+ question: {
219
+ type: "string",
220
+ required: true,
221
+ description: "The specific question to ask the user."
222
+ },
223
+ header: {
224
+ type: "string",
225
+ description: "Optional short heading for the question, such as \"Confirm\" or \"Choose Mode\"."
226
+ },
227
+ options: {
228
+ type: "array",
229
+ description: "Optional choices to show the user. If you recommend one, put it first and append \"(Recommended)\" to that label.",
230
+ items: {
231
+ type: "object",
232
+ additionalProperties: true,
233
+ properties: {
234
+ label: {
235
+ type: "string",
236
+ required: true,
237
+ description: "Short user-facing option label."
238
+ },
239
+ description: {
240
+ type: "string",
241
+ description: "One sentence explaining the tradeoff or impact."
242
+ }
243
+ }
244
+ }
245
+ },
246
+ multi_select: {
247
+ type: "boolean",
248
+ description: "Whether the user may select more than one option. Defaults to false."
249
+ }
250
+ }
251
+ }
252
+ },
253
+ [TIMED_WAIT_PARAMETER]: {
254
+ type: "integer",
255
+ description: `Wait seconds for the entire batch (default ${defaultTimeout}); omit unless the user specifies a duration. Use -1 only when an answer is required before proceeding.`
256
+ }
257
+ },
258
+ output: {
259
+ schema: { oneOf: [{
260
+ type: "object",
261
+ additionalProperties: false,
262
+ properties: {
263
+ pending: {
264
+ type: "boolean",
265
+ enum: [true],
266
+ required: true,
267
+ description: "True when the foreground wait expired before the user submitted an answer batch. The questions remain answerable; this is not a skipped answer."
268
+ },
269
+ callId: {
270
+ type: "string",
271
+ required: true,
272
+ description: "Tool call whose unanswered questions remain pending."
273
+ },
274
+ message: {
275
+ type: "string",
276
+ required: true,
277
+ description: "How to continue while the questions stay answerable."
278
+ }
279
+ }
280
+ }, {
281
+ type: "object",
282
+ additionalProperties: false,
283
+ properties: { answers: {
284
+ type: "array",
285
+ required: true,
286
+ description: "Submitted answer batch with one item per question. A skipped question has empty selected and no custom; unlike pending, the user has completed the batch.",
287
+ items: {
288
+ type: "object",
289
+ additionalProperties: false,
290
+ properties: {
291
+ id: {
292
+ type: "string",
293
+ required: true,
294
+ description: "Stable question id echoed from the request."
295
+ },
296
+ selected: {
297
+ type: "array",
298
+ required: true,
299
+ items: { type: "string" },
300
+ description: "Selected option labels. Empty with no custom means the user explicitly skipped this question."
301
+ },
302
+ custom: {
303
+ type: "string",
304
+ description: "Optional free-form answer; omitted for a skipped question."
305
+ }
306
+ }
307
+ }
308
+ } }
309
+ }] },
310
+ render: (_args, value) => [{
311
+ type: "text",
312
+ text: JSON.stringify(value)
313
+ }]
314
+ },
315
+ presentCall: (args) => presentAskCall(args.questions),
316
+ presentResult: (args, result) => presentAskResult(args.questions, result),
317
+ async execute(args, exec) {
318
+ const timeout = validateTimeout(args.timeout ?? defaultTimeout);
319
+ validateQuestionIds(args.questions);
320
+ const request = questionRequest(args.questions, exec);
321
+ if (timeout !== -1) {
322
+ if (exec.agent === void 0) throw new Error("timed questions require a live agent");
323
+ const result = await ctx.userQuestions.askTimed({
324
+ ...request,
325
+ agent: exec.agent
326
+ }, exec.callId, timeout * 1e3);
327
+ return "pending" in result ? {
328
+ ...result,
329
+ message: pendingNotice
330
+ } : answerResult(result);
331
+ }
332
+ return answerResult(await ctx.userQuestions.ask({
333
+ ...request,
334
+ wait: { callId: exec.callId }
335
+ }));
336
+ }
337
+ }));
338
+ }
339
+ //#endregion
340
+ //#region lib/types/index.js
341
+ /**
342
+ * Model-facing Consumer of the `ctx.userQuestions` capability seam.
343
+ * The tool pauses until a UI provider returns a human answer, then feeds that
344
+ * answer back into the agent loop as an ordinary tool result.
345
+ *
346
+ * @module @deepseek-ai/dsh-tool-ask-user
347
+ */
348
+ const Config = z.object({
349
+ mode: z.union(["legacy", "timed"]).default("legacy"),
350
+ timeout: z.union([-1, z.number().step(1).min(1).max(2147483)]).default(120)
351
+ });
352
+ const name = "tool-ask-user";
353
+ const inject = ["tools", "userQuestions"];
354
+ const description = "Ask the user a concise question when you need confirmation, a choice, or missing information before proceeding. An answer item with empty selected and no custom means the user skipped that question: continue without it, do not ask it again, and do not treat the skip as permission.";
355
+ function apply(ctx, config = {}) {
356
+ if (config.mode === "timed") {
357
+ registerTimedAskUser(ctx, config.timeout);
358
+ return;
359
+ }
360
+ ctx.tools.register(defineTool({
361
+ name: "ask_user_question",
362
+ description,
363
+ parameters: { questions: {
364
+ type: "array",
365
+ required: true,
366
+ description: "Questions to ask the user before continuing.",
367
+ items: {
368
+ type: "object",
369
+ additionalProperties: true,
370
+ properties: {
371
+ id: {
372
+ type: "string",
373
+ required: true,
374
+ description: "Stable id for this question; echoed in the answer."
375
+ },
376
+ question: {
377
+ type: "string",
378
+ required: true,
379
+ description: "The specific question to ask the user."
380
+ },
381
+ header: {
382
+ type: "string",
383
+ description: "Optional short heading for the question, such as \"Confirm\" or \"Choose Mode\"."
384
+ },
385
+ options: {
386
+ type: "array",
387
+ description: "Optional choices to show the user. If you recommend one, put it first and append \"(Recommended)\" to that label.",
388
+ items: {
389
+ type: "object",
390
+ additionalProperties: true,
391
+ properties: {
392
+ label: {
393
+ type: "string",
394
+ required: true,
395
+ description: "Short user-facing option label."
396
+ },
397
+ description: {
398
+ type: "string",
399
+ description: "One sentence explaining the tradeoff or impact."
400
+ }
401
+ }
402
+ }
403
+ },
404
+ multi_select: {
405
+ type: "boolean",
406
+ description: "Whether the user may select more than one option. Defaults to false."
407
+ }
408
+ }
409
+ }
410
+ } },
411
+ output: {
412
+ schema: {
413
+ type: "object",
414
+ additionalProperties: false,
415
+ properties: { answers: {
416
+ type: "array",
417
+ required: true,
418
+ description: "Submitted answer batch with one item per question. A skipped question has empty selected and no custom.",
419
+ items: {
420
+ type: "object",
421
+ additionalProperties: false,
422
+ properties: {
423
+ id: {
424
+ type: "string",
425
+ required: true
426
+ },
427
+ selected: {
428
+ type: "array",
429
+ required: true,
430
+ items: { type: "string" },
431
+ description: "Selected option labels. Empty with no custom means the user explicitly skipped this question."
432
+ },
433
+ custom: {
434
+ type: "string",
435
+ description: "Optional free-form answer; omitted for a skipped question."
436
+ }
437
+ }
438
+ }
439
+ } }
440
+ },
441
+ render: (_args, value) => [{
442
+ type: "text",
443
+ text: JSON.stringify(value)
444
+ }]
445
+ },
446
+ presentCall: (args) => presentAskCall(args.questions),
447
+ presentResult: (args, result) => presentAskResult(args.questions, result),
448
+ async execute(args, exec) {
449
+ return { answers: (await ctx.userQuestions.ask({
450
+ questions: args.questions.map((question) => ({
451
+ id: question.id,
452
+ question: question.question,
453
+ ...question.header !== void 0 ? { header: question.header } : {},
454
+ ...question.options !== void 0 ? { options: question.options } : {},
455
+ ...question.multi_select !== void 0 ? { multiSelect: question.multi_select } : {}
456
+ })),
457
+ ...exec.agent !== void 0 ? { agent: exec.agent } : {},
458
+ signal: exec.signal
459
+ })).answers.map((answer) => ({
460
+ id: answer.id,
461
+ selected: [...answer.selected],
462
+ ...answer.custom !== void 0 ? { custom: answer.custom } : {}
463
+ })) };
464
+ }
465
+ }));
466
+ }
467
+ //#endregion
468
+ export { Config, apply, inject, name };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Model-facing Consumer of the `ctx.userQuestions` capability seam.
3
+ * The tool pauses until a UI provider returns a human answer, then feeds that
4
+ * answer back into the agent loop as an ordinary tool result.
5
+ *
6
+ * @module @deepseek-ai/dsh-tool-ask-user
7
+ */
8
+ import type { Context } from '@deepseek-ai/cordis';
9
+ import z from '@deepseek-ai/schemastery';
10
+ import '@deepseek-ai/dsh-user-questions';
11
+ /** Cordis row selecting the tool schema and its default foreground wait. */
12
+ export interface Config {
13
+ /** Tool definition selected by this Cordis row. Defaults to the blocking legacy tool. */
14
+ mode?: 'legacy' | 'timed';
15
+ /** Foreground wait before automatic continuation. Defaults to 120 seconds. */
16
+ timeout?: number;
17
+ }
18
+ export declare const Config: z<Config>;
19
+ export declare const name = "tool-ask-user";
20
+ export declare const inject: string[];
21
+ export declare function apply(ctx: Context, config?: Config): void;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Host presentation for `ask_user_question`: the question batch and its answer
3
+ * batch as readable lines, instead of the model-facing JSON arguments and
4
+ * result. A host that renders tool presentation views shows the questions and
5
+ * what the user chose; the model-facing result stays compact JSON.
6
+ * @module @deepseek-ai/dsh-tool-ask-user/presentation
7
+ */
8
+ import type { ContentBlock } from '@deepseek-ai/dsh-llm';
9
+ import type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools';
10
+ /** One question the presenter reads from the tool's call arguments. */
11
+ export interface PresentedQuestion {
12
+ /** Stable id linking the question to its answer. */
13
+ readonly id: string;
14
+ /** The question text. */
15
+ readonly question: string;
16
+ /** Optional short label above the question. */
17
+ readonly header?: string | undefined;
18
+ }
19
+ /**
20
+ * The presentation view for a pending `ask_user_question` call.
21
+ *
22
+ * A batch renders as its questions, one per line, no matter how many arrived;
23
+ * the title stays the same so a reader recognizes the Tool across states.
24
+ * @param questions - the questions the call asks.
25
+ * @returns the generic call view.
26
+ */
27
+ export declare function presentAskCall(questions: readonly PresentedQuestion[]): ToolCallView;
28
+ /**
29
+ * The presentation view for a settled `ask_user_question` call.
30
+ *
31
+ * Each question is followed by the labels the user chose, or by a skip marker.
32
+ * A timed call whose window closed without an answer shows that it is still
33
+ * waiting; a failed call declares no view so the ordinary error row remains.
34
+ * @param questions - the questions the call asked.
35
+ * @param result - the settled result projection.
36
+ * @returns the generic result view, or undefined when the result is an error or
37
+ * carries no readable batch.
38
+ */
39
+ export declare function presentAskResult(questions: readonly PresentedQuestion[], result: {
40
+ readonly content: readonly ContentBlock[];
41
+ readonly isError: boolean;
42
+ }): ToolResultView | undefined;
43
+ //# sourceMappingURL=presentation.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Opt-in timed `ask_user_question` tool definition.
3
+ */
4
+ import type { Context } from '@deepseek-ai/cordis';
5
+ /** Model-facing meaning of a skipped answer item, shared by the blocking and timed descriptions. */
6
+ export declare const skippedAnswerGuidance: string;
7
+ /**
8
+ * Register the opt-in timed tool definition.
9
+ * @param ctx - Agent-scoped context receiving the tool.
10
+ * @param timeout - Default foreground wait in seconds.
11
+ */
12
+ export declare function registerTimedAskUser(ctx: Context, timeout?: number): void;
13
+ //# sourceMappingURL=timed.d.ts.map
package/locale/de.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Tool zum Stellen von Benutzerfragen",
4
+ "description": "Lassen Sie die KI dem Benutzer Fragen stellen, wenn sie zusätzliche Informationen oder Auswahlmöglichkeiten benötigt."
5
+ }
6
+ }
package/locale/en.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "meta": {
3
+ "title": "tool-ask-user"
4
+ }
5
+ }
package/locale/es.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Herramienta para hacer preguntas a los usuarios",
4
+ "description": "Deje que la IA haga preguntas al usuario cuando necesite información u opciones adicionales."
5
+ }
6
+ }
package/locale/fr.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Outil Poser des questions aux utilisateurs",
4
+ "description": "Laissez l'IA poser des questions à l'utilisateur lorsqu'elle a besoin d'informations ou de choix supplémentaires."
5
+ }
6
+ }
package/locale/ja.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "ユーザーへの質問ツール",
4
+ "description": "情報の補足や選択が必要な場合に、AI がユーザーに質問できます。"
5
+ }
6
+ }
package/locale/pt.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Ferramenta para fazer perguntas aos usuários",
4
+ "description": "Deixe a IA fazer perguntas ao usuário quando precisar de informações ou escolhas adicionais."
5
+ }
6
+ }
package/locale/ru.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Инструмент «Задавать вопросы пользователям»",
4
+ "description": "Позвольте ИИ задавать пользователю вопросы, когда ему нужна дополнительная информация или выбор."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "向用户提问工具",
4
+ "description": "让 AI 在需要补充信息或选择时向用户提问。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,50 @@
1
1
  {
2
2
  "name": "@fishwithcat/dsh-tool-ask-user",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "description": "Model-facing ask_user_question tool over the ctx.userQuestions seam",
4
+ "version": "0.2.2-alpha.2",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/FishwithCat/deepseek-harness-tui",
11
+ "directory": "packages/interaction/tool-ask-user"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./src/*": "./src/*",
22
+ "./package.json": "./package.json",
23
+ "./locale/*.json": "./locale/*.json"
24
+ },
25
+ "files": [
26
+ "locale/*.json",
27
+ "lib/index.js",
28
+ "lib/types/**/*.d.ts"
29
+ ],
30
+ "license": "MIT",
31
+ "peerDependencies": {
32
+ "@deepseek-ai/dsh-agent": "0.2.2-alpha.2",
33
+ "@deepseek-ai/dsh-tools": "0.2.2-alpha.2",
34
+ "@deepseek-ai/dsh-user-questions": "0.2.2-alpha.2",
35
+ "@deepseek-ai/cordis": "~4.0.6-alpha.1"
36
+ },
37
+ "devDependencies": {
38
+ "@deepseek-ai/dsh-agent": "0.2.2-alpha.2",
39
+ "@deepseek-ai/dsh-llm": "0.2.2-alpha.2",
40
+ "@deepseek-ai/dsh-system-prompt": "0.2.2-alpha.2",
41
+ "@deepseek-ai/dsh-tool-executor-native": "0.2.2-alpha.2",
42
+ "@deepseek-ai/dsh-tool-testkit": "0.2.2-alpha.2",
43
+ "@deepseek-ai/dsh-tools": "0.2.2-alpha.2",
44
+ "@deepseek-ai/dsh-user-questions": "0.2.2-alpha.2",
45
+ "@deepseek-ai/cordis": "~4.0.6-alpha.1"
46
+ },
47
+ "dependencies": {
48
+ "@deepseek-ai/schemastery": "~3.18.6-alpha.1"
49
+ }
50
+ }