@yfwu2020/dsh-selection-explain 0.13.0 → 0.14.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 +3 -3
- package/lib/client.js +11899 -11398
- package/lib/client.js.map +4 -4
- package/lib/host/analyze-conclusion.js +115 -0
- package/lib/host/analyze-conclusion.js.map +1 -0
- package/lib/host/analyze-execution-types.js +2 -0
- package/lib/host/analyze-execution-types.js.map +1 -0
- package/lib/host/analyze-execution.js +166 -0
- package/lib/host/analyze-execution.js.map +1 -0
- package/lib/host/analyze-history.js +110 -0
- package/lib/host/analyze-history.js.map +1 -0
- package/lib/host/analyze-messages.js +95 -0
- package/lib/host/analyze-messages.js.map +1 -0
- package/lib/host/analyze-output.js +69 -0
- package/lib/host/analyze-output.js.map +1 -0
- package/lib/host/analyze-prompt.js +110 -0
- package/lib/host/analyze-prompt.js.map +1 -0
- package/lib/host/analyze-request.js +129 -0
- package/lib/host/analyze-request.js.map +1 -0
- package/lib/host/analyze-round.js +121 -0
- package/lib/host/analyze-round.js.map +1 -0
- package/lib/host/analyze-tool-execution.js +98 -0
- package/lib/host/analyze-tool-execution.js.map +1 -0
- package/lib/host/analyze-tools.js +79 -0
- package/lib/host/analyze-tools.js.map +1 -0
- package/lib/host/analyze-types.js +2 -0
- package/lib/host/analyze-types.js.map +1 -0
- package/lib/host/analyze.js +30 -977
- package/lib/host/analyze.js.map +1 -1
- package/lib/host/native-probe.js +66 -0
- package/lib/host/native-probe.js.map +1 -0
- package/lib/host/plugin.js +9 -10
- package/lib/host/plugin.js.map +1 -1
- package/lib/host/promote-seed.js +111 -0
- package/lib/host/promote-seed.js.map +1 -0
- package/lib/host/promote.js +53 -153
- package/lib/host/promote.js.map +1 -1
- package/lib/host/shot-capture.js +322 -0
- package/lib/host/shot-capture.js.map +1 -0
- package/lib/host/shot-geometry.js +183 -0
- package/lib/host/shot-geometry.js.map +1 -0
- package/lib/host/shot-platform.js +208 -0
- package/lib/host/shot-platform.js.map +1 -0
- package/lib/host/shot-service.js +127 -0
- package/lib/host/shot-service.js.map +1 -0
- package/lib/host/shot-types.js +5 -0
- package/lib/host/shot-types.js.map +1 -0
- package/lib/host/shot.js +117 -949
- package/lib/host/shot.js.map +1 -1
- package/lib/types/host/analyze-conclusion.d.ts +3 -0
- package/lib/types/host/analyze-execution-types.d.ts +54 -0
- package/lib/types/host/analyze-execution.d.ts +3 -0
- package/lib/types/host/analyze-history.d.ts +41 -0
- package/lib/types/host/analyze-messages.d.ts +15 -0
- package/lib/types/host/analyze-output.d.ts +8 -0
- package/lib/types/host/analyze-prompt.d.ts +15 -0
- package/lib/types/host/analyze-request.d.ts +28 -0
- package/lib/types/host/analyze-round.d.ts +7 -0
- package/lib/types/host/analyze-tool-execution.d.ts +4 -0
- package/lib/types/host/analyze-tools.d.ts +15 -0
- package/lib/types/host/analyze-types.d.ts +13 -0
- package/lib/types/host/analyze.d.ts +4 -4
- package/lib/types/host/native-probe.d.ts +10 -0
- package/lib/types/host/promote-seed.d.ts +24 -0
- package/lib/types/host/shot-capture.d.ts +11 -0
- package/lib/types/host/shot-geometry.d.ts +37 -0
- package/lib/types/host/shot-platform.d.ts +11 -0
- package/lib/types/host/shot-service.d.ts +17 -0
- package/lib/types/host/shot-types.d.ts +105 -0
- package/lib/types/host/shot.d.ts +14 -71
- package/native/window-list.c +139 -0
- package/package.json +2 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createUserMessage, ReasoningEffortId } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { name } from './constants.js';
|
|
3
|
+
import { createThinkFilter, splitLeakedReasoning } from './filters.js';
|
|
4
|
+
import { sse } from './http.js';
|
|
5
|
+
import { systemMessageOf } from './messages.js';
|
|
6
|
+
/** Recover a final answer from tool digests when normal rounds produced no body text. */
|
|
7
|
+
export async function concludeAnalyze(env, state, roundEffort) {
|
|
8
|
+
const { deps, request, tools, prompt, messages, res, controller } = env;
|
|
9
|
+
const { ctx, config, models } = deps;
|
|
10
|
+
const { route, question } = request;
|
|
11
|
+
const { sessionId, toolSchemas } = tools;
|
|
12
|
+
const { systemPrompt, routeKey } = prompt;
|
|
13
|
+
const { checkedMessages, baseMessage, openingMessages } = messages;
|
|
14
|
+
// 收尾轮常常"只吐一段工具调用、不写正文"(实测「今天的新闻」一个字都没有)。
|
|
15
|
+
// 这里自己补结论轮:**不重放工具调用链**,而是把结果写成一段自包含的提示 ——
|
|
16
|
+
// 重放消息链的方式实测也不稳(模型面对 tool-call 历史仍可能继续吐工具调用)。
|
|
17
|
+
state.conclusionInfo.tried = true;
|
|
18
|
+
sse(res, { type: 'notice', code: 'conclusion-retry', text: '查询已完成,正在整理结论…' });
|
|
19
|
+
const conclusionUser = [
|
|
20
|
+
'【补充结论】',
|
|
21
|
+
// ⚠️ **必须带上用户这一轮问的是什么**:这一段是最终正文的来源,而它以前只有
|
|
22
|
+
// 「选区块 + 检索资料 + 请给出最终答案」—— 模型看不到问题,就只能顺着选中文字写。
|
|
23
|
+
// 实测症状:问"搜索今天的AI新闻。",正文却在解释选区那个词(如 diagLog / exit)。
|
|
24
|
+
// 特别是收尾轮也带上工具之后(照主会话的做法),正文**每次都**由这里产出,
|
|
25
|
+
// 缺了问题就等于每次都答非所问。
|
|
26
|
+
question ? `【用户这一轮的问题】(这就是你要回答的对象)\n${question}` : '',
|
|
27
|
+
'',
|
|
28
|
+
'【已经查到的资料】',
|
|
29
|
+
...state.toolDigestLines.slice(0, 12),
|
|
30
|
+
'',
|
|
31
|
+
'请**直接回答上面那条「用户这一轮的问题」**:结论先行、必要处带来源链接。',
|
|
32
|
+
'不要复述选中文字,也不要解释它是什么 —— 除非问题问的就是它。',
|
|
33
|
+
'不要再请求工具,不要输出任何工具调用格式,也不要写"我先看看""让我核对一下"这类过程。',
|
|
34
|
+
].join('\n');
|
|
35
|
+
// 先按当前档位试一次;空则**换一个档位**再试(同一档重发没意义)。
|
|
36
|
+
// 以前这里写死 `'off'`:对"必须开推理"的端点(noOffRoutes 里的那些)等于注定失败一轮 ——
|
|
37
|
+
// 用户看到的"工具查询完成了,但模型没有产出正文"就常有它一份。
|
|
38
|
+
const conclusionEfforts = [
|
|
39
|
+
roundEffort,
|
|
40
|
+
models.nextEffortFor(routeKey, roundEffort, new Set(roundEffort ? [roundEffort] : [])),
|
|
41
|
+
].filter((id) => id.length > 0);
|
|
42
|
+
for (const attemptEffort of conclusionEfforts) {
|
|
43
|
+
if (state.answer.trim().length > 0)
|
|
44
|
+
break;
|
|
45
|
+
state.conclusionInfo.rounds += 1;
|
|
46
|
+
try {
|
|
47
|
+
const resume = ctx.llm.stream({
|
|
48
|
+
provider: route.provider,
|
|
49
|
+
model: route.model,
|
|
50
|
+
...(sessionId ? { sessionId: sessionId } : {}),
|
|
51
|
+
system: undefined,
|
|
52
|
+
// 工具**依然带着**(照主会话:任何一轮都不摘工具)。
|
|
53
|
+
// 以前这一轮不带工具,模型要调工具时只能退回文本层 —— 那正是正文里出现
|
|
54
|
+
// DSML / ds_safety_tool_call 标记的唯一来源。带上之后它走协议层,正文就是正文。
|
|
55
|
+
...(toolSchemas.length > 0 ? { tools: toolSchemas } : {}),
|
|
56
|
+
messages: checkedMessages([
|
|
57
|
+
systemMessageOf(systemPrompt, name),
|
|
58
|
+
baseMessage, ...openingMessages,
|
|
59
|
+
createUserMessage({ source: { kind: 'user' }, content: [...state.recoveredMaterialBlocks, { type: 'text', text: conclusionUser }] }),
|
|
60
|
+
]),
|
|
61
|
+
...(config.temperature >= 0 ? { temperature: config.temperature } : {}),
|
|
62
|
+
...(config.maxTokens > 0 ? { maxTokens: config.maxTokens } : {}),
|
|
63
|
+
...(attemptEffort ? { reasoningEffort: ReasoningEffortId(attemptEffort) } : {}),
|
|
64
|
+
signal: controller.signal,
|
|
65
|
+
});
|
|
66
|
+
const thinkAgain = createThinkFilter();
|
|
67
|
+
for await (const chunk of resume) {
|
|
68
|
+
if (chunk.type === 'text-delta') {
|
|
69
|
+
const part = thinkAgain.push(chunk.text);
|
|
70
|
+
if (part.think)
|
|
71
|
+
sse(res, { type: 'thought', text: part.think });
|
|
72
|
+
const text = part.text;
|
|
73
|
+
if (text) {
|
|
74
|
+
state.chars += text.length;
|
|
75
|
+
state.answer += text;
|
|
76
|
+
state.conclusionInfo.chars += text.length;
|
|
77
|
+
sse(res, { type: 'delta', text: text });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else if (chunk.type === 'usage') {
|
|
81
|
+
state.usage = chunk.usage;
|
|
82
|
+
}
|
|
83
|
+
else if (chunk.type === 'finish') {
|
|
84
|
+
if (chunk.reason.kind === 'error') {
|
|
85
|
+
state.conclusionInfo.error = chunk.reason.failure?.message ?? '模型调用失败';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const tail = thinkAgain.flush();
|
|
90
|
+
if (tail.think)
|
|
91
|
+
sse(res, { type: 'thought', text: tail.think });
|
|
92
|
+
if (tail.text) {
|
|
93
|
+
state.chars += tail.text.length;
|
|
94
|
+
state.answer += tail.text;
|
|
95
|
+
state.conclusionInfo.chars += tail.text.length;
|
|
96
|
+
sse(res, { type: 'delta', text: tail.text });
|
|
97
|
+
}
|
|
98
|
+
// 结论轮也可能把"英文核对过程"写进正文:一律按泄漏裁一次
|
|
99
|
+
const leaked = splitLeakedReasoning(state.answer);
|
|
100
|
+
if (leaked.prefix) {
|
|
101
|
+
state.answer = leaked.rest;
|
|
102
|
+
state.chars = state.answer.length;
|
|
103
|
+
sse(res, { type: 'strip', text: leaked.prefix });
|
|
104
|
+
sse(res, { type: 'notice', code: 'reasoning-leak', text: '已去掉模型写进正文的核对过程' });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error?.code === 'context-capacity')
|
|
109
|
+
throw error;
|
|
110
|
+
state.conclusionInfo.error = String(error?.message ?? error);
|
|
111
|
+
ctx.logger?.warn?.(`[${name}] 结论轮失败:${state.conclusionInfo.error}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=analyze-conclusion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-conclusion.js","sourceRoot":"","sources":["../../src/host/analyze-conclusion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-execution-types.js","sourceRoot":"","sources":["../../src/host/analyze-execution-types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { EFFORT_LABEL, looksLikeReasoningRequired, looksLikeUnsupportedTier } from './effort.js';
|
|
3
|
+
import { looksLikeLeakedReasoning, splitLeakedReasoning } from './filters.js';
|
|
4
|
+
import { looksLikeAttachmentFailure } from './history-attachments.js';
|
|
5
|
+
import { sse } from './http.js';
|
|
6
|
+
import { concludeAnalyze } from './analyze-conclusion.js';
|
|
7
|
+
import { finishAnalyzeOutput } from './analyze-output.js';
|
|
8
|
+
import { streamAnalyzeRound } from './analyze-round.js';
|
|
9
|
+
import { executeAnalyzeTools } from './analyze-tool-execution.js';
|
|
10
|
+
/** Coordinate rounds and retries. History attachment recovery always precedes effort retries. */
|
|
11
|
+
export async function executeAnalyze(env) {
|
|
12
|
+
const { deps, request, tools, prompt, messages, res } = env;
|
|
13
|
+
const { ctx, config, models } = deps;
|
|
14
|
+
const { isChat, titleOnly, history } = request;
|
|
15
|
+
const { toolSchemas } = tools;
|
|
16
|
+
const { sentEffort, offSlotEffort, routeKey, isShot } = prompt;
|
|
17
|
+
const { memoryMessages, questionContent } = messages;
|
|
18
|
+
const { clientClosedEarly } = env;
|
|
19
|
+
const state = {
|
|
20
|
+
chars: 0, errored: false, usage: null, answer: '', toolMessages: [], recoveredMaterialBlocks: [],
|
|
21
|
+
toolContextTokens: 0, toolCalls: 0, errorMessage: '', toolDigestLines: [], roundDiag: [],
|
|
22
|
+
conclusionInfo: { tried: false, chars: 0, rounds: 0, error: '' },
|
|
23
|
+
};
|
|
24
|
+
const toolRounds = config.maxToolRounds;
|
|
25
|
+
// 档位被上游拒绝时(400/401/500)重试一次:清单里声明的档位是**建议值**,
|
|
26
|
+
// 实测很多模型并不接受 max(qwen3.7-max 直接 400、minimax-m2.7/gpt-5.6-luna 500)。
|
|
27
|
+
//
|
|
28
|
+
// 以前这里限定了 `isChat && bodyEffort.length > 0` —— 只有追问、且客户端显式传了档位才重试。
|
|
29
|
+
// 于是**首轮**(档位来自配置、默认 off)撞上不吃 off 的模型时无人兜底,整个划词解读全挂。
|
|
30
|
+
// 现在按"这一轮实际在发显式档位"判,三种轮次一视同仁。
|
|
31
|
+
//
|
|
32
|
+
// 2026-10-09 改:重试**不再"去掉档位"**,而是换一个没试过的档(见 nextEffortFor)。
|
|
33
|
+
// 老代码对非 off 档的重试是 `roundEffort = ''`(省略 reasoning),
|
|
34
|
+
// 而省略对"必须开推理"的端点就是关掉推理 —— 实测 20 次重试 0 次成功。
|
|
35
|
+
// 同时给两次机会:上游偶发失败约一半,两次能把成功率抬到 ~90%(代价是多一次往返)。
|
|
36
|
+
const EFFORT_RETRY_LIMIT = 2;
|
|
37
|
+
// 重试与"泄漏检查"都看**真正发出去**的那个档位(sentEffort,映射之后的值):
|
|
38
|
+
// 规范档位是"关"、但这个模型的关档叫 none/minimal 时,检查的必须是发出去的那个。
|
|
39
|
+
let effortRetries = sentEffort.length > 0 ? EFFORT_RETRY_LIMIT : 0;
|
|
40
|
+
const triedEfforts = new Set(sentEffort ? [sentEffort] : []);
|
|
41
|
+
const firstSentEffort = sentEffort;
|
|
42
|
+
let roundEffort = sentEffort;
|
|
43
|
+
const effectiveToolRounds = titleOnly ? 0 : toolRounds;
|
|
44
|
+
for (let round = 0; round <= effectiveToolRounds; round += 1) {
|
|
45
|
+
const wrapUp = round === effectiveToolRounds;
|
|
46
|
+
const { assembler, roundText } = await streamAnalyzeRound(env, state, round, wrapUp, roundEffort);
|
|
47
|
+
if (state.errored) {
|
|
48
|
+
// 附件读不回来(对象仓里的字节被清理/损坏):把**历史**里的附件全降级成文字再试一次。
|
|
49
|
+
// 这是持久化带来的新故障面 —— 引用的寿命超过了那一轮,字节却不一定还在。
|
|
50
|
+
//
|
|
51
|
+
// ⚠️ 必须排在**换档重试前面**:换档是冲着"上游不认这个推理档"去的,
|
|
52
|
+
// 对"附件读不到"毫无意义 —— 排后面的话会先白烧两次模型调用(实测事件序列就是
|
|
53
|
+
// upstream-retry → upstream-retry → attachments-dropped),还会把档位无谓地换掉。
|
|
54
|
+
if (roundText.length === 0 && history.historyHadAttachments && !history.historyDropped && looksLikeAttachmentFailure(state.errorMessage, state.errorCode)) {
|
|
55
|
+
history.historyDropped = true;
|
|
56
|
+
history.historyImages = { kept: 0, omitted: 0, files: 0 };
|
|
57
|
+
messages.openingMessages = [
|
|
58
|
+
...memoryMessages,
|
|
59
|
+
...history.buildHistoryMessages(),
|
|
60
|
+
...(isShot ? [] : [createUserMessage({ source: { kind: 'user' }, content: questionContent })]),
|
|
61
|
+
];
|
|
62
|
+
// 历史附件被丢掉了 → 名单跟着缩小(只放"还看得见的"那些)
|
|
63
|
+
history.attachedPaths = history.collectAttachedPaths(ctx);
|
|
64
|
+
state.errored = false;
|
|
65
|
+
sse(res, {
|
|
66
|
+
type: 'notice',
|
|
67
|
+
code: 'attachments-dropped',
|
|
68
|
+
text: '历史里的附件已经读不回来了(可能被清理过),这一轮先不带上它,其余照常',
|
|
69
|
+
});
|
|
70
|
+
round -= 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// 一个字都没吐出来 → 可以安全重试**同一轮**(保守:已经吐出正文的失败不重试,
|
|
74
|
+
// 免得把半截答案丢掉)。重试换一个没试过的档位,而不是把档位去掉。
|
|
75
|
+
if (roundText.length === 0 && effortRetries > 0) {
|
|
76
|
+
const rejected = roundEffort;
|
|
77
|
+
const next = models.nextEffortFor(routeKey, rejected, triedEfforts);
|
|
78
|
+
if (next) {
|
|
79
|
+
effortRetries -= 1;
|
|
80
|
+
triedEfforts.add(next);
|
|
81
|
+
// 只有"我们发的这个档位确实不被接受"才值得记成事实:
|
|
82
|
+
// · 发的是关档 + 上游说"必须开推理" → 这个 route 不吃关档,记下来;
|
|
83
|
+
// · 发的是开着的档(low/high/max)+ 上游还在说"推理不能关" → **这句不是冲我们来的**
|
|
84
|
+
// (我们没关它),是上游偶发抽风(实测同档位 5/8 成功)。这种情况不记、不诊断,
|
|
85
|
+
// 只如实说"上游返回了错误,已换档重试"。
|
|
86
|
+
// "必须开推理"这句只有在我们发的是**「关」那一格对应的真实档位**时才算数
|
|
87
|
+
// (模型没有 off、关档落在 minimal/low 上时,字符串比较会漏判)
|
|
88
|
+
const rejectedOffSlot = rejected === offSlotEffort;
|
|
89
|
+
const tierIssue = rejectedOffSlot
|
|
90
|
+
? looksLikeReasoningRequired(state.errorMessage)
|
|
91
|
+
: looksLikeUnsupportedTier(state.errorMessage);
|
|
92
|
+
if (rejectedOffSlot && tierIssue)
|
|
93
|
+
models.markNoOff(routeKey);
|
|
94
|
+
roundEffort = next;
|
|
95
|
+
state.errored = false;
|
|
96
|
+
sse(res, {
|
|
97
|
+
type: 'notice',
|
|
98
|
+
code: tierIssue ? 'effort-rejected' : 'upstream-retry',
|
|
99
|
+
...(tierIssue ? { tier: rejected } : {}),
|
|
100
|
+
text: tierIssue
|
|
101
|
+
? rejectedOffSlot
|
|
102
|
+
? `该模型不接受「关」档,已自动改用「${EFFORT_LABEL[next] ?? next}」档(以后不再尝试关档)`
|
|
103
|
+
: `「${EFFORT_LABEL[rejected] ?? rejected}」档该模型不支持,已改用「${EFFORT_LABEL[next] ?? next}」档重试`
|
|
104
|
+
: '上游这次返回了错误,已自动重试',
|
|
105
|
+
});
|
|
106
|
+
round -= 1;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
sse(res, { type: 'error', message: state.errorMessage, code: state.errorCode });
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
const blocks = assembler.blocks();
|
|
114
|
+
const calls = blocks.filter((block) => block.type === 'tool-call');
|
|
115
|
+
if (calls.length === 0) {
|
|
116
|
+
// 最终答案到手:如果发出去的是「关」那一格对应的真实档位,检查有没有把思考写进正文
|
|
117
|
+
if (isChat && firstSentEffort === offSlotEffort) {
|
|
118
|
+
const split = splitLeakedReasoning(state.answer);
|
|
119
|
+
if (split.prefix) {
|
|
120
|
+
models.markLeaky(routeKey);
|
|
121
|
+
state.answer = split.rest;
|
|
122
|
+
state.chars = state.answer.length;
|
|
123
|
+
sse(res, { type: 'strip', text: split.prefix });
|
|
124
|
+
sse(res, {
|
|
125
|
+
type: 'notice',
|
|
126
|
+
code: 'reasoning-leak',
|
|
127
|
+
// 报**真实档位**(模型可能没有 off,叫 none/minimal):客户端据此标对那个档位按钮
|
|
128
|
+
tier: firstSentEffort,
|
|
129
|
+
text: '该模型在「关」档会把思考写进正文,已撤回泄漏段;以后这一档会自动改用「低」',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else if (looksLikeLeakedReasoning(state.answer)) {
|
|
133
|
+
// 句式没认准(模型每次换说法)→ 这次不裁(怕误删正文),但记住它,下次自动抬档
|
|
134
|
+
models.markLeaky(routeKey);
|
|
135
|
+
sse(res, {
|
|
136
|
+
type: 'notice',
|
|
137
|
+
code: 'reasoning-leak',
|
|
138
|
+
tier: firstSentEffort,
|
|
139
|
+
text: '这个模型在「关」档会把思考写进正文;这一档以后自动改用「低」',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
// 既然这一轮要调工具,它刚才流出来的正文就是"过程旁白",不是答案:
|
|
146
|
+
// 让前端把这部分撤回去(顺带当成思考尾巴显示),免得"我怎么想的"混进小窗正文。
|
|
147
|
+
// 实测踩过:追问"搜索今天的新闻"时,模型在工具轮里先吐了一段英文盘算
|
|
148
|
+
// (I have sources with dates… Maybe I should do one more search…),
|
|
149
|
+
// 然后才给中文结论,这段英文被当正文渲染进了消息框。
|
|
150
|
+
if (roundText.length > 0) {
|
|
151
|
+
state.answer = state.answer.slice(0, Math.max(0, state.answer.length - roundText.length));
|
|
152
|
+
sse(res, { type: 'drop', chars: roundText.length, text: roundText.slice(-2000), round });
|
|
153
|
+
}
|
|
154
|
+
// 有的模型不带工具定义也会返回调用;执行端同样遵守开关和轮数上限。
|
|
155
|
+
if (wrapUp || toolSchemas.length === 0)
|
|
156
|
+
break;
|
|
157
|
+
// 执行工具→把结果回灌,再让模型继续(上限 maxToolRounds 轮)
|
|
158
|
+
await executeAnalyzeTools(env, state, blocks, calls, round);
|
|
159
|
+
}
|
|
160
|
+
if (!state.errored && state.answer.trim().length === 0 && state.toolCalls > 0 && triedEfforts.size === 1) {
|
|
161
|
+
await concludeAnalyze(env, state, roundEffort);
|
|
162
|
+
}
|
|
163
|
+
finishAnalyzeOutput(res, state, clientClosedEarly);
|
|
164
|
+
return state.errored ? null : state.answer;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=analyze-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-execution.js","sourceRoot":"","sources":["../../src/host/analyze-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createAssistantMessage, createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { readMaterialCatalog } from './chat-materials.js';
|
|
4
|
+
import { historyContentBlocks, readHistoryAttachments } from './history-attachments.js';
|
|
5
|
+
/** Mutable history and attachment admission state shared by context planning and retries. */
|
|
6
|
+
export class AnalyzeHistory {
|
|
7
|
+
isChat;
|
|
8
|
+
contextState;
|
|
9
|
+
currentAttachments;
|
|
10
|
+
rawHistory;
|
|
11
|
+
selectedHistory;
|
|
12
|
+
catalog;
|
|
13
|
+
historySource;
|
|
14
|
+
historyImages = { kept: 0, omitted: 0, files: 0 };
|
|
15
|
+
historyHadAttachments = false;
|
|
16
|
+
historyDropped = false;
|
|
17
|
+
attachedPaths = new Set();
|
|
18
|
+
contextEstimate = 0;
|
|
19
|
+
constructor(body, isChat, historyStart, route, contextState) {
|
|
20
|
+
this.isChat = isChat;
|
|
21
|
+
this.contextState = contextState;
|
|
22
|
+
this.currentAttachments = readHistoryAttachments(body.attachments);
|
|
23
|
+
this.rawHistory = (Array.isArray(body.history) ? body.history : []).map(raw => {
|
|
24
|
+
const item = (raw || {});
|
|
25
|
+
const attachments = readHistoryAttachments(item.attachments);
|
|
26
|
+
return {
|
|
27
|
+
role: item.role === 'assistant' ? 'assistant' : 'user', text: typeof item.text === 'string' ? item.text : '',
|
|
28
|
+
...(attachments.length ? { attachments } : {})
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
this.selectedHistory = this.rawHistory;
|
|
32
|
+
this.catalog = readMaterialCatalog([...(Array.isArray(body.materials) ? body.materials : []),
|
|
33
|
+
...this.rawHistory.flatMap((t, i) => (t.attachments || []).map(a => ({ ...a, turn: historyStart + i }))),
|
|
34
|
+
...this.currentAttachments.map(a => ({ ...a, turn: historyStart + this.rawHistory.length }))]);
|
|
35
|
+
this.historySource = { provider: route.provider, model: route.model };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 历史规划(纯计算):预算、降级、以及**这次请求真的进了消息的那些附件**。
|
|
39
|
+
* 每次都要能重算 —— 引用失效时会降级再跑一遍(见下面 errored 分支里的那一跳)。
|
|
40
|
+
*/
|
|
41
|
+
planHistory() {
|
|
42
|
+
if (!this.isChat)
|
|
43
|
+
return { blocks: [], kept: [], keptImages: 0, omittedImages: 0, keptFiles: 0, omittedFiles: 0 };
|
|
44
|
+
const window = this.selectedHistory;
|
|
45
|
+
const turns = this.historyDropped
|
|
46
|
+
? window.map((turn) => {
|
|
47
|
+
const item = (turn ?? {});
|
|
48
|
+
return { role: item.role, text: item.text };
|
|
49
|
+
})
|
|
50
|
+
: window;
|
|
51
|
+
const plan = historyContentBlocks(turns, this.currentAttachments);
|
|
52
|
+
this.historyImages = { kept: plan.keptImages, omitted: plan.omittedImages, files: plan.keptFiles + plan.omittedFiles };
|
|
53
|
+
return plan;
|
|
54
|
+
}
|
|
55
|
+
/** 重建历史消息。 */
|
|
56
|
+
buildHistoryMessages() {
|
|
57
|
+
const out = [];
|
|
58
|
+
if (!this.isChat)
|
|
59
|
+
return out;
|
|
60
|
+
const window = this.selectedHistory;
|
|
61
|
+
const plan = this.planHistory();
|
|
62
|
+
window.forEach((turn, index) => {
|
|
63
|
+
const item = turn;
|
|
64
|
+
if (!this.historyDropped && Array.isArray(item.attachments) && item.attachments.length > 0)
|
|
65
|
+
this.historyHadAttachments = true;
|
|
66
|
+
const content = plan.blocks[index] ?? [];
|
|
67
|
+
if (content.length === 0)
|
|
68
|
+
return;
|
|
69
|
+
if (item.role === 'assistant') {
|
|
70
|
+
out.push(createAssistantMessage({ content, source: this.historySource }));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
out.push(createUserMessage({ source: { kind: 'user' }, content }));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 文件工具的访客名单:本轮附件与本小窗保存的文件材料目录。
|
|
80
|
+
* 材料目录中的旧文件可由 selection_material 恢复;不接纳任意外部路径。
|
|
81
|
+
*
|
|
82
|
+
* 路径由附件服务按内容哈希推出(不碰磁盘,纯路径计算,所以每次请求重算没有成本);
|
|
83
|
+
* 引用不合法就当场丢掉 —— 它本来也读不出来,让门禁拒掉即可。
|
|
84
|
+
*/
|
|
85
|
+
collectAttachedPaths(ctx) {
|
|
86
|
+
const paths = new Set();
|
|
87
|
+
const store = ctx.get('attachments');
|
|
88
|
+
if (!store || typeof store.fileHostPath !== 'function')
|
|
89
|
+
return paths;
|
|
90
|
+
const refs = [];
|
|
91
|
+
for (const item of this.currentAttachments)
|
|
92
|
+
if (item.kind === 'file')
|
|
93
|
+
refs.push(item.ref);
|
|
94
|
+
for (const item of this.catalog)
|
|
95
|
+
if (item.kind === 'file')
|
|
96
|
+
refs.push(item.ref);
|
|
97
|
+
for (const ref of refs) {
|
|
98
|
+
try {
|
|
99
|
+
const hostPath = store.fileHostPath(ref);
|
|
100
|
+
if (hostPath)
|
|
101
|
+
paths.add(resolve(hostPath));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
/* 引用不合法:当它不存在(读的时候自然会被门禁拒) */
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return paths;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=analyze-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-history.js","sourceRoot":"","sources":["../../src/host/analyze-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createAssistantMessage, createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { estimateTextTokens } from '../chat-context.js';
|
|
3
|
+
import { shotTitlePromptFor } from '../prompts.js';
|
|
4
|
+
import { estimateRequestTokens, planChatContext } from './chat-context.js';
|
|
5
|
+
import { materialIndex } from './chat-materials.js';
|
|
6
|
+
import { sse } from './http.js';
|
|
7
|
+
/** Compact chat memory if necessary, then construct the initial multimodal messages. */
|
|
8
|
+
export async function prepareAnalyzeMessages(deps, request, tools, prompt, res, controller) {
|
|
9
|
+
const { ctx } = deps;
|
|
10
|
+
const { body, isChat, capacity, initialExplanation, userText, question, route, historyStart, isShotMode, titleOnly, shotScope, shotFrame, history } = request;
|
|
11
|
+
const { currentAttachments, rawHistory, catalog, historySource } = history;
|
|
12
|
+
const { systemPrompt, sentEffort, isShot } = prompt;
|
|
13
|
+
const { toolSchemas } = tools;
|
|
14
|
+
history.contextEstimate = 0;
|
|
15
|
+
if (isChat && capacity) {
|
|
16
|
+
try {
|
|
17
|
+
const fixedTokens = 256 + estimateTextTokens(systemPrompt + userText + initialExplanation + question)
|
|
18
|
+
+ estimateTextTokens(JSON.stringify(toolSchemas))
|
|
19
|
+
+ estimateTextTokens(materialIndex(catalog, historyStart + rawHistory.length))
|
|
20
|
+
+ estimateTextTokens(typeof body.toolDigest === 'string' ? body.toolDigest.slice(0, 2000) : '')
|
|
21
|
+
+ currentAttachments.reduce((n, a) => n + capacity.attachmentPrice(a), 0);
|
|
22
|
+
const planned = await planChatContext(ctx, route, capacity, { state: history.contextState, history: rawHistory, fixedTokens, signal: controller.signal, effort: sentEffort });
|
|
23
|
+
history.contextState = planned.state;
|
|
24
|
+
history.selectedHistory = planned.history;
|
|
25
|
+
history.contextEstimate = planned.estimatedTokens;
|
|
26
|
+
sse(res, {
|
|
27
|
+
type: 'context-state', state: history.contextState,
|
|
28
|
+
budget: capacity.budget, estimatedTokens: history.contextEstimate, modelWindow: capacity.modelWindow,
|
|
29
|
+
compacted: planned.compacted, retainedMessages: history.selectedHistory.length
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
sse(res, { type: 'error', code: 'context-rejected', message: String(error?.message || error) });
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const memoryMessages = isChat ? [
|
|
38
|
+
...(initialExplanation ? [createAssistantMessage({ source: historySource, content: [{ type: 'text', text: initialExplanation }] })] : []),
|
|
39
|
+
...(history.contextState.summary ? [createUserMessage({
|
|
40
|
+
source: { kind: 'user' }, content: [{
|
|
41
|
+
type: 'text',
|
|
42
|
+
text: '【较早对话摘要,可能遗漏细节】\n' + history.contextState.summary + '\n' + materialIndex(catalog, history.contextState.through)
|
|
43
|
+
}]
|
|
44
|
+
})] : []),
|
|
45
|
+
] : [];
|
|
46
|
+
function checkedMessages(messages) {
|
|
47
|
+
if (capacity && estimateRequestTokens(messages, capacity, toolSchemas) > capacity.budget) {
|
|
48
|
+
throw Object.assign(new Error('本轮材料与工具结果超过上下文容量,请缩小问题或引用范围'), { code: 'context-capacity' });
|
|
49
|
+
}
|
|
50
|
+
return messages;
|
|
51
|
+
}
|
|
52
|
+
// ⚠️ 截图模式:图必须**在这一条消息里**。
|
|
53
|
+
// 原先只有 isChat(追问) 才拼 openingMessages,截图走的是 baseMessage 纯文本那条 ——
|
|
54
|
+
// 结果图根本没进请求,模型只会说"我没收到截图"(实测踩到)。
|
|
55
|
+
const shotImageBlocks = isShotMode
|
|
56
|
+
? currentAttachments.map((item) => item.kind === 'image'
|
|
57
|
+
? { type: 'image', attachment: item.ref }
|
|
58
|
+
: { type: 'file', attachment: item.ref })
|
|
59
|
+
: [];
|
|
60
|
+
const baseMessage = createUserMessage({
|
|
61
|
+
source: { kind: 'user' },
|
|
62
|
+
content: shotImageBlocks.length > 0
|
|
63
|
+
? [...shotImageBlocks, { type: 'text', text: userText }]
|
|
64
|
+
: [{ type: 'text', text: userText }],
|
|
65
|
+
});
|
|
66
|
+
// 上一轮查过的东西一并带上:否则追问会反复重查同样的内容(一次工具往返 20~34s)
|
|
67
|
+
const toolDigest = typeof body.toolDigest === 'string' ? body.toolDigest.trim().slice(0, 2000) : '';
|
|
68
|
+
// 顺序很重要:把"已经查到的结果"放**前面**、问题放**最后**。
|
|
69
|
+
// 反过来的话,模型最后读到的是原始检索结果,容易"整理资料"而不是回答问题
|
|
70
|
+
//(实测:问新闻却把上一次的检索结果当成要总结的对象)。
|
|
71
|
+
const questionText = toolDigest
|
|
72
|
+
? `【本会话已经查到的结果】(同一会话里查过的,不要重复查同样的内容;只在与本轮问题相关时才用)\n${toolDigest}\n\n【用户这一轮的问题】\n${question}`
|
|
73
|
+
: question;
|
|
74
|
+
// 附件排在正文**前面**:模型先拿到材料(图片 / 文件句柄),再读到这一轮的问题。
|
|
75
|
+
// 没有附件时 content 与从前逐字节一致(一个元素、纯文本),既有行为一点不变。
|
|
76
|
+
const currentBlocks = currentAttachments.map((item) => item.kind === 'image' ? { type: 'image', attachment: item.ref } : { type: 'file', attachment: item.ref });
|
|
77
|
+
const questionContent = currentBlocks.length > 0 ? [...currentBlocks, { type: 'text', text: questionText }] : [{ type: 'text', text: questionText }];
|
|
78
|
+
let openingMessages = isChat
|
|
79
|
+
? [
|
|
80
|
+
...memoryMessages,
|
|
81
|
+
...history.buildHistoryMessages(),
|
|
82
|
+
// 截图首轮:图 + 问题已经放进 baseMessage(只需要一份,避免图片和问题各发两遍);
|
|
83
|
+
// 追问不走截图模式,当前问题仍然放在这里。
|
|
84
|
+
...(isShot ? [] : [createUserMessage({ source: { kind: 'user' }, content: questionContent })]),
|
|
85
|
+
]
|
|
86
|
+
: [];
|
|
87
|
+
if (titleOnly) {
|
|
88
|
+
// 截图:base 那条消息里已经带了图 + 提问,这里只多一句"只输出标题"
|
|
89
|
+
openingMessages = [
|
|
90
|
+
createUserMessage({ source: { kind: 'user' }, content: [{ type: 'text', text: shotTitlePromptFor(shotScope, shotFrame) }] }),
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
return { memoryMessages, baseMessage, questionContent, openingMessages, checkedMessages };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=analyze-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-messages.js","sourceRoot":"","sources":["../../src/host/analyze-messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { sse } from './http.js';
|
|
3
|
+
export function startAnalyzeOutput(res, request, tools, prompt) {
|
|
4
|
+
const { body, route, isChat, background, context, label, userText } = request;
|
|
5
|
+
const { historyImages, currentAttachments } = request.history;
|
|
6
|
+
const { toolSchemas, agentScope, toolFallbackUsed, wantsFsTools, readRoot, fetchBlockedSample } = tools;
|
|
7
|
+
const { stage, isCode, systemPrompt, sentEffort } = prompt;
|
|
8
|
+
sse(res, {
|
|
9
|
+
type: 'start',
|
|
10
|
+
provider: route.provider,
|
|
11
|
+
model: route.model,
|
|
12
|
+
mode: isChat ? 'chat' : stage === 'detail' ? 'detail' : isCode ? 'code' : 'translation',
|
|
13
|
+
stage: stage === 'detail' ? 'detail' : 'translation',
|
|
14
|
+
backgroundMessages: background ? background.transcript.split('\n').filter((line) => /^\s*(▶\s*)?(用户|助手):/.test(line)).length : 0,
|
|
15
|
+
effort: sentEffort,
|
|
16
|
+
tools: toolSchemas.map((schema) => schema.name),
|
|
17
|
+
toolScope: agentScope,
|
|
18
|
+
// 这一轮请求里附件的情况:本轮带了几件、历史里回带/省略了几张。
|
|
19
|
+
// **一件都没有时不带这个字段**(保持 start 事件与从前逐字节一致)。
|
|
20
|
+
// 注意条件要算上"历史里回带的"—— 只看本轮附件的话,
|
|
21
|
+
// "第二问靠历史里的图回答"这种最该被看见的情况反而不上报。
|
|
22
|
+
...(currentAttachments.length > 0 || historyImages.kept > 0 || historyImages.omitted > 0 || historyImages.files > 0
|
|
23
|
+
? { attachments: { ...historyImages, current: currentAttachments.length } }
|
|
24
|
+
: {}),
|
|
25
|
+
...(toolFallbackUsed ? { toolFallbackUsed: true } : {}),
|
|
26
|
+
...(wantsFsTools ? { readRoot: readRoot || '(不限)' } : {}),
|
|
27
|
+
...(fetchBlockedSample ? { fetchBlocked: fetchBlockedSample } : {}),
|
|
28
|
+
context: {
|
|
29
|
+
chars: context.length,
|
|
30
|
+
label,
|
|
31
|
+
session: background
|
|
32
|
+
? {
|
|
33
|
+
chars: background.transcript.length,
|
|
34
|
+
marked: background.marked,
|
|
35
|
+
// 背景短哈希:用于核对「前缀是否真的没变」(缓存命中的前提)
|
|
36
|
+
hash: createHash('sha1').update(background.transcript).digest('hex').slice(0, 10),
|
|
37
|
+
}
|
|
38
|
+
: null,
|
|
39
|
+
},
|
|
40
|
+
...(body.debug === true
|
|
41
|
+
? { debug: { system: systemPrompt, user: userText, sizes: { system: systemPrompt.length, user: userText.length } } }
|
|
42
|
+
: {}),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Emit the existing empty-answer fallback and terminal diagnostics. */
|
|
46
|
+
export function finishAnalyzeOutput(res, state, clientClosedEarly) {
|
|
47
|
+
if (!state.errored && state.answer.trim().length === 0) {
|
|
48
|
+
// 兜底:连结论轮都没吐字时,至少给一句话(否则面板空白,看起来像"没返回结果")
|
|
49
|
+
const note = state.toolCalls > 0
|
|
50
|
+
? '(工具查询完成了,但模型没有产出正文。可以再追问一句"直接说结论",我按已查到的结果回答。)'
|
|
51
|
+
: '(模型这次没有返回内容,可以点「重新生成」再试一次。)';
|
|
52
|
+
state.answer = note;
|
|
53
|
+
state.chars += note.length;
|
|
54
|
+
sse(res, { type: 'delta', text: note });
|
|
55
|
+
}
|
|
56
|
+
if (!state.errored) {
|
|
57
|
+
sse(res, {
|
|
58
|
+
type: 'done',
|
|
59
|
+
chars: state.chars,
|
|
60
|
+
usage: state.usage,
|
|
61
|
+
toolCalls: state.toolCalls,
|
|
62
|
+
// 诊断用:结论轮/续写各试了几次、拿到多少字、失败原因
|
|
63
|
+
...(state.conclusionInfo.tried ? { conclusion: state.conclusionInfo } : {}),
|
|
64
|
+
...(state.roundDiag.length > 0 ? { rounds: state.roundDiag } : {}),
|
|
65
|
+
clientClosedEarly: clientClosedEarly(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=analyze-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-output.js","sourceRoot":"","sources":["../../src/host/analyze-output.ts"],"names":[],"mappings":"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"}
|