dsh-side-chat-plus 0.3.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/LICENSE +21 -0
- package/README.md +317 -0
- package/README.zh.md +261 -0
- package/cordis.patch.yml +8 -0
- package/dsh.plugin.json +16 -0
- package/lib/client-registry.js +2949 -0
- package/lib/client-registry.js.map +1 -0
- package/lib/client.js +2949 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +840 -0
- package/lib/types/client/api.d.ts +218 -0
- package/lib/types/client/attachments/AttachmentRail.d.ts +39 -0
- package/lib/types/client/attachments/DropOverlay.d.ts +18 -0
- package/lib/types/client/attachments/ImageLightbox.d.ts +20 -0
- package/lib/types/client/attachments/MessageImage.d.ts +38 -0
- package/lib/types/client/attachments/index.d.ts +18 -0
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/client/locales.d.ts +178 -0
- package/lib/types/context-types.d.ts +390 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/settings-shared.d.ts +24 -0
- package/lib/types/trust-fence.d.ts +20 -0
- package/lib/types/wire.d.ts +25 -0
- package/package.json +114 -0
- package/src/client/api.ts +112 -0
- package/src/client/attachments/AttachmentRail.module.css +89 -0
- package/src/client/attachments/AttachmentRail.tsx +173 -0
- package/src/client/attachments/DropOverlay.module.css +38 -0
- package/src/client/attachments/DropOverlay.tsx +62 -0
- package/src/client/attachments/ImageLightbox.module.css +44 -0
- package/src/client/attachments/ImageLightbox.tsx +58 -0
- package/src/client/attachments/MessageImage.module.css +61 -0
- package/src/client/attachments/MessageImage.tsx +120 -0
- package/src/client/attachments/index.ts +19 -0
- package/src/client/client.module.css +1032 -0
- package/src/client/index.tsx +1966 -0
- package/src/client/layout.css +16 -0
- package/src/client/locales.ts +181 -0
- package/src/context-types.ts +384 -0
- package/src/css-modules.d.ts +10 -0
- package/src/index.ts +840 -0
- package/src/settings-shared.ts +33 -0
- package/src/trust-fence.ts +70 -0
- package/src/wire.ts +81 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout push: when the side-chat panel is open it OCCUPIES layout instead of
|
|
3
|
+
* floating over it — the app shell (#root) gives up the right margin so the
|
|
4
|
+
* center column (conversation + input bar) squeezes left, like a VSCode
|
|
5
|
+
* sidebar. The width rides a CSS variable the panel sets.
|
|
6
|
+
*/
|
|
7
|
+
#root {
|
|
8
|
+
margin-right: var(--dsh-subchat-width, 0px);
|
|
9
|
+
transition: margin-right var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@media (prefers-reduced-motion: reduce) {
|
|
13
|
+
#root {
|
|
14
|
+
transition: none;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client locale dictionaries for dsh-side-chat (zh + en), registered under the
|
|
3
|
+
* `sidechat` namespace.
|
|
4
|
+
*/
|
|
5
|
+
export const LOCALE_NS = 'sidechat'
|
|
6
|
+
|
|
7
|
+
export const zh = {
|
|
8
|
+
'ask.new': '在侧边聊天中提问',
|
|
9
|
+
'ask.continue': '继续在激活的侧边聊天中提问',
|
|
10
|
+
'panel.title': '侧边聊天',
|
|
11
|
+
'panel.empty': '当前会话还没有侧边聊天。选中消息文本后点「在侧边聊天中提问」即可发起。',
|
|
12
|
+
'panel.close': '关闭',
|
|
13
|
+
'panel.input.placeholder': '输入消息,回车发送',
|
|
14
|
+
'panel.send': '发送',
|
|
15
|
+
'panel.stop': '停止',
|
|
16
|
+
'panel.lookup': '需要时从工作区 / 主会话查信息',
|
|
17
|
+
'panel.model': '模型',
|
|
18
|
+
'panel.provider': '服务商',
|
|
19
|
+
'panel.effort': '思考难度',
|
|
20
|
+
'panel.permission': '权限',
|
|
21
|
+
'panel.noModel': '(继承)',
|
|
22
|
+
'panel.effortDefault': '默认',
|
|
23
|
+
'panel.expand': '展开侧边聊天',
|
|
24
|
+
'panel.collapse': '收起侧边聊天',
|
|
25
|
+
'panel.dispose': '结束此侧边聊天',
|
|
26
|
+
'panel.delete': '删除',
|
|
27
|
+
'panel.deleteAll': '删除全部',
|
|
28
|
+
'panel.error': '侧边聊天出错',
|
|
29
|
+
'panel.running': '思考中…',
|
|
30
|
+
'panel.copy': '复制',
|
|
31
|
+
'panel.copied': '已复制',
|
|
32
|
+
'panel.footnotes': '脚注',
|
|
33
|
+
'panel.think': '思考',
|
|
34
|
+
'panel.commands': '命令',
|
|
35
|
+
'command.model': '/model 模型',
|
|
36
|
+
'command.permission': '/permission 权限',
|
|
37
|
+
'plan.chipTitle': '计划模式已开启 — 点击关闭(/plan off)',
|
|
38
|
+
'plan.chipAria': '计划模式已开启,按下关闭',
|
|
39
|
+
'goal.label': '目标',
|
|
40
|
+
'image.railGroup': '图片附件',
|
|
41
|
+
'image.railOpen': '查看原图',
|
|
42
|
+
'image.railScrollLeft': '向左滚动',
|
|
43
|
+
'image.railScrollRight': '向右滚动',
|
|
44
|
+
'image.remove': '移除图片',
|
|
45
|
+
'image.label': '图片',
|
|
46
|
+
'image.open': '查看原图',
|
|
47
|
+
'image.loading': '加载中…',
|
|
48
|
+
'image.loadFailed': '加载失败',
|
|
49
|
+
'image.lightboxDialog': '图片预览',
|
|
50
|
+
'image.close': '关闭',
|
|
51
|
+
'image.dropTitle': '拖放图片到此处',
|
|
52
|
+
'image.dropDesc': '支持 PNG / JPEG / WebP / GIF',
|
|
53
|
+
'image.unsupported': '不支持的图片格式',
|
|
54
|
+
'image.tooMany': '图片数量超出限制',
|
|
55
|
+
'image.fileTooLarge': '图片过大',
|
|
56
|
+
'settingsNav': '侧边聊天',
|
|
57
|
+
'settings.lookupTitle': '默认勾选「需要时从工作区 / 主会话查信息」',
|
|
58
|
+
'settings.lookupDesc': '新会话的侧边聊天默认打开此开关;可在每次聊天中临时更改',
|
|
59
|
+
'settings.sendImmediatelyTitle': '选中内容后立即发送',
|
|
60
|
+
'settings.sendImmediatelyDesc': '关闭后,选中的内容会作为附件先放进侧边聊天输入框,由你确认后再发送',
|
|
61
|
+
'settings.defaultPromptTitle': '默认用户提示词',
|
|
62
|
+
'settings.defaultPromptDesc': '「立即发送」开启时,选中的内容会自动附加这段提示词,让回答更符合你的需求',
|
|
63
|
+
'settings.defaultPromptPlaceholder': '例如:请用中文回答,并尽量简洁…',
|
|
64
|
+
'settings.bringModeTitle': '带回内容的方式',
|
|
65
|
+
'settings.bringModeDesc': '把侧边聊天的 AI 回复带回主会话时,内容落在哪里(两种方式都不会立即发送)',
|
|
66
|
+
'settings.bringModeDraftTitle': '写入输入框草稿',
|
|
67
|
+
'settings.bringModeDraftDesc': '内容进入主会话输入框,可直接编辑后再发送',
|
|
68
|
+
'settings.bringModeContextTitle': '注入为折叠提示行',
|
|
69
|
+
'settings.bringModeContextDesc': '内容作为一条折叠的上下文提示行注入主会话(带来源标记),不写输入框;下次对话时模型可见',
|
|
70
|
+
'insert.direct': '直接带回',
|
|
71
|
+
'insert.summarize': '摘要后带回',
|
|
72
|
+
'insert.summarizing': '摘要中…',
|
|
73
|
+
'insert.failed': '无法写入主会话输入框',
|
|
74
|
+
'insert.summarizeFailed': '摘要失败',
|
|
75
|
+
'insert.contextSummary': '侧边聊天带回',
|
|
76
|
+
'insert.summarizeContextSummary': '侧边聊天摘要',
|
|
77
|
+
'question.options': '可选选项',
|
|
78
|
+
'question.option': '选项',
|
|
79
|
+
'question.bringAll': '带入全部',
|
|
80
|
+
'question.bringAllNew': '新会话全部',
|
|
81
|
+
'question.bringOne': '带入',
|
|
82
|
+
'question.bringOneNew': '新会话',
|
|
83
|
+
'question.bringing': '带入中…',
|
|
84
|
+
'question.failed': '带入侧边聊天失败',
|
|
85
|
+
'question.delete': '删除',
|
|
86
|
+
'question.deleteAll': '删除全部',
|
|
87
|
+
'question.collapse': '折叠',
|
|
88
|
+
'question.expand': '展开',
|
|
89
|
+
'question.allPrompt': '请帮我理解上面的问题和各个选项的含义,并给出选择建议。',
|
|
90
|
+
'question.onePrompt': '请帮我理解这个选项的含义,以及它在这个问题中的利弊。',
|
|
91
|
+
'question.openHint': '主会话有一个问题弹框,点击在侧边聊天里询问',
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const en = {
|
|
95
|
+
'ask.new': 'Ask in side chat',
|
|
96
|
+
'ask.continue': 'Continue active side chat',
|
|
97
|
+
'panel.title': 'Side chat',
|
|
98
|
+
'panel.empty': 'No side chat for this conversation yet. Select some message text and choose "Ask in side chat".',
|
|
99
|
+
'panel.close': 'Close',
|
|
100
|
+
'panel.input.placeholder': 'Type a message, Enter to send',
|
|
101
|
+
'panel.send': 'Send',
|
|
102
|
+
'panel.stop': 'Stop',
|
|
103
|
+
'panel.lookup': 'Look up workspace / parent when needed',
|
|
104
|
+
'panel.model': 'Model',
|
|
105
|
+
'panel.provider': 'Provider',
|
|
106
|
+
'panel.effort': 'Effort',
|
|
107
|
+
'panel.permission': 'Permission',
|
|
108
|
+
'panel.noModel': '(inherited)',
|
|
109
|
+
'panel.effortDefault': 'Default',
|
|
110
|
+
'panel.expand': 'Expand side chat',
|
|
111
|
+
'panel.collapse': 'Collapse side chat',
|
|
112
|
+
'panel.dispose': 'End this side chat',
|
|
113
|
+
'panel.delete': 'Delete',
|
|
114
|
+
'panel.deleteAll': 'Delete all',
|
|
115
|
+
'panel.error': 'Side chat error',
|
|
116
|
+
'panel.running': 'Thinking…',
|
|
117
|
+
'panel.copy': 'Copy',
|
|
118
|
+
'panel.copied': 'Copied',
|
|
119
|
+
'panel.footnotes': 'Footnotes',
|
|
120
|
+
'panel.think': 'Think',
|
|
121
|
+
'panel.commands': 'Commands',
|
|
122
|
+
'command.model': '/model Model',
|
|
123
|
+
'command.permission': '/permission Permission',
|
|
124
|
+
'plan.chipTitle': 'Plan mode on — click to turn off (/plan off)',
|
|
125
|
+
'plan.chipAria': 'Plan mode on, press to turn off',
|
|
126
|
+
'goal.label': 'Goal',
|
|
127
|
+
'image.railGroup': 'Image attachments',
|
|
128
|
+
'image.railOpen': 'Open original',
|
|
129
|
+
'image.railScrollLeft': 'Scroll left',
|
|
130
|
+
'image.railScrollRight': 'Scroll right',
|
|
131
|
+
'image.remove': 'Remove image',
|
|
132
|
+
'image.label': 'Image',
|
|
133
|
+
'image.open': 'Open original',
|
|
134
|
+
'image.loading': 'Loading…',
|
|
135
|
+
'image.loadFailed': 'Load failed',
|
|
136
|
+
'image.lightboxDialog': 'Image preview',
|
|
137
|
+
'image.close': 'Close',
|
|
138
|
+
'image.dropTitle': 'Drop images here',
|
|
139
|
+
'image.dropDesc': 'PNG / JPEG / WebP / GIF',
|
|
140
|
+
'image.unsupported': 'Unsupported image type',
|
|
141
|
+
'image.tooMany': 'Too many images',
|
|
142
|
+
'image.fileTooLarge': 'Image too large',
|
|
143
|
+
'settingsNav': 'Side chat',
|
|
144
|
+
'settings.lookupTitle': 'Default on: "look up workspace / parent when needed"',
|
|
145
|
+
'settings.lookupDesc': 'New conversations start with this switch on; you can still change it per chat',
|
|
146
|
+
'settings.sendImmediatelyTitle': 'Send selected text immediately',
|
|
147
|
+
'settings.sendImmediatelyDesc': 'When off, the selection is staged as an attachment in the composer for you to confirm before sending',
|
|
148
|
+
'settings.defaultPromptTitle': 'Default prompt',
|
|
149
|
+
'settings.defaultPromptDesc': 'When "send immediately" is on, this prompt is appended to the selection so the answer matches your needs',
|
|
150
|
+
'settings.defaultPromptPlaceholder': 'e.g. Answer in Chinese and keep it concise…',
|
|
151
|
+
'settings.bringModeTitle': 'Bring-back target',
|
|
152
|
+
'settings.bringModeDesc': 'Where a side-chat AI reply lands when brought back (neither mode sends immediately)',
|
|
153
|
+
'settings.bringModeDraftTitle': 'Into the composer draft',
|
|
154
|
+
'settings.bringModeDraftDesc': 'Text lands in the main composer so you can edit before sending',
|
|
155
|
+
'settings.bringModeContextTitle': 'As a collapsed context row',
|
|
156
|
+
'settings.bringModeContextDesc': 'Text is injected as a collapsed, source-tagged context row — not into the composer; the model sees it next turn',
|
|
157
|
+
'insert.direct': 'Insert directly',
|
|
158
|
+
'insert.summarize': 'Summarize & insert',
|
|
159
|
+
'insert.summarizing': 'Summarizing…',
|
|
160
|
+
'insert.failed': 'Could not write to the main composer',
|
|
161
|
+
'insert.summarizeFailed': 'Summarization failed',
|
|
162
|
+
'insert.contextSummary': 'Brought from side chat',
|
|
163
|
+
'insert.summarizeContextSummary': 'Side chat summary',
|
|
164
|
+
'question.options': 'Options',
|
|
165
|
+
'question.option': 'Option',
|
|
166
|
+
'question.bringAll': 'Bring all',
|
|
167
|
+
'question.bringAllNew': 'New chat (all)',
|
|
168
|
+
'question.bringOne': 'Bring',
|
|
169
|
+
'question.bringOneNew': 'New chat',
|
|
170
|
+
'question.bringing': 'Bringing…',
|
|
171
|
+
'question.failed': 'Failed to bring into the side chat',
|
|
172
|
+
'question.delete': 'Delete',
|
|
173
|
+
'question.deleteAll': 'Delete all',
|
|
174
|
+
'question.collapse': 'Collapse',
|
|
175
|
+
'question.expand': 'Expand',
|
|
176
|
+
'question.allPrompt': 'Please explain what this question is asking and what each option means, and advise how I should choose.',
|
|
177
|
+
'question.onePrompt': 'Please explain what this option means and its trade-offs for this question.',
|
|
178
|
+
'question.openHint': 'The main conversation has a question dialog — click to ask in the side chat',
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export type SidechatLocaleKey = keyof typeof zh
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural types for the cordis services this plugin consumes, plus the
|
|
3
|
+
* Context augmentation both halves share. A third-party plugin resolves
|
|
4
|
+
* outside the DSH monorepo's single cordis instance, so the upstream
|
|
5
|
+
* `declare module 'cordis'` augmentations do not reach this Context; the
|
|
6
|
+
* members below mirror the actual runtime shapes this plugin touches.
|
|
7
|
+
*
|
|
8
|
+
* The `sessions` field is a union of the HOST store face (get/list) and the
|
|
9
|
+
* CLIENT list feed (list.getSnapshot/subscribe): each half only touches its
|
|
10
|
+
* own side, and the shared declaration keeps the two cordis instance layers
|
|
11
|
+
* from colliding under one tsconfig.
|
|
12
|
+
*/
|
|
13
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
14
|
+
import type { Context } from 'cordis'
|
|
15
|
+
|
|
16
|
+
/** One named webserver route. */
|
|
17
|
+
export interface SideWebRoute {
|
|
18
|
+
kind: 'exact' | 'prefix'
|
|
19
|
+
path: string
|
|
20
|
+
handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The webServer service face this plugin uses. */
|
|
24
|
+
export interface SideWebServer {
|
|
25
|
+
register(route: SideWebRoute): () => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A published session's header slice (authoritative cwd, lineage, origin). */
|
|
29
|
+
export interface SideSessionHeader {
|
|
30
|
+
cwd?: string
|
|
31
|
+
parentSession?: string
|
|
32
|
+
origin?: 'subagent'
|
|
33
|
+
delegationDepth?: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** One session event (fold source for history and permission current). */
|
|
37
|
+
export interface SideSessionEvent {
|
|
38
|
+
type: string
|
|
39
|
+
seq: number
|
|
40
|
+
time: number
|
|
41
|
+
data: Record<string, unknown>
|
|
42
|
+
surfaceOp?: 'append' | 'replace' | 'remove'
|
|
43
|
+
sourceEventSeqs?: number[]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The live session face the host reads (header + append-only event log). */
|
|
47
|
+
export interface SideSession {
|
|
48
|
+
id: string
|
|
49
|
+
header: SideSessionHeader
|
|
50
|
+
events?: readonly SideSessionEvent[]
|
|
51
|
+
requestHeader?: () => { config?: { provider?: string; model?: string; reasoningEffort?: string; maxTokens?: number } } | undefined
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The host session store face (`ctx.sessions` host side). */
|
|
55
|
+
export interface SideSessionStore {
|
|
56
|
+
get(id: string): SideSession | undefined
|
|
57
|
+
list(): SideSession[]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** One session list row (client list feed). */
|
|
61
|
+
export interface SideSessionSummary {
|
|
62
|
+
id: string
|
|
63
|
+
displayTitle: string
|
|
64
|
+
cwd?: string
|
|
65
|
+
origin?: 'subagent'
|
|
66
|
+
parentId?: string
|
|
67
|
+
running: boolean
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The session list snapshot the browser half subscribes to. */
|
|
71
|
+
export interface SideSessionList {
|
|
72
|
+
current: string | undefined
|
|
73
|
+
byId: Record<string, SideSessionSummary>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** One selectable answer in a user-question dialog. */
|
|
77
|
+
export interface SideQuestionOption {
|
|
78
|
+
label: string
|
|
79
|
+
description?: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One question in a pending user-question dialog. */
|
|
83
|
+
export interface SideQuestionItem {
|
|
84
|
+
id: string
|
|
85
|
+
question: string
|
|
86
|
+
detail?: string
|
|
87
|
+
header?: string
|
|
88
|
+
options?: SideQuestionOption[]
|
|
89
|
+
multiSelect?: boolean
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** A pending main-conversation interaction (question / plan-review / approval dialog). */
|
|
93
|
+
export interface SidePendingInteraction {
|
|
94
|
+
/** Presentation discriminator: the question family, or an approval. */
|
|
95
|
+
kind: 'question' | 'plan-review' | 'approval'
|
|
96
|
+
/** Opaque render identity and request key (e.g. `question:1`). */
|
|
97
|
+
key: string
|
|
98
|
+
sessionId: string
|
|
99
|
+
/** The request's question list (present for the question family). */
|
|
100
|
+
questions?: SideQuestionItem[]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The per-session pending-interaction source exposed by the `uiSession` service. */
|
|
104
|
+
export interface SidePendingInteractionStore {
|
|
105
|
+
getSnapshot(): ReadonlyMap<string, SidePendingInteraction>
|
|
106
|
+
subscribe(fn: () => void): () => void
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The client sessions service face (list feed + scope resolution). */
|
|
110
|
+
export interface SideSessionsService {
|
|
111
|
+
list: {
|
|
112
|
+
getSnapshot(): SideSessionList
|
|
113
|
+
subscribe(fn: () => void): () => void
|
|
114
|
+
}
|
|
115
|
+
/** Resolve an Agent-scoped context view for a listed session id (use-and-discard). */
|
|
116
|
+
scope(id: string): Context | undefined
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The client UI-session service face (per-session pending interactions). */
|
|
120
|
+
export interface SideUiSessionService {
|
|
121
|
+
/** Per-session pending UI interaction (question / plan-review / approval). */
|
|
122
|
+
pendingInteractions: SidePendingInteractionStore
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Agent options (provider/model/maxTokens). */
|
|
126
|
+
export interface SideAgentOptions {
|
|
127
|
+
provider?: string
|
|
128
|
+
model?: string
|
|
129
|
+
maxTokens?: number
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** The live agent face (`ctx.agents.get(id)` / `AgentHandle.agent`). */
|
|
133
|
+
export interface SideAgent {
|
|
134
|
+
readonly id: string
|
|
135
|
+
readonly options: SideAgentOptions
|
|
136
|
+
readonly session: SideSession
|
|
137
|
+
readonly status: string
|
|
138
|
+
readonly ctx: Context
|
|
139
|
+
followup(message: unknown): void
|
|
140
|
+
inject(message: unknown): void
|
|
141
|
+
cancel(cause: { kind: 'user' | 'parent' | 'disposed' } | { kind: 'hook'; reason: string }): void
|
|
142
|
+
whenIdle(): Promise<void>
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** The agent handle `ctx.agents.create` resolves (owner tears the agent down). */
|
|
146
|
+
export interface SideAgentHandle {
|
|
147
|
+
agent: SideAgent
|
|
148
|
+
dispose(): Promise<void>
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** `ctx.agents.create` options (mirror of CreateAgentOptions). */
|
|
152
|
+
export interface SideCreateAgentOptions {
|
|
153
|
+
sessionId: string
|
|
154
|
+
meta?: {
|
|
155
|
+
cwd?: string
|
|
156
|
+
parentSession?: string
|
|
157
|
+
agentPreset?: string
|
|
158
|
+
}
|
|
159
|
+
agentOptions?: SideAgentOptions
|
|
160
|
+
setup?: (agentCtx: Context) => void | Promise<void>
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** The host agent registry face. */
|
|
164
|
+
export interface SideAgentsService {
|
|
165
|
+
get(id: string): SideAgent | undefined
|
|
166
|
+
create(options: SideCreateAgentOptions): Promise<SideAgentHandle>
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Live provider / model / reasoning-effort selection for one agent. */
|
|
170
|
+
export interface SideModelSelection {
|
|
171
|
+
provider: string
|
|
172
|
+
model: string
|
|
173
|
+
reasoningEffort?: string
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Mutable selection plus the value captured when the current step entered
|
|
178
|
+
* prompt assembly (`current` / `assembled`).
|
|
179
|
+
*/
|
|
180
|
+
export interface SideModelSelectionRef {
|
|
181
|
+
current: SideModelSelection | undefined
|
|
182
|
+
assembled: SideModelSelection | undefined
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Couple a mutable selection to an agent's prompt assembly and request routing
|
|
187
|
+
* (`installModelSelection` on the agent package). Typed structurally rather
|
|
188
|
+
* than imported: this plugin resolves outside the DSH monorepo's single cordis
|
|
189
|
+
* instance, so the upstream export is reached through a loose signature.
|
|
190
|
+
*/
|
|
191
|
+
export type SideInstallModelSelection = (agentCtx: Context, selection: SideModelSelectionRef) => () => void
|
|
192
|
+
|
|
193
|
+
/** The workspace registry face (archive a session durably). */
|
|
194
|
+
export interface SideWorkspaceRegistry {
|
|
195
|
+
archiveSession(sessionId: string): Promise<void>
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** `sessionQuery.readSession` snapshot. */
|
|
199
|
+
export interface SideSessionLogSnapshot {
|
|
200
|
+
session: SideSessionHeader
|
|
201
|
+
events: SideSessionEvent[]
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** The session query face. */
|
|
205
|
+
export interface SideSessionQuery {
|
|
206
|
+
readSession(sessionId: string): Promise<SideSessionLogSnapshot>
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Sandbox mode vocabulary (read from the session override). */
|
|
210
|
+
export type SideSandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access'
|
|
211
|
+
|
|
212
|
+
/** The sandbox policy face. */
|
|
213
|
+
export interface SideSandboxPolicy {
|
|
214
|
+
overrideOf(session: SideSession): SideSandboxMode | undefined
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** One permission preset option. */
|
|
218
|
+
export interface SidePresetOption {
|
|
219
|
+
value: string
|
|
220
|
+
name: string
|
|
221
|
+
description?: string
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** The permission presets face. */
|
|
225
|
+
export interface SidePermissionPresets {
|
|
226
|
+
current(events: readonly SideSessionEvent[]): string
|
|
227
|
+
set(session: SideSession, name: string): void
|
|
228
|
+
selectFor(state: unknown): { options: SidePresetOption[]; currentValue: string }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** The agent presets face (composeFrom joins a child to the parent's composition). */
|
|
232
|
+
export interface SideAgentPresets {
|
|
233
|
+
composeFrom(agentCtx: Context, parentCtx: Context): string | undefined
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** One provider route. */
|
|
237
|
+
export interface SideLlmProvider {
|
|
238
|
+
id: string
|
|
239
|
+
name: string
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** One model entry. */
|
|
243
|
+
export interface SideLlmModel {
|
|
244
|
+
provider: string
|
|
245
|
+
id: string
|
|
246
|
+
name: string
|
|
247
|
+
description?: string
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** One reasoning-effort entry. */
|
|
251
|
+
export interface SideLlmEffort {
|
|
252
|
+
id: string
|
|
253
|
+
name: string
|
|
254
|
+
description?: string
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** One model-request stream chunk (minimal structural view for text collection). */
|
|
258
|
+
export interface SideLlmStreamChunk {
|
|
259
|
+
type: string
|
|
260
|
+
text?: string
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Minimal generate options the summarize route builds (a hand-built user prompt). */
|
|
264
|
+
export interface SideLlmGenerateOptions {
|
|
265
|
+
provider: string
|
|
266
|
+
model: string
|
|
267
|
+
reasoningEffort?: string
|
|
268
|
+
maxTokens?: number
|
|
269
|
+
signal?: AbortSignal
|
|
270
|
+
messages: Array<{
|
|
271
|
+
id?: string
|
|
272
|
+
role: 'user' | 'assistant' | 'system'
|
|
273
|
+
content: Array<{ type: 'text'; text: string }>
|
|
274
|
+
source?: { kind: string }
|
|
275
|
+
}>
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** The llm face (model/effort catalog + one-shot streaming calls). */
|
|
279
|
+
export interface SideLlm {
|
|
280
|
+
listProviders(): SideLlmProvider[]
|
|
281
|
+
listModels(provider: string): Promise<SideLlmModel[]>
|
|
282
|
+
resolveModelInfo(provider: string, model: string): Promise<{
|
|
283
|
+
provider: string
|
|
284
|
+
id: string
|
|
285
|
+
name: string
|
|
286
|
+
reasoning?: { efforts: readonly SideLlmEffort[]; defaultEffort?: string }
|
|
287
|
+
}>
|
|
288
|
+
stream(options: SideLlmGenerateOptions): AsyncIterable<SideLlmStreamChunk>
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** The client locale service face. */
|
|
292
|
+
export interface SideLocaleService {
|
|
293
|
+
getSnapshot(): { active: string }
|
|
294
|
+
subscribe(fn: () => void): () => void
|
|
295
|
+
register(ns: string, locale: string, dict: Record<string, string>): () => void
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** The host settings service face (namespace registration + read/write). */
|
|
299
|
+
export interface SideSettingsService {
|
|
300
|
+
register(ns: unknown, schema: unknown): { get(): unknown; watch(cb: (next: unknown, prev: unknown) => void): () => void }
|
|
301
|
+
describe(opts: { redactSecrets?: boolean }): Array<{ ns: unknown; value?: unknown; revision?: number }>
|
|
302
|
+
update(ns: unknown, patch: Record<string, unknown>, expectedRevision?: number): Promise<void>
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** The client slots service face (settings.section registration). */
|
|
306
|
+
export interface SideSlotsService {
|
|
307
|
+
inject(name: string, factory: () => () => void): void
|
|
308
|
+
register(options: Record<string, unknown>, component: unknown): () => void
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** One durable image reference (mirror of ImageAttachmentRef). */
|
|
312
|
+
export interface SideImageAttachmentRef {
|
|
313
|
+
attachmentId: string
|
|
314
|
+
mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'
|
|
315
|
+
bytes: number
|
|
316
|
+
width: number
|
|
317
|
+
height: number
|
|
318
|
+
name?: string
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** The host attachment store face (`ctx.attachments`). */
|
|
322
|
+
export interface SideAttachmentStore {
|
|
323
|
+
readonly imageLimits: {
|
|
324
|
+
maxImageBytes: number
|
|
325
|
+
maxImagesPerMessage: number
|
|
326
|
+
maxMessageImageBytes: number
|
|
327
|
+
maxImagePixels: number
|
|
328
|
+
mediaTypes: readonly string[]
|
|
329
|
+
}
|
|
330
|
+
validateImage(input: { data: Uint8Array; mediaType: string; name?: string }): Promise<void>
|
|
331
|
+
saveImage(input: { data: Uint8Array; mediaType: string; name?: string }): Promise<SideImageAttachmentRef>
|
|
332
|
+
readImage(ref: SideImageAttachmentRef): Promise<{ ref: SideImageAttachmentRef; data: Uint8Array }>
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** The host command registry face (`ctx.commands`). */
|
|
336
|
+
export interface SideCommandsService {
|
|
337
|
+
list(agent: SideAgent): Array<{ name: string; description: string }>
|
|
338
|
+
execute(agent: SideAgent, line: string, signal: AbortSignal): Promise<unknown>
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** The per-session composer input face this plugin writes to (draft-only). */
|
|
342
|
+
export interface SideSessionInput {
|
|
343
|
+
/** Replace the session composer draft (never submits). */
|
|
344
|
+
setDraft(text: string): void
|
|
345
|
+
/** Live input state store (draft read). */
|
|
346
|
+
state: { getSnapshot(): { draft: string } }
|
|
347
|
+
/** Surface a notice on the session composer. */
|
|
348
|
+
notify(level: 'info' | 'error', text: string): void
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** The conversation service face (`ctx.conversation`) — input registry only. */
|
|
352
|
+
export interface SideConversationService {
|
|
353
|
+
input: {
|
|
354
|
+
/** Resolve the input facade for one session-scope context. */
|
|
355
|
+
for(actx: Context): SideSessionInput
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
declare module 'cordis' {
|
|
360
|
+
interface Context {
|
|
361
|
+
webServer: SideWebServer
|
|
362
|
+
sessions: SideSessionStore & SideSessionsService
|
|
363
|
+
agents: SideAgentsService
|
|
364
|
+
workspaceRegistry: SideWorkspaceRegistry
|
|
365
|
+
sessionQuery: SideSessionQuery
|
|
366
|
+
sandboxPolicy: SideSandboxPolicy
|
|
367
|
+
permissionPresets: SidePermissionPresets
|
|
368
|
+
agentPresets: SideAgentPresets
|
|
369
|
+
llm: SideLlm
|
|
370
|
+
locale: SideLocaleService
|
|
371
|
+
settings: SideSettingsService
|
|
372
|
+
slots: SideSlotsService
|
|
373
|
+
attachments: SideAttachmentStore
|
|
374
|
+
commands: SideCommandsService
|
|
375
|
+
conversation: SideConversationService
|
|
376
|
+
uiSession: SideUiSessionService
|
|
377
|
+
inject(deps: string[], callback: (ctx: Context) => void): void
|
|
378
|
+
get(name: string): unknown | undefined
|
|
379
|
+
on(name: string, listener: (...args: any[]) => any): () => void
|
|
380
|
+
effect(fn: () => void | (() => void), label?: string): void
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export type { Context }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** CSS module typing (the tsdown CSS plugin inlines hashed class maps). */
|
|
2
|
+
declare module '*.module.css' {
|
|
3
|
+
const classes: Record<string, string>
|
|
4
|
+
export default classes
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare module '*.css' {
|
|
8
|
+
const content: string
|
|
9
|
+
export default content
|
|
10
|
+
}
|