@deepseek-ai/dsh-client-ui-user-questions 0.1.5-rc.2 → 0.1.6-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.
- package/README.i18n.yaml +2 -2
- package/README.md +7 -5
- package/README.zh.md +12 -10
- package/lib/client.js +71 -68
- package/lib/types/client/PlanReviewPanel.d.ts +3 -3
- package/lib/types/client/contract/slots.d.ts +22 -12
- package/package.json +18 -17
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-user-questions/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: abbf855706b478857540b12712c5999082b0ab22
|
|
6
|
+
README.zh.md: 995035cbb08ff6c64e2b91b61ab49b2bd473b9b7
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
|
|
9
9
|
|
|
10
10
|
## Summary
|
|
11
11
|
|
|
12
|
-
When an agent asks a question in the Web client, this package replaces the chat composer with an interactive question surface. Users can move through questions, choose one or multiple options, enter custom answers, skip items, and submit one structured answer batch. Single-choice selections advance immediately, while drafts survive Session navigation for the lifetime of the page. A single question with a supported presentation intent can use a dedicated surface, including the plan-review card with `
|
|
12
|
+
When an agent asks a question in the Web client, this package replaces the chat composer with an interactive question surface. Users can move through questions, choose one or multiple options, enter custom answers, skip items, and submit one structured answer batch. Single-choice selections advance immediately, while drafts survive Session navigation for the lifetime of the page. A single question with a supported presentation intent can use a dedicated surface, including the plan-review card with `Request changes` and `Approve` actions.
|
|
13
13
|
|
|
14
14
|
## Table of Contents
|
|
15
15
|
|
|
@@ -29,15 +29,15 @@ When the agent asks a question, the composer becomes the question surface: answe
|
|
|
29
29
|
|
|
30
30
|
### Answering
|
|
31
31
|
|
|
32
|
-
A multi-select draft keeps its selected labels while the user opens or edits the custom answer, so its submitted item may carry both `selected` and `custom`; a single-select custom answer remains exclusive. Question detail reuses the assistant-output `MarkdownText` primitive, including its GFM rendering and untrusted-content policy. The capped card keeps its title, navigation, and submission actions fixed while long detail and choices share an internal scroll region. "Skip
|
|
32
|
+
A multi-select draft keeps its selected labels while the user opens or edits the custom answer, so its submitted item may carry both `selected` and `custom`; a single-select custom answer remains exclusive. Question detail reuses the assistant-output `MarkdownText` primitive, including its GFM rendering and untrusted-content policy. The capped card keeps its title, navigation, and submission actions fixed while long detail and choices share an internal scroll region. "Skip" retains other drafts and emits the existing blank `{ selected: [] }` result for that item, while close rejects the whole wait as `ASK_CANCELLED`.
|
|
33
33
|
|
|
34
34
|
### The plan-review card
|
|
35
35
|
|
|
36
|
-
A `plan-review` intent — set by `dsh-plan-mode` on the `exit_plan_mode` review — renders
|
|
36
|
+
A `plan-review` intent — set by `dsh-plan-mode` on the `exit_plan_mode` review — renders a compact approval card: a `Plan review` strip with a `View full plan` link, the plan title and a two-line plain-text summary, and `Request changes` / `Approve` actions. The complete plan opens in the sidebar through the link or its permanent Chat card. Approve answers with the asker's approval label; `Request changes` rejects the wait as `ASK_CANCELLED`, returning the composer for the user's feedback without submitting an approval. The card has no separate refusal button.
|
|
37
37
|
|
|
38
38
|
### Failure and recovery
|
|
39
39
|
|
|
40
|
-
The generic question flow keeps its current page, selected labels, custom text, and explicit skips in a non-persisted Slot store scoped to the owning Session and keyed by the pending request's local render identity. Switching from Session A to B
|
|
40
|
+
The generic question flow keeps its current page, selected labels, custom text, and explicit skips in a non-persisted Slot store scoped to the owning Session generation and keyed by the pending request's local render identity. Switching from Session A to B retires A when no other reference owns it, so returning to A starts an empty question draft; another reference that keeps A's generation alive also keeps that draft. A different request identity reads an empty draft and replaces the previous value on its first edit; a successful answer or cancellation clears the matching value. The host remains authoritative for whether the request is pending.
|
|
41
41
|
|
|
42
42
|
-----
|
|
43
43
|
|
|
@@ -51,12 +51,14 @@ The package is one ownership rule: rendering a question is a host UI capability,
|
|
|
51
51
|
|
|
52
52
|
### Intent surface election
|
|
53
53
|
|
|
54
|
-
The card
|
|
54
|
+
The card accepts one question declaring the intent, carrying the plan as `detail`, and offering the named approve label, with at most one alternative and no multi-select. Its secondary action returns to the composer for change requests. Larger choices and multi-select questions remain in the generic flow.
|
|
55
55
|
|
|
56
56
|
### Copy and locale
|
|
57
57
|
|
|
58
58
|
Composer chrome copy (pager, buttons, placeholders, validation feedback) is bilingual: the plugin registers zh/en dictionaries under the `question` namespace of `dsh-client-locale` and hands the entry its bound translator plus the locale snapshot source through the inject face, so a locale switch re-renders a mounted composer. Question and option text arrives from the model and renders verbatim; carrier failure messages also display untranslated.
|
|
59
59
|
|
|
60
|
+
A plan review exposes `conversation.plan-review.actions` with its request key, full text, and optional invocation identity. The plan plugin opens logged plans from history and unlogged reviews as temporary sidebar previews. Opening a document does not answer or dismiss the review.
|
|
61
|
+
|
|
60
62
|
</details>
|
|
61
63
|
|
|
62
64
|
-----
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@ kind: "package-reference"
|
|
|
9
9
|
|
|
10
10
|
## 概述
|
|
11
11
|
|
|
12
|
-
当 agent
|
|
12
|
+
当 agent(智能体)在 Web 客户端中提问时,本包会用交互式提问界面接管聊天编辑器。用户可以在问题之间导航、选择一个或多个选项、输入自定义答案、跳过问题,并提交一批结构化答案。选择单选项后会立即前进,而草稿会在当前页面的生命周期内跨会话导航保留。若唯一的问题声明了受支持的呈现意图,则可使用专用界面,包括带 `Request changes` 和 `Approve` 操作的 plan-review 卡片。
|
|
13
13
|
|
|
14
14
|
## 目录
|
|
15
15
|
|
|
@@ -29,15 +29,15 @@ kind: "package-reference"
|
|
|
29
29
|
|
|
30
30
|
### 作答
|
|
31
31
|
|
|
32
|
-
用户打开或编辑自定义答案时,多选题草稿会保留已选中的标签,因此提交项可以同时携带 `selected` 与 `custom`;单选题的自定义答案仍保持互斥。问题详情复用助手输出的 `MarkdownText` 原语,包括其 GFM
|
|
32
|
+
用户打开或编辑自定义答案时,多选题草稿会保留已选中的标签,因此提交项可以同时携带 `selected` 与 `custom`;单选题的自定义答案仍保持互斥。问题详情复用助手输出的 `MarkdownText` 原语,包括其 GFM 渲染与不受信任内容策略。限高卡片保持标题、导航与提交动作固定,超长的详情与选项共享内部滚动区。「跳过」会保留其他草稿,并为该项发出既有的空 `{ selected: [] }` 结果;关闭则以 `ASK_CANCELLED` 拒绝整个等待。
|
|
33
33
|
|
|
34
34
|
### plan-review 卡片
|
|
35
35
|
|
|
36
|
-
`plan-review` 意图——由 `dsh-plan-mode` 在 `exit_plan_mode`
|
|
36
|
+
`plan-review` 意图——由 `dsh-plan-mode` 在 `exit_plan_mode` 审阅上设置——渲染紧凑审批卡片:顶部为带“查看全文”链接的“计划待审”条带,正文显示计划标题和两行纯文本摘要,底部提供“要求修改”和“同意执行”。通过链接或聊天历史中的常驻卡片可在侧边栏阅读完整计划。“同意执行”用提问方的批准标签回答;“要求修改”以 `ASK_CANCELLED` 拒绝等待,让编辑器归位供用户输入反馈,不会提交批准。卡片不再单列拒绝按钮。
|
|
37
37
|
|
|
38
38
|
### 失败与恢复
|
|
39
39
|
|
|
40
|
-
通用提问流程把当前题号、已选标签、自定义文本和显式跳过状态保存在非持久化
|
|
40
|
+
通用提问流程把当前题号、已选标签、自定义文本和显式跳过状态保存在非持久化 slot 存储中;该存储归属对应 Session generation,并以待处理请求的本地渲染标识为键。从 Session A 切换到 B 时,如果没有其他引用持有 A,A 就会结束,因此返回 A 时会得到空的问题草稿;如果另一个引用继续持有 A 的 generation,该草稿也会保留。不同的请求标识读取空草稿,并在首次编辑时替换旧值;成功回答或取消会清除相符的值。请求是否仍在等待由主机保持权威。
|
|
41
41
|
|
|
42
42
|
-----
|
|
43
43
|
|
|
@@ -49,14 +49,16 @@ kind: "package-reference"
|
|
|
49
49
|
|
|
50
50
|
本包是一条归属规则:渲染提问是宿主的 UI 能力,拥有该工具则是 agent 的能力,因此 `tool-ask-user` 行属于需要它的各个 preset(以及没有 preset 的 TUI 组装)。
|
|
51
51
|
|
|
52
|
-
###
|
|
52
|
+
### 意图界面选择
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
卡片接管声明了意图、以 `detail` 携带计划、提供了被指名的批准标签的单个问题,要求除批准外最多一个选项,且非多选。次要操作返回编辑器供用户提出修改要求。更多选项或多选问题仍由通用流程处理。
|
|
55
55
|
|
|
56
56
|
### 文案与 locale
|
|
57
57
|
|
|
58
58
|
编辑器外框文案(翻页器、按钮、占位符、校验提示)是双语的:插件在 `dsh-client-locale` 的 `question` 命名空间下注册 zh/en 词典,并通过 inject face 把绑定的翻译函数和 locale 快照源交给该条目,因此切换语言会重新渲染已挂载的编辑器。问题与选项文本来自模型并原样渲染;载体失败消息也不经翻译直接显示。
|
|
59
59
|
|
|
60
|
+
计划审批通过 `conversation.plan-review.actions` 插槽提供请求键、完整正文和可选的调用标识。计划插件从历史中打开已记录计划,并把没有调用标识的审批作为临时侧边栏预览打开。打开文档不会回答或关闭审批。
|
|
61
|
+
|
|
60
62
|
</details>
|
|
61
63
|
|
|
62
64
|
-----
|
|
@@ -67,9 +69,9 @@ kind: "package-reference"
|
|
|
67
69
|
以下页面覆盖编辑器宿主、工具 seam 与 plan-mode 消费方。
|
|
68
70
|
|
|
69
71
|
- [ui-conversation](../ui-conversation/README.zh.md)——拥有 `conversation.composer` 链的聊天界面。
|
|
70
|
-
- [tool-ask-user](../../interaction/tool-ask-user/README.zh.md)
|
|
72
|
+
- [tool-ask-user](../../interaction/tool-ask-user/README.zh.md)——面向模型的工具;本 UI 会渲染其 schema 与答案。
|
|
71
73
|
- [ui-plan](../ui-plan/README.zh.md)——设置 `plan-review` 意图的 plan-mode 界面。
|
|
72
|
-
- [user-questions](../../interaction/user-questions/README.zh.md)——Host 侧提问 seam
|
|
74
|
+
- [user-questions](../../interaction/user-questions/README.zh.md)——Host 侧提问 seam 及其应答方 waterfall(瀑布式事件)。
|
|
73
75
|
|
|
74
76
|
-----
|
|
75
77
|
|
|
@@ -89,7 +91,7 @@ kind: "package-reference"
|
|
|
89
91
|
|
|
90
92
|
这些限制定义草稿持久性与编辑器归属;它们是当前包约束。
|
|
91
93
|
|
|
92
|
-
-
|
|
94
|
+
- **未提交草稿的生命周期限于当前页面与会话**:只要该会话作用域仍留在页面内,会话导航就会保留草稿;完整刷新页面、会话被裁剪,或待处理请求以新的本地标识重新交付时,则从空草稿开始。存储从不把草稿写入主机、`localStorage` 或磁盘。
|
|
93
95
|
- **每次只有一个请求拥有编辑器**:后续待处理请求仍留在会话快照中,并在较早请求落定后显示。
|
|
94
96
|
|
|
95
97
|
<a id="dev-note"></a>
|
|
@@ -102,4 +104,4 @@ kind: "package-reference"
|
|
|
102
104
|
|
|
103
105
|
</details>
|
|
104
106
|
|
|
105
|
-
**运行时不变式:**
|
|
107
|
+
**运行时不变式:** 不发布伴生入口。工具与 slot 注册都是由各自注册表持有和观察的 effect;Host 待处理表通过公开的 wire protocol 测试。
|
package/lib/client.js
CHANGED
|
@@ -21,16 +21,10 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
* Narrow a request to a renderable plan review, or return undefined to leave it
|
|
22
22
|
* to the generic question flow.
|
|
23
23
|
*
|
|
24
|
-
* The card
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* label the intent names, and is a binary single choice: at most one option
|
|
29
|
-
* besides approve, and not multi-select. A third option or a multi-select batch
|
|
30
|
-
* has answers two buttons cannot express, so the generic flow keeps it — as it
|
|
31
|
-
* keeps any request whose intent the asker's own service would have rejected,
|
|
32
|
-
* because the client sits downstream of a wire boundary and every request must
|
|
33
|
-
* stay answerable.
|
|
24
|
+
* The card offers approval and a return to the composer for change requests.
|
|
25
|
+
* It accepts one question carrying the plan as detail and the named approve
|
|
26
|
+
* option, with at most one alternative and no multi-select. Larger choices
|
|
27
|
+
* remain in the generic question flow.
|
|
34
28
|
*
|
|
35
29
|
* @param questions - the request's whole question batch.
|
|
36
30
|
* @returns The narrowed review, or undefined when the generic flow owns it.
|
|
@@ -50,6 +44,7 @@ window.__ModuleLoader__.load({
|
|
|
50
44
|
id: question.id,
|
|
51
45
|
question: question.question,
|
|
52
46
|
plan: question.detail,
|
|
47
|
+
...intent.callId === void 0 ? {} : { callId: intent.callId },
|
|
53
48
|
approve,
|
|
54
49
|
...decline === void 0 ? {} : { decline }
|
|
55
50
|
};
|
|
@@ -205,7 +200,7 @@ window.__ModuleLoader__.load({
|
|
|
205
200
|
}
|
|
206
201
|
//#endregion
|
|
207
202
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-user-questions/src/client/PlanReviewPanel.module.css.mjs
|
|
208
|
-
const css$1 = ".LVzXQa_frame{padding:6px calc(var(--dsh-composer-side-clearance) + 16px) 10px;justify-content:center;display:flex}.LVzXQa_card{width:100%;max-width:var(--dsh-chat-content-width)
|
|
203
|
+
const css$1 = ".LVzXQa_frame{padding:6px calc(var(--dsh-composer-side-clearance) + 16px) 10px;justify-content:center;display:flex}.LVzXQa_card{width:100%;max-width:var(--dsh-chat-content-width);--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);background:var(--dsw-specific-input-major);box-shadow:var(--dsw-elevation-panel);color:var(--dsw-alias-label-primary);border:0;border-radius:20px;flex-direction:column;display:flex;overflow:hidden}.LVzXQa_card,.LVzXQa_card *{box-sizing:border-box}.LVzXQa_strip{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary);flex-shrink:0;align-items:center;gap:8px;padding:12px 16px;font-size:14px;line-height:20px;display:flex}.LVzXQa_dot{corner-shape:round;background:var(--dsw-alias-state-warn-primary);border-radius:50%;width:8px;height:8px}.LVzXQa_footer{flex-shrink:0;justify-content:space-between;align-items:center;gap:12px;padding:8px 16px 12px;display:flex}.LVzXQa_feedback{min-height:16px;color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}.LVzXQa_actions{flex-shrink:0;align-items:center;gap:8px;display:flex}.LVzXQa_summary{min-width:0;padding:14px 16px 12px}.LVzXQa_title{text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:15px;font-weight:500;line-height:22px;overflow:hidden}.LVzXQa_description{-webkit-line-clamp:2;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;margin:8px 0 0;font-size:14px;line-height:24px;display:-webkit-box;overflow:hidden}.LVzXQa_discuss{gap:6px}@media (width<=720px){.LVzXQa_card{border-radius:16px}.LVzXQa_footer{align-items:flex-end;padding:8px 12px 10px}}.LVzXQa_previewActions{align-items:center;margin-left:auto;display:flex}";
|
|
209
204
|
const tagId$1 = "@deepseek-ai/dsh-client-ui-user-questions/PlanReviewPanel.module.css";
|
|
210
205
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
211
206
|
const tag = document.createElement("style");
|
|
@@ -216,14 +211,17 @@ window.__ModuleLoader__.load({
|
|
|
216
211
|
}
|
|
217
212
|
var PlanReviewPanel_module_css_default = {
|
|
218
213
|
"actions": "LVzXQa_actions",
|
|
219
|
-
"body": "LVzXQa_body",
|
|
220
214
|
"card": "LVzXQa_card",
|
|
215
|
+
"description": "LVzXQa_description",
|
|
221
216
|
"discuss": "LVzXQa_discuss",
|
|
222
217
|
"dot": "LVzXQa_dot",
|
|
223
218
|
"feedback": "LVzXQa_feedback",
|
|
224
219
|
"footer": "LVzXQa_footer",
|
|
225
220
|
"frame": "LVzXQa_frame",
|
|
226
|
-
"
|
|
221
|
+
"previewActions": "LVzXQa_previewActions",
|
|
222
|
+
"strip": "LVzXQa_strip",
|
|
223
|
+
"summary": "LVzXQa_summary",
|
|
224
|
+
"title": "LVzXQa_title"
|
|
227
225
|
};
|
|
228
226
|
//#endregion
|
|
229
227
|
//#region lib/types/client/PlanReviewPanel.js
|
|
@@ -238,19 +236,12 @@ window.__ModuleLoader__.load({
|
|
|
238
236
|
return description === void 0 ? {} : { title: description };
|
|
239
237
|
}
|
|
240
238
|
/**
|
|
241
|
-
* Render
|
|
239
|
+
* Render plan review controls; the submitted document opens in the sidebar.
|
|
242
240
|
*
|
|
243
241
|
* @param props - the question domain face, the narrowed plan review, and `t`.
|
|
244
242
|
* @returns The plan-review takeover for this request.
|
|
245
243
|
*/
|
|
246
|
-
function PlanReviewPanel({ pending, review, t }) {
|
|
247
|
-
const markdownLabels = (0, react.useMemo)(() => ({
|
|
248
|
-
code: {
|
|
249
|
-
copyLabel: t("copy"),
|
|
250
|
-
copiedLabel: t("copied")
|
|
251
|
-
},
|
|
252
|
-
footnotes: t("markdown.footnotes")
|
|
253
|
-
}), [t]);
|
|
244
|
+
function PlanReviewPanel({ pending, review, t, renderSlot }) {
|
|
254
245
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
255
246
|
const [error, setError] = (0, react.useState)(null);
|
|
256
247
|
const settle = (send) => {
|
|
@@ -267,7 +258,14 @@ window.__ModuleLoader__.load({
|
|
|
267
258
|
selected: [label]
|
|
268
259
|
}] }));
|
|
269
260
|
};
|
|
270
|
-
const
|
|
261
|
+
const summary = (0, react.useMemo)(() => {
|
|
262
|
+
const title = (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-line" });
|
|
263
|
+
const description = (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-paragraph" });
|
|
264
|
+
return {
|
|
265
|
+
title,
|
|
266
|
+
description: description === title ? "" : description
|
|
267
|
+
};
|
|
268
|
+
}, [review.plan]);
|
|
271
269
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
272
270
|
className: PlanReviewPanel_module_css_default.frame,
|
|
273
271
|
"data-plan-review-key": pending.key,
|
|
@@ -277,15 +275,27 @@ window.__ModuleLoader__.load({
|
|
|
277
275
|
children: [
|
|
278
276
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
279
277
|
className: PlanReviewPanel_module_css_default.strip,
|
|
280
|
-
children: [
|
|
278
|
+
children: [
|
|
279
|
+
(0, react_jsx_runtime.jsx)("span", { className: PlanReviewPanel_module_css_default.dot }),
|
|
280
|
+
t("plan.header"),
|
|
281
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
282
|
+
className: PlanReviewPanel_module_css_default.previewActions,
|
|
283
|
+
children: renderSlot("conversation.plan-review.actions", {
|
|
284
|
+
review,
|
|
285
|
+
requestKey: pending.key
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
]
|
|
281
289
|
}),
|
|
282
|
-
(0, react_jsx_runtime.
|
|
283
|
-
className: PlanReviewPanel_module_css_default.
|
|
284
|
-
"
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
290
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
291
|
+
className: PlanReviewPanel_module_css_default.summary,
|
|
292
|
+
children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
293
|
+
className: PlanReviewPanel_module_css_default.title,
|
|
294
|
+
children: summary.title
|
|
295
|
+
}), summary.description !== "" && (0, react_jsx_runtime.jsx)("p", {
|
|
296
|
+
className: PlanReviewPanel_module_css_default.description,
|
|
297
|
+
children: summary.description
|
|
298
|
+
})]
|
|
289
299
|
}),
|
|
290
300
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
291
301
|
className: PlanReviewPanel_module_css_default.footer,
|
|
@@ -295,36 +305,24 @@ window.__ModuleLoader__.load({
|
|
|
295
305
|
children: error
|
|
296
306
|
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
297
307
|
className: PlanReviewPanel_module_css_default.actions,
|
|
298
|
-
children: [
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
children: t("plan.decline")
|
|
317
|
-
}),
|
|
318
|
-
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
319
|
-
variant: "primary",
|
|
320
|
-
...tooltip(review.approve.description),
|
|
321
|
-
disabled: busy,
|
|
322
|
-
onClick: () => {
|
|
323
|
-
decide(review.approve.label);
|
|
324
|
-
},
|
|
325
|
-
children: t("plan.approve")
|
|
326
|
-
})
|
|
327
|
-
]
|
|
308
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
309
|
+
variant: "outline",
|
|
310
|
+
className: PlanReviewPanel_module_css_default.discuss,
|
|
311
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 }),
|
|
312
|
+
disabled: busy,
|
|
313
|
+
onClick: () => {
|
|
314
|
+
settle(() => pending.cancel());
|
|
315
|
+
},
|
|
316
|
+
children: t("plan.discuss")
|
|
317
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
318
|
+
variant: "primary",
|
|
319
|
+
...tooltip(review.approve.description),
|
|
320
|
+
disabled: busy,
|
|
321
|
+
onClick: () => {
|
|
322
|
+
decide(review.approve.label);
|
|
323
|
+
},
|
|
324
|
+
children: t("plan.approve")
|
|
325
|
+
})]
|
|
328
326
|
})]
|
|
329
327
|
})
|
|
330
328
|
]
|
|
@@ -460,7 +458,8 @@ window.__ModuleLoader__.load({
|
|
|
460
458
|
}, question.key) : (0, react_jsx_runtime.jsx)(PlanReviewPanel, {
|
|
461
459
|
pending: question,
|
|
462
460
|
review,
|
|
463
|
-
t: props.t
|
|
461
|
+
t: props.t,
|
|
462
|
+
renderSlot: props.renderSlot
|
|
464
463
|
}, question.key);
|
|
465
464
|
}
|
|
466
465
|
function QuestionFlow({ pending, t, useStore, actions }) {
|
|
@@ -799,12 +798,12 @@ window.__ModuleLoader__.load({
|
|
|
799
798
|
"nav.cancel": "放弃整组问题",
|
|
800
799
|
"option.recommended": "推荐",
|
|
801
800
|
"custom.placeholder": "输入你的答案",
|
|
802
|
-
"action.skip": "
|
|
801
|
+
"action.skip": "跳过",
|
|
803
802
|
"action.next": "下一题",
|
|
804
803
|
"plan.header": "计划待审",
|
|
805
|
-
"plan.approve": "
|
|
804
|
+
"plan.approve": "同意执行",
|
|
806
805
|
"plan.decline": "拒绝",
|
|
807
|
-
"plan.discuss": "
|
|
806
|
+
"plan.discuss": "要求修改"
|
|
808
807
|
};
|
|
809
808
|
/** English dictionary, checked complete against the zh key set. */
|
|
810
809
|
const en = {
|
|
@@ -817,12 +816,12 @@ window.__ModuleLoader__.load({
|
|
|
817
816
|
"nav.cancel": "Dismiss all questions",
|
|
818
817
|
"option.recommended": "Recommended",
|
|
819
818
|
"custom.placeholder": "Type your answer",
|
|
820
|
-
"action.skip": "Skip
|
|
819
|
+
"action.skip": "Skip",
|
|
821
820
|
"action.next": "Next",
|
|
822
821
|
"plan.header": "Plan review",
|
|
823
822
|
"plan.approve": "Approve",
|
|
824
823
|
"plan.decline": "Refuse",
|
|
825
|
-
"plan.discuss": "
|
|
824
|
+
"plan.discuss": "Request changes"
|
|
826
825
|
};
|
|
827
826
|
//#endregion
|
|
828
827
|
//#region lib/types/client/index.js
|
|
@@ -875,7 +874,11 @@ window.__ModuleLoader__.load({
|
|
|
875
874
|
name: "conversation.composer",
|
|
876
875
|
select: ({ pendingInteraction }) => pendingInteraction instanceof PendingQuestion ? pendingInteraction : null,
|
|
877
876
|
locale: NS,
|
|
878
|
-
store: questionDraftStore
|
|
877
|
+
store: questionDraftStore,
|
|
878
|
+
children: { "conversation.plan-review.actions": {
|
|
879
|
+
kind: "list",
|
|
880
|
+
scope: "session"
|
|
881
|
+
} }
|
|
879
882
|
}, QuestionComposer));
|
|
880
883
|
ctx.remote.$on("user-questions/request", function(request, next) {
|
|
881
884
|
return answerQuestion(ctx, this, request, next, registerPendingInteraction);
|
|
@@ -3,12 +3,12 @@ import type { PendingQuestion, PlanReview, QuestionComposerProps } from './contr
|
|
|
3
3
|
export type PlanReviewPanelProps = {
|
|
4
4
|
pending: PendingQuestion;
|
|
5
5
|
review: PlanReview;
|
|
6
|
-
} & Pick<QuestionComposerProps, 't'>;
|
|
6
|
+
} & Pick<QuestionComposerProps, 't' | 'renderSlot'>;
|
|
7
7
|
/**
|
|
8
|
-
* Render
|
|
8
|
+
* Render plan review controls; the submitted document opens in the sidebar.
|
|
9
9
|
*
|
|
10
10
|
* @param props - the question domain face, the narrowed plan review, and `t`.
|
|
11
11
|
* @returns The plan-review takeover for this request.
|
|
12
12
|
*/
|
|
13
|
-
export declare function PlanReviewPanel({ pending, review, t }: PlanReviewPanelProps): import("react").JSX.Element;
|
|
13
|
+
export declare function PlanReviewPanel({ pending, review, t, renderSlot }: PlanReviewPanelProps): import("react").JSX.Element;
|
|
14
14
|
//# sourceMappingURL=PlanReviewPanel.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Question composer props and one pending Remote waterfall response. */
|
|
2
|
-
import type { PropsLocale, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
+
import type { ToolCallId } from '@deepseek-ai/dsh-llm/brand';
|
|
3
4
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
4
5
|
import type { AskUserQuestionAnswer, AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions';
|
|
5
6
|
import type { createQuestionDraftStore } from '../draft-store.ts';
|
|
@@ -9,6 +10,19 @@ declare module '@deepseek-ai/dsh-client-ui-session/client' {
|
|
|
9
10
|
question: PendingQuestion;
|
|
10
11
|
}
|
|
11
12
|
}
|
|
13
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
14
|
+
interface SlotMap {
|
|
15
|
+
/** Actions for the exact plan under review; approval remains with the question composer. */
|
|
16
|
+
'conversation.plan-review.actions': {
|
|
17
|
+
kind: 'list';
|
|
18
|
+
scope: 'session';
|
|
19
|
+
owner: {
|
|
20
|
+
review: PlanReview;
|
|
21
|
+
requestKey: PendingQuestion['key'];
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
12
26
|
/** One structured answer batch covering every question of the request. */
|
|
13
27
|
export type QuestionAnswer = AskUserQuestionAnswer;
|
|
14
28
|
/** One question of the request. */
|
|
@@ -29,6 +43,8 @@ export interface PlanReview {
|
|
|
29
43
|
question: string;
|
|
30
44
|
/** The plan markdown under review. */
|
|
31
45
|
plan: string;
|
|
46
|
+
/** Logged tool invocation used to reopen this plan. */
|
|
47
|
+
callId?: ToolCallId;
|
|
32
48
|
/** The option that approves the plan. */
|
|
33
49
|
approve: QuestionOption;
|
|
34
50
|
/** The option that declines it; absent when the asker offered no other option. */
|
|
@@ -38,16 +54,10 @@ export interface PlanReview {
|
|
|
38
54
|
* Narrow a request to a renderable plan review, or return undefined to leave it
|
|
39
55
|
* to the generic question flow.
|
|
40
56
|
*
|
|
41
|
-
* The card
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* label the intent names, and is a binary single choice: at most one option
|
|
46
|
-
* besides approve, and not multi-select. A third option or a multi-select batch
|
|
47
|
-
* has answers two buttons cannot express, so the generic flow keeps it — as it
|
|
48
|
-
* keeps any request whose intent the asker's own service would have rejected,
|
|
49
|
-
* because the client sits downstream of a wire boundary and every request must
|
|
50
|
-
* stay answerable.
|
|
57
|
+
* The card offers approval and a return to the composer for change requests.
|
|
58
|
+
* It accepts one question carrying the plan as detail and the named approve
|
|
59
|
+
* option, with at most one alternative and no multi-select. Larger choices
|
|
60
|
+
* remain in the generic question flow.
|
|
51
61
|
*
|
|
52
62
|
* @param questions - the request's whole question batch.
|
|
53
63
|
* @returns The narrowed review, or undefined when the generic flow owns it.
|
|
@@ -102,7 +112,7 @@ export type QuestionWait = PendingQuestion;
|
|
|
102
112
|
* standard locale seat; the carrier plus the domain face above carry the
|
|
103
113
|
* whole behavior surface.
|
|
104
114
|
*/
|
|
105
|
-
export type QuestionComposerProps = PropsRuntime<'conversation.composer'> & PropsStore<ReturnType<typeof createQuestionDraftStore>> & {
|
|
115
|
+
export type QuestionComposerProps = PropsRuntime<'conversation.composer'> & PropsStore<ReturnType<typeof createQuestionDraftStore>> & PropsRenderSlots<'conversation.plan-review.actions'> & {
|
|
106
116
|
matched: QuestionWait;
|
|
107
117
|
} & PropsLocale<'question'>;
|
|
108
118
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-user-questions",
|
|
3
3
|
"description": "Web ask_user_question composer takeover and plan-review presentation UI",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -46,23 +46,24 @@
|
|
|
46
46
|
"@types/react": "~18.3.1",
|
|
47
47
|
"react": "^18.2.0",
|
|
48
48
|
"clsx": "^2.0.0",
|
|
49
|
+
"@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
|
|
49
50
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
50
|
-
"@deepseek-ai/dsh-
|
|
51
|
-
"@deepseek-ai/dsh-api-
|
|
52
|
-
"@deepseek-ai/dsh-
|
|
53
|
-
"@deepseek-ai/dsh-client-
|
|
54
|
-
"@deepseek-ai/dsh-
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
-
"@deepseek-ai/dsh-
|
|
57
|
-
"@deepseek-ai/dsh-user-questions": "^0.1.
|
|
58
|
-
"@deepseek-ai/dsh-client-ui-
|
|
59
|
-
"@deepseek-ai/dsh-client-ui-
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/dsh-
|
|
65
|
-
"@deepseek-ai/dsh-client-
|
|
51
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.6-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
|
|
54
|
+
"@deepseek-ai/dsh-client-store": "^0.1.6-alpha.2",
|
|
55
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.2",
|
|
56
|
+
"@deepseek-ai/dsh-tools": "^0.1.6-alpha.2",
|
|
57
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.2",
|
|
58
|
+
"@deepseek-ai/dsh-user-questions": "^0.1.6-alpha.2",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.2",
|
|
61
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.6-alpha.2",
|
|
62
|
+
"@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
|
|
63
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.2",
|
|
64
|
+
"@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
|
|
65
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2",
|
|
66
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.6-alpha.2"
|
|
66
67
|
},
|
|
67
68
|
"files": [
|
|
68
69
|
"lib/index.js",
|