@deepseek-ai/dsh-client-ui-user-questions 0.1.7-rc.2 → 0.2.0-rc.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 CHANGED
@@ -3,41 +3,47 @@
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
5
  /:
6
- en: b50469addda9db2d
7
- zh: ae560611295a5f4d
6
+ en: 50286bfa65e45456
7
+ zh: 2347492bb65bd1b4
8
8
  /deepseek-ai-dsh-client-ui-user-questions:
9
9
  en: f109e91b29d71f55
10
10
  zh: 73200984bad7f908
11
11
  /deepseek-ai-dsh-client-ui-user-questions/summary:
12
- en: 7e81c6a53759ff37
13
- zh: b83f666c4ef4cbd3
12
+ en: 1aa6291852d48a08
13
+ zh: 414eed268fb2cf1f
14
14
  /deepseek-ai-dsh-client-ui-user-questions/table-of-contents:
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
17
17
  /deepseek-ai-dsh-client-ui-user-questions/use-this-package:
18
- en: 4aa048dcb7282f12
19
- zh: d2731da0870aa6a0
18
+ en: 8d3815c19858ac85
19
+ zh: 94fc905fa202d334
20
20
  /deepseek-ai-dsh-client-ui-user-questions/use-this-package/answering:
21
- en: 8b6f37bfb11a2c3a
22
- zh: 59d8951211f9b21b
21
+ en: cc19c065d0aeac1e
22
+ zh: 91c8cbe08b438e7f
23
+ /deepseek-ai-dsh-client-ui-user-questions/use-this-package/reading-a-settled-question-back:
24
+ en: 10975f68ff9c6fcc
25
+ zh: 92246aadc363f0eb
23
26
  /deepseek-ai-dsh-client-ui-user-questions/use-this-package/the-plan-review-card:
24
27
  en: 6b12f1362c614a39
25
28
  zh: 27d9cf54d4cbd5d2
26
29
  /deepseek-ai-dsh-client-ui-user-questions/use-this-package/failure-and-recovery:
27
- en: da530ef485c07417
28
- zh: b07525cfcd5034f0
30
+ en: 3509678f4d183834
31
+ zh: 625542b79e434eb5
29
32
  /deepseek-ai-dsh-client-ui-user-questions/understand-the-implementation:
30
33
  en: 77e1b2585acdf67b
31
34
  zh: d433ec185c6b8f57
35
+ /deepseek-ai-dsh-client-ui-user-questions/understand-the-implementation/reopening-a-panel:
36
+ en: 4350f2fbc41f6c86
37
+ zh: a11ef5e97d0c936e
32
38
  /deepseek-ai-dsh-client-ui-user-questions/understand-the-implementation/intent-surface-election:
33
- en: 7f3e0e2460317462
34
- zh: cb6b9410410e2f29
39
+ en: 126a889edbc42edd
40
+ zh: 7e08968cd61d42a2
35
41
  /deepseek-ai-dsh-client-ui-user-questions/understand-the-implementation/copy-and-locale:
36
- en: 1a144dbf8bf39d43
37
- zh: 66bccf9c343395c7
42
+ en: 00b3f92cdad70faf
43
+ zh: ab672ddc2faef857
38
44
  /deepseek-ai-dsh-client-ui-user-questions/further-exploration:
39
- en: 70e1ae005fa86e3c
40
- zh: 9c779d63b3f921cc
45
+ en: dc98d242987579a3
46
+ zh: a193b9f33a197089
41
47
  /deepseek-ai-dsh-client-ui-user-questions/model-experience:
42
48
  en: 198421eb8ed8923f
43
49
  zh: 84f719be6e6dfe62
@@ -45,8 +51,8 @@
45
51
  en: 1032ba29b7d7f9d7
46
52
  zh: 01f1dbf4c2164fd2
47
53
  /deepseek-ai-dsh-client-ui-user-questions/known-limitations-and-deferred-work:
48
- en: beb6dc6d1496e799
49
- zh: d92150a88a797c21
54
+ en: d61767a407077aaf
55
+ zh: 891e7bffa61f3017
50
56
  /deepseek-ai-dsh-client-ui-user-questions/known-limitations-and-deferred-work/dev-note:
