webaiapi 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +184 -2
- package/bin/webapi.mjs +45 -0
- package/dist/browser/auth-capture.d.ts +110 -0
- package/dist/browser/auth-capture.d.ts.map +1 -0
- package/dist/browser/auth-capture.js +487 -0
- package/dist/browser/auth-capture.js.map +1 -0
- package/dist/browser/credentials.d.ts +102 -0
- package/dist/browser/credentials.d.ts.map +1 -0
- package/dist/browser/credentials.js +209 -0
- package/dist/browser/credentials.js.map +1 -0
- package/dist/browser/js-eval.d.ts +44 -0
- package/dist/browser/js-eval.d.ts.map +1 -0
- package/dist/browser/js-eval.js +20 -0
- package/dist/browser/js-eval.js.map +1 -0
- package/dist/browser/login-flow.d.ts +171 -0
- package/dist/browser/login-flow.d.ts.map +1 -0
- package/dist/browser/login-flow.js +606 -0
- package/dist/browser/login-flow.js.map +1 -0
- package/dist/browser/manager.d.ts +144 -0
- package/dist/browser/manager.d.ts.map +1 -0
- package/dist/browser/manager.js +586 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/browser/platforms.d.ts +96 -0
- package/dist/browser/platforms.d.ts.map +1 -0
- package/dist/browser/platforms.js +288 -0
- package/dist/browser/platforms.js.map +1 -0
- package/dist/browser/sse-capture.d.ts +23 -0
- package/dist/browser/sse-capture.d.ts.map +1 -0
- package/dist/browser/sse-capture.js +199 -0
- package/dist/browser/sse-capture.js.map +1 -0
- package/dist/browser/stealth.d.ts +12 -0
- package/dist/browser/stealth.d.ts.map +1 -0
- package/dist/browser/stealth.js +12 -0
- package/dist/browser/stealth.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +441 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +90 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +246 -0
- package/dist/config.js.map +1 -0
- package/dist/controllers/history-db.d.ts +56 -0
- package/dist/controllers/history-db.d.ts.map +1 -0
- package/dist/controllers/history-db.js +260 -0
- package/dist/controllers/history-db.js.map +1 -0
- package/dist/controllers/request-pool.d.ts +78 -0
- package/dist/controllers/request-pool.d.ts.map +1 -0
- package/dist/controllers/request-pool.js +222 -0
- package/dist/controllers/request-pool.js.map +1 -0
- package/dist/controllers/router.d.ts +172 -0
- package/dist/controllers/router.d.ts.map +1 -0
- package/dist/controllers/router.js +569 -0
- package/dist/controllers/router.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/log/api-logger.d.ts +55 -0
- package/dist/log/api-logger.d.ts.map +1 -0
- package/dist/log/api-logger.js +264 -0
- package/dist/log/api-logger.js.map +1 -0
- package/dist/log/debug-logger.d.ts +49 -0
- package/dist/log/debug-logger.d.ts.map +1 -0
- package/dist/log/debug-logger.js +285 -0
- package/dist/log/debug-logger.js.map +1 -0
- package/dist/log/logger.d.ts +16 -0
- package/dist/log/logger.d.ts.map +1 -0
- package/dist/log/logger.js +35 -0
- package/dist/log/logger.js.map +1 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +90 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/providers/base.d.ts +83 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +51 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/chatglm-dom-extract.d.ts +24 -0
- package/dist/providers/chatglm-dom-extract.d.ts.map +1 -0
- package/dist/providers/chatglm-dom-extract.js +175 -0
- package/dist/providers/chatglm-dom-extract.js.map +1 -0
- package/dist/providers/chatglm-dom.d.ts +110 -0
- package/dist/providers/chatglm-dom.d.ts.map +1 -0
- package/dist/providers/chatglm-dom.js +384 -0
- package/dist/providers/chatglm-dom.js.map +1 -0
- package/dist/providers/chatglm-sse.d.ts +119 -0
- package/dist/providers/chatglm-sse.d.ts.map +1 -0
- package/dist/providers/chatglm-sse.js +241 -0
- package/dist/providers/chatglm-sse.js.map +1 -0
- package/dist/providers/chatglm.d.ts +288 -0
- package/dist/providers/chatglm.d.ts.map +1 -0
- package/dist/providers/chatglm.js +1631 -0
- package/dist/providers/chatglm.js.map +1 -0
- package/dist/routes/chat.d.ts +117 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +1346 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/compress.d.ts +142 -0
- package/dist/routes/compress.d.ts.map +1 -0
- package/dist/routes/compress.js +551 -0
- package/dist/routes/compress.js.map +1 -0
- package/dist/routes/failover.d.ts +34 -0
- package/dist/routes/failover.d.ts.map +1 -0
- package/dist/routes/failover.js +221 -0
- package/dist/routes/failover.js.map +1 -0
- package/dist/routes/helpers.d.ts +174 -0
- package/dist/routes/helpers.d.ts.map +1 -0
- package/dist/routes/helpers.js +525 -0
- package/dist/routes/helpers.js.map +1 -0
- package/dist/routes/meta.d.ts +31 -0
- package/dist/routes/meta.d.ts.map +1 -0
- package/dist/routes/meta.js +184 -0
- package/dist/routes/meta.js.map +1 -0
- package/dist/routes/sse.d.ts +82 -0
- package/dist/routes/sse.d.ts.map +1 -0
- package/dist/routes/sse.js +77 -0
- package/dist/routes/sse.js.map +1 -0
- package/dist/server/app.d.ts +24 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +292 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/middleware/api-key.d.ts +61 -0
- package/dist/server/middleware/api-key.d.ts.map +1 -0
- package/dist/server/middleware/api-key.js +95 -0
- package/dist/server/middleware/api-key.js.map +1 -0
- package/dist/server/middleware/rate-limit.d.ts +67 -0
- package/dist/server/middleware/rate-limit.d.ts.map +1 -0
- package/dist/server/middleware/rate-limit.js +134 -0
- package/dist/server/middleware/rate-limit.js.map +1 -0
- package/dist/server/middleware/timeout.d.ts +34 -0
- package/dist/server/middleware/timeout.d.ts.map +1 -0
- package/dist/server/middleware/timeout.js +64 -0
- package/dist/server/middleware/timeout.js.map +1 -0
- package/dist/server/types.d.ts +20 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/tools/build.d.ts +14 -0
- package/dist/tools/build.d.ts.map +1 -0
- package/dist/tools/build.js +105 -0
- package/dist/tools/build.js.map +1 -0
- package/dist/tools/clean.d.ts +32 -0
- package/dist/tools/clean.d.ts.map +1 -0
- package/dist/tools/clean.js +65 -0
- package/dist/tools/clean.js.map +1 -0
- package/dist/tools/convert.d.ts +50 -0
- package/dist/tools/convert.d.ts.map +1 -0
- package/dist/tools/convert.js +289 -0
- package/dist/tools/convert.js.map +1 -0
- package/dist/tools/names.d.ts +138 -0
- package/dist/tools/names.d.ts.map +1 -0
- package/dist/tools/names.js +578 -0
- package/dist/tools/names.js.map +1 -0
- package/dist/tools/parse.d.ts +31 -0
- package/dist/tools/parse.d.ts.map +1 -0
- package/dist/tools/parse.js +273 -0
- package/dist/tools/parse.js.map +1 -0
- package/dist/tools/placeholder.d.ts +21 -0
- package/dist/tools/placeholder.d.ts.map +1 -0
- package/dist/tools/placeholder.js +135 -0
- package/dist/tools/placeholder.js.map +1 -0
- package/dist/tools/prompts.d.ts +42 -0
- package/dist/tools/prompts.d.ts.map +1 -0
- package/dist/tools/prompts.js +69 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/protocol.d.ts +58 -0
- package/dist/tools/protocol.d.ts.map +1 -0
- package/dist/tools/protocol.js +287 -0
- package/dist/tools/protocol.js.map +1 -0
- package/dist/tools/repair.d.ts +83 -0
- package/dist/tools/repair.d.ts.map +1 -0
- package/dist/tools/repair.js +510 -0
- package/dist/tools/repair.js.map +1 -0
- package/dist/tools/workspace.d.ts +40 -0
- package/dist/tools/workspace.d.ts.map +1 -0
- package/dist/tools/workspace.js +224 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/types/message.d.ts +87 -0
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/message.js +85 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/openai.d.ts +100 -0
- package/dist/types/openai.d.ts.map +1 -0
- package/dist/types/openai.js +66 -0
- package/dist/types/openai.js.map +1 -0
- package/dist/utils/errors.d.ts +82 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +115 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/mutex.d.ts +31 -0
- package/dist/utils/mutex.d.ts.map +1 -0
- package/dist/utils/mutex.js +61 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/prompt.d.ts +150 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +514 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/text.d.ts +30 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +70 -0
- package/dist/utils/text.js.map +1 -0
- package/package.json +67 -4
- package/postinstall.mjs +34 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工具协议注入与消息拍平 —— `legacy-python/src/utils/tool_calls.py` 的一部分。
|
|
3
|
+
*
|
|
4
|
+
* 网页版模型没有原生 function calling,只能靠「把工具说明写成文本注入提示词,
|
|
5
|
+
* 再解析模型输出的 XML 标签」来模拟 OpenAI 的 tool_calls 协议。
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ 提示词里的每一条强指令都对应一次真实事故(注释里标了日期),
|
|
8
|
+
* 删任何一条前请先看 `docs/hard-constraints.md`。
|
|
9
|
+
*/
|
|
10
|
+
import { logger } from '../log/logger.js';
|
|
11
|
+
import { messageToDict, toolNameOf, toolParamNames, toolRequiredParams, } from '../types/message.js';
|
|
12
|
+
import { detectToolNames, createToolMaps } from './names.js';
|
|
13
|
+
/** 工具调用的 XML 标签。 */
|
|
14
|
+
export const TOOL_CALL_OPEN = '<tool_call>';
|
|
15
|
+
export const TOOL_CALL_CLOSE = '</tool_call>';
|
|
16
|
+
/** 匹配 `<tool_call>...</tool_call>` 块。 */
|
|
17
|
+
export const TOOL_CALL_PATTERN = new RegExp(`${escapeLiteral(TOOL_CALL_OPEN)}\\s*(.*?)\\s*${escapeLiteral(TOOL_CALL_CLOSE)}`, 'su');
|
|
18
|
+
function escapeLiteral(text) {
|
|
19
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 工具说明在提示词中的最大长度。
|
|
23
|
+
*
|
|
24
|
+
* 客户端的工具说明常常很长(含 Usage/Examples),全部注入会吃掉输入框额度,
|
|
25
|
+
* 且**提示词越长模型越容易「只描述不调用」**。截断成一句话足够选对工具。
|
|
26
|
+
*/
|
|
27
|
+
export const TOOL_DESC_MAX_LEN = 80;
|
|
28
|
+
/** 对话中展示的已知路径上限。 */
|
|
29
|
+
const MAX_DISPLAY_PATHS = 15;
|
|
30
|
+
/**
|
|
31
|
+
* 把 OpenAI `tools` 定义渲染成注入用的文本块。
|
|
32
|
+
*
|
|
33
|
+
* 返回的文本会被追加到系统提示里,告诉模型用 `<tool_call>` 标签输出调用。
|
|
34
|
+
*
|
|
35
|
+
* 工具列表用**紧凑格式**:`名称(必填*,可选):说明`。
|
|
36
|
+
* 27 个工具实测从 11,892 字符降到 3,462 字符(-71%)。
|
|
37
|
+
*/
|
|
38
|
+
export function formatToolsAsText(tools, options = {}) {
|
|
39
|
+
if (tools.length === 0)
|
|
40
|
+
return '';
|
|
41
|
+
const { workspacePath = '', knownFilePaths } = options;
|
|
42
|
+
// 检测客户端实际工具名(仅用于提示词里的示例,映射表由 createToolMaps 单独提供)
|
|
43
|
+
const detected = detectToolNames(tools);
|
|
44
|
+
if (Object.keys(detected).length > 0) {
|
|
45
|
+
logger.info({ detected }, '[tool_calls] 检测到客户端工具名映射');
|
|
46
|
+
}
|
|
47
|
+
const writeName = detected['write'] ?? 'Write';
|
|
48
|
+
const editName = detected['edit'] ?? 'SearchReplace';
|
|
49
|
+
const lines = [
|
|
50
|
+
'# 工具调用协议',
|
|
51
|
+
'',
|
|
52
|
+
'需要读取/创建/修改文件或执行命令时,**必须输出工具调用**,不要只用文字描述应该做什么。',
|
|
53
|
+
'',
|
|
54
|
+
`格式(${TOOL_CALL_OPEN} 与 ${TOOL_CALL_CLOSE} 内不要空行,JSON 必须单行):`,
|
|
55
|
+
TOOL_CALL_OPEN,
|
|
56
|
+
'{"name": "工具名", "arguments": {"参数名": "参数值"}}',
|
|
57
|
+
TOOL_CALL_CLOSE,
|
|
58
|
+
'',
|
|
59
|
+
'规则:',
|
|
60
|
+
`- 修改已有文件用 ${editName},创建新文件用 ${writeName};可用工具见下方列表`,
|
|
61
|
+
'- 工具名与参数名必须严格照抄下方列表中的真实名称',
|
|
62
|
+
// ⚠️ 2026-10-14 实测:模型想创建文件却调 edit_file 并套用 write_file 的签名
|
|
63
|
+
// (edit_file(path, content))→ 客户端按签名校验拒收「未知参数 content」,
|
|
64
|
+
// 白烧一轮工具往返。单独点破这一类混淆。
|
|
65
|
+
'- **调用前逐个核对参数名**:不同工具的参数不同(例如「创建/写内容」与「搜索替换修改」' +
|
|
66
|
+
'是两个不同的工具,参数完全不同),**不要把一个工具的参数套到另一个工具上**;' +
|
|
67
|
+
'参数名只能从下方该工具的括号里选',
|
|
68
|
+
'- **禁止输出占位符**(如 `<工具名>`、`<参数名>`、`<参数值>`、`参数1`、`值1`),必须替换成真实值',
|
|
69
|
+
'- file_path 必须使用真实绝对路径,不要编造',
|
|
70
|
+
// ⚠️ 2026-09-27:ChatGLM 网页端模型会看到页面自带工具(search/open/click/find),
|
|
71
|
+
// 误判「没有 read_file 等文件工具」→ 放弃调用工具、只输出分析文字。
|
|
72
|
+
// 必须显式声明工具清单的唯一性。
|
|
73
|
+
`- **本次对话可用的工具只有下方列出的这 ${tools.length} 个**,它们是真实可用的,请直接调用`,
|
|
74
|
+
'- 忽略运行环境自带的其他工具(如 search / open / click / find / browser 等),' +
|
|
75
|
+
'它们不可用,禁止调用;也不要因为「缺少文件工具」而只用文字描述',
|
|
76
|
+
// ⚠️ 2026-10-14 实测:ChatGLM 判定问题要「跑代码」(SSE 里 answer_type=python)时,
|
|
77
|
+
// 会调用它**平台自带**的代码沙箱 execute_sandbox_code。该名字不在客户端工具列表里
|
|
78
|
+
// → 被 filterUnknownToolCalls 丢弃 → 整轮降级成纯文本后客户端结束回合
|
|
79
|
+
// (用户看到「对话无故停止」)。要跑代码必须用下方列表里的命令执行工具。
|
|
80
|
+
'- 网页平台自带的**代码沙箱/代码执行**能力(实测名字为 `execute_sandbox_code`)' +
|
|
81
|
+
'同样不可用,禁止调用;要运行代码或命令请用下方列表里的命令执行工具',
|
|
82
|
+
// ⚠️ 2026-09-27 22:0x:模型反复调网页端自带 search,拿回一堆与本地项目无关的知识,
|
|
83
|
+
// 把整轮对话耗光,最后只能输出「我从未真正读到过本项目代码」。
|
|
84
|
+
// ⚠️ 2026-10-14:更糟的形态是拿它去查**命令语法/用法**(实测 45 个 query 全是
|
|
85
|
+
// 「bash 怎么删带空格的目录」「怎么用 nohup 重启服务」),单轮在平台 search 上刷了
|
|
86
|
+
// 57 次、耗掉 210s,最后零工具调用。所以这里要点破「语法也不用搜」。
|
|
87
|
+
'- **不要联网搜索,命令语法也别搜**:本地代码工程任务不需要外部知识;' +
|
|
88
|
+
'`bash` 怎么写、某个命令怎么用,**直接试一次**比搜十次快(用下方命令执行工具)。' +
|
|
89
|
+
'若已经搜过,直接忽略那些结果继续干活',
|
|
90
|
+
// ⚠️ 2026-10-14 实测:模型会把本协议的句子当正文抄出来(连说三遍
|
|
91
|
+
// 「搜索结果与本任务无关,忽略」,整轮空转 210s)。必须显式禁止复述。
|
|
92
|
+
'- **禁止复述本协议**:不要把本节的任何句子/规则/清单抄进回答,也不要解释自己在遵守什么规则;' +
|
|
93
|
+
'直接给出工具调用,需要说明就一句话',
|
|
94
|
+
'- **第一步必须调用下方工具**(如 list_dir / read_file / search_content)读取本地文件:' +
|
|
95
|
+
'不要先输出计划、不要先解释、也不要用文字描述「我准备做什么」',
|
|
96
|
+
// ⚠️ 2026-09-28 20:54:模型凭空认为「工具轮数已达上限(8/8)」,
|
|
97
|
+
// 交了一份「需先补读 X、待下一轮执行」的计划书当最终回答 —— 纯文本回复会让客户端直接结束回合。
|
|
98
|
+
'- **本次会话没有工具调用轮数上限**:需要更多文件内容就继续调用读取工具' +
|
|
99
|
+
'(可一次并行读多个),累了也不要停',
|
|
100
|
+
'- **禁止用计划代替动作**:不要回答「需先补读 X 文件」「待下一轮执行」' +
|
|
101
|
+
'「工具轮数已达上限」「我下一步会…」——想读就直接读、想改就直接改,' +
|
|
102
|
+
'用真实的工具调用推进任务',
|
|
103
|
+
'- 只有**任务全部完成**后才输出总结文字;没做完就继续调用工具,' +
|
|
104
|
+
'也不要把计划清单写进项目文件里',
|
|
105
|
+
// ⚠️ 2026-10-14 实测死循环:模型每轮都重发同一条 `bash ./start.sh status`
|
|
106
|
+
// 并配同一段「无需进一步操作」的结论 → 客户端的 agent 一直转。
|
|
107
|
+
// 原生模型的行为是:任务完成就返回纯文本(无工具调用)= 本轮结束。
|
|
108
|
+
'- **不要重复调用**:同一条调用(同工具 + 同参数)已经执行过就不要再来一次;' +
|
|
109
|
+
'**任务完成就直接输出结论文字结束本轮**(没有工具调用是正常的收尾方式)',
|
|
110
|
+
'',
|
|
111
|
+
];
|
|
112
|
+
if (workspacePath) {
|
|
113
|
+
lines.push(`当前项目目录:\`${workspacePath}\``);
|
|
114
|
+
}
|
|
115
|
+
if (knownFilePaths && knownFilePaths.length > 0) {
|
|
116
|
+
const display = knownFilePaths.slice(0, MAX_DISPLAY_PATHS);
|
|
117
|
+
lines.push(`对话中已出现的真实路径:${display.map((p) => `\`${p}\``).join(', ')}`);
|
|
118
|
+
if (knownFilePaths.length > MAX_DISPLAY_PATHS) {
|
|
119
|
+
lines.push(`(另有 ${knownFilePaths.length - MAX_DISPLAY_PATHS} 个路径已省略)`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
lines.push('');
|
|
123
|
+
// ===== 工具列表:紧凑格式 =====
|
|
124
|
+
lines.push('## 可用工具(格式:名称(参数):说明;参数带 * 为必填)');
|
|
125
|
+
for (const tool of tools) {
|
|
126
|
+
const name = toolNameOf(tool) || 'unknown';
|
|
127
|
+
const description = (tool?.function?.description ?? '').trim();
|
|
128
|
+
const props = tool?.function?.parameters?.properties ?? {};
|
|
129
|
+
const required = toolRequiredParams(tool);
|
|
130
|
+
const propNames = Object.keys(props);
|
|
131
|
+
const reqNames = propNames.filter((p) => required.includes(p));
|
|
132
|
+
const optNames = propNames.filter((p) => !required.includes(p));
|
|
133
|
+
const paramsDesc = [...reqNames.map((p) => `${p}*`), ...optNames].join(', ');
|
|
134
|
+
// 说明压成一行(去换行取首句)并截断
|
|
135
|
+
let oneLine = description.split(/\s+/).filter(Boolean).join(' ');
|
|
136
|
+
if (oneLine.length > TOOL_DESC_MAX_LEN) {
|
|
137
|
+
oneLine = `${oneLine.slice(0, TOOL_DESC_MAX_LEN - 1)}…`;
|
|
138
|
+
}
|
|
139
|
+
lines.push(`- ${name}(${paramsDesc}):${oneLine}`);
|
|
140
|
+
}
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 一次算出「注入文本 + 映射表」。
|
|
145
|
+
*
|
|
146
|
+
* 路由层应该用这个函数而不是分别调用 `formatToolsAsText` / `createToolMaps`,
|
|
147
|
+
* 避免映射表与提示词里的工具列表不一致。
|
|
148
|
+
*/
|
|
149
|
+
export function buildToolProtocol(tools, options = {}) {
|
|
150
|
+
return {
|
|
151
|
+
text: formatToolsAsText(tools, options),
|
|
152
|
+
maps: createToolMaps(tools),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** 工具结果截断上限(Read 类例外,保留全文)。 */
|
|
156
|
+
const TOOL_RESULT_MAX = 5000;
|
|
157
|
+
/** assistant 文本截断上限。 */
|
|
158
|
+
const ASSISTANT_TEXT_MAX = 3000;
|
|
159
|
+
/** 工具调用参数截断上限。 */
|
|
160
|
+
const TOOL_ARGS_MAX = 3000;
|
|
161
|
+
/** function 角色结果截断上限。 */
|
|
162
|
+
const FUNCTION_RESULT_MAX = 3000;
|
|
163
|
+
/** Read 类工具名(结果保留全文,AI 需要完整内容才能正确生成替换片段)。 */
|
|
164
|
+
const READ_TOOL_NAMES = new Set(['read', 'readfile', 'get_file_content']);
|
|
165
|
+
/**
|
|
166
|
+
* 把所有消息拍平成一段文本(等价于 `format_messages_as_text`)。
|
|
167
|
+
*
|
|
168
|
+
* 目的:让网页版模型在**一次提示**里看到完整对话上下文。
|
|
169
|
+
*
|
|
170
|
+
* 截断策略(这里是**唯一会丢内容**的地方):
|
|
171
|
+
* - tool_call 参数 > 3000 字符 → 截断
|
|
172
|
+
* - assistant 文本 > 3000 字符 → 截断
|
|
173
|
+
* - tool 结果 > 5000 字符 → 截断(Read 类例外,保留全文)
|
|
174
|
+
*/
|
|
175
|
+
export function formatMessagesAsText(messages) {
|
|
176
|
+
const parts = [];
|
|
177
|
+
for (const raw of messages) {
|
|
178
|
+
const m = messageToDict(raw);
|
|
179
|
+
const role = m.role;
|
|
180
|
+
let content = m.content ?? '';
|
|
181
|
+
if (role === 'system') {
|
|
182
|
+
parts.push(`[System]\n${asText(content)}`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (role === 'user') {
|
|
186
|
+
if (Array.isArray(content)) {
|
|
187
|
+
const textParts = [];
|
|
188
|
+
for (const item of content) {
|
|
189
|
+
if (item && typeof item === 'object') {
|
|
190
|
+
const rec = item;
|
|
191
|
+
if (rec['type'] === 'text')
|
|
192
|
+
textParts.push(String(rec['text'] ?? ''));
|
|
193
|
+
else if (rec['type'] === 'image_url')
|
|
194
|
+
textParts.push('[Image provided]');
|
|
195
|
+
}
|
|
196
|
+
else if (typeof item === 'string') {
|
|
197
|
+
textParts.push(item);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
parts.push(`[User]\n${textParts.join(' ')}`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
parts.push(`[User]\n${asText(content)}`);
|
|
204
|
+
}
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (role === 'assistant') {
|
|
208
|
+
let text = asText(content);
|
|
209
|
+
const toolCalls = m.tool_calls;
|
|
210
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
211
|
+
for (const tc of toolCalls) {
|
|
212
|
+
const name = tc.function?.name ?? '';
|
|
213
|
+
let args = tc.function?.arguments ?? '';
|
|
214
|
+
if (args && typeof args === 'object')
|
|
215
|
+
args = JSON.stringify(args);
|
|
216
|
+
let argsStr = String(args);
|
|
217
|
+
if (argsStr.length > TOOL_ARGS_MAX) {
|
|
218
|
+
argsStr = `${argsStr.slice(0, TOOL_ARGS_MAX)}... [参数已截断]`;
|
|
219
|
+
}
|
|
220
|
+
text += `\n${TOOL_CALL_OPEN}\n{"name": "${name}", "arguments": ${argsStr}}\n${TOOL_CALL_CLOSE}`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (text.length > ASSISTANT_TEXT_MAX) {
|
|
224
|
+
text = `${text.slice(0, ASSISTANT_TEXT_MAX)}... [回复已截断]`;
|
|
225
|
+
}
|
|
226
|
+
parts.push(`[Assistant]\n${text}`);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (role === 'tool') {
|
|
230
|
+
let text = asText(content);
|
|
231
|
+
const name = m.name ?? '';
|
|
232
|
+
const lowerName = name.toLowerCase();
|
|
233
|
+
if (!READ_TOOL_NAMES.has(lowerName) && text.length > TOOL_RESULT_MAX) {
|
|
234
|
+
text = `${text.slice(0, TOOL_RESULT_MAX)}\n... [工具结果已截断,原始长度 ${text.length} 字符]`;
|
|
235
|
+
}
|
|
236
|
+
// 写入成功后提示 AI 别重复 Read / 覆盖
|
|
237
|
+
if (['write_file', 'edit_file'].includes(lowerName) && text.toLowerCase().includes('success')) {
|
|
238
|
+
text +=
|
|
239
|
+
'\n\n[系统提示:文件已完整更新。如需进一步修改,请基于最新内容使用 SearchReplace,不要再用 write_file 覆盖。]';
|
|
240
|
+
}
|
|
241
|
+
// 替换失败时提示换用整文件写入
|
|
242
|
+
if (['searchreplace', 'edit_file', 'str_replace'].includes(lowerName) &&
|
|
243
|
+
(text.toLowerCase().includes('fail') ||
|
|
244
|
+
text.toLowerCase().includes('error') ||
|
|
245
|
+
text.toLowerCase().includes('not found'))) {
|
|
246
|
+
text +=
|
|
247
|
+
'\n\n[系统提示:SearchReplace 失败,可能是缩进或空格不匹配。建议改用 write_file 写入完整文件内容,而不是用 SearchReplace 修改局部。]';
|
|
248
|
+
}
|
|
249
|
+
parts.push(`[Tool Result: ${name} (id=${m.tool_call_id ?? ''})]\n${text}`);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (role === 'function') {
|
|
253
|
+
let text = asText(content);
|
|
254
|
+
if (text.length > FUNCTION_RESULT_MAX) {
|
|
255
|
+
text = `${text.slice(0, FUNCTION_RESULT_MAX)}\n... [函数结果已截断,原始长度 ${text.length} 字符]`;
|
|
256
|
+
}
|
|
257
|
+
parts.push(`[Function Result: ${m.name ?? ''}]\n${text}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return parts.join('\n\n');
|
|
261
|
+
}
|
|
262
|
+
/** 把 content(字符串或数组)压成纯文本。 */
|
|
263
|
+
function asText(content) {
|
|
264
|
+
if (content == null)
|
|
265
|
+
return '';
|
|
266
|
+
if (typeof content === 'string')
|
|
267
|
+
return content;
|
|
268
|
+
if (Array.isArray(content)) {
|
|
269
|
+
return content
|
|
270
|
+
.map((item) => {
|
|
271
|
+
if (typeof item === 'string')
|
|
272
|
+
return item;
|
|
273
|
+
if (item && typeof item === 'object') {
|
|
274
|
+
const rec = item;
|
|
275
|
+
if (rec['type'] === 'image_url')
|
|
276
|
+
return '[Image provided]';
|
|
277
|
+
return String(rec['text'] ?? '');
|
|
278
|
+
}
|
|
279
|
+
return '';
|
|
280
|
+
})
|
|
281
|
+
.join('');
|
|
282
|
+
}
|
|
283
|
+
return String(content);
|
|
284
|
+
}
|
|
285
|
+
/** 便捷:取工具的参数名列表(供 reparse 提示词等使用)。 */
|
|
286
|
+
export { toolParamNames };
|
|
287
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/tools/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python `re` 的 `\w` 等价「内容」(Unicode 字母 / 数字 / 下划线);JS 的 `\w` 只有 ASCII。
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ 这是**类内容**不是类本身 —— 要嵌进别的字符类时用它:
|
|
5
|
+
* `` `[/${PY_W_CHARS}.\\-]+` ``。单独使用时用 {@link PY_W}。
|
|
6
|
+
*/
|
|
7
|
+
export declare const PY_W_CHARS: string;
|
|
8
|
+
/** 等价于 Python `\w` 的完整字符类,可直接放进正则。 */
|
|
9
|
+
export declare const PY_W: string;
|
|
10
|
+
/**
|
|
11
|
+
* DOM 损坏指示器:key 前后出现转义引号、值前出现「预览」前缀。
|
|
12
|
+
* 这些模式在正常 JSON 里不会出现,可作为可靠信号。
|
|
13
|
+
*/
|
|
14
|
+
export declare const DOM_CORRUPTION_INDICATOR: RegExp;
|
|
15
|
+
/**
|
|
16
|
+
* DOM 预览损坏指示器(无反斜杠版):`"pat"path":`、`"nam"name":`。
|
|
17
|
+
* 正常 JSON 的 key 只有一对引号,出现两对即损坏。
|
|
18
|
+
*/
|
|
19
|
+
export declare const DOM_PREVIEW_KEY_INDICATOR: RegExp;
|
|
20
|
+
/** 破碎标签迹象 —— 用于决定是否启用 Pattern 6/7 兜底。 */
|
|
21
|
+
export declare const BROKEN_TAG_INDICATOR: RegExp;
|
|
22
|
+
/** 判断文本是否含智能引号。 */
|
|
23
|
+
export declare function hasSmartQuotes(text: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* 尝试把字符串解析为 JSON(宽容处理代码围栏、非法转义、尾部逗号)。
|
|
26
|
+
*
|
|
27
|
+
* 解析失败时的兜底顺序与原实现一致:
|
|
28
|
+
* 1. 去掉代码围栏后直接 parse
|
|
29
|
+
* 2. 修复非法转义后 parse
|
|
30
|
+
* 3. 若含 DOM 损坏特征 → 返回 undefined(交给 Pattern 7 抢救,不要用正则兜底)
|
|
31
|
+
* 4. 否则用正则提取参数(SearchReplace 缺字段时视为损坏,也返回 undefined)
|
|
32
|
+
*/
|
|
33
|
+
export declare function tryParseJson(raw: string): Record<string, unknown> | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* 修复 AI 输出的常见 JSON 问题(等价于 `_repair_json`)。
|
|
36
|
+
*
|
|
37
|
+
* - 字符串值内的真实换行 → `\n` / `\r` / `\t`
|
|
38
|
+
* - **非法转义序列**(如 `\d` `\w` `\s` 等正则字符)→ 双反斜杠转义
|
|
39
|
+
* - 尾部逗号 → 删除
|
|
40
|
+
* - 被截断在 `\` 处 → 补一个反斜杠
|
|
41
|
+
*/
|
|
42
|
+
export declare function repairJson(text: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* JSON 解析完全失败时的最后兜底:用正则从损坏文本里抠出参数。
|
|
45
|
+
*
|
|
46
|
+
* 提取到的值若含智能引号(DOM 损坏标志)则返回 undefined,
|
|
47
|
+
* 交给 `repairDomCorruptedJson` 做完整修复。
|
|
48
|
+
*/
|
|
49
|
+
export declare function extractToolCallByRegex(text: string): Record<string, unknown> | undefined;
|
|
50
|
+
/** 转义正则字面量(等价于 Python `re.escape`,覆盖所有元字符)。 */
|
|
51
|
+
export declare function escapeRegExp(text: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* 从 DOM 损坏的 JSON 中提取复杂多行字段值(等价于 `_extract_complex_field_from_corrupted`)。
|
|
54
|
+
*
|
|
55
|
+
* 三种损坏模式:
|
|
56
|
+
* - A:key 重复(预览值 + 完整值)
|
|
57
|
+
* - B:值提前闭合(值里的引号未转义)→ 靠「下一个已知 key」定位边界
|
|
58
|
+
* - C:无损坏,普通 `"field": "value"`
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractComplexFieldFromCorrupted(text: string, field: string): string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* 从 DOM 损坏的 JSON 中提取文件路径值(等价于 `_extract_path_from_corrupted`)。
|
|
63
|
+
*
|
|
64
|
+
* 路径值会出现多个「预览前缀」,**最长的那一个**才是完整路径。
|
|
65
|
+
*/
|
|
66
|
+
export declare function extractPathFromCorrupted(text: string): string | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* 修复被 DOM 渲染破坏的 tool_call JSON(等价于 `_repair_dom_corrupted_json`)。
|
|
69
|
+
*
|
|
70
|
+
* 策略:**不逐字符修复**(`\"` → `"` 会产生 `""` 破坏引号配对),
|
|
71
|
+
* 而是从损坏文本里按 token 提取已知 key/value,再重建 JSON。
|
|
72
|
+
*
|
|
73
|
+
* 修复顺序(每一步都有踩坑原因):
|
|
74
|
+
* 1. 先归一化智能引号
|
|
75
|
+
* 2. **再清理 HTML 标签** —— 必须在引号归一化/取 token 之前,
|
|
76
|
+
* 否则 span 的属性引号会打乱后续处理(曾导致 Pattern 7 修复失败、长度不变)
|
|
77
|
+
* 3. token 提取 → 找工具名 / 参数对
|
|
78
|
+
* 4. 路径字段用「最长 `/-前缀字符串`」修正(token 只能拿到 `/ho` 这种短前缀)
|
|
79
|
+
* 5. 工具名缺失时按参数推断
|
|
80
|
+
* 6. 复杂字段用正则重新提取完整值,并移除 token 阶段的短垃圾值
|
|
81
|
+
*/
|
|
82
|
+
export declare function repairDomCorruptedJson(text: string): string;
|
|
83
|
+
//# sourceMappingURL=repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../../src/tools/repair.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,eAAO,MAAM,UAAU,QAA0B,CAAC;AAElD,sCAAsC;AACtC,eAAO,MAAM,IAAI,QAAoB,CAAC;AAKtC;;;GAGG;AACH,eAAO,MAAM,wBAAwB,QAMpC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAA0C,CAAC;AAEjF,yCAAyC;AACzC,eAAO,MAAM,oBAAoB,QAA+B,CAAC;AAKjE,mBAAmB;AACnB,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgD7E;AAaD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+C/C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgErC;AAED,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAyBD;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,SAAS,CAoCpB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUzE;AA8ED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuH3D"}
|