@deepseek-ai/dsh-client-ui-conversation 0.1.7-rc.2 → 0.2.0-rc.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 +4 -4
- package/README.md +4 -0
- package/README.zh.md +4 -0
- package/lib/client.js +89 -25
- package/lib/types/client/apply.d.ts +0 -1
- package/lib/types/client/contract/composer-submission.d.ts +18 -0
- package/lib/types/client/contract/draft-editor.d.ts +1 -1
- package/lib/types/client/contract/input.d.ts +5 -2
- package/lib/types/client/input/facade.d.ts +7 -2
- package/lib/types/client/input/hub.d.ts +0 -9
- package/lib/types/client/input/submission-analytics.d.ts +10 -0
- package/package.json +34 -33
package/README.i18n.yaml
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
en: 0ca51f37788dcbdb
|
|
7
7
|
zh: 14d73c6bc8d4e17f
|
|
8
8
|
/deepseek-ai-dsh-client-ui-conversation:
|
|
9
|
-
en:
|
|
10
|
-
zh:
|
|
9
|
+
en: 77ecbd074ef3a3ce
|
|
10
|
+
zh: 2c0e2b720e3b201e
|
|
11
11
|
/deepseek-ai-dsh-client-ui-conversation/summary:
|
|
12
12
|
en: bac0bf0d7330f3b1
|
|
13
13
|
zh: 84a895f4b26d8490
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
en: 13ae68865fa315d7
|
|
19
19
|
zh: c152f020abf20f35
|
|
20
20
|
/deepseek-ai-dsh-client-ui-conversation/shell-and-standard-props:
|
|
21
|
-
en:
|
|
22
|
-
zh:
|
|
21
|
+
en: 7f1d7a29d2238f3a
|
|
22
|
+
zh: f7a66d2f34a1cd42
|
|
23
23
|
/deepseek-ai-dsh-client-ui-conversation/temporary-composer-entries:
|
|
24
24
|
en: bb1244310f5c0382
|
|
25
25
|
zh: 824b84077432b559
|
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@ kind: "package-reference"
|
|
|
7
7
|
|
|
8
8
|
English | [中文](README.zh.md)
|
|
9
9
|
|
|
10
|
+
Desktop product events use the optional [product analytics service](../product-analytics/README.md); ordinary Web interactions are excluded.
|
|
11
|
+
|
|
10
12
|
## Summary
|
|
11
13
|
|
|
12
14
|
`ui-conversation` owns target-neutral Conversation assembly and the shared browser shell. It consumes Session Controller `SessionEventLikeEntry` feeds, exposes React-free registries and per-Session bindings through `ctx.uiConversation`, and contributes the `useConversation`, `useInput`, and `inputActions` standard props through `ctx.uiSession`. It also owns the per-session durable image URL cache: `ctx.uiConversation.imageUrl(sessionId, attachment)` resolves one session-authorized browser URL per attachment and revokes it with the Session binding, so every Conversation target shares one `session.attachment` read. Concrete targets such as Chat are separate packages that register their own Definitions, snapshot builders, Views, and renderers.
|
|
@@ -74,6 +76,8 @@ The resident composer survives no-Session and Session transitions. Whitespace hi
|
|
|
74
76
|
|
|
75
77
|
Plain Enter uses the configured delivery mode, exactly Ctrl+Enter or Cmd+Enter uses its complement, and Shift+Enter inserts a line break. Enter with Alt, AltGraph, both Ctrl and Cmd, or Shift plus Ctrl/Cmd leaves the draft and command menu unchanged and keeps the DOM event available to application shortcuts. The Conversation plugin registers the fixed send, newline, complementary-delivery, command-menu, and reference-menu rows and reserves their bindings until it unloads.
|
|
76
78
|
|
|
79
|
+
Each composer attempt carries its original occurrence time, gesture, delivery intent, and Session model/run-state snapshot through asynchronous command arbitration. The ordinary-message notification fires once before reference serialization, including attachment-only submissions; handled or claimed commands do not notify. Snapshot and notification failures cannot block sending.
|
|
80
|
+
|
|
77
81
|
Default sends commit optimistically: Enter clears the draft, occurrence table, and undo history in the same transaction, keeps the composer in `plain`, and runs the send as a detached attempt, so typing and further sends continue during the flight. `sendSession` registers a Session submission echo (`session.beginSubmission`) with the delivery mode before serializing, preserving selected image and file order in `pendingSubmissions`; Session derives the placement from that mode and its current running state, so idle sends use the transcript, busy Queue sends use QueueDock, and busy Steer sends use the pending-steering surface. It then yields one paint, encodes images through the browser's native `FileReader` data-URL path, and cites staged file receipts. Command submissions use the same receipts for generic files, so sending `/goal` or `/plan` never reads those browser files again. The prompt reuses the submission `requestId`; Session retires the echo once at its display handoff, correlated by that `rpcId`. Concurrent failures are restored together in submission order until the user edits the restored content; command submissions keep the frozen `submitting` phase. Detached attempts retain their attachment ids through admission and Session scope disposal. An observed retirement immediately exposes each image preview through the durable cache, replaces it with the canonical URL after fetching the admitted attachment, revokes each URL after its use ends, and releases file cards. Selected generic files enter one FIFO background-upload queue; `maxConcurrentFileUploads` defaults to two active Worker transports, the Conversation service retains queued and active operations plus byte progress across Session navigation, and removing a draft skips its queued transfer or aborts its active transport. Where the browser shell exposes `__DSH_HOST_PATHS__` (the Desktop application), dropped or pasted folders and dropped, picked, or pasted non-image files with a real path become `@path` chips; images keep uploading. Drag-and-drop and paste identify directories through the browser entry API; when that API is absent or returns no entry, pasted items retain ordinary file handling. The file picker cannot select directories. References require the `ui-reference` plugin and the original paths to remain readable by the model's file tools. Paths inside the workspace are relative; others remain absolute. The whole batch is validated before insertion, retains source order and selected text, and uses whitespace-separated, closed-quote mentions. A browser without the bridge refuses dropped or pasted folders; a Desktop folder without a reported path is rejected separately. Continuable subagents disable attachment intake and skip local echoes because their transport does not preserve the browser request id.
|
|
78
82
|
|
|
79
83
|
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.
|
package/README.zh.md
CHANGED
|
@@ -7,6 +7,8 @@ kind: "package-reference"
|
|
|
7
7
|
|
|
8
8
|
[English](README.md) | 中文
|
|
9
9
|
|
|
10
|
+
桌面端产品事件使用可选的[产品埋点服务](../product-analytics/README.zh.md),不包含普通 Web 交互。
|
|
11
|
+
|
|
10
12
|
## 概述
|
|
11
13
|
|
|
12
14
|
`ui-conversation` 拥有与 target 无关的 Conversation 组装和共享浏览器 shell。它消费 Session Controller 的 `SessionEventLikeEntry` feed,通过 `ctx.uiConversation` 暴露不依赖 React 的注册表与逐 Session binding,并通过 `ctx.uiSession` 提供 `useConversation`、`useInput` 和 `inputActions` 标准 props。它还拥有按会话的持久化图片 URL 缓存:`ctx.uiConversation.imageUrl(sessionId, attachment)` 为每个附件解析一个经会话授权的浏览器 URL,并随 Session binding 释放而撤销,因此所有 Conversation target 共享一次 `session.attachment` 读取。Chat 等具体 target 位于独立包,由各自包注册 Definition、快照 builder、View 和 renderer。
|
|
@@ -74,6 +76,8 @@ Session 首次绑定或缓存的 Session 成为 current 时,shell 会在渲染
|
|
|
74
76
|
|
|
75
77
|
普通 Enter 使用已配置的投递模式,严格的 Ctrl+Enter 或 Cmd+Enter 使用互补模式,Shift+Enter 插入换行。带 Alt、AltGraph、同时带 Ctrl 与 Cmd,或 Shift 与 Ctrl/Cmd 的 Enter 保持草稿和指令菜单不变,并将 DOM 事件留给应用快捷键。Conversation 插件注册发送、换行、互补投递、命令菜单和引用菜单的固定条目,并在卸载前保留这些键位。
|
|
76
78
|
|
|
79
|
+
每次输入框提交都携带原始发生时间、操作来源、投递意图以及会话模型和运行状态快照,贯穿异步命令裁决。普通消息通知在引用序列化前发出一次,纯附件提交也遵循这一规则;已处理或认领的命令不发出通知。快照读取与通知消费异常不能阻断发送。
|
|
80
|
+
|
|
77
81
|
默认发送采用乐观提交:Enter 在同一事务里清空草稿、occurrence 表和撤销历史,composer 保持 `plain`,发送作为 detached attempt 运行,发送期间可以继续输入和提交。`sendSession` 在序列化之前用投递模式注册 Session 提交回显(`session.beginSubmission`),并在 `pendingSubmissions` 中保留图片与文件的选择顺序;Session 根据该模式与当前运行状态推导位置,因此空闲发送进入 transcript(文本记录),繁忙时 Queue 进入 QueueDock,繁忙时 Steer 进入 pending-steering 区域。随后让出一帧,图片经浏览器原生 `FileReader` data-URL 路径编码,文件则引用已暂存凭证。命令提交也用同一凭证表示通用文件,因此发送 `/goal` 或 `/plan` 时不会再次读取这些浏览器文件。提示词复用提交 `requestId`;Session 按同一 `rpcId` 关联展示接管,并仅退休回显一次。多个并发发送失败时,在用户编辑还原内容之前按提交顺序合并还原;命令提交保持冻结的 `submitting` 阶段。Detached attempt 持有附件 id,直到 admission 完成或 Session scope 销毁。回显以 observed 退休时,durable 图片缓存立即公开每个预览 URL,读取 admitted 附件后用规范化 URL 替换预览,并在各 URL 停止使用后撤销,同时释放文件卡。选中的通用文件进入同一个先进先出的后台上传队列;`maxConcurrentFileUploads` 默认允许两个 Worker transport 同时运行,Conversation 服务在切换 Session 时继续持有排队和运行中的传输操作及字节进度,移除草稿会跳过排队中的传输或中止正在运行的传输。浏览器 shell 暴露 `__DSH_HOST_PATHS__` 时(桌面应用),拖入或粘贴的文件夹以及拖入、选择或粘贴的带真实路径的非图片文件会成为 `@路径` chip;图片仍然上传。拖放和粘贴通过浏览器 entry API 识别目录;该 API 不可用或没有返回 entry 时,粘贴项沿用普通文件处理。文件选择器不能选择目录。引用需要启用 `ui-reference` 插件,原路径也必须仍可由模型的文件工具读取。工作区内的路径使用相对形式,其他路径保留绝对形式。整批文件先校验再插入,保留来源顺序和已选中的文字,引用之间有空白分隔,含空格的路径使用闭合引号。没有该桥的浏览器会拒绝拖入或粘贴的文件夹,桌面端无法获取文件夹路径时单独报错。continuable 子代理禁用附件入口,也不创建本地回显,因为其 transport 不保留浏览器 request id。
|
|
78
82
|
|
|
79
83
|
排队提交的本地回显在禁用的编辑、删除、插话按钮旁显示“发送中…”;折叠后的队列在标题栏保留发送状态。匹配的 Host 队列行替换回显后,各操作按原有的纯文本内容和运行状态要求启用。仅收到提示词确认不会启用队列操作。提交失败会移除回显并显示错误;输入框为空或仍保留上一次自动恢复的内容时,composer 恢复失败草稿,保留用户随后输入的文字。
|
package/lib/client.js
CHANGED
|
@@ -3831,7 +3831,7 @@ window.__ModuleLoader__.load({
|
|
|
3831
3831
|
switch (ev.type) {
|
|
3832
3832
|
case "draft-changed": return this.onDraftChanged(ev.draft);
|
|
3833
3833
|
case "claim": return this.onClaim(ev.claim);
|
|
3834
|
-
case "enter": return this.onEnter(ev.mode, ev.draft);
|
|
3834
|
+
case "enter": return this.onEnter(ev.mode, ev.draft, ev.submission);
|
|
3835
3835
|
case "adjudicated": return this.onAdjudicated(ev.attempt, ev.outcome);
|
|
3836
3836
|
case "adjudication-failed": return this.onAdjudicationFailed(ev.attempt, ev.message);
|
|
3837
3837
|
case "submit-settled": return this.onSubmitSettled(ev);
|
|
@@ -3857,7 +3857,7 @@ window.__ModuleLoader__.load({
|
|
|
3857
3857
|
return [];
|
|
3858
3858
|
}
|
|
3859
3859
|
/** Mint an attempt and controller without assigning its lifecycle owner. */
|
|
3860
|
-
mintAttempt(mode, draft) {
|
|
3860
|
+
mintAttempt(mode, draft, submission) {
|
|
3861
3861
|
const controller = new AbortController();
|
|
3862
3862
|
this.seq += 1;
|
|
3863
3863
|
return {
|
|
@@ -3865,20 +3865,21 @@ window.__ModuleLoader__.load({
|
|
|
3865
3865
|
seq: this.seq,
|
|
3866
3866
|
signal: controller.signal,
|
|
3867
3867
|
draftSnapshot: draft,
|
|
3868
|
-
mode
|
|
3868
|
+
mode,
|
|
3869
|
+
...submission === void 0 ? {} : { submission }
|
|
3869
3870
|
},
|
|
3870
3871
|
controller
|
|
3871
3872
|
};
|
|
3872
3873
|
}
|
|
3873
3874
|
/** Mint the frozen command/adjudication attempt. */
|
|
3874
|
-
beginAttempt(mode, draft) {
|
|
3875
|
-
const flight = this.mintAttempt(mode, draft);
|
|
3875
|
+
beginAttempt(mode, draft, submission) {
|
|
3876
|
+
const flight = this.mintAttempt(mode, draft, submission);
|
|
3876
3877
|
this.inflight = flight;
|
|
3877
3878
|
return flight.attempt;
|
|
3878
3879
|
}
|
|
3879
3880
|
/** Mint an ordinary send that leaves the phase plain. */
|
|
3880
|
-
beginDetached(mode, draft) {
|
|
3881
|
-
const flight = this.mintAttempt(mode, draft);
|
|
3881
|
+
beginDetached(mode, draft, submission) {
|
|
3882
|
+
const flight = this.mintAttempt(mode, draft, submission);
|
|
3882
3883
|
this.detached.set(flight.attempt.seq, flight.controller);
|
|
3883
3884
|
this.claim = void 0;
|
|
3884
3885
|
this.phase = "plain";
|
|
@@ -3896,10 +3897,10 @@ window.__ModuleLoader__.load({
|
|
|
3896
3897
|
retainSuffixOf: attempt.draftSnapshot
|
|
3897
3898
|
}];
|
|
3898
3899
|
}
|
|
3899
|
-
onEnter(mode, draft) {
|
|
3900
|
+
onEnter(mode, draft, submission) {
|
|
3900
3901
|
if (this.phase === "adjudicating" || this.phase === "submitting") return [];
|
|
3901
3902
|
if (this.phase === "claimed" && this.claim !== void 0) {
|
|
3902
|
-
const attempt = this.beginAttempt(mode, draft);
|
|
3903
|
+
const attempt = this.beginAttempt(mode, draft, submission);
|
|
3903
3904
|
this.phase = "submitting";
|
|
3904
3905
|
return [{
|
|
3905
3906
|
type: "begin-submit",
|
|
@@ -3911,7 +3912,7 @@ window.__ModuleLoader__.load({
|
|
|
3911
3912
|
const trimmed = draft.trim();
|
|
3912
3913
|
if (trimmed === "") return [];
|
|
3913
3914
|
if (trimmed.startsWith("/")) {
|
|
3914
|
-
const attempt = this.beginAttempt(mode, draft);
|
|
3915
|
+
const attempt = this.beginAttempt(mode, draft, submission);
|
|
3915
3916
|
this.phase = "adjudicating";
|
|
3916
3917
|
return [{
|
|
3917
3918
|
type: "adjudicate",
|
|
@@ -3919,7 +3920,7 @@ window.__ModuleLoader__.load({
|
|
|
3919
3920
|
draft
|
|
3920
3921
|
}];
|
|
3921
3922
|
}
|
|
3922
|
-
return this.detachedEffects(this.beginDetached(mode, draft));
|
|
3923
|
+
return this.detachedEffects(this.beginDetached(mode, draft, submission));
|
|
3923
3924
|
}
|
|
3924
3925
|
onAdjudicated(attempt, outcome) {
|
|
3925
3926
|
const flight = this.inflight;
|
|
@@ -13622,7 +13623,19 @@ window.__ModuleLoader__.load({
|
|
|
13622
13623
|
* (adjudicating/submitting) force-closes the transient layers: the popup
|
|
13623
13624
|
* dismisses and the menu tracks frozen.
|
|
13624
13625
|
*/
|
|
13625
|
-
submit(mode = "queue") {
|
|
13626
|
+
submit(mode = "queue", source) {
|
|
13627
|
+
if (this.disposed) return;
|
|
13628
|
+
const timestamp = Date.now();
|
|
13629
|
+
let state;
|
|
13630
|
+
if (this.snapshot.phase === "plain" && (this.snapshot.draft.trim() !== "" || this.attachmentIds.length > 0)) try {
|
|
13631
|
+
state = this.deps.submissionState?.();
|
|
13632
|
+
} catch (_error) {}
|
|
13633
|
+
const submission = Object.freeze({
|
|
13634
|
+
timestamp,
|
|
13635
|
+
mode,
|
|
13636
|
+
...source === void 0 ? {} : { source },
|
|
13637
|
+
...state === void 0 ? {} : { state }
|
|
13638
|
+
});
|
|
13626
13639
|
if (this.snapshot.draft.trim() === "" && this.attachmentIds.length > 0) {
|
|
13627
13640
|
if (this.snapshot.phase === "plain") {
|
|
13628
13641
|
const attachmentIds = [...this.attachmentIds];
|
|
@@ -13634,6 +13647,7 @@ window.__ModuleLoader__.load({
|
|
|
13634
13647
|
attachmentIds
|
|
13635
13648
|
});
|
|
13636
13649
|
this.commitSend(attachmentIds);
|
|
13650
|
+
this.notifySubmission(submission);
|
|
13637
13651
|
this.deps.defaultSink("", attachmentIds, mode, controller.signal).then((outcome) => {
|
|
13638
13652
|
if (this.disposed || !this.attachmentFlights.delete(flight)) return;
|
|
13639
13653
|
if (outcome.kind === "success") return;
|
|
@@ -13655,7 +13669,8 @@ window.__ModuleLoader__.load({
|
|
|
13655
13669
|
this.dispatchRun({
|
|
13656
13670
|
type: "enter",
|
|
13657
13671
|
mode,
|
|
13658
|
-
draft: this.projection.clipboardText
|
|
13672
|
+
draft: this.projection.clipboardText,
|
|
13673
|
+
submission
|
|
13659
13674
|
});
|
|
13660
13675
|
const phase = this.snapshot.phase;
|
|
13661
13676
|
if (phase === "adjudicating" || phase === "submitting") {
|
|
@@ -13881,7 +13896,8 @@ window.__ModuleLoader__.load({
|
|
|
13881
13896
|
/** Dispatch + execute, refreshing the claim decoration when the styled token flips. */
|
|
13882
13897
|
dispatchRun(ev) {
|
|
13883
13898
|
const beforeToken = this.activeClaimToken();
|
|
13884
|
-
this.
|
|
13899
|
+
const effects = this.core.dispatch(ev);
|
|
13900
|
+
this.run(effects);
|
|
13885
13901
|
if (this.activeClaimToken() !== beforeToken) this.draftEditor.refreshClaimDecoration();
|
|
13886
13902
|
}
|
|
13887
13903
|
run(effects) {
|
|
@@ -13931,6 +13947,7 @@ window.__ModuleLoader__.load({
|
|
|
13931
13947
|
* its editor snapshot. Chip-free drafts skip the async detour.
|
|
13932
13948
|
*/
|
|
13933
13949
|
sinkSerialized(attempt, draft, mode) {
|
|
13950
|
+
this.notifySubmission(attempt.submission);
|
|
13934
13951
|
const attachmentIds = [...this.attachmentIds];
|
|
13935
13952
|
this.attachmentIds = [];
|
|
13936
13953
|
const occurrences = this.projection.occurrences;
|
|
@@ -13972,6 +13989,12 @@ window.__ModuleLoader__.load({
|
|
|
13972
13989
|
this.settleDetachedFailure(attempt, message);
|
|
13973
13990
|
});
|
|
13974
13991
|
}
|
|
13992
|
+
notifySubmission(submission) {
|
|
13993
|
+
if (submission === void 0) return;
|
|
13994
|
+
try {
|
|
13995
|
+
this.deps.messageSubmitted?.(submission);
|
|
13996
|
+
} catch (_error) {}
|
|
13997
|
+
}
|
|
13975
13998
|
/** Settle one detached default send independently of other sends. */
|
|
13976
13999
|
settleSink(attempt, pending) {
|
|
13977
14000
|
pending.then((outcome) => {
|
|
@@ -14135,6 +14158,27 @@ window.__ModuleLoader__.load({
|
|
|
14135
14158
|
}
|
|
14136
14159
|
};
|
|
14137
14160
|
//#endregion
|
|
14161
|
+
//#region lib/types/client/input/submission-analytics.js
|
|
14162
|
+
/**
|
|
14163
|
+
* Report the original message occurrence without reading newer Session facts.
|
|
14164
|
+
* @param ctx - client context.
|
|
14165
|
+
* @param submission - original occurrence and Session snapshot.
|
|
14166
|
+
*/
|
|
14167
|
+
function reportMessageSubmission(ctx, submission) {
|
|
14168
|
+
const { state, timestamp, mode } = submission;
|
|
14169
|
+
if (state === void 0) return;
|
|
14170
|
+
const model = state.model;
|
|
14171
|
+
ctx.get("productAnalytics")?.track("send_button_click", {
|
|
14172
|
+
...state.sessionId === void 0 ? {} : { session_id: state.sessionId },
|
|
14173
|
+
...model === void 0 ? {} : {
|
|
14174
|
+
model_name: `${model.provider}/${model.name}`,
|
|
14175
|
+
...model.effort === void 0 ? {} : { thinking_effort: model.effort }
|
|
14176
|
+
},
|
|
14177
|
+
run_mode: state.runMode,
|
|
14178
|
+
msg_type: state.running ? mode : "default"
|
|
14179
|
+
}, timestamp);
|
|
14180
|
+
}
|
|
14181
|
+
//#endregion
|
|
14138
14182
|
//#region lib/types/client/input/hub.js
|
|
14139
14183
|
/** Session-addressed input facade registry (SessionInputResolver face + composer-layer extras). */
|
|
14140
14184
|
var InputHub = class {
|
|
@@ -14175,6 +14219,26 @@ window.__ModuleLoader__.load({
|
|
|
14175
14219
|
const { session, ctx: actx } = binding;
|
|
14176
14220
|
const shell = new SessionInputShell({
|
|
14177
14221
|
actx,
|
|
14222
|
+
submissionState: () => {
|
|
14223
|
+
const state = session.getSnapshot();
|
|
14224
|
+
const model = session.projections.faceOf("modelSelection").getSnapshot();
|
|
14225
|
+
const plan = session.projections.faceOf("plan").getSnapshot();
|
|
14226
|
+
const goal = session.projections.faceOf("goal").getSnapshot();
|
|
14227
|
+
const selection = model?.next ?? model?.lastUsed;
|
|
14228
|
+
return Object.freeze({
|
|
14229
|
+
...state.blank ? {} : { sessionId: state.sessionId },
|
|
14230
|
+
...selection == null ? {} : { model: Object.freeze({
|
|
14231
|
+
provider: selection.provider,
|
|
14232
|
+
name: selection.model,
|
|
14233
|
+
...selection.reasoningEffort === void 0 ? {} : { effort: selection.reasoningEffort }
|
|
14234
|
+
}) },
|
|
14235
|
+
runMode: plan?.active ? "plan" : goal?.goal.phase === "active" ? "goal" : "default",
|
|
14236
|
+
running: state.running
|
|
14237
|
+
});
|
|
14238
|
+
},
|
|
14239
|
+
messageSubmitted: (submission) => {
|
|
14240
|
+
reportMessageSubmission(this.rootCtx, submission);
|
|
14241
|
+
},
|
|
14178
14242
|
inputTriggers: () => this.controller(actx),
|
|
14179
14243
|
popup: () => this.popup(actx),
|
|
14180
14244
|
inbox: session.projections.faceOf("inbox"),
|
|
@@ -14549,10 +14613,10 @@ window.__ModuleLoader__.load({
|
|
|
14549
14613
|
"tool.title.searchSessions": "搜索会话",
|
|
14550
14614
|
"tool.title.traceSession": "追踪会话",
|
|
14551
14615
|
"tool.title.listModels": "查看可用模型",
|
|
14552
|
-
"tool.title.subagent": "
|
|
14553
|
-
"tool.title.listAgents": "
|
|
14616
|
+
"tool.title.subagent": "创建子智能体",
|
|
14617
|
+
"tool.title.listAgents": "查看子智能体",
|
|
14554
14618
|
"tool.title.sendMessage": "发送消息",
|
|
14555
|
-
"tool.title.interruptAgent": "
|
|
14619
|
+
"tool.title.interruptAgent": "中断智能体",
|
|
14556
14620
|
"tool.title.listJobs": "查看后台任务",
|
|
14557
14621
|
"tool.title.readJob": "读取任务输出",
|
|
14558
14622
|
"tool.title.killJob": "取消后台任务",
|
|
@@ -14625,14 +14689,14 @@ window.__ModuleLoader__.load({
|
|
|
14625
14689
|
"detail.field.turn": "轮次",
|
|
14626
14690
|
"detail.field.step": "步骤",
|
|
14627
14691
|
"detail.field.callId": "调用 ID",
|
|
14628
|
-
"detail.field.agents": "
|
|
14692
|
+
"detail.field.agents": "启动智能体数",
|
|
14629
14693
|
"detail.field.result": "结果",
|
|
14630
14694
|
"detail.field.parent": "父级",
|
|
14631
14695
|
"detail.field.depth": "层级",
|
|
14632
14696
|
"detail.field.exitCode": "退出码",
|
|
14633
14697
|
"detail.field.signal": "信号",
|
|
14634
14698
|
"detail.field.previousStatus": "中断前状态",
|
|
14635
|
-
"detail.field.agent": "
|
|
14699
|
+
"detail.field.agent": "智能体 ID",
|
|
14636
14700
|
"detail.field.job": "任务 ID",
|
|
14637
14701
|
"detail.field.task": "任务内容",
|
|
14638
14702
|
"detail.field.processGroup": "进程组",
|
|
@@ -14640,7 +14704,7 @@ window.__ModuleLoader__.load({
|
|
|
14640
14704
|
"detail.field.bestMatch": "最相关事件",
|
|
14641
14705
|
"detail.field.target": "目标事件",
|
|
14642
14706
|
"detail.field.surface": "记录状态",
|
|
14643
|
-
"detail.agents.count": "{count}
|
|
14707
|
+
"detail.agents.count": "{count} 个智能体",
|
|
14644
14708
|
"detail.jobs.count": "{count} 个后台任务",
|
|
14645
14709
|
"detail.terminals.count": "{count} 个终端",
|
|
14646
14710
|
"detail.tasks.count": "{count} 个团队任务",
|
|
@@ -14659,15 +14723,15 @@ window.__ModuleLoader__.load({
|
|
|
14659
14723
|
"detail.wait.title": "子智能体状态",
|
|
14660
14724
|
"detail.wait.timeout": "等待超时",
|
|
14661
14725
|
"detail.wait.changed": "检测到变化",
|
|
14662
|
-
"detail.agent.reply": "
|
|
14726
|
+
"detail.agent.reply": "智能体回复",
|
|
14663
14727
|
"detail.models.title": "可用模型",
|
|
14664
14728
|
"detail.output.lines": "第 {begin}–{end} 行,共 {total} 行",
|
|
14665
14729
|
"detail.output.truncated": "输出已截断",
|
|
14666
14730
|
"detail.providers.count": "{count} 个检查提供方",
|
|
14667
14731
|
"detail.plugins.count": "{count} 个动态插件",
|
|
14668
14732
|
"detail.workflow.script": "工作流脚本",
|
|
14669
|
-
"detail.ralph.reportedComplete": "
|
|
14670
|
-
"detail.ralph.reportedBlocker": "
|
|
14733
|
+
"detail.ralph.reportedComplete": "智能体报告完成",
|
|
14734
|
+
"detail.ralph.reportedBlocker": "智能体报告受阻",
|
|
14671
14735
|
"detail.ralph.limit": "已达到轮次上限",
|
|
14672
14736
|
"detail.report.nextSteps": "待完成事项",
|
|
14673
14737
|
"detail.trace.replacedBy": "被替换为",
|
|
@@ -16759,7 +16823,7 @@ window.__ModuleLoader__.load({
|
|
|
16759
16823
|
g.showToast(g.t("file.stillUploading"));
|
|
16760
16824
|
return;
|
|
16761
16825
|
}
|
|
16762
|
-
keyboard.submit(resolveSubmitMode(g.busyEnter, g.running, accelerated ? "accelerated" : "enter", g.steeringAvailable));
|
|
16826
|
+
keyboard.submit(resolveSubmitMode(g.busyEnter, g.running, accelerated ? "accelerated" : "enter", g.steeringAvailable), "enter");
|
|
16763
16827
|
},
|
|
16764
16828
|
intakeFiles: (files, directories) => {
|
|
16765
16829
|
gate.current.intakeFiles(files, directories);
|
|
@@ -17335,7 +17399,7 @@ window.__ModuleLoader__.load({
|
|
|
17335
17399
|
}
|
|
17336
17400
|
if (keyboard === void 0) return;
|
|
17337
17401
|
/* v8 ignore next -- defensive: the primary button is disabled for empty, disabled, and pending-upload states. */
|
|
17338
|
-
if (!empty && !disabled && !machineBusy && !uploadsPending) keyboard.submit(primarySubmitMode);
|
|
17402
|
+
if (!empty && !disabled && !machineBusy && !uploadsPending) keyboard.submit(primarySubmitMode, "click");
|
|
17339
17403
|
};
|
|
17340
17404
|
const claimActive = (input?.phase === "claimed" || input?.phase === "submitting") && input.claim !== void 0 && draft.startsWith(input.claim.token);
|
|
17341
17405
|
const rawHint = claimActive && input.claim.hint !== void 0 && draft.slice(input.claim.token.length).trim() === "" ? input.claim.hint : null;
|
|
@@ -5,4 +5,22 @@ export type { BusyEnterBehavior } from '../../submission-settings.ts';
|
|
|
5
5
|
export type InputSubmitMode = BusyEnterBehavior;
|
|
6
6
|
/** Keyboard gesture whose delivery mode the submission policy resolves. */
|
|
7
7
|
export type ComposerSubmitGesture = 'enter' | 'accelerated';
|
|
8
|
+
/** Session facts captured when a message submission starts, before asynchronous command arbitration. */
|
|
9
|
+
export interface MessageSubmissionState {
|
|
10
|
+
readonly sessionId?: import('@deepseek-ai/dsh-session/types').SessionId;
|
|
11
|
+
readonly model?: {
|
|
12
|
+
readonly provider: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly effort?: string;
|
|
15
|
+
};
|
|
16
|
+
readonly runMode: 'default' | 'plan' | 'goal';
|
|
17
|
+
readonly running: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Immutable occurrence and delivery intent carried by one composer attempt. */
|
|
20
|
+
export interface MessageSubmission {
|
|
21
|
+
readonly timestamp: number;
|
|
22
|
+
readonly source?: 'click' | 'enter';
|
|
23
|
+
readonly mode: InputSubmitMode;
|
|
24
|
+
readonly state?: MessageSubmissionState;
|
|
25
|
+
}
|
|
8
26
|
//# sourceMappingURL=composer-submission.d.ts.map
|
|
@@ -35,7 +35,7 @@ export interface ComposerKeyboard {
|
|
|
35
35
|
/** The shell-owned Lexical editor the composer binds its contenteditable to. */
|
|
36
36
|
readonly editor: LexicalEditor;
|
|
37
37
|
/** Submit with an explicit delivery mode resolved by the submission policy (Enter gestures and the primary Send button). */
|
|
38
|
-
submit(mode: InputSubmitMode): void;
|
|
38
|
+
submit(mode: InputSubmitMode, source?: 'click' | 'enter'): void;
|
|
39
39
|
/**
|
|
40
40
|
* Steer every still-pending queued message into the running turn (the
|
|
41
41
|
* empty-draft accelerated-Enter gesture; the queue dock's per-row steer
|
|
@@ -11,7 +11,7 @@ import type { InboxState } from '@deepseek-ai/dsh-agent/types';
|
|
|
11
11
|
import type { ObservableSnapshot, SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
12
12
|
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
13
13
|
import type { ArbitrateKey, ArbitrateOutcome, Occurrence, ReferenceInsert, TokenSpan } from './draft-editor.ts';
|
|
14
|
-
import type { InputSubmitMode } from './composer-submission.ts';
|
|
14
|
+
import type { InputSubmitMode, MessageSubmission } from './composer-submission.ts';
|
|
15
15
|
/** Attachment payload passed to a claimed command submission. */
|
|
16
16
|
export type SubmitAttachment = {
|
|
17
17
|
readonly type: 'image';
|
|
@@ -173,7 +173,7 @@ export interface SessionInput extends InputTarget {
|
|
|
173
173
|
* THE complexity sink: enter adjudication, submit transaction, and the default sink live inside.
|
|
174
174
|
* @param mode - delivery intent retained through asynchronous adjudication and serialization.
|
|
175
175
|
*/
|
|
176
|
-
submit(mode?: InputSubmitMode): void;
|
|
176
|
+
submit(mode?: InputSubmitMode, source?: 'click' | 'enter'): void;
|
|
177
177
|
/**
|
|
178
178
|
* Surface a notice outside the machine's own effect stream: detached
|
|
179
179
|
* command results and business notifications render through here.
|
|
@@ -268,6 +268,8 @@ export interface SubmitAttempt {
|
|
|
268
268
|
readonly draftSnapshot: string;
|
|
269
269
|
/** Default-message delivery intent retained while slash adjudication is pending. */
|
|
270
270
|
readonly mode: InputSubmitMode;
|
|
271
|
+
/** Original message occurrence, retained across command arbitration. */
|
|
272
|
+
readonly submission?: MessageSubmission;
|
|
271
273
|
}
|
|
272
274
|
/**
|
|
273
275
|
* Submit-machine input events (the machine's single write path). Text
|
|
@@ -290,6 +292,7 @@ export type InputEvent =
|
|
|
290
292
|
readonly type: 'enter';
|
|
291
293
|
readonly mode: InputSubmitMode;
|
|
292
294
|
readonly draft: string;
|
|
295
|
+
readonly submission?: MessageSubmission;
|
|
293
296
|
} | {
|
|
294
297
|
readonly type: 'adjudicated';
|
|
295
298
|
readonly attempt: SubmitAttempt;
|
|
@@ -14,7 +14,7 @@ import { type ObservableSnapshot, type SnapshotStore } from '@deepseek-ai/dsh-cl
|
|
|
14
14
|
import type { LexicalEditor } from 'lexical';
|
|
15
15
|
import type { CommandClaim, ConsumeTokenRequest, DraftAttachmentId, InputActions, InputNotice, InputState, InputTriggerController, SessionInput, SubmitAttachment, SubmitOutcome } from '../contract/input.ts';
|
|
16
16
|
import type { ArbitrateKey, ArbitrateOutcome, ComposerKeyboard, ReferenceInsert, TokenSpan } from '../contract/draft-editor.ts';
|
|
17
|
-
import type { InputSubmitMode } from '../contract/composer-submission.ts';
|
|
17
|
+
import type { InputSubmitMode, MessageSubmission, MessageSubmissionState } from '../contract/composer-submission.ts';
|
|
18
18
|
/** Popup face the shell needs (dismissal only; typed structurally to avoid a value import). */
|
|
19
19
|
export interface PopupDismissFace {
|
|
20
20
|
dismiss(): void;
|
|
@@ -28,6 +28,10 @@ export interface PopupDismissFace {
|
|
|
28
28
|
export interface SessionInputDeps {
|
|
29
29
|
/** Session-scope ctx handed to claim.submit transactions. */
|
|
30
30
|
actx: Context;
|
|
31
|
+
/** Snapshot the Session facts before asynchronous command arbitration. */
|
|
32
|
+
submissionState?: () => MessageSubmissionState;
|
|
33
|
+
/** Notify one ordinary message attempt before reference serialization. */
|
|
34
|
+
messageSubmitted?: (submission: MessageSubmission) => void;
|
|
31
35
|
/** Enter adjudication face resolver; absent/undefined answer = every '/' line falls to the default sink. */
|
|
32
36
|
inputTriggers?: (() => InputTriggerController | undefined) | undefined;
|
|
33
37
|
/** PopupSelect shell face resolver (dismissal on submit lock / escape). */
|
|
@@ -141,7 +145,7 @@ export declare class SessionInputShell implements SessionInput {
|
|
|
141
145
|
* (adjudicating/submitting) force-closes the transient layers: the popup
|
|
142
146
|
* dismisses and the menu tracks frozen.
|
|
143
147
|
*/
|
|
144
|
-
submit(mode?: InputSubmitMode): void;
|
|
148
|
+
submit(mode?: InputSubmitMode, source?: 'click' | 'enter'): void;
|
|
145
149
|
/**
|
|
146
150
|
* Keyboard arbitration while the menu is open.
|
|
147
151
|
* @param key - the intercepted key.
|
|
@@ -284,6 +288,7 @@ export declare class SessionInputShell implements SessionInput {
|
|
|
284
288
|
* its editor snapshot. Chip-free drafts skip the async detour.
|
|
285
289
|
*/
|
|
286
290
|
private sinkSerialized;
|
|
291
|
+
private notifySubmission;
|
|
287
292
|
/** Settle one detached default send independently of other sends. */
|
|
288
293
|
private settleSink;
|
|
289
294
|
/** Restore one failed detached send without overwriting text entered after a restoration. */
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* InputHub: the SessionInputResolver implementation (`ctx.conversation.input`) — one
|
|
3
|
-
* SessionInputShell per session, created inside the uiSession provide
|
|
4
|
-
* materialization (the 'input' standard-kit entry IS the
|
|
5
|
-
* creation trigger) and torn down by the scope disposer (instance-and-scope
|
|
6
|
-
* share one lifecycle). The hub registers the scoped input-mutation
|
|
7
|
-
* listeners on each Session context and owns the default-sink choreography: every session is a
|
|
8
|
-
* real host entity, so the sink is one unconditional prompt path.
|
|
9
|
-
*/
|
|
10
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
11
2
|
import type { SessionBinding } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
12
3
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Maps ordinary message occurrences to Desktop product events. */
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { MessageSubmission } from '../contract/composer-submission.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Report the original message occurrence without reading newer Session facts.
|
|
6
|
+
* @param ctx - client context.
|
|
7
|
+
* @param submission - original occurrence and Session snapshot.
|
|
8
|
+
*/
|
|
9
|
+
export declare function reportMessageSubmission(ctx: Context, submission: MessageSubmission): void;
|
|
10
|
+
//# sourceMappingURL=submission-analytics.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.
|
|
4
|
+
"version": "0.2.0-rc.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -61,38 +61,39 @@
|
|
|
61
61
|
"@lexical/plain-text": "^0.49.0",
|
|
62
62
|
"@lexical/history": "^0.49.0",
|
|
63
63
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
64
|
-
"@deepseek-ai/dsh-api-remotes": "0.
|
|
65
|
-
"@deepseek-ai/dsh-api-session-controller": "0.
|
|
66
|
-
"@deepseek-ai/dsh-api-workspace-controller": "0.
|
|
67
|
-
"@deepseek-ai/dsh-attachment": "0.
|
|
68
|
-
"@deepseek-ai/dsh-
|
|
69
|
-
"@deepseek-ai/dsh-client-
|
|
70
|
-
"@deepseek-ai/dsh-client-
|
|
71
|
-
"@deepseek-ai/dsh-client-
|
|
72
|
-
"@deepseek-ai/dsh-client-
|
|
73
|
-
"@deepseek-ai/dsh-client-ui-
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-
|
|
75
|
-
"@deepseek-ai/dsh-client-ui-
|
|
76
|
-
"@deepseek-ai/dsh-
|
|
77
|
-
"@deepseek-ai/dsh-client-ui-
|
|
78
|
-
"@deepseek-ai/dsh-
|
|
79
|
-
"@deepseek-ai/dsh-client-
|
|
80
|
-
"@deepseek-ai/dsh-
|
|
81
|
-
"@deepseek-ai/dsh-
|
|
82
|
-
"@deepseek-ai/dsh-llm-retry": "0.
|
|
83
|
-
"@deepseek-ai/dsh-
|
|
84
|
-
"@deepseek-ai/dsh-
|
|
85
|
-
"@deepseek-ai/dsh-
|
|
86
|
-
"@deepseek-ai/dsh-
|
|
87
|
-
"@deepseek-ai/dsh-
|
|
88
|
-
"@deepseek-ai/dsh-
|
|
89
|
-
"@deepseek-ai/dsh-
|
|
90
|
-
"@deepseek-ai/dsh-
|
|
91
|
-
"@deepseek-ai/dsh-
|
|
92
|
-
"@deepseek-ai/dsh-
|
|
93
|
-
"@deepseek-ai/dsh-
|
|
94
|
-
"@deepseek-ai/dsh-
|
|
95
|
-
"@deepseek-ai/dsh-client-
|
|
64
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.0-rc.1",
|
|
65
|
+
"@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.1",
|
|
66
|
+
"@deepseek-ai/dsh-api-workspace-controller": "0.2.0-rc.1",
|
|
67
|
+
"@deepseek-ai/dsh-attachment": "0.2.0-rc.1",
|
|
68
|
+
"@deepseek-ai/dsh-client-file-upload": "0.2.0-rc.1",
|
|
69
|
+
"@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.2.0-rc.1",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.1",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.1",
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-workspace": "0.2.0-rc.1",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
|
|
76
|
+
"@deepseek-ai/dsh-brand": "0.2.0-rc.1",
|
|
77
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
|
|
78
|
+
"@deepseek-ai/dsh-commands": "0.2.0-rc.1",
|
|
79
|
+
"@deepseek-ai/dsh-client-test-runtime": "0.2.0-rc.1",
|
|
80
|
+
"@deepseek-ai/dsh-goal": "0.2.0-rc.1",
|
|
81
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.1",
|
|
82
|
+
"@deepseek-ai/dsh-llm-retry": "0.2.0-rc.1",
|
|
83
|
+
"@deepseek-ai/dsh-plan-mode": "0.2.0-rc.1",
|
|
84
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.1",
|
|
85
|
+
"@deepseek-ai/dsh-util-values": "0.2.0-rc.1",
|
|
86
|
+
"@deepseek-ai/dsh-token-meter": "0.2.0-rc.1",
|
|
87
|
+
"@deepseek-ai/dsh-tool-todo": "0.2.0-rc.1",
|
|
88
|
+
"@deepseek-ai/dsh-util-crypto": "0.2.0-rc.1",
|
|
89
|
+
"@deepseek-ai/dsh-workspace": "0.2.0-rc.1",
|
|
90
|
+
"@deepseek-ai/dsh-file-reference": "0.2.0-rc.1",
|
|
91
|
+
"@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.1",
|
|
92
|
+
"@deepseek-ai/dsh-agent": "0.2.0-rc.1",
|
|
93
|
+
"@deepseek-ai/dsh-settings": "0.2.0-rc.1",
|
|
94
|
+
"@deepseek-ai/dsh-client-shortcuts": "0.2.0-rc.1",
|
|
95
|
+
"@deepseek-ai/dsh-client-product-analytics": "0.2.0-rc.1",
|
|
96
|
+
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.1"
|
|
96
97
|
},
|
|
97
98
|
"files": [
|
|
98
99
|
"lib/index.js",
|