51
- en: 7c763299daed17e4
52
- zh: fb410b366b407ec7
57
+ en: 5dd8c89b228f4037
58
+ zh: cf8d2774370d1b74
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Web ask_user_question feature for the dsh web client: the composer-takeover question UI and the plan-review approval card."
2
+ description: "Web ask_user_question feature for the dsh web client: the attached question card, timed wait, drafts, late replies, and the plan-review approval card."
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -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 `Request changes` and `Approve` actions.
12
+ The Web client shows an agent's question beside the chat input. Users choose options, enter text, skip questions, and submit one answer batch. A timed card counts down; focus pauses it, editing or `Take time` holds it, and expiry lets the agent continue while the question stays answerable. Closing a card linked to a tool call hides it; its tool row reopens it and later shows recorded answers. The Host preserves the question across restart, while this browser preserves unfinished input across reload.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -25,11 +25,17 @@ When an agent asks a question in the Web client, this package replaces the chat
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
- When the agent asks a question, the composer becomes the question surface: answer each question, navigate with the pager, or skip it. Single-select choices advance immediately; Enter continues the flow and submits once every question is answered or skipped, while Shift+Enter breaks a line instead (during IME composition Enter only confirms the input candidate without advancing).
28
+ When the agent asks a question, the attached card temporarily occupies the composer seat: answer each question, navigate with the pager, or skip it. A first choice marked “Recommended” starts selected, but remains an unsubmitted draft and does not pause a timed countdown. Clicking a single-select choice advances immediately. Enter on a focused option attempts to submit the batch without selecting that option; missing answers return to the first incomplete question. Enter in a text answer continues the flow, while Shift+Enter breaks a line instead (during IME composition Enter only confirms the input candidate without advancing).
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" retains other drafts and emits the existing blank `{ selected: [] }` result for that item, while close rejects the whole wait as `ASK_CANCELLED`.
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. Close is not an answer: a question the Host named by tool call only leaves the composer seat, and its `ask_user_question` tool call row brings the panel back; a request that carries no tool call has no row to return from, so closing it rejects the whole wait as `ASK_CANCELLED`.
33
+
34
+ ### Reading a settled question back
35
+
36
+ Each late reply is shown once, including when it opens a new Turn. Replies follow normal Chat process grouping and whole-Turn folding. Expand the containing Turn and work group to read a reply that has been folded away.
37
+
38
+ A question that already settled opens as a read-only card: the same pager over the recorded answers, marked `Answered`. Every option and text field is disabled, Skip and the submit action are gone, a question the user skipped says so in place of its empty answer, and a free-text field appears only where the recorded answer used one. Closing it removes the card, and the tool call row builds another from the same record.
33
39
 
34
40
  ### The plan-review card
35
41
 
@@ -37,7 +43,19 @@ A `plan-review` intent — set by `dsh-plan-mode` on the `exit_plan_mode` review
37
43
 
38
44
  ### Failure and recovery
