@yfwu2020/dsh-selection-explain 0.10.3 → 0.10.5
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 +13 -11
- package/cordis.patch.yml +1 -1
- package/lib/client.js +10694 -12424
- package/lib/client.js.map +7 -0
- package/lib/config-values.js +55 -0
- package/lib/config-values.js.map +1 -0
- package/lib/host/analyze.js +795 -0
- package/lib/host/analyze.js.map +1 -0
- package/lib/host/config.js +81 -0
- package/lib/host/config.js.map +1 -0
- package/lib/host/constants.js +25 -0
- package/lib/host/constants.js.map +1 -0
- package/lib/host/context.js +237 -0
- package/lib/host/context.js.map +1 -0
- package/lib/host/design-skill.js +42 -0
- package/lib/host/design-skill.js.map +1 -0
- package/lib/host/effort.js +239 -0
- package/lib/host/effort.js.map +1 -0
- package/lib/host/filters.js +132 -0
- package/lib/host/filters.js.map +1 -0
- package/lib/host/history-store.js +404 -0
- package/lib/host/history-store.js.map +1 -0
- package/lib/host/http.js +46 -0
- package/lib/host/http.js.map +1 -0
- package/lib/host/messages.js +14 -0
- package/lib/host/messages.js.map +1 -0
- package/lib/host/mic.js +246 -0
- package/lib/host/mic.js.map +1 -0
- package/lib/host/models.js +246 -0
- package/lib/host/models.js.map +1 -0
- package/lib/host/plugin.js +41 -0
- package/lib/host/plugin.js.map +1 -0
- package/lib/host/promote.js +219 -0
- package/lib/host/promote.js.map +1 -0
- package/lib/host/routes.js +237 -0
- package/lib/host/routes.js.map +1 -0
- package/lib/host/sessions.js +181 -0
- package/lib/host/sessions.js.map +1 -0
- package/lib/host/settings-store.js +140 -0
- package/lib/host/settings-store.js.map +1 -0
- package/lib/host/speech.js +320 -0
- package/lib/host/speech.js.map +1 -0
- package/lib/host/tools.js +179 -0
- package/lib/host/tools.js.map +1 -0
- package/lib/host/types.js +2 -0
- package/lib/host/types.js.map +1 -0
- package/lib/index.js +10 -3691
- package/lib/index.js.map +1 -1
- package/lib/prompts.js +1 -1
- package/lib/settings.js +17 -27
- package/lib/settings.js.map +1 -1
- package/lib/types/config-values.d.ts +175 -0
- package/lib/types/host/analyze.d.ts +10 -0
- package/lib/types/host/config.d.ts +147 -0
- package/lib/types/host/constants.d.ts +24 -0
- package/lib/types/host/context.d.ts +41 -0
- package/lib/types/host/design-skill.d.ts +1 -0
- package/lib/types/host/effort.d.ts +61 -0
- package/lib/types/host/filters.d.ts +20 -0
- package/lib/types/host/history-store.d.ts +13 -0
- package/lib/types/host/http.d.ts +8 -0
- package/lib/types/host/messages.d.ts +13 -0
- package/lib/types/host/mic.d.ts +17 -0
- package/lib/types/host/models.d.ts +57 -0
- package/lib/types/host/plugin.d.ts +3 -0
- package/lib/types/host/promote.d.ts +9 -0
- package/lib/types/host/routes.d.ts +14 -0
- package/lib/types/host/sessions.d.ts +14 -0
- package/lib/types/host/settings-store.d.ts +8 -0
- package/lib/types/host/speech.d.ts +23 -0
- package/lib/types/host/tools.d.ts +39 -0
- package/lib/types/host/types.d.ts +89 -0
- package/lib/types/index.d.ts +12 -441
- package/lib/types/prompts.d.ts +1 -1
- package/lib/types/settings.d.ts +1 -1
- package/package.json +31 -21
- package/assets/code.png +0 -0
- package/assets/detail.png +0 -0
- package/assets/quotes.png +0 -0
- package/assets/stage1.png +0 -0
- package/assets/stage2.png +0 -0
- package/assets/translation.png +0 -0
- package/assets/voice-card-light.png +0 -0
- package/assets/voice-inserted.png +0 -0
- package/assets/voice-settings.png +0 -0
- package/assets/voice.png +0 -0
- package/assets/web.png +0 -0
- package/scripts/build-demo-pages.mjs +0 -350
- package/scripts/build-vcard-lab.mjs +0 -834
- package/scripts/build.sh +0 -147
- package/scripts/crop-png.mjs +0 -142
- package/scripts/dump-prompt.mjs +0 -143
- package/scripts/fixtures/fake-mic-probe.sh +0 -9
- package/scripts/gen-star-path.mjs +0 -71
- package/scripts/measure-cost.mjs +0 -251
- package/scripts/smoke-bridge.mjs +0 -365
- package/scripts/smoke-panel.mjs +0 -1903
- package/scripts/smoke-voice.mjs +0 -774
- package/scripts/test-bridge.mjs +0 -412
- package/scripts/test-client.mjs +0 -6175
- package/scripts/test-effort-map.mjs +0 -129
- package/scripts/test-effort-retry.mjs +0 -109
- package/scripts/test-escape-focus.mjs +0 -101
- package/scripts/test-filters.mjs +0 -146
- package/scripts/test-format.mjs +0 -93
- package/scripts/test-guard.mjs +0 -48
- package/scripts/test-mic-idle.mjs +0 -158
- package/scripts/test-model-follow.mjs +0 -193
- package/scripts/test-prompt.mjs +0 -193
- package/scripts/test-route-cache.mjs +0 -138
- package/scripts/test-settings-behavior.mjs +0 -188
- package/scripts/test-settings-host.mjs +0 -48
- package/scripts/test-settings.mjs +0 -329
- package/scripts/test-speech.mjs +0 -220
- package/scripts/test-transcript.mjs +0 -151
- package/src/client/index.js +0 -12580
- package/src/index.ts +0 -4179
- package/src/prompts.ts +0 -144
- package/src/settings.ts +0 -313
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Config } from './config.js';
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
+
/** Owns settings-store state for one plugin instance. */
|
|
5
|
+
export declare function createSettingsStore(ctx: Context, config: Config): {
|
|
6
|
+
loadSettings: () => Promise<void>;
|
|
7
|
+
handleSettings: (req: IncomingMessage, res: ServerResponse) => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Config } from './config.js';
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
+
/**
|
|
5
|
+
* 校验客户端送上来的音频是不是**规范**的 16kHz 单声道 PCM16 WAV。
|
|
6
|
+
*
|
|
7
|
+
* 为什么抠得这么死:这个格式是浏览器端编码器(MediaRecorder → decodeAudioData →
|
|
8
|
+
* OfflineAudioContext 重采样 → 手写 WAV 头)唯一会产出的形状。逐字段对齐之后,
|
|
9
|
+
* "音频不对"就只剩两种可能——客户端版本对不上、或者有人手工构造了这个请求。
|
|
10
|
+
* 光看二进制长度不算数:头里写的采样率/声道/位深必须是那一套,否则识别服务会按
|
|
11
|
+
* 错误的采样率解释这段音频(听起来像快放/慢放),识别结果自然全错。
|
|
12
|
+
*
|
|
13
|
+
* @param audio 完整音频字节
|
|
14
|
+
* @param maxSeconds 允许的最长时长
|
|
15
|
+
* @returns 时长(秒)
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateWave(audio: Buffer, maxSeconds: number): number;
|
|
18
|
+
/** Owns speech state for one plugin instance. */
|
|
19
|
+
export declare function createSpeech(ctx: Context, config: Config): {
|
|
20
|
+
handleSpeech: (req: IncomingMessage, res: ServerResponse) => void;
|
|
21
|
+
handleSpeechTranscribe: (req: IncomingMessage, res: ServerResponse) => void;
|
|
22
|
+
handleSpeechPrepare: (req: IncomingMessage, res: ServerResponse) => void;
|
|
23
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
/**
|
|
4
|
+
* 决定这一轮给模型哪些工具(纯函数,便于单测)。
|
|
5
|
+
*
|
|
6
|
+
* 规则:
|
|
7
|
+
* ① 首选清单里**确实存在**的直接放行;
|
|
8
|
+
* ② 如果首选里的**联网工具一个都不在**(例如没装 free-search 插件),
|
|
9
|
+
* 就把备用清单里存在的补上 —— 否则小窗会变成完全不能联网;
|
|
10
|
+
* ③ 备用只补"联网"这一类,不会顺手把别的东西带进来。
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveToolNames(preferred: string[], fallback: string[], visible: string[]): string[];
|
|
13
|
+
export declare function webFetchUsable(): Promise<{
|
|
14
|
+
usable: boolean;
|
|
15
|
+
sample: string;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* 路径是否落在允许的根目录里(root 为空 = 不设限)。
|
|
19
|
+
*
|
|
20
|
+
* 为什么需要它:read/grep/glob 能读**用户有权读的任何文件**(`~/.ssh/id_rsa`、`.env`、
|
|
21
|
+
* `~/.dsh/settings.yaml`……),而划词的触发源(选中文字/上下文/搜索结果)可能是别人写的。
|
|
22
|
+
* 这里只做词法判断(`resolve` 不跟随符号链接),挡住"顺着一段被注入的文字去读项目外的机密"。
|
|
23
|
+
*/
|
|
24
|
+
export declare function isInsideRoot(root: string, target: string): boolean;
|
|
25
|
+
/** 文件类工具:这些工具的参数里有 path,需要过边界检查。 */
|
|
26
|
+
export declare const FS_TOOL_NAMES: string[];
|
|
27
|
+
/** 工具调用的人类可读描述(给前端状态栏用)。 */
|
|
28
|
+
export declare function describeToolCall(name: string, args: unknown): string;
|
|
29
|
+
/** 从工具结果里抽出:文本长度 / 预览 / 链接(前端只用它拼追问摘要,**不渲染**)。 */
|
|
30
|
+
export declare function digestToolResult(content: ContentBlock[]): {
|
|
31
|
+
chars: number;
|
|
32
|
+
preview: string;
|
|
33
|
+
urls: string[];
|
|
34
|
+
};
|
|
35
|
+
/** 执行一个工具并把结果压成模型可读的内容块(带长度上限)。 */
|
|
36
|
+
export declare function runTool(ctx: Context, name: string, args: unknown, signal: AbortSignal, maxChars: number, agent: unknown): Promise<{
|
|
37
|
+
content: ContentBlock[];
|
|
38
|
+
isError: boolean;
|
|
39
|
+
}>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** 一次请求的入参。 */
|
|
2
|
+
export interface AnalyzeBody {
|
|
3
|
+
text?: unknown;
|
|
4
|
+
context?: unknown;
|
|
5
|
+
label?: unknown;
|
|
6
|
+
title?: unknown;
|
|
7
|
+
url?: unknown;
|
|
8
|
+
/** 当前会话 id(客户端从 ctx.sessions.list 快照取),用于拉取会话背景。 */
|
|
9
|
+
sessionId?: unknown;
|
|
10
|
+
/** 「重新生成」用:为 true 时跳过共享结果缓存。 */
|
|
11
|
+
refresh?: unknown;
|
|
12
|
+
/** 两阶段:'translation'(首轮,仅翻译 + 8 条背景)| 'detail'(按需,详解 + 完整背景)。 */
|
|
13
|
+
stage?: unknown;
|
|
14
|
+
/** 'code' | 'text':选中文字是不是代码(代码走「注释」提示词:代码块 + 逐句注释 + 小结)。 */
|
|
15
|
+
kind?: unknown;
|
|
16
|
+
/** 本会话已用过的工具结果摘要(追问时带上,避免重复联网)。 */
|
|
17
|
+
toolDigest?: unknown;
|
|
18
|
+
/** 小窗对话历史(A′):整段对话的持久化条目。 */
|
|
19
|
+
key?: unknown;
|
|
20
|
+
parts?: unknown;
|
|
21
|
+
pinned?: unknown;
|
|
22
|
+
/** 单次请求的推理档位覆盖(off / low / high / max);不传用插件配置。 */
|
|
23
|
+
effort?: unknown;
|
|
24
|
+
/** 小窗的「模型」控件:显式指定 provider + model(按清单校验,缺省跟随会话默认)。 */
|
|
25
|
+
provider?: unknown;
|
|
26
|
+
model?: unknown;
|
|
27
|
+
/** 网页模式(小窗里的开关):复杂问题默认用网页回答,并注入设计规范。 */
|
|
28
|
+
webAnswer?: unknown;
|
|
29
|
+
/** 客户端上报的当前深浅('dark' | 'light'):网页输出按它选配色。 */
|
|
30
|
+
theme?: unknown;
|
|
31
|
+
/** 追问模式下用户这一轮的问题。 */
|
|
32
|
+
question?: unknown;
|
|
33
|
+
/** 追问模式下的历史轮次:[{ role: 'user' | 'assistant', text }]。 */
|
|
34
|
+
history?: unknown;
|
|
35
|
+
/** 升格为正式会话时的入参。 */
|
|
36
|
+
translation?: unknown;
|
|
37
|
+
detail?: unknown;
|
|
38
|
+
turns?: unknown;
|
|
39
|
+
/** 诊断开关:为 true 时把实际发给模型的提示词回传在 SSE 的 start 事件里(客户端不传)。 */
|
|
40
|
+
debug?: unknown;
|
|
41
|
+
}
|
|
42
|
+
/** 会话背景读取结果。 */
|
|
43
|
+
export interface SessionBackground {
|
|
44
|
+
/** 已格式化的对话记录(时间顺序,最后一条最新)。 */
|
|
45
|
+
transcript: string;
|
|
46
|
+
/** 是否在记录里标出了选中文字所在的消息。 */
|
|
47
|
+
marked: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** 会话背景读取入参。 */
|
|
50
|
+
export interface BackgroundOptions {
|
|
51
|
+
maxMessages: number;
|
|
52
|
+
maxChars: number;
|
|
53
|
+
/** 用于在记录里定位选中位置(归一化后做包含匹配)。 */
|
|
54
|
+
marker: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* ctx.sessionQuery 的宽松视图。
|
|
58
|
+
*
|
|
59
|
+
* · readSurface —— 会话的**消息表面**(对话背景用)。
|
|
60
|
+
* · readSession —— **原始事件**(带 data)。读会话模型必须走它:
|
|
61
|
+
* `model/selection` 在文档里写明是 log-only,"never enters derived model history",
|
|
62
|
+
* 所以它**不会**出现在 readSurface 的 surface 里(实测:用它读到的永远是空)。
|
|
63
|
+
*/
|
|
64
|
+
export interface SessionQueryLike {
|
|
65
|
+
readSurface?: (sessionId: string) => Promise<{
|
|
66
|
+
events?: readonly unknown[];
|
|
67
|
+
}>;
|
|
68
|
+
readSession?: (sessionId: string) => Promise<{
|
|
69
|
+
events?: readonly unknown[];
|
|
70
|
+
}>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* ctx.sessions 的宽松视图 —— 只用来做"会话有没有新事件"的零成本探测。
|
|
74
|
+
*
|
|
75
|
+
* `seq` 是 Session 上的 getter(= 日志长度,每次 append 都会涨),同步读、不碰日志;
|
|
76
|
+
* 拿它跟上次解析时记下的值一比,就知道"结论有没有可能变"(见 liveSeqOf)。
|
|
77
|
+
*/
|
|
78
|
+
export interface SessionsLike {
|
|
79
|
+
get?: (sessionId: string) => {
|
|
80
|
+
seq?: number;
|
|
81
|
+
} | undefined;
|
|
82
|
+
}
|
|
83
|
+
/** 解析出的模型路由。 */
|
|
84
|
+
export interface Route {
|
|
85
|
+
provider: string;
|
|
86
|
+
model: string;
|
|
87
|
+
}
|
|
88
|
+
/** 会话自己记的模型选择(与 Route 同形,单独取名是为了在注释里说清"来源不同")。 */
|
|
89
|
+
export type SessionModel = Route;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,444 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* 症状极具迷惑性:`↗ 升格` 的 HTTP 请求返回 `ok: true`(那时只写进了内存里的会话面),
|
|
14
|
-
* 随后那轮 opener 运行失败、整个 artifact 一个字都没落盘 —— 新会话只剩表头。
|
|
15
|
-
* 离线测试也照样全绿(校验发生在真实内核里,不在构建期),所以另配了
|
|
16
|
-
* scripts/test-format.mjs 钉住这个 shape。
|
|
17
|
-
*
|
|
18
|
-
* 第三方插件的规范形态是 `plugin:<插件名>`:内核 v3→v4 迁移把那种 `plugin` 包装
|
|
19
|
-
* 重写成 `plugin:<完整插件名>`(`producerKind()` 对不在同名表里的插件就是这么算的),
|
|
20
|
-
* 所以这里写的与迁移结果逐字节一致 —— 新旧会话归因相同,且 v3 内核下同样合法
|
|
21
|
-
* (直写的 kind 迁移时原样保留)。
|
|
22
|
-
*/
|
|
23
|
-
export declare const PLUGIN_SOURCE_KIND = "plugin:@yfwu2020/dsh-selection-explain";
|
|
24
|
-
/** 路由注册与模型调用所需的服务。 */
|
|
25
|
-
export declare const inject: string[];
|
|
26
|
-
/** 插件配置。 */
|
|
27
|
-
export interface Config {
|
|
28
|
-
/** 固定 provider 路由;留空 = 跟随主会话(用户在 DSH 里选的默认模型)。 */
|
|
29
|
-
provider: string;
|
|
30
|
-
/** 固定 model id;留空 = 跟随主会话。 */
|
|
31
|
-
model: string;
|
|
32
|
-
/**
|
|
33
|
-
* **追问**单独用的 provider;留空 = 跟首轮/次轮同一个(默认如此)。
|
|
34
|
-
*
|
|
35
|
-
* 为什么要能单独设:首轮/次轮要的是"读懂上下文",追问往往是"快速问一句",
|
|
36
|
-
* 两者对模型的要求不同(一个要准、一个要快)。
|
|
37
|
-
*/
|
|
38
|
-
chatProvider: string;
|
|
39
|
-
/** **追问**单独用的 model id;留空 = 跟首轮/次轮同一个。 */
|
|
40
|
-
chatModel: string;
|
|
41
|
-
/** **次轮详解**的推理档位(off / low / high / max);留空 = 适配器默认。 */
|
|
42
|
-
reasoningEffort: string;
|
|
43
|
-
/** **首轮**(翻译 / 解读 / 注释)的推理档位。 */
|
|
44
|
-
translationReasoningEffort: string;
|
|
45
|
-
historyMaxEntries: number;
|
|
46
|
-
/** 采样温度。 */
|
|
47
|
-
temperature: number;
|
|
48
|
-
/** 输出上限。 */
|
|
49
|
-
maxTokens: number;
|
|
50
|
-
/** 单次调用超时(毫秒)。 */
|
|
51
|
-
timeoutMs: number;
|
|
52
|
-
/** 选中文字长度上限(字符)。 */
|
|
53
|
-
maxSelectionChars: number;
|
|
54
|
-
/** 上下文长度上限(字符)。 */
|
|
55
|
-
maxContextChars: number;
|
|
56
|
-
/** 每分钟最大请求数(本地限流,防止误触发刷爆额度)。 */
|
|
57
|
-
maxRequestsPerMinute: number;
|
|
58
|
-
/** 是否注入当前会话的对话背景(判断指代与前提的关键)。 */
|
|
59
|
-
sessionContext: boolean;
|
|
60
|
-
/** 会话背景最多保留多少条消息(从最新往前取);第二阶段(详解)用这个值。 */
|
|
61
|
-
sessionContextMaxMessages: number;
|
|
62
|
-
/** 第一阶段(仅翻译)用的背景条数:更少 → 首字更快;点「展开详解」时才用上面那个上限。 */
|
|
63
|
-
sessionContextFastMessages: number;
|
|
64
|
-
/** 会话背景字符上限;0 = 不限(默认),只按消息条数取窗口。 */
|
|
65
|
-
sessionContextMaxChars: number;
|
|
66
|
-
/**
|
|
67
|
-
* 引用(❝)上下文:引用文字所在的那一组对话 ± 几组(一组 = 用户消息 + 它的助手回复)。
|
|
68
|
-
* 默认 1 = 上下各一组(需求:至少带上引用所在那一组与上下各一组)。
|
|
69
|
-
*/
|
|
70
|
-
quoteContextRounds: number;
|
|
71
|
-
/** 引用上下文里单条消息的字数上限(超了**围绕引用**截断,不裁掉引用本身)。 */
|
|
72
|
-
quoteContextMaxCharsPerTurn: number;
|
|
73
|
-
/** 引用上下文整段的字数上限(超了丢最早的几组)。 */
|
|
74
|
-
quoteContextMaxChars: number;
|
|
75
|
-
/** 共享结果缓存 TTL(毫秒):同会话+同选中+同局部片段+同背景时直接回放;0 = 关闭。 */
|
|
76
|
-
resultCacheTtlMs: number;
|
|
77
|
-
/** 是否允许解读过程调用工具(联网搜索等)。 */
|
|
78
|
-
tools: boolean;
|
|
79
|
-
/** 允许调用的工具名(逗号分隔);默认只放联网搜索与抓取。 */
|
|
80
|
-
toolNames: string;
|
|
81
|
-
fallbackToolNames: string;
|
|
82
|
-
/** 最多几轮工具调用。 */
|
|
83
|
-
maxToolRounds: number;
|
|
84
|
-
/** 单个工具结果注入模型前的字符上限。 */
|
|
85
|
-
toolResultMaxChars: number;
|
|
86
|
-
/** 文件类工具(read/grep/glob)的读取边界:'' = 会话工作目录,'*' = 不限制,其他 = 该目录 */
|
|
87
|
-
toolReadRoot: string;
|
|
88
|
-
/** 追问(对话小窗)用的推理档位:通常比次轮详解轻,响应更快。 */
|
|
89
|
-
chatReasoningEffort: string;
|
|
90
|
-
/**
|
|
91
|
-
* 侧边栏 HTML 预览里的划词桥(默认开)。
|
|
92
|
-
*
|
|
93
|
-
* 侧边栏的预览是不透明源沙箱 iframe,父页面读不到里面的选区 —— 只有往被预览的
|
|
94
|
-
* 文档里注入一段桥脚本才能划词。代价:预览帧要多一个 `allow-scripts`
|
|
95
|
-
* (仍然**没有** `allow-same-origin`,预览页读不到 GUI 数据),基础预览那份
|
|
96
|
-
* 已清洗过的 HTML 的 CSP 会从 `script-src 'none'` 放宽到 `'unsafe-inline'`。
|
|
97
|
-
* 关掉 = 侧边栏网页里不弹「解读」按钮。
|
|
98
|
-
*/
|
|
99
|
-
bridgeSidebarPreview: boolean;
|
|
100
|
-
/** 是否显示右下角悬浮胶囊(最近一次划词的状态入口)。 */
|
|
101
|
-
pillEnabled: boolean;
|
|
102
|
-
/**
|
|
103
|
-
* 静置多久把胶囊收成小球(毫秒)。
|
|
104
|
-
*
|
|
105
|
-
* 只在**没装费用胶囊**时生效 —— 有费用胶囊时两者并排,收球会让它们错位。
|
|
106
|
-
* 默认 10 秒:短于这个数会显得"刚看一眼就没了",长了又失去"收起来不挡视线"的意义。
|
|
107
|
-
*/
|
|
108
|
-
pillIdleMs: number;
|
|
109
|
-
/**
|
|
110
|
-
* 开麦结束、**一个字都没说**时,直接收起临时输入框。
|
|
111
|
-
*
|
|
112
|
-
* 默认开(2026-10-09 用户指定):等于替用户按了 Esc(带关机动画)。
|
|
113
|
-
* 关掉则回到"卡片留着" —— 一个字没说时可以接着手动打字。
|
|
114
|
-
*
|
|
115
|
-
* 注意"结束"不是"松手那一瞬间":输入法在松手后还会做一次**智能整理**(改写输入框内容),
|
|
116
|
-
* 所以真正动作要等到文字定稿(见客户端的 VOICE_SETTLE_MS)。否则会取消掉马上就要落进来的整理结果。
|
|
117
|
-
*/
|
|
118
|
-
voiceCancelOnSilence: boolean;
|
|
119
|
-
/**
|
|
120
|
-
* 开麦结束、**已经说出文字**时,直接发送(跳过手动点发送键)。
|
|
121
|
-
*
|
|
122
|
-
* 默认开(2026-10-09 用户指定):等于替用户点了发送键。
|
|
123
|
-
* 关掉则回到"先看一眼再点" —— 发送会开小窗、开始一次真实请求,不可逆。
|
|
124
|
-
*
|
|
125
|
-
* 同样要等文字定稿:松手那一刻输入法还没整理完,立刻发送发出去的是没整理的草稿。
|
|
126
|
-
*/
|
|
127
|
-
voiceAutoSend: boolean;
|
|
128
|
-
}
|
|
129
|
-
/** 配置 schema(缺省值即推荐值)。 */
|
|
130
|
-
export declare const Config: z<Schemastery.ObjectS<{
|
|
131
|
-
provider: z<string, string>;
|
|
132
|
-
model: z<string, string>;
|
|
133
|
-
chatProvider: z<string, string>;
|
|
134
|
-
chatModel: z<string, string>;
|
|
135
|
-
reasoningEffort: z<string, string>;
|
|
136
|
-
/** 首轮单独一档:默认关闭思考,优先快速给出翻译、解读或注释。 */
|
|
137
|
-
translationReasoningEffort: z<string, string>;
|
|
138
|
-
/**
|
|
139
|
-
* 小窗对话历史(A′):把整段对话落到插件自己的目录,重划同一个词直接回放。
|
|
140
|
-
* 0 = 关闭历史。只留最近 N 个「划词条目」(每个条目内含它自己的全部追问轮次)。
|
|
141
|
-
*/
|
|
142
|
-
historyMaxEntries: z<number, number>;
|
|
143
|
-
/** 采样温度。**默认 -1 = 不传**(交给供应商默认,与主会话一致)。0~2 之间才真的传。 */
|
|
144
|
-
temperature: z<number, number>;
|
|
145
|
-
/**
|
|
146
|
-
* 单次调用的输出上限(tokens)。**默认 0 = 不限制** —— 不传这个参数,交给模型/供应商自己的上限。
|
|
147
|
-
*
|
|
148
|
-
* 为什么不默认给个数:这是**每次调用**的上限,联网检索后的答案经常要 2~4k tokens,
|
|
149
|
-
* 之前默认 1200 会让回答"悄悄截断在句子中间"(实测);而给死一个更大的数也一样会在别的场景截断。
|
|
150
|
-
* 想限制(控成本/控时延)就填正数,仍然生效。
|
|
151
|
-
*/
|
|
152
|
-
maxTokens: z<number, number>;
|
|
153
|
-
timeoutMs: z<number, number>;
|
|
154
|
-
maxSelectionChars: z<number, number>;
|
|
155
|
-
maxContextChars: z<number, number>;
|
|
156
|
-
maxRequestsPerMinute: z<number, number>;
|
|
157
|
-
sessionContext: z<boolean, boolean>;
|
|
158
|
-
sessionContextMaxMessages: z<number, number>;
|
|
159
|
-
sessionContextFastMessages: z<number, number>;
|
|
160
|
-
sessionContextMaxChars: z<number, number>;
|
|
161
|
-
quoteContextRounds: z<number, number>;
|
|
162
|
-
quoteContextMaxCharsPerTurn: z<number, number>;
|
|
163
|
-
quoteContextMaxChars: z<number, number>;
|
|
164
|
-
resultCacheTtlMs: z<number, number>;
|
|
165
|
-
tools: z<boolean, boolean>;
|
|
166
|
-
/**
|
|
167
|
-
* 工具白名单(逗号分隔)。
|
|
168
|
-
*
|
|
169
|
-
* 默认改用 **free-search 插件**的工具(`advanced_search` / `platform_search`),不再用 `web_search`:
|
|
170
|
-
* 会话里的 `web_search` 是官方 DeepSeek 搜索(复用 @deepseek-ai/dsh-tool-web 的 schema),
|
|
171
|
-
* 而新装的 dsh-free-search 只注册了 advanced_search / platform_search / free_search_test ——
|
|
172
|
-
* 引擎更多(ddg/bing/searxng/anysearch/exa/tavily/keenable/firecrawl/parallel…)、失败自动换引擎、
|
|
173
|
-
* 还支持时间过滤与平台搜索。
|
|
174
|
-
*/
|
|
175
|
-
toolNames: z<string, string>;
|
|
176
|
-
/**
|
|
177
|
-
* **备用**工具清单:只在"首选里的联网工具一个都不在"时才补进来。
|
|
178
|
-
*
|
|
179
|
-
* 场景:没装 free-search 插件(或它没注册工具)时,会话里通常仍有官方 `web_search`;
|
|
180
|
-
* 不补的话小窗会变成完全不能联网。装了 free-search 就完全用不到这一项。
|
|
181
|
-
*/
|
|
182
|
-
fallbackToolNames: z<string, string>;
|
|
183
|
-
maxToolRounds: z<number, number>;
|
|
184
|
-
toolResultMaxChars: z<number, number>;
|
|
185
|
-
toolReadRoot: z<string, string>;
|
|
186
|
-
chatReasoningEffort: z<string, string>;
|
|
187
|
-
/**
|
|
188
|
-
* 侧边栏 HTML 预览里的划词桥。关掉就不往预览帧里注入桥脚本,
|
|
189
|
-
* 侧边栏网页里选中文字不会再弹「解读」。
|
|
190
|
-
*/
|
|
191
|
-
bridgeSidebarPreview: z<boolean, boolean>;
|
|
192
|
-
/** 悬浮胶囊开关(小窗设置页可改)。 */
|
|
193
|
-
pillEnabled: z<boolean, boolean>;
|
|
194
|
-
/** 静置收球时长(毫秒)——默认 10 秒,见 Config 注释。 */
|
|
195
|
-
pillIdleMs: z<number, number>;
|
|
196
|
-
/** 空录音是否收起卡片(默认开,见 Config 注释)。 */
|
|
197
|
-
voiceCancelOnSilence: z<boolean, boolean>;
|
|
198
|
-
/** 有字是否自动发送(默认开,见 Config 注释)。 */
|
|
199
|
-
voiceAutoSend: z<boolean, boolean>;
|
|
200
|
-
}>, Schemastery.ObjectT<{
|
|
201
|
-
provider: z<string, string>;
|
|
202
|
-
model: z<string, string>;
|
|
203
|
-
chatProvider: z<string, string>;
|
|
204
|
-
chatModel: z<string, string>;
|
|
205
|
-
reasoningEffort: z<string, string>;
|
|
206
|
-
/** 首轮单独一档:默认关闭思考,优先快速给出翻译、解读或注释。 */
|
|
207
|
-
translationReasoningEffort: z<string, string>;
|
|
208
|
-
/**
|
|
209
|
-
* 小窗对话历史(A′):把整段对话落到插件自己的目录,重划同一个词直接回放。
|
|
210
|
-
* 0 = 关闭历史。只留最近 N 个「划词条目」(每个条目内含它自己的全部追问轮次)。
|
|
211
|
-
*/
|
|
212
|
-
historyMaxEntries: z<number, number>;
|
|
213
|
-
/** 采样温度。**默认 -1 = 不传**(交给供应商默认,与主会话一致)。0~2 之间才真的传。 */
|
|
214
|
-
temperature: z<number, number>;
|
|
215
|
-
/**
|
|
216
|
-
* 单次调用的输出上限(tokens)。**默认 0 = 不限制** —— 不传这个参数,交给模型/供应商自己的上限。
|
|
217
|
-
*
|
|
218
|
-
* 为什么不默认给个数:这是**每次调用**的上限,联网检索后的答案经常要 2~4k tokens,
|
|
219
|
-
* 之前默认 1200 会让回答"悄悄截断在句子中间"(实测);而给死一个更大的数也一样会在别的场景截断。
|
|
220
|
-
* 想限制(控成本/控时延)就填正数,仍然生效。
|
|
221
|
-
*/
|
|
222
|
-
maxTokens: z<number, number>;
|
|
223
|
-
timeoutMs: z<number, number>;
|
|
224
|
-
maxSelectionChars: z<number, number>;
|
|
225
|
-
maxContextChars: z<number, number>;
|
|
226
|
-
maxRequestsPerMinute: z<number, number>;
|
|
227
|
-
sessionContext: z<boolean, boolean>;
|
|
228
|
-
sessionContextMaxMessages: z<number, number>;
|
|
229
|
-
sessionContextFastMessages: z<number, number>;
|
|
230
|
-
sessionContextMaxChars: z<number, number>;
|
|
231
|
-
quoteContextRounds: z<number, number>;
|
|
232
|
-
quoteContextMaxCharsPerTurn: z<number, number>;
|
|
233
|
-
quoteContextMaxChars: z<number, number>;
|
|
234
|
-
resultCacheTtlMs: z<number, number>;
|
|
235
|
-
tools: z<boolean, boolean>;
|
|
236
|
-
/**
|
|
237
|
-
* 工具白名单(逗号分隔)。
|
|
238
|
-
*
|
|
239
|
-
* 默认改用 **free-search 插件**的工具(`advanced_search` / `platform_search`),不再用 `web_search`:
|
|
240
|
-
* 会话里的 `web_search` 是官方 DeepSeek 搜索(复用 @deepseek-ai/dsh-tool-web 的 schema),
|
|
241
|
-
* 而新装的 dsh-free-search 只注册了 advanced_search / platform_search / free_search_test ——
|
|
242
|
-
* 引擎更多(ddg/bing/searxng/anysearch/exa/tavily/keenable/firecrawl/parallel…)、失败自动换引擎、
|
|
243
|
-
* 还支持时间过滤与平台搜索。
|
|
244
|
-
*/
|
|
245
|
-
toolNames: z<string, string>;
|
|
246
|
-
/**
|
|
247
|
-
* **备用**工具清单:只在"首选里的联网工具一个都不在"时才补进来。
|
|
248
|
-
*
|
|
249
|
-
* 场景:没装 free-search 插件(或它没注册工具)时,会话里通常仍有官方 `web_search`;
|
|
250
|
-
* 不补的话小窗会变成完全不能联网。装了 free-search 就完全用不到这一项。
|
|
251
|
-
*/
|
|
252
|
-
fallbackToolNames: z<string, string>;
|
|
253
|
-
maxToolRounds: z<number, number>;
|
|
254
|
-
toolResultMaxChars: z<number, number>;
|
|
255
|
-
toolReadRoot: z<string, string>;
|
|
256
|
-
chatReasoningEffort: z<string, string>;
|
|
257
|
-
/**
|
|
258
|
-
* 侧边栏 HTML 预览里的划词桥。关掉就不往预览帧里注入桥脚本,
|
|
259
|
-
* 侧边栏网页里选中文字不会再弹「解读」。
|
|
260
|
-
*/
|
|
261
|
-
bridgeSidebarPreview: z<boolean, boolean>;
|
|
262
|
-
/** 悬浮胶囊开关(小窗设置页可改)。 */
|
|
263
|
-
pillEnabled: z<boolean, boolean>;
|
|
264
|
-
/** 静置收球时长(毫秒)——默认 10 秒,见 Config 注释。 */
|
|
265
|
-
pillIdleMs: z<number, number>;
|
|
266
|
-
/** 空录音是否收起卡片(默认开,见 Config 注释)。 */
|
|
267
|
-
voiceCancelOnSilence: z<boolean, boolean>;
|
|
268
|
-
/** 有字是否自动发送(默认开,见 Config 注释)。 */
|
|
269
|
-
voiceAutoSend: z<boolean, boolean>;
|
|
270
|
-
}>>;
|
|
271
|
-
/**
|
|
272
|
-
* 决定这一轮给模型哪些工具(纯函数,便于单测)。
|
|
273
|
-
*
|
|
274
|
-
* 规则:
|
|
275
|
-
* ① 首选清单里**确实存在**的直接放行;
|
|
276
|
-
* ② 如果首选里的**联网工具一个都不在**(例如没装 free-search 插件),
|
|
277
|
-
* 就把备用清单里存在的补上 —— 否则小窗会变成完全不能联网;
|
|
278
|
-
* ③ 备用只补"联网"这一类,不会顺手把别的东西带进来。
|
|
279
|
-
*/
|
|
280
|
-
declare function resolveToolNames(preferred: string[], fallback: string[], visible: string[]): string[];
|
|
281
|
-
/** 会话背景读取结果。 */
|
|
282
|
-
interface SessionBackground {
|
|
283
|
-
/** 已格式化的对话记录(时间顺序,最后一条最新)。 */
|
|
284
|
-
transcript: string;
|
|
285
|
-
/** 是否在记录里标出了选中文字所在的消息。 */
|
|
286
|
-
marked: boolean;
|
|
287
|
-
}
|
|
288
|
-
/** 会话背景读取入参。 */
|
|
289
|
-
interface BackgroundOptions {
|
|
290
|
-
maxMessages: number;
|
|
291
|
-
maxChars: number;
|
|
292
|
-
/** 用于在记录里定位选中位置(归一化后做包含匹配)。 */
|
|
293
|
-
marker: string;
|
|
294
|
-
}
|
|
295
|
-
declare function createThinkFilter(): {
|
|
296
|
-
push: (text: string) => {
|
|
297
|
-
text: string;
|
|
298
|
-
think: string;
|
|
299
|
-
};
|
|
300
|
-
flush: () => {
|
|
301
|
-
text: string;
|
|
302
|
-
think: string;
|
|
303
|
-
};
|
|
304
|
-
};
|
|
305
|
-
/**
|
|
306
|
-
* 宽松判据:开头是**英文盘算**、后面才是**中文答案**。
|
|
307
|
-
* 只用来"记住这个模型在关档会泄漏"(下次自动抬档),**不用来裁剪** ——
|
|
308
|
-
* 裁错了会误删正文,而记错了只是下次少一个档位可选,代价不对称。
|
|
309
|
-
*/
|
|
310
|
-
declare function looksLikeLeakedReasoning(text: string): boolean;
|
|
311
|
-
/**
|
|
312
|
-
* 规范四格 → 当前模型**真实声明**的档位(返回 '' 表示这个模型没有可发的档位)。
|
|
313
|
-
*
|
|
314
|
-
* 规则一条到底(对 `off>low>high>max` 这类 4 档模型恰好是恒等映射):
|
|
315
|
-
* · 关 → 声明里**最弱**的那档(模型没有 off 这类档时,就是它"能关到"的最小思考)
|
|
316
|
-
* · 最高 → 声明里**最强**的那档
|
|
317
|
-
* · 低/高 → 在整条刻度上取 1/3、2/3 处**最近的档**;候选**排除两端**(最弱那档留给「关」、
|
|
318
|
-
* 最强那档留给「最高」,四个格子于是各有落点),并保证 关 ≤ 低 ≤ 高 ≤ 最高 单调;
|
|
319
|
-
* 同样近时「低」取更浅的、「高」取更深的 —— 低要省、高要深。
|
|
320
|
-
*
|
|
321
|
-
* ⚠️ 这里**没有**任何按模型写死的表:输入只有"这个模型自己声明的档位列表"。
|
|
322
|
-
* 名字认得出来(off/low/high/max、minimal、xhigh…)就用名字的深度刻度;认不出来
|
|
323
|
-
* (别的 adapter 可能叫 a/b/c、tier1/tier2,或者干脆是数字)就按**它在声明里的位置**插值 ——
|
|
324
|
-
* 所以任何用户换任何模型都能落位,插件作者没见过那个模型也能映射。
|
|
325
|
-
* 为什么不让「低/高」也去抢最弱那档:那两个格子表达的是"开着思考、但别太深",
|
|
326
|
-
* 落到"关"那一档等于**把用户要的思考关掉**;只有「关」该动那一档。
|
|
327
|
-
* 只有一档可发时(如 kimi-k3 只有 max),四格都落到它 —— 模型没有别的选择。
|
|
328
|
-
*
|
|
329
|
-
* 返回 '' 表示"这个模型没有可发的档位"(声明为空),调用方据此**不带** reasoningEffort。
|
|
330
|
-
*/
|
|
331
|
-
declare function mapEffortToModel(declared: Array<{
|
|
332
|
-
id: string;
|
|
333
|
-
name?: string;
|
|
334
|
-
}>, canonical: string): string;
|
|
335
|
-
/**
|
|
336
|
-
* 一个模型的四格映射(设置页给用户看的就是它;请求时也走这份算)。
|
|
337
|
-
* 返回空串的格子表示"没有可发的档位"(模型不支持推理时四个格子都是空串)。
|
|
338
|
-
*/
|
|
339
|
-
declare function effortMapOf(declared: Array<{
|
|
340
|
-
id: string;
|
|
341
|
-
name?: string;
|
|
342
|
-
}>): Record<string, string>;
|
|
343
|
-
/**
|
|
344
|
-
* 这条上游错误是不是"**我们发的这个档位**不被接受"。
|
|
345
|
-
*
|
|
346
|
-
* ⚠️ 判据必须窄。免费/预览端点的上游会**偶发**返回
|
|
347
|
-
* `Reasoning is mandatory for this endpoint and cannot be disabled.` ——
|
|
348
|
-
* 2026-10-09 实测(`opencode-go/step-5-preview-free`,交错发送排除时间漂移):
|
|
349
|
-
* · effort=low 成功 5/8;effort=high 成功 5/8 —— **同一档位时好时坏,档位不是变量**;
|
|
350
|
-
* · 对照模型 `longcat-2.5-preview-free` 6/6 成功(连 off 都收)。
|
|
351
|
-
* 所以只认"明确说这个档位无效"的措辞;"必须开推理"另有一条判据
|
|
352
|
-
* (见 looksLikeReasoningRequired,只在**我们发的是关档**时才算数)。
|
|
353
|
-
* 把偶发失败当成"档位不支持"会连锁出三个错:给用户一句错诊断、把失败永久记进
|
|
354
|
-
* noOffRoutes(以后再也不发这个档)、清掉用户选的档位。
|
|
355
|
-
*/
|
|
356
|
-
declare function looksLikeUnsupportedTier(message: string): boolean;
|
|
357
|
-
/** 上游要求"必须开推理"——只有在**我们这次把推理关掉**(发的 off)时,这句才是冲我们来的。 */
|
|
358
|
-
declare function looksLikeReasoningRequired(message: string): boolean;
|
|
359
|
-
/**
|
|
360
|
-
* 换一个"没试过的"档位(重试用)。
|
|
361
|
-
*
|
|
362
|
-
* 为什么**绝不能省略档位**(老代码就是省略):省略 = 请求里不带 reasoning,
|
|
363
|
-
* 对"必须开推理"的端点等于把推理关掉 —— 实测 20 次这样的重试 **0 次成功**,
|
|
364
|
-
* 而同一档位首发成功率约 60%。省略比"发一个可能不被接受的档"更糟。
|
|
365
|
-
*
|
|
366
|
-
* 顺序:模型自己声明的 defaultEffort → 沿档位阶梯往上走一格(离"关"越远越安全)。
|
|
367
|
-
* 返回空串表示"没档位可换了",调用方就不重试。
|
|
368
|
-
*/
|
|
369
|
-
declare function pickNextEffort(declared: string[], defaultEffort: string | null | undefined, rejected: string, tried: Set<string>): string;
|
|
370
|
-
declare function splitLeakedReasoning(text: string): {
|
|
371
|
-
prefix: string;
|
|
372
|
-
rest: string;
|
|
373
|
-
};
|
|
374
|
-
/**
|
|
375
|
-
* 校验客户端送上来的音频是不是**规范**的 16kHz 单声道 PCM16 WAV。
|
|
376
|
-
*
|
|
377
|
-
* 为什么抠得这么死:这个格式是浏览器端编码器(MediaRecorder → decodeAudioData →
|
|
378
|
-
* OfflineAudioContext 重采样 → 手写 WAV 头)唯一会产出的形状。逐字段对齐之后,
|
|
379
|
-
* "音频不对"就只剩两种可能——客户端版本对不上、或者有人手工构造了这个请求。
|
|
380
|
-
* 光看二进制长度不算数:头里写的采样率/声道/位深必须是那一套,否则识别服务会按
|
|
381
|
-
* 错误的采样率解释这段音频(听起来像快放/慢放),识别结果自然全错。
|
|
382
|
-
*
|
|
383
|
-
* @param audio 完整音频字节
|
|
384
|
-
* @param maxSeconds 允许的最长时长
|
|
385
|
-
* @returns 时长(秒)
|
|
386
|
-
*/
|
|
387
|
-
export declare function validateWave(audio: Buffer, maxSeconds: number): number;
|
|
388
|
-
/**
|
|
389
|
-
* 路径是否落在允许的根目录里(root 为空 = 不设限)。
|
|
390
|
-
*
|
|
391
|
-
* 为什么需要它:read/grep/glob 能读**用户有权读的任何文件**(`~/.ssh/id_rsa`、`.env`、
|
|
392
|
-
* `~/.dsh/settings.yaml`……),而划词的触发源(选中文字/上下文/搜索结果)可能是别人写的。
|
|
393
|
-
* 这里只做词法判断(`resolve` 不跟随符号链接),挡住"顺着一段被注入的文字去读项目外的机密"。
|
|
394
|
-
*/
|
|
395
|
-
export declare function isInsideRoot(root: string, target: string): boolean;
|
|
396
|
-
/**
|
|
397
|
-
* 把会话的当前模型界面整理成「会话背景」文本。
|
|
398
|
-
*
|
|
399
|
-
* 只保留**真实对话**:用户真正发的话(source.kind === 'user')与助手回复的正文。
|
|
400
|
-
* 三类内容一律剔除,否则会把有效窗口挤没(实测:430 条 surface 事件里绝大多数是
|
|
401
|
-
* 工具调用/结果,且 harness 注入的 system-reminder 单条可达 1.2 万字):
|
|
402
|
-
* - tool/result 与纯工具调用的助手步骤(无正文)
|
|
403
|
-
* - system/message(系统提示词)
|
|
404
|
-
* - source.kind !== 'user' 的用户角色消息(运行环境快照、skill 目录等 harness 注入)
|
|
405
|
-
*/
|
|
406
|
-
export declare function transcriptOf(events: readonly unknown[], options: BackgroundOptions): SessionBackground;
|
|
407
|
-
/** 引用上下文的结果。 */
|
|
408
|
-
export interface QuoteContext {
|
|
409
|
-
/** 「用户:…/助手:…」逐行拼好的上下文(引用部分用【】标出);没命中时为空串。 */
|
|
410
|
-
transcript: string;
|
|
411
|
-
/** 引用文字是否在会话里定位到了(没定位到 → 客户端退回自己的局部上下文)。 */
|
|
412
|
-
matched: boolean;
|
|
413
|
-
/** 带进来的对话组数(一组 = 一条用户消息 + 它的助手回复)。 */
|
|
414
|
-
rounds: number;
|
|
415
|
-
}
|
|
416
|
-
/** 引用上下文的窗口与长度(默认值:上下各一组、单条 2000 字、总共 6000 字)。 */
|
|
417
|
-
export interface QuoteContextOptions {
|
|
418
|
-
/** 引用前后各取几组对话(默认 1)。 */
|
|
419
|
-
roundsAround?: number;
|
|
420
|
-
/** 单条消息的字数上限(超出时**围绕引用**截断,别把引用本身裁掉)。 */
|
|
421
|
-
maxCharsPerTurn?: number;
|
|
422
|
-
/** 整段上下文的字数上限(超出时丢最早的那几组)。 */
|
|
423
|
-
maxChars?: number;
|
|
424
|
-
}
|
|
425
|
-
/**
|
|
426
|
-
* **引用上下文**:引用文字所在的那一组对话 ± N 组(一组 = 一条用户消息 + 它的助手回复)。
|
|
427
|
-
*
|
|
428
|
-
* 与 `transcriptOf`(解读用的会话背景)的区别,两条都是为引用量身定的:
|
|
429
|
-
* ① 窗口是**锚点两侧** —— 引用常常是"上面那句"和"下面那句"的对照,只有上文不够;
|
|
430
|
-
* ② 按**轮**取整 —— 上下各至少一整组(用户消息 + AI 回复),不会切在半个回合上。
|
|
431
|
-
* 噪音过滤与 `transcriptOf` 完全一致(工具调用/结果、系统提示、harness 注入一律不进)。
|
|
432
|
-
*/
|
|
433
|
-
export declare function quoteContextOf(events: readonly unknown[], marker: string, options?: QuoteContextOptions): QuoteContext;
|
|
434
|
-
/** 注册路由、解析模型路由、转发 LLM 流。 */
|
|
435
|
-
export declare function apply(ctx: Context, rawConfig: Config): void;
|
|
436
|
-
/** 类型引用(供声明文件 re-export,避免仅用于类型增强的 import 被判为未使用)。 */
|
|
437
|
-
export type { WebServer };
|
|
438
|
-
/**
|
|
439
|
-
* 纯函数内部件,仅供单测直接调用(Cordis 只用 default export,多这几个具名导出没有副作用)。
|
|
440
|
-
* 这三个都是"流式文本手术刀",靠真实请求验证会被模型的随机发挥带偏,必须能确定性单测。
|
|
441
|
-
*/
|
|
1
|
+
/** Public DSH plugin entry; implementation lives in host/. */
|
|
2
|
+
export { name, inject, PLUGIN_SOURCE_KIND } from './host/constants.js';
|
|
3
|
+
export { Config } from './host/config.js';
|
|
4
|
+
export { apply } from './host/plugin.js';
|
|
5
|
+
export { validateWave } from './host/speech.js';
|
|
6
|
+
export { isInsideRoot } from './host/tools.js';
|
|
7
|
+
export { transcriptOf, quoteContextOf } from './host/context.js';
|
|
8
|
+
export type { QuoteContext, QuoteContextOptions } from './host/context.js';
|
|
9
|
+
export type { WebServer } from '@deepseek-ai/dsh-host-webserver';
|
|
10
|
+
import { createThinkFilter, splitLeakedReasoning, looksLikeLeakedReasoning } from './host/filters.js';
|
|
11
|
+
import { resolveToolNames } from './host/tools.js';
|
|
12
|
+
import { looksLikeUnsupportedTier, looksLikeReasoningRequired, pickNextEffort, mapEffortToModel, effortMapOf } from './host/effort.js';
|
|
442
13
|
export declare const __internals: {
|
|
443
14
|
createThinkFilter: typeof createThinkFilter;
|
|
444
15
|
splitLeakedReasoning: typeof splitLeakedReasoning;
|
package/lib/types/prompts.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* 改动提示词的注意事项:
|
|
11
11
|
* · 结构契约由客户端解析(按 `## 翻译` / `## 详解` 标题切分),改标题会同时影响渲染;
|
|
12
|
-
* ·
|
|
12
|
+
* · tests/unit/prompt.test.mjs 里有"提示词契约测试"——删掉关键约束会直接 FAIL;
|
|
13
13
|
* · 想知道模型**实际收到**什么(含 harness 注入与会话背景拼接结果),跑
|
|
14
14
|
* `node scripts/dump-prompt.mjs --all`(需要 DSH 正在运行)。
|
|
15
15
|
*/
|
package/lib/types/settings.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* · 小窗设置页要渲染 20+ 个字段,字段的标题 / 说明 / 单位 / 边界**必须**与 host 的
|
|
6
6
|
* 校验规则是同一份数据 —— 分两处写迟早会漂(UI 说 1~600,host 却按 1~200 截断)。
|
|
7
7
|
* 所以 GET /settings 直接把这份 spec 发给客户端,客户端只负责画,不做业务判断。
|
|
8
|
-
* · 纯数据 +
|
|
8
|
+
* · 纯数据 + 纯函数,仅依赖共享配置,不 import cordis / node,单测可以直接跑(见 tests/unit/settings.test.mjs)。
|
|
9
9
|
*
|
|
10
10
|
* 分组是**导航结构**,不是装饰:20+ 项平铺会淹没用户,按"用户想去哪类事"分 6 组。
|
|
11
11
|
*/
|