@ahggg/dsh-side-chat 0.7.3 → 1.0.0
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.md +15 -12
- package/README.zh-CN.md +15 -12
- package/lib/client/apply.js +48 -32
- package/lib/client/contracts.d.ts +3 -58
- package/lib/client/dsh/ReadOnlyConversation.d.ts +10 -0
- package/lib/client/dsh/ReadOnlyConversation.js +91 -0
- package/lib/client/dsh/SideChatOverlay.d.ts +7 -0
- package/lib/client/{rc6/Rc6SideChatOverlay.js → dsh/SideChatOverlay.js} +26 -56
- package/lib/client/{rc6 → dsh}/context.d.ts +4 -6
- package/lib/client/dsh/conversation-store.d.ts +22 -0
- package/lib/client/dsh/conversation-store.js +19 -0
- package/lib/client/dsh/primitive-labels.d.ts +2 -0
- package/lib/client/dsh/primitive-labels.js +4 -0
- package/lib/client/{rc6 → dsh}/remote-adapter.d.ts +2 -2
- package/lib/client/dsh/remote-adapter.js +22 -0
- package/lib/client/dsh/sessions-adapter.d.ts +56 -0
- package/lib/client/dsh/sessions-adapter.js +185 -0
- package/lib/client/index.d.ts +2 -2
- package/lib/client/panel/SelectionQuote.js +8 -1
- package/lib/client/panel/SideChatErrorState.js +1 -1
- package/lib/client/panel/SideChatModelSelect.js +37 -18
- package/lib/client/panel/SideChatPanel.js +12 -5
- package/lib/client/panel/messages.d.ts +1 -1
- package/lib/client/panel/messages.js +8 -8
- package/lib/client/parent-composer/ParentConversationAnnotations.d.ts +3 -2
- package/lib/client/parent-composer/ParentConversationAnnotations.js +50 -30
- package/lib/client/parent-composer/add-to-conversation.d.ts +14 -28
- package/lib/client/parent-composer/add-to-conversation.js +131 -545
- package/lib/client/parent-composer/annotation-persistence.d.ts +8 -8
- package/lib/client/parent-composer/annotation-persistence.js +106 -102
- package/lib/client/parent-composer/composer-reference.d.ts +17 -55
- package/lib/client/parent-composer/composer-reference.js +20 -72
- package/lib/client/parent-composer/referenced-conversation.d.ts +5 -7
- package/lib/client/parent-composer/referenced-conversation.js +21 -73
- package/lib/client/selection/ConversationAnnotationMarkers.js +5 -1
- package/lib/client/selection/SelectionActions.js +2 -1
- package/lib/client/selection/conversation-dom.d.ts +5 -0
- package/lib/client/selection/conversation-dom.js +24 -0
- package/lib/client/selection/selection-controller.d.ts +1 -1
- package/lib/client/selection/selection-controller.js +7 -3
- package/lib/client/selection/selection-normalizer.js +1 -1
- package/lib/client/side-chat-controller.d.ts +28 -41
- package/lib/client/side-chat-controller.js +245 -337
- package/lib/client.js +81 -52
- package/lib/host/index.d.ts +1 -1
- package/lib/host/index.js +1 -1
- package/lib/host/read-only-chat-service.d.ts +30 -0
- package/lib/host/read-only-chat-service.js +314 -0
- package/lib/index.d.ts +16 -8
- package/lib/index.js +34 -13
- package/lib/remote.d.ts +23 -14
- package/lib/remote.js +2 -5
- package/lib/shared/constants.d.ts +0 -13
- package/lib/shared/constants.js +0 -13
- package/lib/shared/contracts.d.ts +52 -19
- package/lib/shared/contracts.js +2 -3
- package/lib/shared/error-codes.d.ts +1 -1
- package/lib/shared/error-codes.js +2 -2
- package/lib/shared/{archived-wire.d.ts → side-chat-wire.d.ts} +109 -20
- package/lib/shared/side-chat-wire.js +34 -0
- package/lib/typert.d.ts +3 -68
- package/lib/typert.js +60 -4
- package/package.json +76 -56
- package/lib/client/rc6/ArchivedConversation.d.ts +0 -14
- package/lib/client/rc6/ArchivedConversation.js +0 -231
- package/lib/client/rc6/Rc6SideChatOverlay.d.ts +0 -7
- package/lib/client/rc6/SideChatTool.d.ts +0 -22
- package/lib/client/rc6/SideChatTool.js +0 -404
- package/lib/client/rc6/primitive-labels.d.ts +0 -7
- package/lib/client/rc6/primitive-labels.js +0 -60
- package/lib/client/rc6/remote-adapter.js +0 -34
- package/lib/client/rc6/runtime-compat.d.ts +0 -120
- package/lib/client/rc6/runtime-compat.js +0 -187
- package/lib/client/rc6/sessions-adapter.d.ts +0 -64
- package/lib/client/rc6/sessions-adapter.js +0 -387
- package/lib/host/archived-fork-service.d.ts +0 -28
- package/lib/host/archived-fork-service.js +0 -309
- package/lib/shared/archived-wire.js +0 -47
- /package/lib/client/{rc6 → dsh}/context.js +0 -0
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@ Ask a focused follow-up about selected text without leaving your current DeepSee
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
Install DSH 0.
|
|
11
|
+
Install DSH 0.2.0-rc.1 if it is not already available. This release is on npm's `next` tag, not `latest`. Refresh only this package's registry metadata before adding it, so pnpm cannot reuse an older `latest` value immediately after a release:
|
|
12
12
|
|
|
13
13
|
```powershell
|
|
14
|
-
npm install --global @deepseek-ai/dsh@0.
|
|
14
|
+
npm install --global @deepseek-ai/dsh@0.2.0-rc.1
|
|
15
15
|
pnpm cache delete "@ahggg/dsh-side-chat"
|
|
16
16
|
dsh plugin --profile web add @ahggg/dsh-side-chat@latest
|
|
17
17
|
```
|
|
@@ -43,7 +43,7 @@ On phones and tablets, long-press text in a completed message to select it. The
|
|
|
43
43
|
3. Click `Add to chat` to add an optional comment before attaching the passage to the main composer, `More details` to send an explanation request immediately, or `Ask in side chat` to write a focused question.
|
|
44
44
|
4. When writing your own message or question, press `Enter` to send it.
|
|
45
45
|
5. After a Side Chat reply settles, click `Add to conversation` to attach that focused discussion to the main composer as one conversation reference.
|
|
46
|
-
6.
|
|
46
|
+
6. Click `×`, or press `Esc` while focused inside the Side Chat panel, when you are done. Escape in another composer or menu does not close Side Chat.
|
|
47
47
|
|
|
48
48
|
Useful details:
|
|
49
49
|
|
|
@@ -53,27 +53,30 @@ Useful details:
|
|
|
53
53
|
- `Add to chat` keeps any existing draft text and can collect multiple numbered passages, each with its own optional comment, in one annotation capsule.
|
|
54
54
|
- `Add to conversation` captures the Side Chat's user/assistant history, preserves the main draft, and refreshes the existing reference instead of duplicating it when clicked again.
|
|
55
55
|
- The input grows with its content and becomes scrollable at its maximum height.
|
|
56
|
-
- While a reply is running,
|
|
56
|
+
- While a reply is running, use Stop to interrupt it; send a follow-up after it finishes or stops. Text entered while a send is pending stays in the composer.
|
|
57
57
|
- Assistant replies use DSH's native Markdown rendering.
|
|
58
58
|
- Hover over `N annotations` to preview every selected passage and its comment.
|
|
59
59
|
- Before sending, hover over the annotation capsule and click `×` to remove it; after sending, the same capsule appears above the user message.
|
|
60
|
-
-
|
|
60
|
+
- Your first Side Chat message displays the selected passage as one annotation and your question as plain text, not internal XML.
|
|
61
|
+
- The main conversation stays visible. No child Session is created.
|
|
61
62
|
|
|
62
63
|
## What happens to the conversation
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
`Ask in side chat` and `More details` use direct, streaming model calls through DSH's configured provider. On the first send, the plugin captures a **read-only text snapshot** of the parent conversation through the selected message's completed turn. Later parent prompts are excluded, and this context stays fixed for follow-ups. Opening the draft alone makes no model call.
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
Side Chat keeps its own temporary message history in memory. It does **not** fork, copy, create, or archive a DSH Session, run an Agent, or write a Session event log. It has **no tools, command execution, or file-editing capability**. Parent reasoning and image/file attachment bytes are omitted; historical tool text is only reference material. The initial model uses the saved Side Chat choice, or the selected parent turn's configuration. Changing it affects only subsequent Side Chat replies.
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
Closing the panel, reloading/disconnecting the client, or unloading the plugin cancels active work and discards the temporary discussion. Host records also expire after 30 minutes idle. To keep a discussion, use **Add to conversation**, then **send the parent draft** to store the reference in the parent history. Adding a reference alone does not send it. References already added to the parent draft are separate from the temporary panel and survive its closure.
|
|
70
|
+
|
|
71
|
+
The text snapshot and Side Chat history are sent to the model on each request, so normal provider token usage still applies; avoiding Session copies does not eliminate context tokens or guarantee cache reuse. Archived Sessions created by older plugin versions are not automatically deleted.
|
|
69
72
|
|
|
70
73
|
## Current limitations
|
|
71
74
|
|
|
72
75
|
- A selection must stay inside one completed message.
|
|
73
|
-
- Attachments and `/side` are not supported
|
|
74
|
-
- Closed
|
|
75
|
-
-
|
|
76
|
-
-
|
|
76
|
+
- This is a text-only, read-only discussion, not a second Agent. Attachments, tools, Steer, and `/side` are not supported.
|
|
77
|
+
- Closed or expired discussions cannot be reopened. There is no “keep as normal Session” action.
|
|
78
|
+
- Context is limited to 2,097,152 characters and rejected rather than silently truncated. Each question is limited to 65,536 characters; each reply (including reasoning) to 262,144 characters. A discussion permits at most 64 questions and 2,097,152 question/reply/reasoning characters. Output limits produce an explicit error and keep only the displayed partial reply.
|
|
79
|
+
- Model requests time out after two minutes. Provider-specific context/output limits may be lower.
|
|
77
80
|
|
|
78
81
|
## Upgrade or remove
|
|
79
82
|
|
package/README.zh-CN.md
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
|
11
|
-
如果尚未安装 DSH 0.
|
|
11
|
+
如果尚未安装 DSH 0.2.0-rc.1,先安装它。该版本对应 npm 的 `next` 标签,而非 `latest`。添加插件前只刷新这个包的 registry metadata,避免刚发布新版本时 pnpm 仍复用旧的 `latest`:
|
|
12
12
|
|
|
13
13
|
```powershell
|
|
14
|
-
npm install --global @deepseek-ai/dsh@0.
|
|
14
|
+
npm install --global @deepseek-ai/dsh@0.2.0-rc.1
|
|
15
15
|
pnpm cache delete "@ahggg/dsh-side-chat"
|
|
16
16
|
dsh plugin --profile web add @ahggg/dsh-side-chat@latest
|
|
17
17
|
```
|
|
@@ -43,7 +43,7 @@ pnpm build
|
|
|
43
43
|
3. 点击 `Add to chat` 可以先填写一条可选批注,再把引用加入主会话输入框;点击 `More details` 可以立即发送详细解释请求;点击 `Ask in side chat` 可以自己输入聚焦问题。
|
|
44
44
|
4. 自己输入消息或问题时,按 `Enter` 发送。
|
|
45
45
|
5. Side Chat 回复完成后,点击 `Add to conversation`,即可把这段聚焦讨论作为一个会话引用加入主会话输入框。
|
|
46
|
-
6.
|
|
46
|
+
6. 完成后点击 `×` 关闭,或者在 Side Chat 面板内聚焦时按 `Esc`。在其他输入框或菜单中按 Escape 不会关闭 Side Chat。
|
|
47
47
|
|
|
48
48
|
常用操作:
|
|
49
49
|
|
|
@@ -53,27 +53,30 @@ pnpm build
|
|
|
53
53
|
- `Add to chat` 会保留输入框中已有的草稿,并可把多段带序号的文本及各自的可选批注汇总到同一个 annotation 胶囊中。
|
|
54
54
|
- `Add to conversation` 会捕获 Side Chat 中的用户/助手历史、保留主会话草稿;再次点击时会刷新已有引用,而不是重复添加。
|
|
55
55
|
- 输入框会随内容自动增高,达到最大高度后在内部滚动。
|
|
56
|
-
-
|
|
56
|
+
- 回复生成期间,可使用 Stop 中断;等回复结束或停止后再发送追问。等待发送结果时新输入的文字会保留在输入框中。
|
|
57
57
|
- Assistant 回复使用 DSH 原生 Markdown 渲染。
|
|
58
58
|
- hover `N annotations` 可以预览每一段所选文本及对应批注。
|
|
59
59
|
- 发送前可以 hover annotation 胶囊并点击 `×` 移除;发送后,同一个胶囊会显示在用户消息上方。
|
|
60
|
-
-
|
|
60
|
+
- Side Chat 的首条消息会把选区显示为一个 annotation,问题正文保持纯文本,不显示内部 XML。
|
|
61
|
+
- 主会话会一直保留在页面中,插件不会创建 child Session。
|
|
61
62
|
|
|
62
63
|
## 会话和数据如何处理
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
`Ask in side chat` 和 `More details` 直接通过 DSH 配置的 provider 发起流式模型调用。第一次发送时,插件读取主会话截至所选消息所在轮次结束的**只读文本快照**,不包含后续主会话问题。此后追问一直使用这份固定上下文。仅打开草稿不会调用模型。
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
Side Chat 只在内存中保留独立的临时讨论历史,**不会 fork、复制、创建或归档 DSH Session,也不会启动 Agent 或写入 Session 事件日志**。它**没有工具调用、命令执行和文件修改能力**。主会话的推理内容以及图片、文件附件的字节不会传入;过去的工具文本仅作为参考资料。初始模型优先使用已保存的 Side Chat 选择,否则使用所选父会话轮次的配置;之后切换模型只影响 Side Chat 的后续回复。
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
关闭面板、刷新或断开客户端、卸载插件时,会取消正在运行的请求并丢弃临时讨论。Host 记录闲置 30 分钟后也会过期。如果希望保留讨论,请点击 **Add to conversation**,然后**发送主会话草稿**,将引用存入主会话历史。只添加引用不会自动发送;已经添加到主会话草稿的引用独立于临时面板,不会随面板关闭而删除。
|
|
70
|
+
|
|
71
|
+
每次调用模型仍会发送文本快照和 Side Chat 历史,因此仍产生正常的 provider token 用量;不复制 Session 不代表不消耗上下文 token,也不保证缓存复用。旧版插件创建的归档 Session 不会自动删除。
|
|
69
72
|
|
|
70
73
|
## 当前限制
|
|
71
74
|
|
|
72
75
|
- 选区必须位于同一条已完成消息内。
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
76
|
+
- 这是纯文本只读讨论,不是另一个 Agent;不支持附件、工具、Steer 和 `/side`。
|
|
77
|
+
- 关闭或过期后不能重新打开,也没有“保留为普通 Session”操作。
|
|
78
|
+
- 父上下文上限为 2,097,152 个字符,超过时明确拒绝而不会静默截断。每条问题上限为 65,536 个字符,每次回复(含推理)上限为 262,144 个字符;每次讨论最多 64 条问题,问题、回复和推理合计最多 2,097,152 个字符。达到输出上限会明确报错,仅保留已经显示的部分回复。
|
|
79
|
+
- 单次模型请求两分钟后超时;provider 自身的上下文或输出限制可能更低。
|
|
77
80
|
|
|
78
81
|
## 升级或卸载
|
|
79
82
|
|
package/lib/client/apply.js
CHANGED
|
@@ -4,40 +4,56 @@ import { selectionReferenceSource } from './parent-composer/add-to-conversation.
|
|
|
4
4
|
import { mountParentConversationAnnotations } from './parent-composer/ParentConversationAnnotations.js';
|
|
5
5
|
import { sideChatConversationReferenceSource } from './parent-composer/referenced-conversation.js';
|
|
6
6
|
import { SideChatController } from './side-chat-controller.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { mountSideChatRemote } from './dsh/remote-adapter.js';
|
|
8
|
+
import { SideChatOverlay } from './dsh/SideChatOverlay.js';
|
|
9
|
+
import { DshSideChatSessions } from './dsh/sessions-adapter.js';
|
|
10
10
|
export const name = 'side-chat-client';
|
|
11
|
-
export const inject = ['conversation', 'inputTriggers', 'modelDirectories', 'remote', 'sessions', 'slots'];
|
|
11
|
+
export const inject = ['conversation', 'inputTriggers', 'modelDirectories', 'remote', 'sessions', 'slots', 'uiConversation', 'uiWorkspace'];
|
|
12
12
|
export async function apply(ctx) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
ctx.effect(() =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
13
|
+
const cleanups = [];
|
|
14
|
+
let disposed = false;
|
|
15
|
+
let cleanupOperation;
|
|
16
|
+
const cleanup = () => {
|
|
17
|
+
disposed = true;
|
|
18
|
+
cleanupOperation ??= (async () => {
|
|
19
|
+
for (const dispose of cleanups.splice(0).reverse()) {
|
|
20
|
+
try {
|
|
21
|
+
await dispose();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.warn('[dsh-side-chat] Cleanup failed', error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
return cleanupOperation;
|
|
29
|
+
};
|
|
30
|
+
ctx.effect(() => cleanup, 'dsh-side-chat.clientLifecycle');
|
|
31
|
+
try {
|
|
32
|
+
const stylesheet = document.createElement('style');
|
|
33
|
+
stylesheet.textContent = sideChatCss;
|
|
34
|
+
stylesheet.dataset.plugin = 'dsh-side-chat';
|
|
35
|
+
stylesheet.dataset['dshSideChat'] = 'styles';
|
|
36
|
+
document.head.append(stylesheet);
|
|
37
|
+
cleanups.push(() => { stylesheet.remove(); });
|
|
38
|
+
const clientCtx = ctx;
|
|
39
|
+
const mounted = await mountSideChatRemote(clientCtx);
|
|
40
|
+
if (disposed) {
|
|
39
41
|
await mounted.dispose();
|
|
40
|
-
|
|
42
|
+
return;
|
|
41
43
|
}
|
|
42
|
-
|
|
44
|
+
cleanups.push(mounted.dispose);
|
|
45
|
+
cleanups.push(clientCtx.inputTriggers.registerSource(selectionReferenceSource));
|
|
46
|
+
cleanups.push(clientCtx.inputTriggers.registerSource(sideChatConversationReferenceSource));
|
|
47
|
+
const sessions = new DshSideChatSessions(clientCtx);
|
|
48
|
+
cleanups.push(mountParentConversationAnnotations(clientCtx, sessionId => { sessions.removeConversationAnnotations(sessionId); }));
|
|
49
|
+
const controller = new SideChatController(mounted.remote, sessions);
|
|
50
|
+
cleanups.push(() => controller.dispose());
|
|
51
|
+
cleanups.push(clientCtx.slots.inject('shell.overlay', () => clientCtx.slots.register({
|
|
52
|
+
name: 'shell.overlay', id: 'dsh-side-chat', order: 90,
|
|
53
|
+
}, () => createElement(SideChatOverlay, { controller, sessions }))));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
await cleanup();
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
43
59
|
}
|
|
@@ -1,67 +1,12 @@
|
|
|
1
|
-
import type { ConversationSelection, SessionId, SideChatModelSelection,
|
|
2
|
-
|
|
3
|
-
export interface SideChatSessionSnapshot {
|
|
4
|
-
readonly status: 'idle' | 'running' | 'needs-input' | 'needs-approval' | 'failed' | 'interrupted';
|
|
5
|
-
}
|
|
6
|
-
export interface SideChatQuestionAnswer {
|
|
7
|
-
readonly answers: readonly {
|
|
8
|
-
readonly id: string;
|
|
9
|
-
readonly selected: readonly string[];
|
|
10
|
-
readonly custom?: string;
|
|
11
|
-
}[];
|
|
12
|
-
}
|
|
13
|
-
export interface SideChatSessionBinding extends HostObservable<SideChatSessionSnapshot> {
|
|
14
|
-
readonly sessionId: SessionId;
|
|
15
|
-
prompt(content: readonly SideChatPromptPart[], mode: 'queue' | 'steer'): Promise<{
|
|
16
|
-
readonly ok: true;
|
|
17
|
-
} | {
|
|
18
|
-
readonly ok: false;
|
|
19
|
-
readonly error: SideChatWireError;
|
|
20
|
-
}>;
|
|
21
|
-
updateQueue(itemId: string, action: {
|
|
22
|
-
readonly kind: 'edit';
|
|
23
|
-
readonly content: readonly SideChatPromptPart[];
|
|
24
|
-
} | {
|
|
25
|
-
readonly kind: 'remove';
|
|
26
|
-
} | {
|
|
27
|
-
readonly kind: 'steer';
|
|
28
|
-
}): Promise<{
|
|
29
|
-
readonly ok: true;
|
|
30
|
-
} | {
|
|
31
|
-
readonly ok: false;
|
|
32
|
-
readonly error: SideChatWireError;
|
|
33
|
-
}>;
|
|
34
|
-
cancel(): Promise<{
|
|
35
|
-
readonly ok: true;
|
|
36
|
-
} | {
|
|
37
|
-
readonly ok: false;
|
|
38
|
-
readonly error: SideChatWireError;
|
|
39
|
-
}>;
|
|
40
|
-
respondApproval(interactionId: string, decision: 'approve' | 'decline'): Promise<{
|
|
41
|
-
readonly ok: true;
|
|
42
|
-
} | {
|
|
43
|
-
readonly ok: false;
|
|
44
|
-
readonly error: SideChatWireError;
|
|
45
|
-
}>;
|
|
46
|
-
respondQuestion(interactionId: string, answer: SideChatQuestionAnswer | null): Promise<{
|
|
47
|
-
readonly ok: true;
|
|
48
|
-
} | {
|
|
49
|
-
readonly ok: false;
|
|
50
|
-
readonly error: SideChatWireError;
|
|
51
|
-
}>;
|
|
52
|
-
}
|
|
53
|
-
export interface SideChatSessionLease {
|
|
54
|
-
readonly sessionId: SessionId;
|
|
55
|
-
readonly binding: SideChatSessionBinding;
|
|
56
|
-
release(): void;
|
|
57
|
-
}
|
|
1
|
+
import type { ConversationSelection, SessionId, SideChatModelSelection, SideChatWireError } from '../shared/contracts.js';
|
|
2
|
+
/** Parent-only DSH integration. Side discussions never retain a child Session. */
|
|
58
3
|
export interface SideChatClientSessions {
|
|
59
4
|
currentSessionId(): SessionId | undefined;
|
|
60
5
|
lastCompletedSeq(parentSessionId: SessionId): number | undefined;
|
|
61
6
|
selectionIsCurrent(selection: ConversationSelection): boolean;
|
|
62
7
|
sideChatModelPreference(): SideChatModelSelection | undefined;
|
|
63
8
|
rememberSideChatModelPreference(selection: SideChatModelSelection): void;
|
|
64
|
-
|
|
9
|
+
retainParent(sessionId: SessionId): () => void;
|
|
65
10
|
openSession(sessionId: SessionId): Promise<void>;
|
|
66
11
|
notify(message: {
|
|
67
12
|
readonly kind: 'status' | 'warning';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { SideChatState } from '../../shared/contracts.js';
|
|
3
|
+
import type { SideChatController } from '../side-chat-controller.js';
|
|
4
|
+
/** The UI renders structured plugin messages, never model-facing prompt serialization. */
|
|
5
|
+
export declare function ReadOnlyConversation({ state, controller, modelControl, locale }: {
|
|
6
|
+
readonly state: SideChatState;
|
|
7
|
+
readonly controller: SideChatController;
|
|
8
|
+
readonly modelControl?: ReactNode;
|
|
9
|
+
readonly locale?: 'en' | 'zh-CN';
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { DisclosureRow, IconThinkOutlineRegular, MarkdownText } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
4
|
+
import { SelectionQuote } from '../panel/SelectionQuote.js';
|
|
5
|
+
import { SIDE_CHAT_MESSAGES } from '../panel/messages.js';
|
|
6
|
+
import { SendIcon } from '../panel/SendIcon.js';
|
|
7
|
+
import { StopIcon } from '../panel/StopIcon.js';
|
|
8
|
+
import { useAutoGrowingTextarea } from '../panel/use-auto-growing-textarea.js';
|
|
9
|
+
import { MARKDOWN_LABELS } from './primitive-labels.js';
|
|
10
|
+
function Reasoning({ text, running }) {
|
|
11
|
+
const [expanded, setExpanded] = useState(false);
|
|
12
|
+
const lines = text.trimEnd().split('\n');
|
|
13
|
+
return _jsx("div", { className: "dsh-side-chat-reasoning", "data-variant": "think", "data-state": running ? 'running' : 'ok', children: _jsx(DisclosureRow, { rowClassName: "dsh-side-chat-reasoning-row", leadingClassName: "dsh-side-chat-reasoning-leading", titleClassName: "dsh-side-chat-reasoning-title", chevronClassName: "dsh-side-chat-reasoning-chevron", icon: _jsx(IconThinkOutlineRegular, { size: 14 }), title: "Think", open: expanded, expandable: true, expandOnRowClick: true, onToggle: () => { setExpanded(value => !value); }, collapsedContent: _jsx("span", { className: "dsh-side-chat-reasoning-summary", children: running ? lines.at(-1) : lines[0] }), children: _jsx("div", { className: "dsh-side-chat-reasoning-body", children: text }) }) });
|
|
14
|
+
}
|
|
15
|
+
function Message({ message, locale }) {
|
|
16
|
+
const bubble = _jsxs("article", { className: "dsh-side-chat-message", "data-role": message.role, children: [_jsx("span", { className: "dsh-side-chat-message-role", children: message.role === 'user' ? 'You' : 'Assistant' }), message.role === 'user'
|
|
17
|
+
? _jsx("div", { className: "dsh-side-chat-message-text", children: message.text })
|
|
18
|
+
: _jsxs(_Fragment, { children: [message.reasoning && _jsx(Reasoning, { text: message.reasoning, running: message.status === 'streaming' }), _jsx(MarkdownText, { text: message.text, streaming: message.status === 'streaming', labels: MARKDOWN_LABELS }), message.status === 'streaming' && message.text === '' && !message.reasoning && _jsx("span", { children: "Thinking\u2026" }), message.status === 'stopped' && _jsx("span", { className: "dsh-side-chat-message-note", children: "Stopped" }), message.status === 'error' && _jsx("span", { className: "dsh-side-chat-message-note", children: "Reply failed" })] })] });
|
|
19
|
+
return message.selectedText === undefined ? bubble : _jsxs("div", { className: "dsh-side-chat-annotated-user-message", children: [_jsx(SelectionQuote, { selections: [{ text: message.selectedText }], messages: SIDE_CHAT_MESSAGES[locale] }), bubble] });
|
|
20
|
+
}
|
|
21
|
+
/** The UI renders structured plugin messages, never model-facing prompt serialization. */
|
|
22
|
+
export function ReadOnlyConversation({ state, controller, modelControl, locale = 'en' }) {
|
|
23
|
+
const [draft, setDraft] = useState('');
|
|
24
|
+
const [sending, setSending] = useState(false);
|
|
25
|
+
const [stopping, setStopping] = useState(false);
|
|
26
|
+
const [actionError, setActionError] = useState();
|
|
27
|
+
const sendingRef = useRef(false);
|
|
28
|
+
const stoppingRef = useRef(false);
|
|
29
|
+
const revision = useRef(0);
|
|
30
|
+
const follow = useRef(true);
|
|
31
|
+
const scrollRef = useRef(null);
|
|
32
|
+
const inputRef = useAutoGrowingTextarea(draft);
|
|
33
|
+
const running = state.phase === 'running';
|
|
34
|
+
const interactive = ['ready', 'running'].includes(state.phase);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const element = scrollRef.current;
|
|
37
|
+
if (element !== null && follow.current)
|
|
38
|
+
element.scrollTop = element.scrollHeight;
|
|
39
|
+
}, [state.messages]);
|
|
40
|
+
const submit = async (event) => {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
if (draft.trim().length === 0 || !interactive || running || sendingRef.current || stoppingRef.current)
|
|
43
|
+
return;
|
|
44
|
+
const before = revision.current;
|
|
45
|
+
sendingRef.current = true;
|
|
46
|
+
setSending(true);
|
|
47
|
+
setActionError(undefined);
|
|
48
|
+
try {
|
|
49
|
+
const result = await controller.send(draft);
|
|
50
|
+
if (result.ok && before === revision.current)
|
|
51
|
+
setDraft('');
|
|
52
|
+
else if (!result.ok && controller.getSnapshot().error?.message !== result.error.message)
|
|
53
|
+
setActionError(result.error.message);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
setActionError('The message could not be sent. Your draft has been kept.');
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
sendingRef.current = false;
|
|
60
|
+
setSending(false);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const stop = async () => {
|
|
64
|
+
if (stoppingRef.current)
|
|
65
|
+
return;
|
|
66
|
+
stoppingRef.current = true;
|
|
67
|
+
setStopping(true);
|
|
68
|
+
setActionError(undefined);
|
|
69
|
+
try {
|
|
70
|
+
const result = await controller.cancel();
|
|
71
|
+
if (!result.ok)
|
|
72
|
+
setActionError(result.error.message);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
setActionError('The request could not be stopped. Try closing Side Chat.');
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
stoppingRef.current = false;
|
|
79
|
+
setStopping(false);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return _jsxs("div", { className: "dsh-side-chat-conversation", children: [_jsxs("div", { ref: scrollRef, className: "dsh-side-chat-transcript", "aria-live": "polite", onScroll: event => {
|
|
83
|
+
const element = event.currentTarget;
|
|
84
|
+
follow.current = element.scrollHeight - element.scrollTop - element.clientHeight < 48;
|
|
85
|
+
}, children: [state.messages.map(message => _jsx(Message, { message: message, locale: locale }, message.id)), actionError !== undefined && _jsx("div", { className: "dsh-side-chat-turn-notice", role: "alert", children: actionError })] }), _jsxs("form", { className: "dsh-side-chat-composer", "data-composer-card": "", onSubmit: event => { void submit(event); }, children: [_jsx("textarea", { ref: inputRef, rows: 1, value: draft, disabled: !interactive, placeholder: "Reply in Side Chat", onChange: event => { ++revision.current; setDraft(event.target.value); }, onKeyDown: event => {
|
|
86
|
+
if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing && event.keyCode !== 229) {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
event.currentTarget.form?.requestSubmit();
|
|
89
|
+
}
|
|
90
|
+
} }), _jsxs("div", { className: "dsh-side-chat-composer-actions", children: [modelControl, running && _jsx("button", { type: "button", className: "dsh-side-chat-stop-button", "aria-label": "Stop generating", disabled: !interactive || stopping, onClick: () => { void stop(); }, children: _jsx(StopIcon, {}) }), _jsx("button", { type: "submit", className: "dsh-side-chat-send-button", "aria-label": "Send", disabled: !interactive || running || sending || stopping || draft.trim().length === 0, children: _jsx(SendIcon, {}) })] })] })] });
|
|
91
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SideChatController } from '../side-chat-controller.js';
|
|
2
|
+
import { DshSideChatSessions } from './sessions-adapter.js';
|
|
3
|
+
/** Selection toolbar and plugin-owned read-only discussion panel. */
|
|
4
|
+
export declare function SideChatOverlay({ controller, sessions, }: {
|
|
5
|
+
readonly controller: SideChatController;
|
|
6
|
+
readonly sessions: DshSideChatSessions;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,8 +7,9 @@ import { SideChatPanel } from '../panel/SideChatPanel.js';
|
|
|
7
7
|
import { ConversationAnnotationMarkers } from '../selection/ConversationAnnotationMarkers.js';
|
|
8
8
|
import { captureDomConversationSelection } from '../selection/selection-controller.js';
|
|
9
9
|
import { SelectionActions } from '../selection/SelectionActions.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { conversationChatRoot, focusConversationComposer } from '../selection/conversation-dom.js';
|
|
11
|
+
import { ReadOnlyConversation } from './ReadOnlyConversation.js';
|
|
12
|
+
import { DshSideChatSessions, selectionDescriptor } from './sessions-adapter.js';
|
|
12
13
|
const MORE_DETAILS_PROMPT = 'Please explain the selected passage in more detail.';
|
|
13
14
|
const TOUCH_SELECTION_SETTLE_MS = 300;
|
|
14
15
|
const TOUCH_ACTIVATION_SUPPRESS_MS = 750;
|
|
@@ -24,28 +25,8 @@ function captureEvent(event) {
|
|
|
24
25
|
'.dsh-side-chat-annotation-marker',
|
|
25
26
|
].join(', ')) !== null);
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
'[data-composer-seat] textarea',
|
|
30
|
-
'[data-composer-seat] [role="textbox"]',
|
|
31
|
-
'[data-composer-seat] [contenteditable="true"]',
|
|
32
|
-
].join(', '));
|
|
33
|
-
if (input === null)
|
|
34
|
-
return;
|
|
35
|
-
input.focus();
|
|
36
|
-
if (input instanceof HTMLTextAreaElement) {
|
|
37
|
-
input.setSelectionRange(input.value.length, input.value.length);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const range = document.createRange();
|
|
41
|
-
range.selectNodeContents(input);
|
|
42
|
-
range.collapse(false);
|
|
43
|
-
const selection = window.getSelection();
|
|
44
|
-
selection?.removeAllRanges();
|
|
45
|
-
selection?.addRange(range);
|
|
46
|
-
}
|
|
47
|
-
/** rc.6 compatibility surface: selection toolbar plus a non-current child conversation panel. */
|
|
48
|
-
export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
28
|
+
/** Selection toolbar and plugin-owned read-only discussion panel. */
|
|
29
|
+
export function SideChatOverlay({ controller, sessions, }) {
|
|
49
30
|
const state = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
|
|
50
31
|
const currentSessionId = useSyncExternalStore(sessions.subscribeList, () => sessions.currentSessionId(), () => sessions.currentSessionId());
|
|
51
32
|
const composerInput = useSyncExternalStore(sessions.subscribeConversationInput, sessions.currentConversationInputSnapshot, sessions.currentConversationInputSnapshot);
|
|
@@ -62,11 +43,11 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
62
43
|
const generation = ++captureGeneration.current;
|
|
63
44
|
const parentSessionId = sessions.currentSessionId();
|
|
64
45
|
const face = parentSessionId === undefined ? undefined : sessions.face(parentSessionId);
|
|
65
|
-
const conversationRoot =
|
|
46
|
+
const conversationRoot = parentSessionId === undefined ? undefined : conversationChatRoot(parentSessionId);
|
|
66
47
|
const browserSelection = window.getSelection();
|
|
67
48
|
if (parentSessionId === undefined
|
|
68
49
|
|| face === undefined
|
|
69
|
-
|| conversationRoot ===
|
|
50
|
+
|| conversationRoot === undefined
|
|
70
51
|
|| browserSelection === null
|
|
71
52
|
|| browserSelection.isCollapsed) {
|
|
72
53
|
if (generation === captureGeneration.current)
|
|
@@ -86,7 +67,7 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
86
67
|
},
|
|
87
68
|
},
|
|
88
69
|
});
|
|
89
|
-
if (generation === captureGeneration.current) {
|
|
70
|
+
if (generation === captureGeneration.current && sessions.currentSessionId() === parentSessionId) {
|
|
90
71
|
setActiveSelection({ value: captured, touch });
|
|
91
72
|
}
|
|
92
73
|
}
|
|
@@ -193,11 +174,13 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
193
174
|
touchInteraction.current = false;
|
|
194
175
|
cancelScheduledCapture();
|
|
195
176
|
if (event.key === 'Escape') {
|
|
177
|
+
// Escape in a menu, annotation editor, or main composer belongs to
|
|
178
|
+
// that control. Closing discards the temporary discussion, so it must
|
|
179
|
+
// not fire from every keyup in the document.
|
|
196
180
|
++captureGeneration.current;
|
|
197
181
|
annotationEditing.current = false;
|
|
198
182
|
setActiveSelection(null);
|
|
199
183
|
setEditingAnnotation(null);
|
|
200
|
-
void controller.close();
|
|
201
184
|
return;
|
|
202
185
|
}
|
|
203
186
|
if (captureEvent(event))
|
|
@@ -253,34 +236,25 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
253
236
|
const askDisabledReason = state.phase === 'closed'
|
|
254
237
|
? undefined
|
|
255
238
|
: 'Close the current Side Chat before starting another one.';
|
|
256
|
-
const childFace = state.childSessionId === undefined ? undefined : sessions.face(state.childSessionId);
|
|
257
|
-
const childCwd = state.childSessionId === undefined ? undefined : sessions.cwd(state.childSessionId);
|
|
258
|
-
const inheritedThroughSeq = state.inheritedThroughSeq;
|
|
259
239
|
const locale = navigator.language.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en';
|
|
260
240
|
const modelDirectory = state.parentSessionId === undefined
|
|
261
241
|
? undefined
|
|
262
242
|
: sessions.modelDirectory?.(state.parentSessionId);
|
|
263
|
-
const addToConversationDisabled =
|
|
264
|
-
||
|
|
265
|
-
|| state.
|
|
266
|
-
|| state.childSessionId === undefined
|
|
267
|
-
|| state.phase !== 'ready';
|
|
243
|
+
const addToConversationDisabled = state.parentSessionId === undefined
|
|
244
|
+
|| state.chatId === undefined || state.phase !== 'ready'
|
|
245
|
+
|| !state.messages.some(message => message.role === 'assistant' && message.text.trim().length > 0);
|
|
268
246
|
const addToConversation = () => {
|
|
269
247
|
const parentSessionId = state.parentSessionId;
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
if (parentSessionId === undefined
|
|
273
|
-
|| childSessionId === undefined
|
|
274
|
-
|| inheritedThroughSeq === undefined
|
|
275
|
-
|| face === undefined) {
|
|
248
|
+
const chatId = state.chatId;
|
|
249
|
+
if (parentSessionId === undefined || chatId === undefined || state.phase !== 'ready') {
|
|
276
250
|
sessions.notify({ kind: 'warning', text: 'The Side Chat conversation is not ready to add yet.' });
|
|
277
251
|
return;
|
|
278
252
|
}
|
|
253
|
+
const parentTitle = sessions.title(parentSessionId);
|
|
279
254
|
const reference = referencedSideChatConversation({
|
|
280
|
-
conversationId:
|
|
281
|
-
title:
|
|
282
|
-
|
|
283
|
-
inheritedThroughSeq,
|
|
255
|
+
conversationId: chatId,
|
|
256
|
+
title: [locale === 'zh-CN' ? '侧边对话' : 'Side Chat', parentTitle].filter(Boolean).join(' · '),
|
|
257
|
+
messages: state.messages,
|
|
284
258
|
});
|
|
285
259
|
if (reference.conversation.length === 0) {
|
|
286
260
|
sessions.notify({ kind: 'warning', text: 'The Side Chat does not have any conversation history to add yet.' });
|
|
@@ -291,7 +265,7 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
291
265
|
sessions.notify({ kind: 'warning', text: 'Could not add the Side Chat to the main conversation.' });
|
|
292
266
|
return;
|
|
293
267
|
}
|
|
294
|
-
void sessions.openSession(parentSessionId).then(
|
|
268
|
+
void sessions.openSession(parentSessionId).then(() => focusConversationComposer(parentSessionId), () => {
|
|
295
269
|
sessions.notify({ kind: 'warning', text: 'The Side Chat was added, but its parent conversation could not be opened.' });
|
|
296
270
|
});
|
|
297
271
|
}
|
|
@@ -301,12 +275,12 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
301
275
|
};
|
|
302
276
|
const modelControl = modelDirectory === undefined
|
|
303
277
|
? undefined
|
|
304
|
-
: (_jsx(SideChatModelSelect, { directory: modelDirectory, selection: state.modelSelection, locked: ['creating', '
|
|
278
|
+
: (_jsx(SideChatModelSelect, { directory: modelDirectory, selection: state.modelSelection, locked: ['creating', 'running', 'closing'].includes(state.phase) || state.error?.operation === 'close', validateInitialSelection: state.chatId === undefined, locale: locale, onInitialize: (selection, options) => {
|
|
305
279
|
if (options.remember)
|
|
306
280
|
void controller.selectModel(selection);
|
|
307
281
|
else
|
|
308
282
|
controller.initializeModel(selection);
|
|
309
|
-
}, onSelect: (selection) => controller.selectModel(selection) }, `${state.parentSessionId}:${state.
|
|
283
|
+
}, onSelect: (selection) => controller.selectModel(selection) }, `${state.parentSessionId}:${state.chatId ?? 'draft'}`));
|
|
310
284
|
return (_jsxs("div", { className: "dsh-side-chat-overlay", children: [_jsx(ConversationAnnotationMarkers, { annotations: annotations, ...editingAnnotation === null
|
|
311
285
|
? {}
|
|
312
286
|
: { activeAnnotationIndex: editingAnnotation.annotationIndex }, onEdit: (annotation, restoredSelection) => {
|
|
@@ -318,7 +292,7 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
318
292
|
} }), activeSelection !== null && (_jsx(SelectionActions, { selection: activeSelection.value, touchInteraction: activeSelection.touch, annotationNumber: sessions.nextConversationAnnotationNumber(), ...askDisabledReason === undefined ? {} : { askDisabledReason }, onAddToChat: (captured, comment) => {
|
|
319
293
|
try {
|
|
320
294
|
if (sessions.addSelectionToConversation(captured, comment))
|
|
321
|
-
|
|
295
|
+
focusConversationComposer(captured.parentSessionId);
|
|
322
296
|
else
|
|
323
297
|
sessions.notify({ kind: 'warning', text: 'Could not add the selection to the current chat.' });
|
|
324
298
|
}
|
|
@@ -373,12 +347,8 @@ export function Rc6SideChatOverlay({ controller, sessions, }) {
|
|
|
373
347
|
}, onMoreDetails: () => { }, onAskInSideChat: () => { }, onDismiss: () => {
|
|
374
348
|
annotationEditing.current = false;
|
|
375
349
|
setEditingAnnotation(null);
|
|
376
|
-
} }, `annotation:${String(editingAnnotation.annotationIndex)}`)), state.phase !== 'closed' && (_jsx(SideChatPanel, { state: state, locale: locale,
|
|
377
|
-
? {}
|
|
378
|
-
: {
|
|
379
|
-
embeddedConversation: (_jsx(ArchivedConversation, { face: childFace, inheritedThroughSeq: inheritedThroughSeq, controller: controller, cwd: childCwd, ...state.selection === undefined ? {} : { selection: state.selection }, locale: locale, modelControl: modelControl })),
|
|
380
|
-
}, modelControl: modelControl, onDraftChange: (draft) => { controller.setDraft(draft); }, onFirstSend: (question) => controller.sendFirst(question), onClose: () => controller.close(), onRetry: () => controller.retry(), onFocusParent: () => {
|
|
350
|
+
} }, `annotation:${String(editingAnnotation.annotationIndex)}`)), state.phase !== 'closed' && (_jsx(SideChatPanel, { state: state, locale: locale, embeddedConversation: _jsx(ReadOnlyConversation, { state: state, controller: controller, locale: locale, modelControl: modelControl }, state.chatId), modelControl: modelControl, onDraftChange: (draft) => { controller.setDraft(draft); }, onFirstSend: (question) => controller.sendFirst(question), onClose: () => controller.close(), onRetry: () => controller.retry(), onFocusParent: () => {
|
|
381
351
|
if (state.parentSessionId !== undefined)
|
|
382
352
|
void sessions.openSession(state.parentSessionId);
|
|
383
|
-
}, onAddToConversation: addToConversation, addToConversationDisabled: addToConversationDisabled, onRemoveSelection: () => { controller.clearSelection(); } }))] }));
|
|
353
|
+
}, onAddToConversation: addToConversation, addToConversationDisabled: addToConversationDisabled, ...state.chatId === undefined ? { onRemoveSelection: () => { controller.clearSelection(); } } : {} }))] }));
|
|
384
354
|
}
|
|
@@ -4,10 +4,10 @@ import type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
|
4
4
|
import type { UiConversation } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
5
5
|
import type { ModelDirectoryResolver } from '@deepseek-ai/dsh-client-ui-model-selection/client';
|
|
6
6
|
import type { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client';
|
|
7
|
-
import type {
|
|
7
|
+
import type { UiWorkspace } from '@deepseek-ai/dsh-client-ui-workspace/client';
|
|
8
8
|
import type { ParentConversationService, SelectionReferenceSource } from '../parent-composer/add-to-conversation.js';
|
|
9
9
|
/** Browser-only Cordis view for a package that also compiles the Host half. */
|
|
10
|
-
export type
|
|
10
|
+
export type DshClientContext = Omit<Context, 'conversation' | 'inputTriggers' | 'modelDirectories' | 'remote' | 'sessions' | 'slots' | 'uiConversation' | 'uiWorkspace'> & {
|
|
11
11
|
readonly conversation: ParentConversationService;
|
|
12
12
|
readonly inputTriggers: {
|
|
13
13
|
registerSource(source: SelectionReferenceSource): () => void;
|
|
@@ -16,8 +16,6 @@ export type Rc6ClientContext = Omit<Context, 'conversation' | 'inputTriggers' |
|
|
|
16
16
|
readonly remote: ClientRemote;
|
|
17
17
|
readonly sessions: ISessions;
|
|
18
18
|
readonly slots: SlotRegistry;
|
|
19
|
-
|
|
20
|
-
readonly uiConversation
|
|
21
|
-
/** Added by DSH 0.1.2; absent on the monolithic 0.1.0/0.1.1 runtime. */
|
|
22
|
-
readonly uiSession?: Pick<UiSession, 'pendingInteractions'>;
|
|
19
|
+
readonly uiWorkspace: UiWorkspace;
|
|
20
|
+
readonly uiConversation: Pick<UiConversation, 'binding'>;
|
|
23
21
|
};
|