39
45
 
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.
46
+ An answer field autofocuses only when its answer channel is ready and no countdown exists. Manual focus and blur during the claim handshake are retained: the countdown starts paused only if the answer surface still has focus when the remaining duration arrives.
47
+
48
+ Returning a local answer does not release its foreground claim: the Host closes that stream after accepting the waterfall outcome. The plugin owns the claim through this delivery interval. Explicit delegation releases it before calling the next answerer, and plugin disposal cancels any remaining claims.
49
+
50
+ The card has two sources. A live Host request creates it and carries the answer back. For a timed request, the Client first opens the question-owned `attachWait` stream and derives a local deadline from its remaining-duration frame. The card remains live while that first frame is pending. The claim lasts until the request settles or the Client disconnects, including while the panel is hidden. The card owns the countdown; at zero it rejects with `ASK_TIMED_OUT` and stays available. Once the projection lists the call as continued, answers use the `answer` Remote method. Card removal follows the projection, and plugin teardown releases its requests and claims.
51
+
52
+ A submission through the pending request is sent, not confirmed: when another browser settled the same request first, the gateway drops the late outcome silently. The card therefore keeps its draft until the projection closes it, and if the call turns continued while a submission is in flight, the controls re-arm with a hint so the same draft goes through the Remote path. An accepted Remote answer steers the agent at its nearest step. While its steer waits in the durable Inbox, the editable card closes and the question row shows the submitted answers read-only, including after a browser reconnect. Multiple pending steers are admitted together at that boundary; an active tool wait must finish before the agent can read them. Discarding a pending steer leaves the question answerable, and the user can reopen its row to submit again. A second answer while the first remains pending reports `REPLY_QUEUED`. Pristine focus freezes this browser's remaining countdown and blur resumes that remainder. The first answer mutation changes the local wait to indefinite, and `Take time` does the same explicitly. Those choices persist with this browser's draft across Session navigation and, for tool-call-keyed requests, reload. Another browser has its own countdown and can still settle the shared request; the Host projection remains the authority for whether the question is open or continued.
53
+
54
+ Each Session and pending request has an independent draft in browser storage. A tool-call-keyed request restores unfinished input after Session navigation, page reload, or browser restart; progress that no longer matches the question batch is ignored. An unnamed legacy request has a unique card key and cannot be restored after reload. A hidden panel keeps its draft for the next opening; a mounted closed card clears its own draft, and the next mounted card prunes drafts no live card owns. Drafts do not synchronize to another browser or device; the Host-projected question does.
55
+
56
+ A browser that reconnects while the tool call is open receives the pending request again and can still complete it with the remaining time. A Session reopened after the agent or process ended shows the card as continued; submitting resumes the Session's root agent and enters the answer as a new user turn.
57
+
58
+ Settled question replies remain compact in chat history. A caret marks the bubble as a disclosure; clicking it reopens the read-only question and answer details, and never reopens the settled tool call for a second submission. Its copy action writes each question with the answer the user gave, the same text whether the bubble is open or closed.
41
59
 
42
60
  -----
43
61
 
@@ -49,16 +67,20 @@ The generic question flow keeps its current page, selected labels, custom text,
49
67
 
50
68
  The package is one ownership rule: rendering a question is a host UI capability, having the tool is an agent capability, so the `tool-ask-user` row belongs to the presets that want it (and to the TUI composition, which has no presets).
51
69
 
70
+ ### Reopening a panel
71
+
72
+ This package fills `userQuestionPanels`, the optional capability `dsh-client-ui-tool` declares for its `ask_user_question` row. `reveal(sessionId, callId)` republishes that call's card as the last equal-precedence pending interaction, so the composer seat shows it again, and returns `false` when this Client holds no card for the call — a legacy unkeyed request, another browser's question, or a card the projection already closed. Whether a question still takes an answer comes from the `userQuestions` Session projection, which the row reads directly, so the capability carries no state of its own.
73
+
74
+ `review(sessionId, callId, record)` builds a card from the questions and answers the row parsed out of its own transcript, because the projection lists only answerable calls. That card has no answer channel and no countdown, the projection sweep leaves it alone, and closing it removes it rather than parking it in the registry. A call that still holds a live card shows the live one, so a stale copy never replaces a standing request; for the same reason a review card renders the record itself and takes only the page position from a draft its live card left behind.
75
+
52
76
  ### Intent surface election
53
77
 
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.
78
+ 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. 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, and opening a document does not answer or dismiss the review.
55
79
 
56
80
  ### Copy and locale
57
81
 
58
82
  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
83
 
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
-
62
84
  </details>
63
85
 
64
86
  -----
@@ -68,7 +90,8 @@ A plan review exposes `conversation.plan-review.actions` with its request key, f
68
90
 
69
91
  These pages cover the composer host, the tool seam, and the plan-mode consumer.
70
92
 
71
- - [ui-conversation](../ui-conversation/README.md) — the chat surface owning the `conversation.composer` chain.
93
+ - [ui-conversation](../ui-conversation/README.md) — the chat surface owning the `conversation.composer` slot.
94
+ - [ui-tool](../ui-tool/README.md) — the tool call transcript whose `ask_user_question` row reopens a hidden panel.
72
95
  - [tool-ask-user](../../interaction/tool-ask-user/README.md) — the model-facing tool whose schema and answers this UI renders.
73
96
  - [ui-plan](../ui-plan/README.md) — the plan-mode surface that sets the `plan-review` intent.
