@deepseek-ai/dsh-client-ui-conversation 0.1.3-alpha.2 → 0.1.5-alpha.1

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
@@ -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-conversation/README.md
5
- README.md: 9a1a12ed86afe4d5ccea63045aeade5860f309cc
6
- README.zh.md: 372f24039a3c880520c2ad690a996754b2ed2e0b
5
+ README.md: edfcb83193d4513fba846f673d3572c35e8c0d1e
6
+ README.zh.md: f92e4c77ba3d3a2ceb96758e5817e447ba2ec1ac
package/README.md CHANGED
@@ -31,7 +31,7 @@ The adapter passes each `SessionEventLikeEntry` directly to the assembler. Its o
31
31
 
32
32
  A target becomes active when shell selection resolves it or when its source receives a first subscriber. The assembler replaces that target from current Contexts once and keeps it active for later incremental flushes; creating a source does not activate it and unsubscription does not deactivate it.
33
33
 
34
- Target packages declaration-merge their snapshot and Location data maps, then register with `ctx.uiConversation.events.register(...)` and `ctx.uiConversation.views.register(...)`. A target reads its Session-owned source with `ctx.uiConversation.binding(binding).target(targetId)`. Registrations are Cordis effects and their returned disposers remove the contribution from the same registry.
34
+ Target packages declaration-merge their snapshot and Location data maps, then register with `ctx.uiConversation.events.register(...)` and `ctx.uiConversation.views.register(...)`. A target reads its Session-owned source with `ctx.uiConversation.binding(binding).target(targetId)`. Registrations are Cordis effects and their returned disposers remove the contribution from the same registry. The shared request inspection serves every target: `ctx.uiConversation.inspectSystemPrompt(previous, event)` interprets system messages and positional replacements as immutable loaded-surface state. It selects the last nonempty surviving system node in surface order, retains only surviving replacement positions for chained rewrites, and withholds the prompt after an unindexed older endpoint until prepend replay supplies its order. Target-owned Definitions retain historical cards independently. `ctx.uiConversation.inspectRequestPrompt(previous, header, system)` classifies request changes against that effective prompt; ordinary messages and stream chunks require no system-state work.
35
35
 
36
36
  <a id="shell-and-standard-props"></a>
37
37
  ## Shell and standard props
@@ -48,7 +48,7 @@ Default sends commit optimistically: Enter clears the draft, occurrence table, a
48
48
 
49
49
  Queued submission echoes show “Sending…” beside disabled edit, remove, and steer buttons; a collapsed dock keeps the sending status in its header. A matching Host queue row replaces the echo and enables each action according to its normal text-content and running-state requirements. Prompt acknowledgement alone does not enable queue actions. A failed submission removes its echo and displays an error; the composer restores the failed draft when it is empty or still contains the previous automatic restoration, preserving subsequently typed text.
50
50
 
51
- While a normal composer is running, its primary pointer action remains Stop when the draft is empty or input is unavailable. Actionable text or attachments switch the same seat to Queue Send; clearing or successfully submitting the draft restores Stop. The busy-Enter setting selects the Queue or Steer keyboard action for ordinary Sessions and continuable children. Their QueueDock rows share Edit, Remove, and Steer, and an empty draft shares the steer-all chord. One-shot children remain read-only. Plan mode and active goals do not change attachment intake. Continuable children keep separate Send and Stop actions but expose no paperclip, paste, or drop intake; if their parent is offline, Send and the composer gestures lock while QueueDock controls for the live inbox remain available ([decisions](../../../.agents/notes/archived/bug-fix/2026-08-20-running-draft-primary-send.md), [inbox controls](../../../.agents/notes/implemented/feature/2026-08-27-continuable-subagent-human-inbox-control.md)).
51
+ Disabled Send and Stop buttons suppress their tooltips, including a Stop button that becomes a disabled Send button when the turn ends. While a normal composer is running, its primary pointer action remains Stop when the draft is empty or input is unavailable. Actionable text or attachments switch the same seat to Send; clearing or successfully submitting the draft restores Stop. The busy-Enter setting selects the Queue or Steer delivery for ordinary Sessions and continuable children, and the running Send button delivers through the same mode plain Enter resolves to; while it is enabled (no upload pending) over a plain message draft its label names that mode (Queue message or Steer message), so the setting governs Enter and the button together while Cmd/Ctrl+Enter still uses the other mode, and idle sessions, empty drafts, and `/` command lines keep the plain Send label ([decision](../../../.agents/notes/implemented/bug-fix/2026-09-04-busy-send-button-follows-enter-setting.md)). Their QueueDock rows share Edit, Remove, and Steer, and an empty draft shares the steer-all chord. One-shot children remain read-only. Plan mode and active goals do not change attachment intake. Continuable children keep separate Send and Stop actions but expose no paperclip, paste, or drop intake; if their parent is offline, Send and the composer gestures lock while QueueDock controls for the live inbox remain available ([decisions](../../../.agents/notes/archived/bug-fix/2026-08-20-running-draft-primary-send.md), [inbox controls](../../../.agents/notes/implemented/feature/2026-08-27-continuable-subagent-human-inbox-control.md)).
52
52
 
53
53
  <a id="temporary-composer-entries"></a>
54
54
  ## Temporary composer entries
package/README.zh.md CHANGED
@@ -31,7 +31,7 @@ adapter 把每个 `SessionEventLikeEntry` 直接交给 assembler。外层 `type`
31
31
 
32
32
  shell 选择解析出 target 或 target source 收到首个 subscriber 时,该 target 进入 active 状态。assembler 从当前 Context 对它执行一次 replace,并使它参与后续增量 flush;创建 source 不会激活 target,取消订阅也不会停用 target。
33
33
 
34
- target package 通过 declaration merge 扩展 snapshot 与 Location data map,再调用 `ctx.uiConversation.events.register(...)` 和 `ctx.uiConversation.views.register(...)`。target 通过 `ctx.uiConversation.binding(binding).target(targetId)` 读取其 Session-owned source。注册属于 Cordis effect,返回的 disposer 从同一个 registry 移除 contribution
34
+ target package 通过 declaration merge 扩展 snapshot 与 Location data map,再调用 `ctx.uiConversation.events.register(...)` 和 `ctx.uiConversation.views.register(...)`。target 通过 `ctx.uiConversation.binding(binding).target(targetId)` 读取其 Session-owned source。注册属于 Cordis effect,返回的 disposer 从同一个 registry 移除 contribution。共享的请求检查服务于每个 target:`ctx.uiConversation.inspectSystemPrompt(previous, event)` 将系统消息与位置替换解释为不可变的已加载 surface 状态。它按 surface 顺序选择最后一个非空的存活系统节点,为连续重写只保留存活的替换位置;遇到未建立索引的更早端点后,提示词保持不可用,直到向前补页回放提供其顺序。target 自有的 Definition 独立保留历史卡片。`ctx.uiConversation.inspectRequestPrompt(previous, header, system)` 根据该有效提示词分类请求变更;普通消息与流式分片无需处理系统状态。
35
35
 
36
36
  <a id="shell-and-standard-props"></a>
37
37
  ## Shell 与标准 props
@@ -48,7 +48,7 @@ Session 首次绑定或缓存的 Session 成为 current 时,shell 会在渲染
48
48
 
49
49
  排队提交的本地回显在禁用的编辑、删除、插话按钮旁显示“发送中…”;折叠后的队列在标题栏保留发送状态。匹配的 Host 队列行替换回显后,各操作按原有的纯文本内容和运行状态要求启用。仅收到 prompt 确认不会启用队列操作。提交失败会移除回显并显示错误;输入框为空或仍保留上一次自动恢复的内容时,composer 恢复失败草稿,保留用户随后输入的文字。
50
50
 
51
- 普通 composer 运行时,如果草稿为空或输入不可用,主指针操作保持为 Stop。可提交的文字或附件会把同一位置切换为 Queue Send;清空或成功提交草稿后恢复 Stop。繁忙态 Enter 设置会为普通 Session 与可继续 child 选择 Queue 或 Steer 键盘操作。它们的 QueueDock 行共享 Edit、Remove 与 Steer,空草稿也共享 steer-all 组合键。One-shot child 继续只读。Plan Mode 与 active goal 不改变附件入口。可继续 child 保留独立的 Send 与 Stop 操作,但不提供回形针、粘贴或拖放入口;parent 离线时,Send 与 composer 手势锁定,但在线 inbox 的 QueueDock 控制仍可使用([决策](../../../.agents/notes/archived/bug-fix/2026-08-20-running-draft-primary-send.md)、[inbox 控制](../../../.agents/notes/implemented/feature/2026-08-27-continuable-subagent-human-inbox-control.zh.md))。
51
+ Send 和 Stop 按钮禁用时不显示提示气泡,轮次结束后由 Stop 切换成禁用 Send 的按钮也遵循此规则。普通 composer 运行时,如果草稿为空或输入不可用,主指针操作保持为 Stop。可提交的文字或附件会把同一位置切换为 Send;清空或成功提交草稿后恢复 Stop。繁忙态 Enter 设置为普通 Session 与可继续 child 选择 Queue 或 Steer 投递,运行中的 Send 按钮按 plain Enter 解析出的同一模式投递;当它在普通消息草稿上可用(没有待上传文件)时,其标签以该模式命名(排队发送或插话发送),因此该设置同时约束 Enter 与按钮,而 Cmd/Ctrl+Enter 仍使用另一模式;空闲会话、空草稿与 `/` 命令行保留普通的 Send 标签([决策](../../../.agents/notes/implemented/bug-fix/2026-09-04-busy-send-button-follows-enter-setting.zh.md))。它们的 QueueDock 行共享 Edit、Remove 与 Steer,空草稿也共享 steer-all 组合键。One-shot child 继续只读。Plan Mode 与 active goal 不改变附件入口。可继续 child 保留独立的 Send 与 Stop 操作,但不提供回形针、粘贴或拖放入口;parent 离线时,Send 与 composer 手势锁定,但在线 inbox 的 QueueDock 控制仍可使用([决策](../../../.agents/notes/archived/bug-fix/2026-08-20-running-draft-primary-send.md)、[inbox 控制](../../../.agents/notes/implemented/feature/2026-08-27-continuable-subagent-human-inbox-control.zh.md))。
52
52
 
53
53
  <a id="temporary-composer-entries"></a>
54
54
  ## 临时 composer entry