74
97
  - [user-questions](../../interaction/user-questions/README.md) — the Host-side question seam and its answerer waterfall.
@@ -89,10 +112,11 @@ No direct invalidation; `dsh-tool-ask-user` owns the model-visible tool call and
89
112
  <a id="known-limitations-and-deferred-work"></a>
90
113
 
91
114
 
92
- These limits define draft durability and composer ownership; they are current package constraints.
115
+ These limits define question-card ownership and cross-client behavior; they are current package constraints.
93
116
 
94
- - **Unsubmitted drafts have page-and-Session lifetime** — Session navigation preserves them while that Session scope remains in the page, but a full page reload, Session pruning, or a newly delivered pending-request identity starts with an empty draft. The store never writes them to the Host, `localStorage`, or disk.
95
- - **One request owns the composer at a time** — later pending requests remain in the session snapshot and become visible after the earlier request resolves.
117
+ - **Unsubmitted drafts are local to one browser** — Session navigation, page reload, and browser restart preserve them, but another browser or device reconstructs only the Host-stored question.
118
+ - **One request owns the question card at a time** — later pending requests remain in the session snapshot and become visible after the earlier request resolves.
119
+ - **Questions appear in the active Session composer** — durable pending questions do not add a separate sidebar inbox; reopen the owning Session to answer one.
96
120
 
97
121
  <a id="dev-note"></a>
98
122
  ### Dev Note
@@ -104,4 +128,4 @@ None.
104
128
 
105
129
  </details>
106
130
 
107
- **Runtime invariant:** No companion is published. Tool and slot registrations are effects owned and observed by their respective registries; the host pending table is exercised through the public wire protocol.
131
+ **Runtime invariant:** The Host Session projection is authoritative for durable timed questions. Browser storage only preserves unfinished input and never creates or keeps a question open. No runtime invariant companion is published because the Host validates and projects the durable state before this client package renders it.
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "dsh Web 客户端的 ask_user_question 功能:接管编辑器的提问 UI 与 plan-review 审批卡片。"
2
+ description: "dsh Web 客户端的 ask_user_question 功能:附着式提问卡片、计时等待、草稿、迟到回复与 plan-review 审批卡片。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 当 agent(智能体)在 Web 客户端中提问时,本包会用交互式提问界面接管聊天编辑器。用户可以在问题之间导航、选择一个或多个选项、输入自定义答案、跳过问题,并提交一批结构化答案。选择单选项后会立即前进,而草稿会在当前页面的生命周期内跨会话导航保留。若唯一的问题声明了受支持的呈现意图,则可使用专用界面,包括带 `Request changes` 和 `Approve` 操作的 plan-review 卡片。
12
+ Web 客户端在聊天输入框旁显示 agent(智能体)的提问。用户可以选择选项、输入文本、跳过问题,并提交一批答案。计时卡片会倒计时;聚焦时暂停,编辑或选择「慢慢回答」后保持等待,到期则放行 agent,而问题仍可回答。关闭关联工具调用的卡片只是隐藏面板;工具调用行可以重新打开它,之后也能展示已记录的回答。Host 重启后仍保留问题;此浏览器重新加载后仍保留未提交的输入。
13
13
 
14
14
  ## 目录
15
15
 
@@ -25,11 +25,17 @@ kind: "package-reference"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
- 当 agent 提问时,编辑器变成提问界面:回答每个问题、用翻页器导航,或跳过它。选择单选选项后会立即前进;Enter 继续流程,并在所有问题均已回答或跳过后提交,而 Shift+Enter 改为换行(IME 组合输入期间按 Enter 只会确认输入候选,不会前进)。
28
+ 当 agent 提问时,附着式卡片会暂时占用编辑器位置:回答每个问题、用翻页器导航,或跳过它。首个带推荐标记的选项会预先选中,但仍只是未提交的草稿,不会暂停计时倒计时。点击单选选项会立即前进。聚焦选项时按 Enter 会尝试提交整组答案,不会选中该选项;若有缺失答案,则回到第一道未完成的问题。文本答案中的 Enter 会继续流程,Shift+Enter 则换行(IME 组合输入期间按 Enter 只会确认输入候选,不会前进)。
29
29
 
30
30
  ### 作答
31
31
 
32
- 用户打开或编辑自定义答案时,多选题草稿会保留已选中的标签,因此提交项可以同时携带 `selected` 与 `custom`;单选题的自定义答案仍保持互斥。问题详情复用助手输出的 `MarkdownText` 原语,包括其 GFM 渲染与不受信任内容策略。限高卡片保持标题、导航与提交动作固定,超长的详情与选项共享内部滚动区。「跳过」会保留其他草稿,并为该项发出既有的空 `{ selected: [] }` 结果;关闭则以 `ASK_CANCELLED` 拒绝整个等待。
32
+ 用户打开或编辑自定义答案时,多选题草稿会保留已选中的标签,因此提交项可以同时携带 `selected` 与 `custom`;单选题的自定义答案仍保持互斥。问题详情复用助手输出的 `MarkdownText` 原语,包括其 GFM 渲染与不受信任内容策略。限高卡片保持标题、导航与提交动作固定,超长的详情与选项共享内部滚动区。「跳过」会保留其他草稿,并为该项发出既有的空 `{ selected: [] }` 结果。关闭不是一种回答:Host 以工具调用命名的问题只是离开编辑器位置,其 `ask_user_question` 工具调用行会把面板带回来;不携带工具调用的请求没有可返回的行,关闭它仍以 `ASK_CANCELLED` 拒绝整个等待。
33
+
34
+ ### 回看已结束的问题
35
+
36
+ 每条迟到回复只显示一次,包括由它开启新轮次的情况。回复遵循 Chat 原有的过程分组与整轮折叠规则。回复被收起时,展开所属轮次和工作分组即可查看。
37
+
38
+ 已经结束的问题以只读卡片打开:同一个翻页器走过已记录的回答,并标注「已回答」。所有选项与文本框都被禁用,跳过与提交动作消失,用户当时跳过的问题会在空回答处说明这一点,自由文本框只出现在当时确实用过它的回答上。关闭它会移除该卡片,工具调用行会用同一份记录再建一个。
33
39
 
34
40
  ### plan-review 卡片
35
41
 
@@ -37,7 +43,19 @@ kind: "package-reference"
37
43
 
38
44
  ### 失败与恢复
39
45
 