package/lib/client.js CHANGED
@@ -828,34 +828,120 @@ window.__ModuleLoader__.load({
828
828
  //#endregion
829
829
  //#region lib/types/client/contract/request-inspection.js
830
830
  /**
831
- * Canonicalize one request header and classify its model-visible prompt change.
831
+ * Canonicalize one request header against the system node in force and
832
+ * classify the model-visible prompt change.
832
833
  * @param previous - Prompt from the preceding loaded request header, when available.
833
834
  * @param event - Durable full request header to inspect.
835
+ * @param system - Effective nonempty system prompt after loaded surface replacements; empty when removed.
836
+ * An in-history update already presented its text at its own position, so the header reports no system change for it.
834
837
  * @returns The canonical prompt and an initial/system/tool change when it can be established.
835
838
  */
836
- function inspectRequestPrompt(previous, event) {
839
+ function inspectRequestPrompt(previous, event, system) {
837
840
  const header = event.data.header;
838
841
  const rawTools = header.tools;
839
842
  const prompt = {
840
843
  config: header.config,
841
- system: header.system ?? "",
844
+ system: system?.text ?? "",
842
845
  tools: Array.isArray(rawTools) ? rawTools : []
843
846
  };
844
847
  if (previous === void 0 && event.data.reason !== "initial") return { prompt };
845
- const systemChanged = previous !== void 0 && previous.system !== prompt.system;
848
+ const systemChanged = previous !== void 0 && previous.system !== prompt.system && system?.update !== true;
846
849
  const toolsChanged = previous !== void 0 && JSON.stringify(previous.tools) !== JSON.stringify(prompt.tools);
847
850
  if (previous !== void 0 && !systemChanged && !toolsChanged) return { prompt };
851
+ const origin = system !== void 0 && (previous === void 0 || systemChanged) ? system : event;
848
852
  return {
849
853
  prompt,
850
854
  change: {
851
- seq: event.seq,
852
- time: event.time,
855
+ seq: origin.seq,
856
+ time: origin.time,
853
857
  kind: previous === void 0 ? "initial" : systemChanged && toolsChanged ? "system-and-tools" : systemChanged ? "system" : "tools",
854
858
  ...previous === void 0 ? {} : { previous }
855
859
  }
856
860
  };
857
861
  }
858
862
  //#endregion
863
+ //#region ../../core/session/src/surface.ts
864
+ /** Runtime counterpart of the message-producing event union. */
865
+ const SURFACE_EVENT_TYPES = new Set([
866
+ "system/message",
867
+ "user/message",
868
+ "assistant/message",
869
+ "tool/result"
870
+ ]);
871
+ /**
872
+ * Narrow an event to a surface-eligible event carrying its required marker.
873
+ * @param event - event to test.
874
+ * @returns true when both the type and marker identify a surface event.
875
+ */
876
+ function isSurfaceEvent(event) {
877
+ if (!SURFACE_EVENT_TYPES.has(event.type)) return false;
878
+ return event.surfaceOp !== void 0;
879
+ }
880
+ //#endregion
881
+ //#region lib/types/client/contract/system-prompt.js
882
+ /**
883
+ * Apply a system event or positional replacement without retaining ordinary messages.
884
+ * Replacement positions inherit their start endpoint, not their chronological seq.
885
+ * Unknown older endpoint order withholds the prompt until prepend replay resolves it.
886
+ * @param previous - Interpretation at the preceding relevant event in the loaded window.
887
+ * @param event - System message or surface replacement already admitted by Session.
888
+ * @returns Immutable surviving system facts and the effective nonempty prompt.
889
+ */
890
+ function inspectSystemPrompt(previous, event) {
891
+ const op = isSurfaceEvent(event) ? event.surfaceOp : void 0;
892
+ const firstSeq = previous?.firstSeq ?? event.seq;
893
+ let nodes = previous?.nodes ?? [];
894
+ let replacements = previous?.replacements ?? /* @__PURE__ */ new Map();
895
+ const unknownEndpoint = (seq) => seq < firstSeq && !replacements.has(seq);
896
+ const uncertain = previous?.uncertain === true || op !== void 0 && op !== "append" && (unknownEndpoint(op.startSeq) || unknownEndpoint(op.endSeq));
897
+ if (uncertain) return {
898
+ firstSeq,
899
+ uncertain,
900
+ nodes: [],
901
+ replacements: /* @__PURE__ */ new Map(),
902
+ effective: void 0,
903
+ introduced: void 0
904
+ };
905
+ let position = event.seq;
906
+ if (op !== void 0 && op !== "append") {
907
+ position = replacements.get(op.startSeq) ?? op.startSeq;
908
+ const end = replacements.get(op.endSeq) ?? op.endSeq;
909
+ nodes = nodes.filter((item) => item.position < position || item.position > end);
910
+ const retained = new Map([...replacements].filter(([, value]) => value < position || value > end));
911
+ retained.set(event.seq, position);
912
+ replacements = retained;
913
+ }
914
+ const introduced = event.type === "system/message" ? {
915
+ seq: event.seq,
916
+ time: event.time,
917
+ turn: event.data.turn,
918
+ step: event.data.step,
919
+ text: event.data.message.content.flatMap((block) => block.type === "text" ? [block.text] : []).join(""),
920
+ update: op === "append" && previous?.nodes.some((item) => item.node.text !== "") === true
921
+ } : void 0;
922
+ if (introduced !== void 0) nodes = [...nodes, {
923
+ position,
924
+ node: introduced
925
+ }].sort((a, b) => a.position - b.position);
926
+ const surviving = nodes.findLast((item) => item.node.text !== "")?.node;
927
+ const effective = surviving === previous?.nodes.findLast((item) => item.node.text !== "")?.node ? previous?.effective : introduced !== void 0 && introduced === surviving ? introduced : {
928
+ seq: event.seq,
929
+ time: event.time,
930
+ turn: surviving?.turn ?? 0,
931
+ step: surviving?.step ?? 0,
932
+ text: surviving?.text ?? "",
933
+ update: false
934
+ };
935
+ return {
936
+ firstSeq,
937
+ uncertain,
938
+ nodes,
939
+ replacements,
940
+ effective,
941
+ introduced
942
+ };
943
+ }
944
+ //#endregion
859
945
  //#region lib/types/client/contract/conversation.js
860
946
  /**
861
947
  * Build a stable collision-free key for one Definition-local business identity.
@@ -2581,17 +2667,28 @@ window.__ModuleLoader__.load({
2581
2667
  return this.images.seed(sessionId, attachment, url);
2582
2668
  }
2583
2669
  /**
2584
- * Canonicalize one `request/header` event against the previous prompt state.
2670
+ * Interpret a system message or surface replacement for target-owned prompt Definitions.
2671
+ * @param previous - System facts at the preceding relevant loaded event.
2672
+ * @param event - Durable system message or positional replacement.
2673
+ * @returns Immutable prompt interpretation at this event.
2674
+ */
2675
+ inspectSystemPrompt(previous, event) {
2676
+ return inspectSystemPrompt(previous, event);
2677
+ }
2678
+ /**
2679
+ * Canonicalize one `request/header` event against the previous prompt state
2680
+ * and the `system/message` node in force.
2585
2681
  *
2586
2682
  * A pure interpretation shared by the Chat and Trajectory Definitions, exposed
2587
2683
  * as a service method because cross-plugin value imports are forbidden in
2588
2684
  * client bundles.
2589
2685
  * @param previous - prompt recorded by the preceding loaded header, if any.
2590
2686
  * @param event - the `request/header` session event to interpret.
2687
+ * @param system - effective prompt after loaded surface replacements, if any.
2591
2688
  * @returns the canonical prompt snapshot and any model-visible change.
2592
2689
  */
2593
- inspectRequestPrompt(previous, event) {
2594
- return inspectRequestPrompt(previous, event);
2690
+ inspectRequestPrompt(previous, event, system) {
2691
+ return inspectRequestPrompt(previous, event, system);
2595
2692
  }
2596
2693
  drop(record, releaseScope) {
2597
2694
  if (this.bindings.get(record.source.sessionId) !== record) return;
@@ -13461,17 +13558,34 @@ window.__ModuleLoader__.load({
13461
13558
  //#endregion
13462
13559
  //#region lib/types/client/input/submission-policy.js
13463
13560
  /**
13464
- * Composer submission policy. It owns the live busy-Enter
13465
- * preference and resolves keyboard gestures into queue/steer delivery modes;
13466
- * Host and Agent keep the actual delivery-window authority.
13561
+ * Composer submission policy. It owns the live busy-Enter preference and
13562
+ * resolves submission gestures into queue/steer delivery modes; Host and
13563
+ * Agent keep the actual delivery-window authority.
13467
13564
  */
13468
13565
  /**
13469
- * Busy-Enter policy used by both the composer inject face and its Settings row.
13470
- * Direct `steer` is intentionally best-effort: AgentLoop turns a closed-window
13471
- * submission into the next waking Queue item.
13566
+ * Resolve one submission gesture against the busy-Enter preference. Plain
13567
+ * Enter and the primary Send button share the `enter` gesture, so the button
13568
+ * delivers exactly what Enter would. Direct `steer` is intentionally
13569
+ * best-effort: AgentLoop turns a closed-window submission into the next waking
13570
+ * Queue item.
13571
+ * @param preferred - the live busy-Enter preference.
13572
+ * @param running - whether the addressed agent currently reports busy.
13573
+ * @param gesture - plain Enter (or the Send button) or the Cmd/Ctrl-accelerated chord.
13574
+ * @param steeringAvailable - whether this session transport supports steering.
13575
+ * @returns Queue outside steer-capable busy state; otherwise the preferred mode or its opposite.
13576
+ */
13577
+ function resolveSubmitMode(preferred, running, gesture, steeringAvailable) {
13578
+ if (!running || !steeringAvailable) return "queue";
13579
+ if (gesture === "enter") return preferred;
13580
+ return preferred === "queue" ? "steer" : "queue";
13581
+ }
13582
+ /**
13583
+ * Busy-Enter preference shared by the composer bar inject face and its
13584
+ * Settings row: one live store the bar's submission gestures and Send label
13585
+ * read, backed by the Host user-settings document when one is composed.
13472
13586
  */
13473
13587
  var ComposerSubmissionPolicy = class {
13474
- /** Reactive preference source for the Settings row. */
13588
+ /** Reactive preference source for the composer bar and the Settings row. */
13475
13589
  busyEnter = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(DEFAULT_BUSY_ENTER_BEHAVIOR);
13476
13590
  host;
13477
13591
  /**
@@ -13490,21 +13604,8 @@ window.__ModuleLoader__.load({
13490
13604
  }
13491
13605
  }
13492
13606
  /**
13493
- * Resolve one keyboard gesture without changing state.
13494
- * @param running - whether the addressed agent currently reports busy.
13495
- * @param gesture - plain Enter or the Cmd/Ctrl-accelerated chord.
13496
- * @param steeringAvailable - whether this session transport supports steering.
13497
- * @returns Queue outside steer-capable busy state; otherwise the preferred mode or its opposite.
13498
- */
13499
- resolve(running, gesture, steeringAvailable) {
13500
- if (!running || !steeringAvailable) return "queue";
13501
- const preferred = this.busyEnter.getSnapshot();
13502
- if (gesture === "enter") return preferred;
13503
- return preferred === "queue" ? "steer" : "queue";
13504
- }
13505
- /**
13506
- * Change the plain-Enter behavior used during busy state; the live value
13507
- * publishes before the durable write starts.
13607
+ * Change the busy-state submission behavior; the live value publishes
13608
+ * before the durable write starts.
13508
13609
  * @param behavior - Queue or Steer.
13509
13610
  */
13510
13611
  setBusyEnter(behavior) {
@@ -13535,15 +13636,17 @@ window.__ModuleLoader__.load({
13535
13636
  "hint.goal": "输入目标,智能体将持续执行",
13536
13637
  "hint.goal.active": "当前目标进行中。可输入 edit 修改 / pause 暂停 / resume 继续 / clear 清除",
13537
13638
  "placeholder.plan": PLAN_NEXT_ACTION_ZH,
13538
- "placeholder.default": "发消息或做任务… / 调用指令 @ 文件或对话",
13639
+ "placeholder.default": "发消息或创建任务, / 调用指令, @ 文件或对话",
13539
13640
  "placeholder.unavailable": "会话不可用",
13540
13641
  "placeholder.parentOffline": "父会话已离线,无法继续发送;仍可停止当前运行",
13541
- "placeholder.hero": "描述你想要构建的内容… / 调用指令 @ 文件或对话",
13642
+ "placeholder.hero": "描述你想要构建的内容, / 调用指令, @ 文件或对话",
13542
13643
  "placeholder.workspace": "选择一个工作区开始",
13543
13644
  "placeholder.steerQueue": "Cmd/Ctrl+Enter 插话发送全部排队消息",
13544
13645
  "input.commands": "指令",
13545
13646
  "input.stop": "停止生成",
13546
13647
  "input.send": "发送消息",
13648
+ "input.send.queue": "排队发送",
13649
+ "input.send.steer": "插话发送",
13547
13650
  "input.accessMode": "访问模式,当前:{name}",
13548
13651
  "attachment.pending": "待发送附件",
13549
13652
  "attachment.scrollLeft": "向左滚动附件",
@@ -13582,10 +13685,10 @@ window.__ModuleLoader__.load({
13582
13685
  "context.aria": "上下文已用 {percent}",
13583
13686
  "context.used": "上下文已用",
13584
13687
  "context.system": "系统提示词",
13585
- "context.tools": "工具",
13688
+ "context.tools": "工具定义",
13586
13689
  "context.messages": "对话消息",
13587
- "settings.enter.title": "繁忙时 Enter 键行为",
13588
- "settings.enter.description": "仅在智能体运行时生效;Cmd/Ctrl+Enter 使用另一行为",
13690
+ "settings.enter.title": "繁忙时的发送行为",
13691
+ "settings.enter.description": "智能体运行时 Enter 键和发送按钮的行为;Cmd/Ctrl+Enter 使用另一行为",
13589
13692
  "settings.enter.queue": "排队发送",
13590
13693
  "settings.enter.steer": "插话发送",
13591
13694
  "access.preset.readOnly": "仅可查看",
@@ -13695,15 +13798,17 @@ window.__ModuleLoader__.load({
13695
13798
  "hint.goal": "describe the objective for a long-running task",
13696
13799
  "hint.goal.active": "goal active — edit / pause / resume / clear",
13697
13800
  "placeholder.plan": PLAN_NEXT_ACTION_EN,
13698
- "placeholder.default": "Message or run a task... / commands, @ files or sessions",
13801
+ "placeholder.default": "Message or run a task, / commands, @ files or sessions",
13699
13802
  "placeholder.unavailable": "Session unavailable",
13700
13803
  "placeholder.parentOffline": "Parent session offline; sending is unavailable but you can still stop the run",
13701
- "placeholder.hero": "Describe what you want to build... / commands, @ files or sessions",
13804
+ "placeholder.hero": "Describe what you want to build, / commands, @ files or sessions",
13702
13805
  "placeholder.workspace": "Choose a workspace to start",
13703
13806
  "placeholder.steerQueue": "Cmd/Ctrl+Enter steers all queued messages",
13704
13807
  "input.commands": "Commands",
13705
13808
  "input.stop": "Stop generating",
13706
13809
  "input.send": "Send message",
13810
+ "input.send.queue": "Queue message",
13811
+ "input.send.steer": "Steer message",
13707
13812
  "input.accessMode": "Access mode, current: {name}",
13708
13813
  "attachment.pending": "Pending attachments",
13709
13814
  "attachment.scrollLeft": "Scroll attachments left",
@@ -13742,10 +13847,10 @@ window.__ModuleLoader__.load({
13742
13847
  "context.aria": "{percent} of context used",
13743
13848
  "context.used": "of context used",
13744
13849
  "context.system": "System prompt",
13745
- "context.tools": "Tools",
13850
+ "context.tools": "Tool definitions",
13746
13851
  "context.messages": "Messages",
13747
- "settings.enter.title": "Enter behavior while busy",
13748
- "settings.enter.description": "Busy only; Cmd/Ctrl+Enter uses the other behavior",
13852
+ "settings.enter.title": "Send behavior while busy",
13853
+ "settings.enter.description": "What Enter and the Send button do while the agent is running; Cmd/Ctrl+Enter uses the other behavior",
13749
13854
  "settings.enter.queue": "Queue",
13750
13855
  "settings.enter.steer": "Steer",
13751
13856
  "access.preset.readOnly": "Read Only",
@@ -14388,7 +14493,7 @@ window.__ModuleLoader__.load({
14388
14493
  }
14389
14494
  //#endregion
14390
14495
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css.mjs
14391
- const css$5 = ".pXSMma_root{justify-content:center;align-items:center;min-width:0;height:100%;padding:0 24px;display:flex}.pXSMma_stack{width:100%;max-width:var(--dsh-composer-card-max-width);flex-direction:column;align-items:stretch;gap:12px;display:flex;overflow:visible}.pXSMma_headline{color:var(--dsw-alias-label-primary);grid-template-columns:34px auto auto;justify-content:center;align-items:center;column-gap:10px;font-size:26px;font-weight:500;line-height:32px;display:grid}.pXSMma_headlineText{grid-area:1/2}.pXSMma_previewBadge{border:.5px solid var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish);font-family:var(--ds-font-family-code);white-space:nowrap;border-radius:24px;grid-area:1/3;align-self:start;margin-top:2px;margin-left:-3px;padding:1px 7px 0;font-size:12px;font-weight:500;line-height:18px}.pXSMma_fishHitbox{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.pXSMma_fish{transform-origin:50% 60%;color:var(--dsw-alias-label-primary);display:block;overflow:visible}@keyframes pXSMma_hero-fish-swim{0%,to{transform:none}35%{transform:rotate(-4deg)translate(-.4px,-.9px)}70%{transform:rotate(1.6deg)translate(.3px,.2px)}}@media (hover:hover) and (prefers-reduced-motion:no-preference){.pXSMma_fishHitbox:hover .pXSMma_fish{animation:1.6s ease-in-out infinite pXSMma_hero-fish-swim}}.pXSMma_body{flex-direction:column;gap:12px;min-width:0;display:flex;position:relative;overflow:visible}.pXSMma_body>*{z-index:1;position:relative}.pXSMma_body>.pXSMma_workspaceRow{z-index:10;align-items:center;min-width:0;padding-left:8px;display:flex}.pXSMma_workspace{max-width:min(100%,360px);min-height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:16px;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.pXSMma_workspace:not(:disabled):hover,.pXSMma_workspace[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.pXSMma_workspace:disabled{cursor:default}.pXSMma_folder{color:var(--dsw-alias-label-primary);flex:none}.pXSMma_workspaceLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.pXSMma_chevron{color:var(--dsw-alias-label-caption);flex:none}.pXSMma_modalInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);width:100%;height:44px;color:var(--dsw-alias-label-primary);background:0 0;border-radius:22px;outline:none;padding:7px 14px;font-size:14px;font-weight:400;line-height:22px}.pXSMma_modalInput::placeholder{color:var(--dsw-alias-label-caption)}.pXSMma_modalInput:disabled{color:var(--dsw-alias-label-dimmed)}.pXSMma_modalAction{min-width:72px}.pXSMma_modalError{color:var(--dsw-alias-state-error-primary);margin-top:8px;font-size:12px;line-height:18px}";
14496
+ const css$5 = ".pXSMma_root{justify-content:center;align-items:center;min-width:0;height:100%;padding:0 24px;display:flex}.pXSMma_stack{width:100%;max-width:var(--dsh-composer-card-max-width);flex-direction:column;align-items:stretch;gap:12px;display:flex;overflow:visible}.pXSMma_headline{color:var(--dsw-alias-label-primary);flex-wrap:wrap;justify-content:center;align-items:center;gap:12px 10px;font-size:26px;font-weight:500;line-height:32px;display:flex}.pXSMma_titleGroup{flex-wrap:wrap;justify-content:center;align-items:center;gap:4px 7px;min-width:0;display:flex}.pXSMma_previewBadge{border:.5px solid var(--dsw-alias-interactive-bg-hover);background:var(--dsw-alias-state-business-tertiary);color:var(--dsw-alias-label-primary-bluish);font-family:var(--ds-font-family-code);white-space:nowrap;border-radius:24px;align-self:flex-start;margin-top:2px;padding:1px 7px 0;font-size:12px;font-weight:500;line-height:18px}.pXSMma_fishHitbox{flex:none;justify-content:center;align-items:center;display:inline-flex}.pXSMma_fish{transform-origin:50% 60%;color:var(--dsw-alias-label-primary);display:block;overflow:visible}@keyframes pXSMma_hero-fish-swim{0%,to{transform:none}35%{transform:rotate(-4deg)translate(-.4px,-.9px)}70%{transform:rotate(1.6deg)translate(.3px,.2px)}}@media (hover:hover) and (prefers-reduced-motion:no-preference){.pXSMma_fishHitbox:hover .pXSMma_fish{animation:1.6s ease-in-out infinite pXSMma_hero-fish-swim}}.pXSMma_body{flex-direction:column;gap:12px;min-width:0;display:flex;position:relative;overflow:visible}.pXSMma_body>*{z-index:1;position:relative}.pXSMma_body>.pXSMma_workspaceRow{z-index:10;align-items:center;min-width:0;padding-left:8px;display:flex}.pXSMma_workspace{max-width:min(100%,360px);min-height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:16px;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.pXSMma_workspace:not(:disabled):hover,.pXSMma_workspace[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.pXSMma_workspace:disabled{cursor:default}.pXSMma_folder{color:var(--dsw-alias-label-primary);flex:none}.pXSMma_workspaceLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.pXSMma_chevron{color:var(--dsw-alias-label-caption);flex:none}.pXSMma_modalInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);width:100%;height:44px;color:var(--dsw-alias-label-primary);background:0 0;border-radius:22px;outline:none;padding:7px 14px;font-size:14px;font-weight:400;line-height:22px}.pXSMma_modalInput::placeholder{color:var(--dsw-alias-label-caption)}.pXSMma_modalInput:disabled{color:var(--dsw-alias-label-dimmed)}.pXSMma_modalAction{min-width:72px}.pXSMma_modalError{color:var(--dsw-alias-state-error-primary);margin-top:8px;font-size:12px;line-height:18px}";
14392
14497
  const tagId$5 = "@deepseek-ai/dsh-client-ui-conversation/HeroShell.module.css";
14393
14498
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
14394
14499
  const tag = document.createElement("style");
@@ -14404,7 +14509,6 @@ window.__ModuleLoader__.load({
14404
14509
  "fishHitbox": "pXSMma_fishHitbox",
14405
14510
  "folder": "pXSMma_folder",
14406
14511
  "headline": "pXSMma_headline",
14407
- "headlineText": "pXSMma_headlineText",
14408
14512
  "hero-fish-swim": "pXSMma_hero-fish-swim",
14409
14513
  "modalAction": "pXSMma_modalAction",
14410
14514
  "modalError": "pXSMma_modalError",
@@ -14412,6 +14516,7 @@ window.__ModuleLoader__.load({
14412
14516
  "previewBadge": "pXSMma_previewBadge",
14413
14517
  "root": "pXSMma_root",
14414
14518
  "stack": "pXSMma_stack",
14519
+ "titleGroup": "pXSMma_titleGroup",
14415
14520
  "workspace": "pXSMma_workspace",
14416
14521
  "workspaceLabel": "pXSMma_workspaceLabel",
14417
14522
  "workspaceRow": "pXSMma_workspaceRow"
@@ -14516,36 +14621,32 @@ window.__ModuleLoader__.load({
14516
14621
  className: HeroShell_module_css_default.stack,
14517
14622
  children: [(0, react_jsx_runtime.jsxs)("div", {
14518
14623
  className: HeroShell_module_css_default.headline,
14519
- children: [
14520
- (0, react_jsx_runtime.jsx)("span", {
14521
- className: HeroShell_module_css_default.fishHitbox,
14522
- onMouseEnter: () => {
14523
- if (window.matchMedia("(hover: hover) and (prefers-reduced-motion: no-preference)").matches) setHovering(true);
14524
- },
14525
- onMouseLeave: () => {
14526
- setHovering(false);
14527
- },
14528
- children: renderSlot("conversation.hero.brand.mark", {
14529
- size: 34,
14530
- className: HeroShell_module_css_default.fish
14531
- }, { fallback: (0, react_jsx_runtime.jsx)(HeroFish, { hovering }) })
14532
- }),
14533
- (0, react_jsx_runtime.jsx)("span", {
14534
- className: HeroShell_module_css_default.headlineText,
14535
- children: t("hero.headline")
14536
- }),
14537
- (0, react_jsx_runtime.jsx)("span", {
14624
+ children: [(0, react_jsx_runtime.jsx)("span", {
14625
+ className: HeroShell_module_css_default.fishHitbox,
14626
+ onMouseEnter: () => {
14627
+ if (window.matchMedia("(hover: hover) and (prefers-reduced-motion: no-preference)").matches) setHovering(true);
14628
+ },
14629
+ onMouseLeave: () => {
14630
+ setHovering(false);
14631
+ },
14632
+ children: renderSlot("conversation.hero.brand.mark", {
14633
+ size: 34,
14634
+ className: HeroShell_module_css_default.fish
14635
+ }, { fallback: (0, react_jsx_runtime.jsx)(HeroFish, { hovering }) })
14636
+ }), (0, react_jsx_runtime.jsxs)("span", {
14637
+ className: HeroShell_module_css_default.titleGroup,
14638
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("hero.headline") }), (0, react_jsx_runtime.jsx)("span", {
14538
14639
  className: HeroShell_module_css_default.previewBadge,
14539
14640
  children: t("hero.preview")
14540
- })
14541
- ]
14641
+ })]
14642
+ })]
14542
14643
  }), (0, react_jsx_runtime.jsx)("div", { className: HeroShell_module_css_default.body })]
14543
14644
  }), children]
14544
14645
  });
14545
14646
  }
14546
14647
  //#endregion
14547
14648
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css.mjs
14548
- const css$4 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);--dsh-chat-content-width:var(--dsh-chat-user-width,clamp(680px, calc(var(--dsh-conversation-column-width,0px) * .64), 920px));--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;min-width:0;height:100%;display:flex;position:relative}.wSkVaW_header{border-bottom:1px solid #0000;flex:none;padding:12px 28px 0 20px;position:relative}.wSkVaW_header:after{content:\"\";z-index:0;background:var(--dsw-alias-border-l3);pointer-events:none;height:.5px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_headerHidden{display:none}.wSkVaW_titleRow{align-items:center;gap:0;min-height:32px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:4px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 11px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_widthHandle{z-index:8;width:min(40px, calc((100% - var(--dsh-chat-content-width)) / 2 - 24px - 24px));cursor:col-resize;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle[data-side=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle:after{content:\"\";background:linear-gradient(to bottom, transparent calc(var(--dsh-width-handle-pointer-y,50%) - 52px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) - 12px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) + 12px), transparent calc(var(--dsh-width-handle-pointer-y,50%) + 52px));opacity:0;pointer-events:none;border-radius:3px;width:3px;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]:after{right:16px}.wSkVaW_widthHandle[data-side=right]:after{left:16px}.wSkVaW_widthHandle:hover:after,.wSkVaW_widthHandle[data-dragging]:after{opacity:1}.wSkVaW_root:has([data-conversation-composer-overlay]) .wSkVaW_widthHandle{display:none}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_body{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat:has([data-trigger-menu]){z-index:9}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding-left:20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
14649
+ const css$4 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);--dsh-chat-content-width:var(--dsh-chat-user-width,clamp(680px, calc(var(--dsh-conversation-column-width,0px) * .64), 920px));--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;min-width:0;height:100%;display:flex;position:relative}.wSkVaW_header{border-bottom:1px solid #0000;flex:none;padding:12px 28px 0 20px;position:relative}.wSkVaW_header:after{content:\"\";z-index:0;background:var(--dsw-alias-border-l3);pointer-events:none;height:.5px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_headerHidden{display:none}.wSkVaW_titleRow{align-items:center;gap:0;min-height:32px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_headerCorner{flex:none;align-items:center;margin-left:12px;margin-right:-16px;display:flex}.wSkVaW_headerCorner:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:4px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 11px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_widthHandle{z-index:8;width:min(40px, calc((100% - var(--dsh-chat-content-width)) / 2 - 24px - 24px));cursor:col-resize;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle[data-side=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle:after{content:\"\";background:linear-gradient(to bottom, transparent calc(var(--dsh-width-handle-pointer-y,50%) - 52px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) - 12px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) + 12px), transparent calc(var(--dsh-width-handle-pointer-y,50%) + 52px));opacity:0;pointer-events:none;border-radius:3px;width:3px;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]:after{right:16px}.wSkVaW_widthHandle[data-side=right]:after{left:16px}.wSkVaW_widthHandle:hover:after,.wSkVaW_widthHandle[data-dragging]:after{opacity:1}.wSkVaW_root:has([data-conversation-composer-overlay]) .wSkVaW_widthHandle{display:none}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_body{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat:has([data-trigger-menu]){z-index:9}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding:0 16px 0 20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
14549
14650
  const tagId$4 = "@deepseek-ai/dsh-client-ui-conversation/ConversationRoot.module.css";
14550
14651
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
14551
14652
  const tag = document.createElement("style");
@@ -14567,6 +14668,7 @@ window.__ModuleLoader__.load({
14567
14668
  "crumbs": "wSkVaW_crumbs",
14568
14669
  "header": "wSkVaW_header",
14569
14670
  "headerActions": "wSkVaW_headerActions",
14671
+ "headerCorner": "wSkVaW_headerCorner",
14570
14672
  "headerHidden": "wSkVaW_headerHidden",
14571
14673
  "headerUtilities": "wSkVaW_headerUtilities",
14572
14674
  "heroWorkspaceRow": "wSkVaW_heroWorkspaceRow",
@@ -14916,49 +15018,57 @@ window.__ModuleLoader__.load({
14916
15018
  "aria-hidden": hideChrome || void 0,
14917
15019
  children: !hideChrome && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
14918
15020
  className: ConversationRoot_module_css_default.titleRow,
14919
- children: [(0, react_jsx_runtime.jsxs)("div", {
14920
- className: ConversationRoot_module_css_default.titleCluster,
14921
- children: [(0, react_jsx_runtime.jsxs)("nav", {
14922
- className: ConversationRoot_module_css_default.crumbs,
14923
- "aria-label": t("session.hierarchy"),
14924
- children: [ancestry.map((summary, index) => {
14925
- const last = index === ancestry.length - 1;
14926
- const title = (0, react_jsx_runtime.jsx)("button", {
14927
- type: "button",
14928
- className: clsx(ConversationRoot_module_css_default.crumb, summary.subagent && ConversationRoot_module_css_default.crumbSubagent, last && ConversationRoot_module_css_default.crumbCurrent),
14929
- disabled: last,
14930
- onClick: () => {
14931
- open(summary.id);
14932
- },
14933
- children: summary.displayTitle
14934
- });
14935
- const lineage = last || summary.subagent;
14936
- const lineageOwner = {
14937
- lineageSessionId: summary.id,
14938
- displayTitle: summary.displayTitle,
14939
- ...last ? {} : { openTitle: () => {
14940
- open(summary.id);
14941
- } }
14942
- };
14943
- return (0, react_jsx_runtime.jsxs)("span", {
14944
- className: ConversationRoot_module_css_default.crumbSeg,
14945
- children: [index > 0 && (0, react_jsx_runtime.jsx)("span", {
14946
- className: ConversationRoot_module_css_default.crumbSep,
14947
- children: "/"
14948
- }), lineage ? summary.subagent ? renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: title }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [title, renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: null })] }) : title]
14949
- }, summary.id);
14950
- }), ancestry.length === 0 && (0, react_jsx_runtime.jsx)("span", {
14951
- className: ConversationRoot_module_css_default.crumbCurrent,
14952
- children: sessionId
15021
+ children: [
15022
+ (0, react_jsx_runtime.jsxs)("div", {
15023
+ className: ConversationRoot_module_css_default.titleCluster,
15024
+ children: [(0, react_jsx_runtime.jsxs)("nav", {
15025
+ className: ConversationRoot_module_css_default.crumbs,
15026
+ "aria-label": t("session.hierarchy"),
15027
+ children: [ancestry.map((summary, index) => {
15028
+ const last = index === ancestry.length - 1;
15029
+ const title = (0, react_jsx_runtime.jsx)("button", {
15030
+ type: "button",
15031
+ className: clsx(ConversationRoot_module_css_default.crumb, summary.subagent && ConversationRoot_module_css_default.crumbSubagent, last && ConversationRoot_module_css_default.crumbCurrent),
15032
+ disabled: last,
15033
+ onClick: () => {
15034
+ open(summary.id);
15035
+ },
15036
+ children: summary.displayTitle
15037
+ });
15038
+ const lineage = last || summary.subagent;
15039
+ const lineageOwner = {
15040
+ lineageSessionId: summary.id,
15041
+ displayTitle: summary.displayTitle,
15042
+ ...last ? {} : { openTitle: () => {
15043
+ open(summary.id);
15044
+ } }
15045
+ };
15046
+ return (0, react_jsx_runtime.jsxs)("span", {
15047
+ className: ConversationRoot_module_css_default.crumbSeg,
15048
+ children: [index > 0 && (0, react_jsx_runtime.jsx)("span", {
15049
+ className: ConversationRoot_module_css_default.crumbSep,
15050
+ children: "/"
15051
+ }), lineage ? summary.subagent ? renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: title }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [title, renderSlot("conversation.session.header.lineage", lineageOwner, { fallback: null })] }) : title]
15052
+ }, summary.id);
15053
+ }), ancestry.length === 0 && (0, react_jsx_runtime.jsx)("span", {
15054
+ className: ConversationRoot_module_css_default.crumbCurrent,
15055
+ children: sessionId
15056
+ })]
15057
+ }), (0, react_jsx_runtime.jsx)("div", {
15058
+ className: ConversationRoot_module_css_default.headerActions,
15059
+ children: renderSlot("conversation.session.header.actions", {})
14953
15060
  })]
14954
- }), (0, react_jsx_runtime.jsx)("div", {
14955
- className: ConversationRoot_module_css_default.headerActions,
14956
- children: renderSlot("conversation.session.header.actions", {})
14957
- })]
14958
- }), (0, react_jsx_runtime.jsx)("div", {
14959
- className: ConversationRoot_module_css_default.headerUtilities,
14960
- children: renderSlot("conversation.session.header.utilities", {})
14961
- })]
15061
+ }),
15062
+ (0, react_jsx_runtime.jsx)("div", {
15063
+ className: ConversationRoot_module_css_default.headerUtilities,
15064
+ children: renderSlot("conversation.session.header.utilities", {})
15065
+ }),
15066
+ (0, react_jsx_runtime.jsx)("div", {
15067
+ className: ConversationRoot_module_css_default.headerCorner,
15068
+ "data-conversation-header-corner": "",
15069
+ children: renderSlot("conversation.session.header.corner", {})
15070
+ })
15071
+ ]
14962
15072
  }), tabs.length > 1 && (0, react_jsx_runtime.jsx)("div", {
14963
15073
  className: ConversationRoot_module_css_default.tabs,
14964
15074
  role: "tablist",
@@ -15631,7 +15741,7 @@ window.__ModuleLoader__.load({
15631
15741
  }
15632
15742
  //#endregion
15633
15743
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css.mjs
15634
- const css$1 = ".uV2eYG_root{padding:0 var(--dsh-composer-side-clearance) 8px;flex-direction:column;align-items:center;display:flex}.uV2eYG_hero{padding:0 var(--dsh-composer-side-clearance)}.uV2eYG_notice{width:100%;max-width:var(--dsh-composer-card-max-width);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:8px;margin-bottom:6px;padding:4px 8px;font-size:12px;line-height:18px}.uV2eYG_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width);--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);background:var(--dsw-specific-input-major);box-shadow:var(--dsw-elevation-soft);font-size:var(--dsh-content-font-size,14px);line-height:calc(24px + var(--dsh-content-font-delta,0px));--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;border-radius:22px;flex-direction:column;gap:12px;padding-top:10px;display:flex;position:relative}.uV2eYG_cardWorkspaceTrigger{--dsw-elevation-stroke-color:transparent;cursor:pointer}.uV2eYG_cardWorkspaceTrigger:after{content:\"\";background:var(--dsw-alias-border-l4);pointer-events:none;border-radius:22px;transition:background-color .1s;position:absolute;inset:-1px;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E\");mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E\")}.uV2eYG_cardWorkspaceTrigger :disabled{pointer-events:none}.uV2eYG_cardWorkspaceTrigger:hover:after{background:var(--dsw-alias-state-business-primary)}.uV2eYG_accessory{align-items:center;gap:8px;padding:10px 12px 0;display:flex}.uV2eYG_overlayAnchor{height:0;position:absolute;inset:0 0 auto}.uV2eYG_scroll{max-height:var(--dsh-composer-text-max-height);margin-right:4px;overflow-y:auto}.uV2eYG_scroll::-webkit-scrollbar-track{margin-top:8px}.uV2eYG_grow{position:relative}.uV2eYG_pending{corner-shape:round;background:var(--dsw-alias-state-business-primary);border-radius:50%;width:8px;height:8px;animation:1s ease-in-out infinite alternate uV2eYG_input-pending}@keyframes uV2eYG_input-pending{0%{opacity:.35}to{opacity:1}}.uV2eYG_input{box-sizing:border-box;font-family:var(--dsw-font-family);font-size:inherit;line-height:inherit;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);caret-color:var(--dsw-alias-state-business-primary);outline:none;padding:4px 8px 0 16px}.uV2eYG_input p{margin:0}.uV2eYG_input p:last-child:after{content:var(--dsh-composer-hint);color:var(--dsw-alias-label-caption)}.uV2eYG_placeholder{color:var(--dsw-alias-label-caption);pointer-events:none;user-select:none;position:absolute;inset:4px 8px auto 16px}.uV2eYG_inputDisabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}.uV2eYG_input[aria-haspopup=menu]{cursor:pointer}.uV2eYG_hero .uV2eYG_input{min-height:52px}.uV2eYG_row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;padding:2px 8px 6px;display:flex;container-type:inline-size}.uV2eYG_tools,.uV2eYG_modes,.uV2eYG_trailing{align-items:center;min-width:0;display:flex}.uV2eYG_tools{gap:16px}.uV2eYG_modes{gap:12px}.uV2eYG_trailing{flex:none;gap:12px;margin-left:auto}.uV2eYG_add{corner-shape:round;background:var(--dsw-specific-selector);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;display:grid}.uV2eYG_add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.uV2eYG_add:disabled{opacity:.5;cursor:default}.uV2eYG_select{max-width:220px;height:28px;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;appearance:none;background-color:#0000;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 4px center;background-repeat:no-repeat;background-size:12px 12px;border:none;border-radius:8px;outline:none;padding:0 20px 0 8px;font-size:13px;font-weight:500;line-height:20px}.uV2eYG_select:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover)}.uV2eYG_select:disabled{opacity:.5;cursor:default}.uV2eYG_primary{corner-shape:round;background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;width:34px;height:34px;transition:background-color .1s;display:grid;transform:translateY(-2px)}.uV2eYG_primary:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}.uV2eYG_primary:disabled{opacity:.4;cursor:default}.uV2eYG_retry{color:inherit;cursor:pointer;background:0 0;border:1px solid;border-radius:4px;margin-left:8px;padding:1px 8px;font-size:12px}";
15744
+ const css$1 = ".uV2eYG_root{padding:0 var(--dsh-composer-side-clearance) 8px;flex-direction:column;align-items:center;display:flex}.uV2eYG_root:has([data-composer-stats]){padding-bottom:4px}.uV2eYG_hero{padding:0 var(--dsh-composer-side-clearance)}.uV2eYG_notice{width:100%;max-width:var(--dsh-composer-card-max-width);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:8px;margin-bottom:6px;padding:4px 8px;font-size:12px;line-height:18px}.uV2eYG_card{box-sizing:border-box;width:100%;max-width:var(--dsh-composer-card-max-width);--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);background:var(--dsw-specific-input-major);box-shadow:var(--dsw-elevation-soft);font-size:var(--dsh-content-font-size,14px);line-height:calc(24px + var(--dsh-content-font-delta,0px));--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;border-radius:22px;flex-direction:column;gap:12px;padding-top:8px;display:flex;position:relative}.uV2eYG_cardWorkspaceTrigger{--dsw-elevation-stroke-color:transparent;cursor:pointer}.uV2eYG_cardWorkspaceTrigger:after{content:\"\";background:var(--dsw-alias-border-l4);pointer-events:none;border-radius:22px;transition:background-color .1s;position:absolute;inset:-1px;-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E\");mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E\")}.uV2eYG_cardWorkspaceTrigger :disabled{pointer-events:none}.uV2eYG_cardWorkspaceTrigger:hover:after{background:var(--dsw-alias-state-business-primary)}.uV2eYG_accessory{align-items:center;gap:8px;padding:10px 12px 0;display:flex}.uV2eYG_overlayAnchor{height:0;position:absolute;inset:0 0 auto}.uV2eYG_scroll{max-height:var(--dsh-composer-text-max-height);margin-right:4px;overflow-y:auto}.uV2eYG_scroll::-webkit-scrollbar-track{margin-top:8px}.uV2eYG_grow{position:relative}.uV2eYG_pending{corner-shape:round;background:var(--dsw-alias-state-business-primary);border-radius:50%;width:8px;height:8px;animation:1s ease-in-out infinite alternate uV2eYG_input-pending}@keyframes uV2eYG_input-pending{0%{opacity:.35}to{opacity:1}}.uV2eYG_input{box-sizing:border-box;min-height:36px;font-family:var(--dsw-font-family);font-size:inherit;line-height:inherit;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);caret-color:var(--dsw-alias-state-business-primary);outline:none;padding:4px 8px 0 14px}.uV2eYG_input p{margin:0}.uV2eYG_input p:last-child:after{content:var(--dsh-composer-hint);color:var(--dsw-alias-label-caption)}.uV2eYG_placeholder{color:var(--dsw-alias-label-caption);white-space:nowrap;text-overflow:ellipsis;pointer-events:none;user-select:none;position:absolute;inset:4px 8px auto 14px;overflow:hidden}.uV2eYG_inputDisabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}.uV2eYG_input[aria-haspopup=menu]{cursor:pointer}.uV2eYG_hero .uV2eYG_input{min-height:52px}.uV2eYG_hero .uV2eYG_placeholder{white-space:normal;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box}.uV2eYG_row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;padding:2px 8px 6px;display:flex;container-type:inline-size}.uV2eYG_tools,.uV2eYG_modes,.uV2eYG_trailing{align-items:center;min-width:0;display:flex}.uV2eYG_tools,.uV2eYG_modes{gap:12px}.uV2eYG_trailing{flex:none;gap:12px;margin-left:auto}.uV2eYG_add{corner-shape:round;background:var(--dsw-specific-selector);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;display:grid}.uV2eYG_add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.uV2eYG_add:disabled{opacity:.5;cursor:default}.uV2eYG_select{max-width:220px;height:28px;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;appearance:none;background-color:#0000;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 4px center;background-repeat:no-repeat;background-size:12px 12px;border:none;border-radius:8px;outline:none;padding:0 20px 0 8px;font-size:13px;font-weight:500;line-height:20px}.uV2eYG_select:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover)}.uV2eYG_select:disabled{opacity:.5;cursor:default}.uV2eYG_primary{corner-shape:round;background:var(--dsw-alias-button-info-fill);color:#fff;cursor:pointer;border:none;border-radius:999px;flex:none;place-items:center;width:34px;height:34px;transition:background-color .1s;display:grid;transform:translateY(-2px)}.uV2eYG_primary:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}.uV2eYG_primary:disabled{opacity:.4;cursor:default}.uV2eYG_retry{color:inherit;cursor:pointer;background:0 0;border:1px solid;border-radius:4px;margin-left:8px;padding:1px 8px;font-size:12px}";
15635
15745
  const tagId$1 = "@deepseek-ai/dsh-client-ui-conversation/InputBar.module.css";
15636
15746
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
15637
15747
  const tag = document.createElement("style");
@@ -15680,9 +15790,10 @@ window.__ModuleLoader__.load({
15680
15790
  * The no-session state renders the SAME div inert as the Workspace-picker
15681
15791
  * trigger instead of a parallel tree.
15682
15792
  */
15683
- const InputBar = (0, react.memo)(function InputBar({ useSession, useInput, inputActions, keyboard, addFiles, removeAttachment, resolveDraftAttachments, retryFileUpload, resolveSubmitMode, toggleCommandMenu, stop, command, t, renderSlot, useFileUploads, useNotices, useLexicon, useMenuLauncher, useProjection, sessionId, variant, disabled: inert = false, blocked, workspacePickerOpen = false, onRequestWorkspace, placeholder, accessory }) {
15793
+ const InputBar = (0, react.memo)(function InputBar({ useSession, useInput, inputActions, keyboard, addFiles, removeAttachment, resolveDraftAttachments, retryFileUpload, toggleCommandMenu, stop, command, t, renderSlot, useBusyEnter, useFileUploads, useNotices, useLexicon, useMenuLauncher, useProjection, sessionId, variant, disabled: inert = false, blocked, workspacePickerOpen = false, onRequestWorkspace, placeholder, accessory }) {
15684
15794
  const input = useInput((s) => s);
15685
15795
  const notice = useNotices((s) => s);
15796
+ const busyEnter = useBusyEnter((s) => s);
15686
15797
  const commandMenuOpen = useMenuLauncher((source) => source === "command");
15687
15798
  const promptError = useSession((s) => s.promptError) ?? null;
15688
15799
  const running = useSession((s) => s.running) ?? false;
@@ -15828,7 +15939,7 @@ window.__ModuleLoader__.load({
15828
15939
  canSteerQueue,
15829
15940
  running,
15830
15941
  steeringAvailable,
15831
- resolveSubmitMode,
15942
+ busyEnter,
15832
15943
  intakeFiles,
15833
15944
  uploadsPending,
15834
15945
  showToast,
@@ -15840,7 +15951,7 @@ window.__ModuleLoader__.load({
15840
15951
  canSteerQueue,
15841
15952
  running,
15842
15953
  steeringAvailable,
15843
- resolveSubmitMode,
15954
+ busyEnter,
15844
15955
  intakeFiles,
15845
15956
  uploadsPending,
15846
15957
  showToast,
@@ -15868,7 +15979,7 @@ window.__ModuleLoader__.load({
15868
15979
  g.showToast(g.t("file.stillUploading"));
15869
15980
  return;
15870
15981
  }
15871
- keyboard.submit(g.resolveSubmitMode(g.running, accelerated ? "accelerated" : "enter", g.steeringAvailable));
15982
+ keyboard.submit(resolveSubmitMode(g.busyEnter, g.running, accelerated ? "accelerated" : "enter", g.steeringAvailable));
15872
15983
  },
15873
15984
  intakeFiles: (files) => {
15874
15985
  gate.current.intakeFiles(files);
@@ -15894,16 +16005,19 @@ window.__ModuleLoader__.load({
15894
16005
  }
15895
16006
  };
15896
16007
  const primaryStops = running && subagent === null && (empty || blocked !== void 0);
16008
+ const primaryDisabled = primaryStops ? stop === void 0 : empty || disabled || machineBusy || uploadsPending;
15897
16009
  const interruptible = running && continuable;
15898
- const primaryLabel = primaryStops ? t("input.stop") : t("input.send");
16010
+ const primarySubmitMode = resolveSubmitMode(busyEnter, running, "enter", steeringAvailable);
16011
+ const plainMessageDraft = !empty && input?.phase === "plain" && !draft.trimStart().startsWith("/");
16012
+ const primaryLabel = primaryStops ? t("input.stop") : running && steeringAvailable && !disabled && !uploadsPending && plainMessageDraft ? t(primarySubmitMode === "steer" ? "input.send.steer" : "input.send.queue") : t("input.send");
15899
16013
  const onPrimary = () => {
15900
16014
  if (primaryStops) {
15901
16015
  stop?.();
15902
16016
  return;
15903
16017
  }
15904
- if (inputActions === void 0) return;
16018
+ if (keyboard === void 0) return;
15905
16019
  /* v8 ignore next -- defensive: the primary button is disabled for empty, disabled, and pending-upload states. */
15906
- if (!empty && !disabled && !machineBusy && !uploadsPending) inputActions.submit();
16020
+ if (!empty && !disabled && !machineBusy && !uploadsPending) keyboard.submit(primarySubmitMode);
15907
16021
  };
15908
16022
  const accessSelect = command === void 0 ? null : (0, react_jsx_runtime.jsx)(PermissionSelect, {
15909
16023
  value: permissions,
@@ -16063,6 +16177,7 @@ window.__ModuleLoader__.load({
16063
16177
  label: t("input.stop"),
16064
16178
  side: "top",
16065
16179
  delayMs: 500,
16180
+ disabled: stop === void 0,
16066
16181
  children: (0, react_jsx_runtime.jsx)("button", {
16067
16182
  type: "button",
16068
16183
  className: InputBar_module_css_default.primary,
@@ -16090,11 +16205,12 @@ window.__ModuleLoader__.load({
16090
16205
  label: primaryLabel,
16091
16206
  side: "top",
16092
16207
  delayMs: 500,
16208
+ disabled: primaryDisabled,
16093
16209
  children: (0, react_jsx_runtime.jsx)("button", {
16094
16210
  type: "button",
16095
16211
  className: InputBar_module_css_default.primary,
16096
16212
  "aria-label": primaryLabel,
16097
- disabled: primaryStops ? stop === void 0 : empty || disabled || machineBusy || uploadsPending,
16213
+ disabled: primaryDisabled,
16098
16214
  onMouseDown: keepFocus,
16099
16215
  onClick: onPrimary,
16100
16216
  children: primaryStops ? (0, react_jsx_runtime.jsx)("svg", {
@@ -16568,6 +16684,10 @@ window.__ModuleLoader__.load({
16568
16684
  "conversation.session.header.utilities": {
16569
16685
  kind: "list",
16570
16686
  scope: "session"
16687
+ },
16688
+ "conversation.session.header.corner": {
16689
+ kind: "single",
16690
+ scope: "session"
16571
16691
  }
16572
16692
  },
16573
16693
  store: conversationStore,
@@ -16622,11 +16742,11 @@ window.__ModuleLoader__.load({
16622
16742
  removeAttachment: void 0,
16623
16743
  resolveDraftAttachments: void 0,
16624
16744
  retryFileUpload: void 0,
16625
- resolveSubmitMode: (running, gesture, steeringAvailable) => submissionPolicy.resolve(running, gesture, steeringAvailable),
16626
16745
  toggleCommandMenu: void 0,
16627
16746
  stop: void 0,
16628
16747
  command: void 0,
16629
16748
  hooks: {
16749
+ busyEnter: submissionPolicy.busyEnter,
16630
16750
  fileUploads: ABSENT_FILE_UPLOADS,
16631
16751
  notices: ABSENT_NOTICES,
16632
16752
  lexicon: ABSENT_LEXICON,
@@ -16656,7 +16776,6 @@ window.__ModuleLoader__.load({
16656
16776
  retryFileUpload: (id) => {
16657
16777
  if (sessions.binding(sessionId) !== void 0) conversation.retryFileUpload(sessionId, id);
16658
16778
  },
16659
- resolveSubmitMode: (running, gesture, steeringAvailable) => submissionPolicy.resolve(running, gesture, steeringAvailable),
16660
16779
  toggleCommandMenu: inputTriggers === void 0 ? void 0 : (selection) => {
16661
16780
  shell.dismissPopup();
16662
16781
  const snapshot = shell.snapshot;
@@ -16681,6 +16800,7 @@ window.__ModuleLoader__.load({
16681
16800
  return result.ok && result.value.matched;
16682
16801
  },
16683
16802
  hooks: {
16803
+ busyEnter: submissionPolicy.busyEnter,
16684
16804
  fileUploads: conversation.fileUploads,
16685
16805
  notices: shell.notices,
16686
16806
  lexicon: shell.lexicon,
@@ -239,7 +239,7 @@ export interface ComposerKeyboard {
239
239
  readonly snapshot: InputState;
240
240
  /** The shell-owned Lexical editor the composer binds its contenteditable to. */
241
241
  readonly editor: LexicalEditor;
242
- /** Submit with an explicit delivery mode resolved by the keyboard policy. */
242
+ /** Submit with an explicit delivery mode resolved by the submission policy (Enter gestures and the primary Send button). */
243
243
  submit(mode: InputSubmitMode): void;
244
244
  /**
245
245
  * Steer every still-pending queued message into the running turn (the
@@ -200,9 +200,10 @@ export interface CompactionSummaryNode {
200
200
  * Fallback for surface events this UI version does not know: the documented
201
201
  * default arm of `SessionEventMap`, which is merge-extensible, so the
202
202
  * projection's switch cannot end in `assertNever`. No event produces this node
203
- * because `isAppendSurfaceEvent` admits only the three types in core's
204
- * `SurfaceEventType`, and each has its own arm and it exists so widening that
205
- * set core-side degrades to a raw row instead of dropping the event silently.
203
+ * because `isAppendSurfaceEvent` admits only the four types in core's
204
+ * `SurfaceEventType`, and each has its own arm (`system/message` is claimed by
205
+ * a Chat Definition that renders no transcript row) and it exists so widening
206
+ * that set core-side degrades to a raw row instead of dropping the event silently.
206
207
  */
207
208
  export interface UnknownSurfaceNode {
208
209
  kind: 'unknown';
@@ -2,20 +2,51 @@ import type { ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm/types';
2
2
  import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
3
3
  import type { AssistantProvenanceView, AssistantRequestConfig } from './records.ts';
4
4
  export type { AssistantProvenanceView, AssistantRequestConfig, } from './records.ts';
5
- /** Complete model-visible request header in force for an ordinary generation. */
5
+ /**
6
+ * Complete model-visible request state in force for an ordinary generation:
7
+ * the `request/header` config and tools plus the system prompt held by the
8
+ * current `system/message` surface node.
9
+ */
6
10
  export interface ConversationPromptSnapshot {
7
11
  /** Provider/model and sampling configuration from the effective request header. */
8
12
  config: AssistantRequestConfig;
9
- /** Rendered system prompt text; empty when the request had no system prompt. */
13
+ /**
14
+ * Rendered text of the `system/message` surface node in force for the
15
+ * request; empty when the surface has no system prompt or the node lies
16
+ * outside the loaded history window.
17
+ */
10
18
  system: string;
11
19
  /** Complete tool catalog sent with the request, including tools that were never called. */
12
20
  tools: readonly ToolSchema[];
13
21
  }
14
- /** System/tool change introduced while preparing one ordinary request. */
22
+ /** Effective prompt or introduced system node, anchored at the event that establishes it. */
23
+ export interface SystemPromptNode {
24
+ /** Sequence of the system event or replacement that establishes this prompt. */
25
+ seq: number;
26
+ /** Unix epoch ms of that event. */
27
+ time: number;
28
+ /** Turn the loop committed the node in. */
29
+ turn: number;
30
+ /** Step the loop committed the node in. */
31
+ step: number;
32
+ /** Rendered system prompt text; empty records "no system prompt". */
33
+ text: string;
34
+ /**
35
+ * True for a prompt appended after an earlier loaded system node: an
36
+ * in-history update the model reads at this position, presented where it
37
+ * was committed rather than by the next request header.
38
+ */
39
+ update: boolean;
40
+ }
41
+ /** System/tool change introduced while preparing one ordinary request, or by an in-history prompt update. */
15
42
  export interface RequestPromptChange {
16
- /** Sequence of the request/header event that introduced this state. */
43
+ /**
44
+ * Sequence of the event that introduced this state: the `system/message`
45
+ * node when it introduced, replaced, or updated the system prompt, otherwise the
46
+ * `request/header` event.
47
+ */
17
48
  seq: number;
18
- /** Unix epoch ms from the request/header event. */
49
+ /** Unix epoch ms of that event. */
19
50
  time: number;
20
51
  /** How the model-visible prompt differs from the previous recorded state. */
21
52
  kind: 'initial' | 'system' | 'tools' | 'system-and-tools';
@@ -24,7 +55,7 @@ export interface RequestPromptChange {
24
55
  }
25
56
  /** Canonical prompt snapshot and any model-visible change introduced by one request header. */
26
57
  export interface RequestPromptInspection {
27
- /** Complete prompt state recorded by the header. */
58
+ /** Complete prompt state in force for the header's request. */
28
59
  prompt: ConversationPromptSnapshot;
29
60
  /** System/tool change relative to the preceding loaded header. */
30
61
  change?: RequestPromptChange;
@@ -34,14 +65,17 @@ export interface RequestPromptInspection {
34
65
  * Trajectory Definitions receive it from the uiConversation service because a
35
66
  * client bundle cannot value-import another plugin's module.
36
67
  */
37
- export type RequestPromptInspector = (previous: ConversationPromptSnapshot | undefined, event: SessionEvent<'request/header'>) => RequestPromptInspection;
68
+ export type RequestPromptInspector = (previous: ConversationPromptSnapshot | undefined, event: SessionEvent<'request/header'>, system: SystemPromptNode | undefined) => RequestPromptInspection;
38
69
  /**
39
- * Canonicalize one request header and classify its model-visible prompt change.
70
+ * Canonicalize one request header against the system node in force and
71
+ * classify the model-visible prompt change.
40
72
  * @param previous - Prompt from the preceding loaded request header, when available.
41
73
  * @param event - Durable full request header to inspect.
74
+ * @param system - Effective nonempty system prompt after loaded surface replacements; empty when removed.
75
+ * An in-history update already presented its text at its own position, so the header reports no system change for it.
42
76
  * @returns The canonical prompt and an initial/system/tool change when it can be established.
43
77
  */
44
- export declare function inspectRequestPrompt(previous: ConversationPromptSnapshot | undefined, event: SessionEvent<'request/header'>): RequestPromptInspection;
78
+ export declare function inspectRequestPrompt(previous: ConversationPromptSnapshot | undefined, event: SessionEvent<'request/header'>, system: SystemPromptNode | undefined): RequestPromptInspection;
45
79
  /** Lifecycle fields shared by ordinary generation and compaction requests. */
46
80
  interface RequestViewBase {
47
81
  /** Sequence that opened the operation represented by this request. */
@@ -12,7 +12,7 @@ import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types';
12
12
  import type { ComposerBlock } from './composer-blocks.ts';
13
13
  import type { ComposerKeyboard, DraftAttachmentId, EditSelection, InputActions, InputNotice, InputState } from './input.ts';
14
14
  import type { createConversationStore } from '../stores.ts';
15
- import type { ComposerSubmitGesture, InputSubmitMode } from './composer-submission.ts';
15
+ import type { BusyEnterBehavior } from './composer-submission.ts';
16
16
  import type { ConversationSnapshot } from './snapshot.ts';
17
17
  import type { ViewTab } from './views.ts';
18
18
  /** Browser-owned draft attachment that has not crossed the durable Host boundary. */
@@ -137,6 +137,18 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
137
137
  scope: 'session';
138
138
  owner: ConversationHeaderActionOwnerProps;
139
139
  };
140
+ /**
141
+ * The header's far-right corner, past the utilities' edge and into the
142
+ * header's own padding, for one control that must keep its place whether or
143
+ * not it currently shows anything. The corner reserves its width while an
144
+ * occupant is registered, so the utilities beside it never move; an
145
+ * occupant with nothing to show renders a same-size placeholder.
146
+ */
147
+ 'conversation.session.header.corner': {
148
+ kind: 'single';
149
+ scope: 'session';
150
+ owner: ConversationHeaderCornerOwnerProps;
151
+ };
140
152
  /** Registered Conversation target Views, rendered one at a time. */
141
153
  'conversation.view': {
142
154
  kind: 'list';
@@ -249,6 +261,11 @@ export interface ConversationHeaderActionOwnerProps {
249
261
  /** Marker field: entries receive no owner-specific values. */
250
262
  children?: never;
251
263
  }
264
+ /** The header corner's occupant derives its state from standard Session props. */
265
+ export interface ConversationHeaderCornerOwnerProps {
266
+ /** Marker field: the occupant receives no owner-specific values. */
267
+ children?: never;
268
+ }
252
269
  /** Plain breadcrumb data handed to the optional lineage renderer. */
253
270
  export interface ConversationHeaderLineageOwnerProps {
254
271
  /** Session represented by this breadcrumb title. */
@@ -331,11 +348,15 @@ export interface ComposerBarInjected {
331
348
  resolveDraftAttachments: ((ids: readonly DraftAttachmentId[]) => readonly ComposerAttachment[]) | undefined;
332
349
  /** Restart one failed file upload; absent without a session. */
333
350
  retryFileUpload: ((id: DraftAttachmentId) => void) | undefined;
334
- resolveSubmitMode: (running: boolean, gesture: ComposerSubmitGesture, steeringAvailable: boolean) => InputSubmitMode;
335
351
  toggleCommandMenu: ((selection: EditSelection) => void) | undefined;
336
352
  stop: (() => void) | undefined;
337
353
  command: ((line: string) => Promise<boolean>) | undefined;
338
354
  hooks: {
355
+ /**
356
+ * Live busy-state submission preference: the delivery mode plain Enter
357
+ * and the primary Send button use while the addressed agent is busy.
358
+ */
359
+ busyEnter: ObservableSnapshot<BusyEnterBehavior>;
339
360
  /** Live per-draft upload states for file-kind drafts. */
340
361
  fileUploads: ObservableSnapshot<DraftFileUploads>;
341
362
  notices: ObservableSnapshot<InputNotice | null>;
@@ -373,7 +394,7 @@ export type ConversationStore = ReturnType<typeof createConversationStore>;
373
394
  /** Full props of the strict Session body. */
374
395
  export type ConversationSessionSlotProps = PropsRuntime<'conversation.session'> & PropsRenderSlots<'conversation.view'> & PropsStore<ConversationStore> & InjectFace<ConversationSessionInjected>;
375
396
  /** Full props of the strict Session header. */
376
- export type ConversationSessionHeaderSlotProps = PropsRuntime<'conversation.session.header'> & PropsRenderSlots<'conversation.session.header.lineage' | 'conversation.session.header.actions' | 'conversation.session.header.utilities'> & PropsStore<ConversationStore> & InjectFace<ConversationSessionHeaderInjected> & PropsLocale<'conversation'>;
397
+ export type ConversationSessionHeaderSlotProps = PropsRuntime<'conversation.session.header'> & PropsRenderSlots<'conversation.session.header.lineage' | 'conversation.session.header.actions' | 'conversation.session.header.utilities' | 'conversation.session.header.corner'> & PropsStore<ConversationStore> & InjectFace<ConversationSessionHeaderInjected> & PropsLocale<'conversation'>;
377
398
  /** Full props of the draft-attachment renderer. */
378
399
  export type ComposerAttachmentsProps = PropsRuntime<'conversation.input.attachments'> & PropsLocale<'conversation'>;
379
400
  /** Owner share common to blank-session Workspace pickers. */
@@ -0,0 +1,35 @@
1
+ /** Immutable system-only interpretation of the loaded Session surface. */
2
+ import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
3
+ import type { SystemPromptNode } from './request-inspection.ts';
4
+ interface PositionedSystem {
5
+ readonly position: number;
6
+ readonly node: SystemPromptNode;
7
+ }
8
+ /** Prompt facts at one log prefix; earlier instances remain valid for historical cards. */
9
+ export interface SystemPromptState {
10
+ /** Earliest relevant loaded event; older unindexed endpoints have unknown surface positions. */
11
+ readonly firstSeq: number;
12
+ /** Missing endpoint order makes the prompt unavailable until prepend replay supplies it. */
13
+ readonly uncertain: boolean;
14
+ /** Loaded system nodes in surface order, including empty dormant nodes. */
15
+ readonly nodes: readonly PositionedSystem[];
16
+ /** Surviving replacement endpoints only, mapped to inherited surface positions. */
17
+ readonly replacements: ReadonlyMap<number, number>;
18
+ /** Effective prompt and its change origin; empty text records removal, undefined means unavailable. */
19
+ readonly effective: SystemPromptNode | undefined;
20
+ /** System event at this position, if any; only this node may own an update card. */
21
+ readonly introduced: SystemPromptNode | undefined;
22
+ }
23
+ /** Pure interpretation supplied to target-owned Definitions through uiConversation. */
24
+ export type SystemPromptInspector = (previous: SystemPromptState | undefined, event: SessionEvent) => SystemPromptState;
25
+ /**
26
+ * Apply a system event or positional replacement without retaining ordinary messages.
27
+ * Replacement positions inherit their start endpoint, not their chronological seq.
28
+ * Unknown older endpoint order withholds the prompt until prepend replay resolves it.
29
+ * @param previous - Interpretation at the preceding relevant event in the loaded window.
30
+ * @param event - System message or surface replacement already admitted by Session.
31
+ * @returns Immutable surviving system facts and the effective nonempty prompt.
32
+ */
33
+ export declare function inspectSystemPrompt(previous: SystemPromptState | undefined, event: SessionEvent): SystemPromptState;
34
+ export {};
35
+ //# sourceMappingURL=system-prompt.d.ts.map
@@ -6,7 +6,8 @@ import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types';
6
6
  import { type ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
7
7
  import type { ConversationViewSnapshotMap } from '../contract/conversation.ts';
8
8
  import type { ConversationSnapshot } from '../contract/snapshot.ts';
9
- import type { ConversationPromptSnapshot, RequestPromptInspection } from '../contract/request-inspection.ts';
9
+ import type { ConversationPromptSnapshot, RequestPromptInspection, SystemPromptNode } from '../contract/request-inspection.ts';
10
+ import { type SystemPromptState } from '../contract/system-prompt.ts';
10
11
  import { ConversationEventRegistry } from './event-registry.ts';
11
12
  import { ConversationViewRegistry } from './view-registry.ts';
12
13
  /** Observable faces published for one Session's Conversation assembly. */
@@ -72,16 +73,25 @@ export declare class UiConversation extends Service {
72
73
  */
73
74
  seedImageUrl(sessionId: SessionId, attachment: ImageAttachmentRef, url: string): boolean;
74
75
  /**
75
- * Canonicalize one `request/header` event against the previous prompt state.
76
+ * Interpret a system message or surface replacement for target-owned prompt Definitions.
77
+ * @param previous - System facts at the preceding relevant loaded event.
78
+ * @param event - Durable system message or positional replacement.
79
+ * @returns Immutable prompt interpretation at this event.
80
+ */
81
+ inspectSystemPrompt(previous: SystemPromptState | undefined, event: SessionEvent): SystemPromptState;
82
+ /**
83
+ * Canonicalize one `request/header` event against the previous prompt state
84
+ * and the `system/message` node in force.
76
85
  *
77
86
  * A pure interpretation shared by the Chat and Trajectory Definitions, exposed
78
87
  * as a service method because cross-plugin value imports are forbidden in
79
88
  * client bundles.
80
89
  * @param previous - prompt recorded by the preceding loaded header, if any.
81
90
  * @param event - the `request/header` session event to interpret.
91
+ * @param system - effective prompt after loaded surface replacements, if any.
82
92
  * @returns the canonical prompt snapshot and any model-visible change.
83
93
  */
84
- inspectRequestPrompt(previous: ConversationPromptSnapshot | undefined, event: SessionEvent<'request/header'>): RequestPromptInspection;
94
+ inspectRequestPrompt(previous: ConversationPromptSnapshot | undefined, event: SessionEvent<'request/header'>, system: SystemPromptNode | undefined): RequestPromptInspection;
85
95
  private drop;
86
96
  }
87
97
  //# sourceMappingURL=assembly.d.ts.map
@@ -10,8 +10,9 @@ export { EMPTY_CONVERSATION_SNAPSHOT, conversationPhase } from './contract/snaps
10
10
  export type { ConversationPhase, ConversationSnapshot, } from './contract/snapshot.ts';
11
11
  export type { AssistantBlock, AssistantMessageNode, AssistantProvenanceView, AssistantRequestConfig, AssistantTiming, CommandNode, CompactionSummaryNode, ContextMessageNode, ConversationNode, ModelRetryNode, PartialAssistant, RunningToolCall, SteeringMessageNode, TodoItem, ToolCallBlock, ToolResultNode, TurnErrorNode, TurnMaxTokensNode, UnknownSurfaceNode, UserMessageNode, } from './contract/records.ts';
12
12
  export type { ContextProvenanceView, ContextRole, KnownContextForm, } from './contract/context-provenance.ts';
13
- export type { ConversationPromptSnapshot, RequestInspectionSnapshot, RequestPromptChange, RequestPromptInspection, RequestPromptInspector, RequestView, } from './contract/request-inspection.ts';
13
+ export type { ConversationPromptSnapshot, RequestInspectionSnapshot, RequestPromptChange, RequestPromptInspection, RequestPromptInspector, RequestView, SystemPromptNode, } from './contract/request-inspection.ts';
14
14
  export { inspectRequestPrompt } from './contract/request-inspection.ts';
15
+ export type { SystemPromptState, SystemPromptInspector } from './contract/system-prompt.ts';
15
16
  export type { ConversationStoreState, ConversationViewRequest, ViewTab } from './contract/views.ts';
16
17
  export { ConversationNodeAssembler } from './conversation/assembler.ts';
17
18
  export type { ConversationEventDefinitions, ConversationViewDefinitions, } from './conversation/assembler.ts';
@@ -21,7 +22,7 @@ export { ConversationLocationIndex } from './conversation/location-index.ts';
21
22
  export type { ConversationLocationDataChange } from './conversation/location-index.ts';
22
23
  export { ConversationViewRegistry } from './conversation/view-registry.ts';
23
24
  export type { ConversationKey } from './locales.ts';
24
- export type { ComposerAttachment, ComposerAttachmentsOwnerProps, ComposerAttachmentsProps, ComposerFileAttachment, ComposerImageAttachment, DraftFileUpload, DraftFileUploads, ComposerBarInjected, ComposerBarOwnerProps, ComposerBarProps, ComposerChainProps, ConversationHeaderActionOwnerProps, ConversationHeaderLineageOwnerProps, ConversationInjected, ConversationSessionHeaderInjected, ConversationSessionHeaderSlotProps, ConversationSessionInjected, ConversationSessionSlotProps, ConversationSlotProps, ConversationStore, ConvViewOwnerProps, ConvViewProps, EmptyWorkspaceOwnerProps, HeroAgentPresetOwnerProps, HeroBrandMarkOwnerProps, InputControlOwnerProps, InputZone, MessageImageLoader, MessageImageSource, MessageImagesOwnerProps, RenderMessageImages, UseConversation, UseConversationViews, } from './contract/slots.ts';
25
+ export type { ComposerAttachment, ComposerAttachmentsOwnerProps, ComposerAttachmentsProps, ComposerFileAttachment, ComposerImageAttachment, DraftFileUpload, DraftFileUploads, ComposerBarInjected, ComposerBarOwnerProps, ComposerBarProps, ComposerChainProps, ConversationHeaderActionOwnerProps, ConversationHeaderCornerOwnerProps, ConversationHeaderLineageOwnerProps, ConversationInjected, ConversationSessionHeaderInjected, ConversationSessionHeaderSlotProps, ConversationSessionInjected, ConversationSessionSlotProps, ConversationSlotProps, ConversationStore, ConvViewOwnerProps, ConvViewProps, EmptyWorkspaceOwnerProps, HeroAgentPresetOwnerProps, HeroBrandMarkOwnerProps, InputControlOwnerProps, InputZone, MessageImageLoader, MessageImageSource, MessageImagesOwnerProps, RenderMessageImages, UseConversation, UseConversationViews, } from './contract/slots.ts';
25
26
  export type { ArbitrateKey, ArbitrateOutcome, BeginCommandRequest, CommandClaim, ConsumeTokenRequest, DraftAttachmentId, InputActions, InputState, InsertReferenceRequest, InsertTextRequest, PickOutcome, ReferenceInsert, SessionInput, SessionInputResolver, SubmitAttachment, SubmitOutcome, TokenSpan, } from './contract/input.ts';
26
27
  export type { ComposerBlock, ComposerBlocks } from './contract/composer-blocks.ts';
27
28
  declare module '@deepseek-ai/cordis' {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Composer submission policy. It owns the live busy-Enter
3
- * preference and resolves keyboard gestures into queue/steer delivery modes;
4
- * Host and Agent keep the actual delivery-window authority.
2
+ * Composer submission policy. It owns the live busy-Enter preference and
3
+ * resolves submission gestures into queue/steer delivery modes; Host and
4
+ * Agent keep the actual delivery-window authority.
5
5
  */
6
6
  import { type SnapshotStore } from '@deepseek-ai/dsh-client-store';
7
7
  import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
@@ -9,12 +9,25 @@ import type { BusyEnterBehavior, ComposerSubmitGesture, InputSubmitMode } from '
9
9
  import type { ConversationSettings } from '../../submission-settings.ts';
10
10
  export { DEFAULT_BUSY_ENTER_BEHAVIOR } from '../../submission-settings.ts';
11
11
  /**
12
- * Busy-Enter policy used by both the composer inject face and its Settings row.
13
- * Direct `steer` is intentionally best-effort: AgentLoop turns a closed-window
14
- * submission into the next waking Queue item.
12
+ * Resolve one submission gesture against the busy-Enter preference. Plain
13
+ * Enter and the primary Send button share the `enter` gesture, so the button
14
+ * delivers exactly what Enter would. Direct `steer` is intentionally
15
+ * best-effort: AgentLoop turns a closed-window submission into the next waking
16
+ * Queue item.
17
+ * @param preferred - the live busy-Enter preference.
18
+ * @param running - whether the addressed agent currently reports busy.
19
+ * @param gesture - plain Enter (or the Send button) or the Cmd/Ctrl-accelerated chord.
20
+ * @param steeringAvailable - whether this session transport supports steering.
21
+ * @returns Queue outside steer-capable busy state; otherwise the preferred mode or its opposite.
22
+ */
23
+ export declare function resolveSubmitMode(preferred: BusyEnterBehavior, running: boolean, gesture: ComposerSubmitGesture, steeringAvailable: boolean): InputSubmitMode;
24
+ /**
25
+ * Busy-Enter preference shared by the composer bar inject face and its
26
+ * Settings row: one live store the bar's submission gestures and Send label
27
+ * read, backed by the Host user-settings document when one is composed.
15
28
  */
16
29
  export declare class ComposerSubmissionPolicy {
17
- /** Reactive preference source for the Settings row. */
30
+ /** Reactive preference source for the composer bar and the Settings row. */
18
31
  readonly busyEnter: SnapshotStore<BusyEnterBehavior>;
19
32
  private readonly host;
20
33
  /**
@@ -25,16 +38,8 @@ export declare class ComposerSubmissionPolicy {
25
38
  */
26
39
  constructor(host?: SettingsScope<ConversationSettings>);
27
40
  /**
28
- * Resolve one keyboard gesture without changing state.
29
- * @param running - whether the addressed agent currently reports busy.
30
- * @param gesture - plain Enter or the Cmd/Ctrl-accelerated chord.
31
- * @param steeringAvailable - whether this session transport supports steering.
32
- * @returns Queue outside steer-capable busy state; otherwise the preferred mode or its opposite.
33
- */
34
- resolve(running: boolean, gesture: ComposerSubmitGesture, steeringAvailable: boolean): InputSubmitMode;
35
- /**
36
- * Change the plain-Enter behavior used during busy state; the live value
37
- * publishes before the durable write starts.
41
+ * Change the busy-state submission behavior; the live value publishes
42
+ * before the durable write starts.
38
43
  * @param behavior - Queue or Steer.
39
44
  */
40
45
  setBusyEnter(behavior: BusyEnterBehavior): void;
@@ -16,6 +16,8 @@ export declare const zh: {
16
16
  'input.commands': string;
17
17
  'input.stop': string;
18
18
  'input.send': string;
19
+ 'input.send.queue': string;
20
+ 'input.send.steer': string;
19
21
  'input.accessMode': string;
20
22
  'attachment.pending': string;
21
23
  'attachment.scrollLeft': string;
@@ -178,6 +180,8 @@ export declare const en: {
178
180
  'input.commands': string;
179
181
  'input.stop': string;
180
182
  'input.send': string;
183
+ 'input.send.queue': string;
184
+ 'input.send.steer': string;
181
185
  'input.accessMode': string;
182
186
  'attachment.pending': string;
183
187
  'attachment.scrollLeft': string;
@@ -14,5 +14,5 @@
14
14
  */
15
15
  import type { ComposerBarProps } from '../contract/slots.ts';
16
16
  export type InputBarProps = ComposerBarProps;
17
- export declare const InputBar: import("react").MemoExoticComponent<({ useSession, useInput, inputActions, keyboard, addFiles, removeAttachment, resolveDraftAttachments, retryFileUpload, resolveSubmitMode, toggleCommandMenu, stop, command, t, renderSlot, useFileUploads, useNotices, useLexicon, useMenuLauncher, useProjection, sessionId, variant, disabled: inert, blocked, workspacePickerOpen, onRequestWorkspace, placeholder, accessory, }: InputBarProps) => import("react").JSX.Element>;
17
+ export declare const InputBar: import("react").MemoExoticComponent<({ useSession, useInput, inputActions, keyboard, addFiles, removeAttachment, resolveDraftAttachments, retryFileUpload, toggleCommandMenu, stop, command, t, renderSlot, useBusyEnter, useFileUploads, useNotices, useLexicon, useMenuLauncher, useProjection, sessionId, variant, disabled: inert, blocked, workspacePickerOpen, onRequestWorkspace, placeholder, accessory, }: InputBarProps) => import("react").JSX.Element>;
18
18
  //# sourceMappingURL=InputBar.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-conversation",
3
3
  "description": "Target-neutral Conversation assembly, shell, composer, queue, and view navigation",
4
- "version": "0.1.3-alpha.2",
4
+ "version": "0.1.5-alpha.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -61,35 +61,35 @@
61
61
  "@types/react-dom": "~18.3.0",
62
62
  "zod": "^4.4.3",
63
63
  "@deepseek-ai/cordis": "^4.0.2",
64
- "@deepseek-ai/dsh-api-remotes": "^0.1.3-alpha.2",
65
- "@deepseek-ai/dsh-api-session-controller": "^0.1.3-alpha.2",
66
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.3-alpha.2",
67
- "@deepseek-ai/dsh-attachment": "^0.1.3-alpha.2",
68
- "@deepseek-ai/dsh-brand": "^0.1.3-alpha.2",
69
- "@deepseek-ai/dsh-client-locale": "^0.1.3-alpha.2",
70
- "@deepseek-ai/dsh-client-file-upload": "^0.1.3-alpha.2",
71
- "@deepseek-ai/dsh-client-store": "^0.1.3-alpha.2",
72
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.3-alpha.2",
73
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.3-alpha.2",
74
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.3-alpha.2",
75
- "@deepseek-ai/dsh-client-ui-session": "^0.1.3-alpha.2",
76
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.3-alpha.2",
77
- "@deepseek-ai/dsh-client-ui-workspace": "^0.1.3-alpha.2",
78
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.3-alpha.2",
79
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.3-alpha.2",
80
- "@deepseek-ai/dsh-commands": "^0.1.3-alpha.2",
81
- "@deepseek-ai/dsh-goal": "^0.1.3-alpha.2",
82
- "@deepseek-ai/dsh-llm": "^0.1.3-alpha.2",
83
- "@deepseek-ai/dsh-llm-retry": "^0.1.3-alpha.2",
84
- "@deepseek-ai/dsh-permission-presets": "^0.1.3-alpha.2",
85
- "@deepseek-ai/dsh-plan-mode": "^0.1.3-alpha.2",
86
- "@deepseek-ai/dsh-session": "^0.1.3-alpha.2",
87
- "@deepseek-ai/dsh-token-meter": "^0.1.3-alpha.2",
88
- "@deepseek-ai/dsh-tool-todo": "^0.1.3-alpha.2",
89
- "@deepseek-ai/dsh-util-crypto": "^0.1.3-alpha.2",
90
- "@deepseek-ai/dsh-workspace": "^0.1.3-alpha.2",
91
- "@deepseek-ai/dsh-util-workspace-path": "^0.1.3-alpha.2",
92
- "@deepseek-ai/dsh-settings": "^0.1.3-alpha.2"
64
+ "@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.1",
65
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.1",
66
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-alpha.1",
67
+ "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.1",
68
+ "@deepseek-ai/dsh-brand": "^0.1.5-alpha.1",
69
+ "@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.1",
70
+ "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
71
+ "@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.1",
72
+ "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-alpha.1",
73
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.1",
74
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.1",
75
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.1",
76
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-alpha.1",
77
+ "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-alpha.1",
78
+ "@deepseek-ai/dsh-commands": "^0.1.5-alpha.1",
79
+ "@deepseek-ai/dsh-goal": "^0.1.5-alpha.1",
80
+ "@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
81
+ "@deepseek-ai/dsh-llm-retry": "^0.1.5-alpha.1",
82
+ "@deepseek-ai/dsh-permission-presets": "^0.1.5-alpha.1",
83
+ "@deepseek-ai/dsh-plan-mode": "^0.1.5-alpha.1",
84
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
85
+ "@deepseek-ai/dsh-tool-todo": "^0.1.5-alpha.1",
86
+ "@deepseek-ai/dsh-util-crypto": "^0.1.5-alpha.1",
87
+ "@deepseek-ai/dsh-workspace": "^0.1.5-alpha.1",
88
+ "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.1",
89
+ "@deepseek-ai/dsh-settings": "^0.1.5-alpha.1",
90
+ "@deepseek-ai/dsh-token-meter": "^0.1.5-alpha.1",
91
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
92
+ "@deepseek-ai/dsh-client-file-upload": "^0.1.5-alpha.1"
93
93
  },
94
94
  "files": [
95
95
  "lib/index.js",