40
- 通用提问流程把当前题号、已选标签、自定义文本和显式跳过状态保存在非持久化 slot 存储中;该存储归属对应 Session generation,并以待处理请求的本地渲染标识为键。从 Session A 切换到 B 时,如果没有其他引用持有 A,A 就会结束,因此返回 A 时会得到空的问题草稿;如果另一个引用继续持有 A 的 generation,该草稿也会保留。不同的请求标识读取空草稿,并在首次编辑时替换旧值;成功回答或取消会清除相符的值。请求是否仍在等待由主机保持权威。
46
+ 回答输入框只有在回答通道就绪且没有倒计时时才自动聚焦。接手握手期间的手动聚焦与失焦会被保留:剩余时长到达时,只有回答区域仍持有焦点,倒计时才以暂停状态开始。
47
+
48
+ 本地返回回答不会释放前台接手记录:Host 接受 waterfall 结果后才关闭该 stream。插件在这段传输期间继续拥有接手记录。显式委托会在调用下一个回答方前释放它,插件卸载则取消剩余接手记录。
49
+
50
+ 卡片有两个来源。Host 的存活请求创建它,回答也经该请求返回。计时请求先由 Client 打开问答业务的 `attachWait` stream,再从剩余时长帧推导本地时钟上的 deadline。等待首帧期间卡片仍保持存活。接手记录持续到请求结算或 Client 断开,收起面板不会释放它。倒计时归卡片所有;到零时以 `ASK_TIMED_OUT` reject,卡片仍可用。投影把调用列为已继续后,回答改用 `answer` Remote 方法。卡片移除遵循投影,插件卸载时释放请求与接手记录。
51
+
52
+ 经挂起请求的提交只算发出,不算确认:另一个浏览器先结算了同一请求时,gateway 会静默丢弃迟到的结果。因此卡片保留草稿直到投影关闭它;若提交在途时该调用变为已继续,控件带提示重新可用,同一份草稿改走 Remote 路径。Remote 接受回答后将回复作为 steer 交给 Agent 的最近一步。steer 在持久 Inbox 中等待期间,可编辑卡片会关闭,问题行会以只读方式显示已提交的答案;浏览器重新连接后也是如此。多个待处理的 steer 会在该步边界一起获准;当前工具等待必须先结束,Agent 才能读取它们。丢弃待处理的 steer 后问题仍可回答,用户可以重新打开问题行提交。第一条回复仍在等待准入时再次提交会收到 `REPLY_QUEUED`。未编辑时聚焦会冻结本浏览器的剩余倒计时,失焦后按该余量恢复。首次修改回答会把本地等待改为无限,「慢慢回答」也会显式执行同样操作。这些选择会随本浏览器草稿跨会话导航保留;对于带工具调用 ID 的请求,重新加载后也会保留。另一浏览器拥有自己的倒计时,仍可结算共享请求;Host projection 继续作为问题处于开放或已继续状态的权威来源。
53
+
54
+ 每个会话和待处理请求在浏览器存储中都有独立草稿。带工具调用 ID 的请求在切换会话、重新加载页面或重启同一个浏览器后会恢复未完成输入;与当前问题批次不符的进度会被忽略。没有 ID 的 legacy 请求使用唯一卡片键,重新加载后不能恢复。隐藏的面板会保留草稿供下次打开;已关闭但仍挂载的卡片会清掉自己的草稿,下一张挂载的卡片会修剪没有存活卡片拥有的草稿。草稿不会同步到另一个浏览器或设备,Host 投影的问题会。
55
+
56
+ 工具调用开放期间重新连接的浏览器会再次收到挂起请求,仍可用剩余时间完成它。在 agent 或进程结束后重新打开的会话把卡片显示为已继续;提交时先恢复会话的根 agent,再把回答作为新的用户轮次送入。
57
+
58
+ 已结算的问题回复在聊天历史中保持紧凑。气泡以三角标记指示可以展开;点击它会展开只读的问题与回答详情,且不会重新打开已经结算的工具调用,也不会产生第二次提交。它的复制动作写出每个问题与用户当时给出的回答,无论气泡展开还是收起都是同一份文本。
41
59
 
42
60
  -----
43
61
 
@@ -49,16 +67,20 @@ kind: "package-reference"
49
67
 
50
68
  本包是一条归属规则:渲染提问是宿主的 UI 能力,拥有该工具则是 agent 的能力,因此 `tool-ask-user` 行属于需要它的各个 preset(以及没有 preset 的 TUI 组装)。
51
69
 
70
+ ### 重新打开面板
71
+
72
+ 本包填充 `userQuestionPanels`——`dsh-client-ui-tool` 为其 `ask_user_question` 行声明的可选能力。`reveal(sessionId, callId)` 把该调用的卡片重新发布为同优先级中最后一个待处理交互,编辑器位置于是再次显示它;当本客户端没有该调用的卡片时返回 `false`——例如旧版未命名的请求、另一个浏览器的问题,或投影已关闭的卡片。问题是否仍可回答取自 `userQuestions` 会话投影,由该行直接读取,因此这项能力自身不携带状态。
73
+
74
+ 投影只列出仍可回答的调用,因此 `review(sessionId, callId, record)` 用该行从自己转录中解析出的问题与回答建卡。这张卡片没有回答通道也没有倒计时,投影清扫不会碰它,关闭它是移除而非留在注册表里。仍持有实时卡片的调用显示实时那张,过期副本不会替换正在进行的请求;同理,只读卡片渲染记录本身,只从实时卡片留下的草稿里取页码。
75
+
52
76
  ### 意图界面选择
53
77
 
54
- 卡片接管声明了意图、以 `detail` 携带计划、提供了被指名的批准标签的单个问题,要求除批准外最多一个选项,且非多选。次要操作返回编辑器供用户提出修改要求。更多选项或多选问题仍由通用流程处理。
78
+ 卡片接管声明了意图、以 `detail` 携带计划、提供了被指名的批准标签的单个问题,要求除批准外最多一个选项,且非多选。次要操作返回编辑器供用户提出修改要求。更多选项或多选问题仍由通用流程处理。计划审批通过 `conversation.plan-review.actions` 插槽提供请求键、完整正文和可选的调用标识;计划插件从历史中打开已记录计划,并把没有调用标识的审批作为临时侧边栏预览打开,打开文档不会回答或关闭审批。
55
79
 
56
80
  ### 文案与 locale
57
81
 
58
82
  编辑器外框文案(翻页器、按钮、占位符、校验提示)是双语的:插件在 `dsh-client-locale` 的 `question` 命名空间下注册 zh/en 词典,并通过 inject face 把绑定的翻译函数和 locale 快照源交给该条目,因此切换语言会重新渲染已挂载的编辑器。问题与选项文本来自模型并原样渲染;载体失败消息也不经翻译直接显示。
59
83
 
60
- 计划审批通过 `conversation.plan-review.actions` 插槽提供请求键、完整正文和可选的调用标识。计划插件从历史中打开已记录计划,并把没有调用标识的审批作为临时侧边栏预览打开。打开文档不会回答或关闭审批。
61
-
62
84
  </details>
63
85
 
64
86
  -----
@@ -68,7 +90,8 @@ kind: "package-reference"
68
90
 
69
91
  以下页面覆盖编辑器宿主、工具 seam 与 plan-mode 消费方。
70
92
 
71
- - [ui-conversation](../ui-conversation/README.zh.md)——拥有 `conversation.composer` 链的聊天界面。
93
+ - [ui-conversation](../ui-conversation/README.zh.md)——拥有 `conversation.composer` slot 的聊天界面。
94
+ - [ui-tool](../ui-tool/README.zh.md)——工具调用记录界面,其 `ask_user_question` 行可重新打开被收起的面板。
72
95
  - [tool-ask-user](../../interaction/tool-ask-user/README.zh.md)——面向模型的工具;本 UI 会渲染其 schema 与答案。
73
96
  - [ui-plan](../ui-plan/README.zh.md)——设置 `plan-review` 意图的 plan-mode 界面。
74
97
  - [user-questions](../../interaction/user-questions/README.zh.md)——Host 侧提问 seam 及其应答方 waterfall(瀑布式事件)。
@@ -89,10 +112,11 @@ kind: "package-reference"
89
112
  <a id="known-limitations-and-deferred-work"></a>
90
113
 
91
114
 
92
- 这些限制定义草稿持久性与编辑器归属;它们是当前包约束。
115
+ 这些限制定义提问卡片归属与跨客户端行为;它们是当前包约束。
93
116
 
94
- - **未提交草稿的生命周期限于当前页面与会话**:只要该会话作用域仍留在页面内,会话导航就会保留草稿;完整刷新页面、会话被裁剪,或待处理请求以新的本地标识重新交付时,则从空草稿开始。存储从不把草稿写入主机、`localStorage` 或磁盘。
95
- - **每次只有一个请求拥有编辑器**:后续待处理请求仍留在会话快照中,并在较早请求落定后显示。
117
+ - **未提交草稿仅保存在一个浏览器中**:切换会话、重新加载页面和重启浏览器后都会保留,但另一个浏览器或设备只会重建 Host 保存的问题。
118
+ - **每次只有一个请求拥有提问卡片**:后续待处理请求仍留在会话快照中,并在较早请求落定后显示。
119
+ - **问题显示在当前会话的编辑器中**:持久待处理问题不会新增独立的侧栏收件箱;请重新打开所属会话进行回答。
96
120
 
97
121
  <a id="dev-note"></a>
98
122
  ### 开发备注
@@ -104,4 +128,4 @@ kind: "package-reference"
104
128
 
105
129
  </details>
106
130
 
107
- **运行时不变式:** 不发布伴生入口。工具与 slot 注册都是由各自注册表持有和观察的 effect;Host 待处理表通过公开的 wire protocol 测试。
131
+ **运行时不变式:** Host 会话投影是持久计时问题的权威来源。浏览器存储只保留未完成输入,绝不会创建问题或让问题继续保持打开。此包不发布运行时不变量 companion,因为 Host 会先校验并投影持久状态,客户端随后才渲染它。