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.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -2
  3. package/bin/webapi.mjs +45 -0
  4. package/dist/browser/auth-capture.d.ts +110 -0
  5. package/dist/browser/auth-capture.d.ts.map +1 -0
  6. package/dist/browser/auth-capture.js +487 -0
  7. package/dist/browser/auth-capture.js.map +1 -0
  8. package/dist/browser/credentials.d.ts +102 -0
  9. package/dist/browser/credentials.d.ts.map +1 -0
  10. package/dist/browser/credentials.js +209 -0
  11. package/dist/browser/credentials.js.map +1 -0
  12. package/dist/browser/js-eval.d.ts +44 -0
  13. package/dist/browser/js-eval.d.ts.map +1 -0
  14. package/dist/browser/js-eval.js +20 -0
  15. package/dist/browser/js-eval.js.map +1 -0
  16. package/dist/browser/login-flow.d.ts +171 -0
  17. package/dist/browser/login-flow.d.ts.map +1 -0
  18. package/dist/browser/login-flow.js +606 -0
  19. package/dist/browser/login-flow.js.map +1 -0
  20. package/dist/browser/manager.d.ts +144 -0
  21. package/dist/browser/manager.d.ts.map +1 -0
  22. package/dist/browser/manager.js +586 -0
  23. package/dist/browser/manager.js.map +1 -0
  24. package/dist/browser/platforms.d.ts +96 -0
  25. package/dist/browser/platforms.d.ts.map +1 -0
  26. package/dist/browser/platforms.js +288 -0
  27. package/dist/browser/platforms.js.map +1 -0
  28. package/dist/browser/sse-capture.d.ts +23 -0
  29. package/dist/browser/sse-capture.d.ts.map +1 -0
  30. package/dist/browser/sse-capture.js +199 -0
  31. package/dist/browser/sse-capture.js.map +1 -0
  32. package/dist/browser/stealth.d.ts +12 -0
  33. package/dist/browser/stealth.d.ts.map +1 -0
  34. package/dist/browser/stealth.js +12 -0
  35. package/dist/browser/stealth.js.map +1 -0
  36. package/dist/cli.d.ts +12 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +441 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/config.d.ts +90 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +246 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/controllers/history-db.d.ts +56 -0
  45. package/dist/controllers/history-db.d.ts.map +1 -0
  46. package/dist/controllers/history-db.js +260 -0
  47. package/dist/controllers/history-db.js.map +1 -0
  48. package/dist/controllers/request-pool.d.ts +78 -0
  49. package/dist/controllers/request-pool.d.ts.map +1 -0
  50. package/dist/controllers/request-pool.js +222 -0
  51. package/dist/controllers/request-pool.js.map +1 -0
  52. package/dist/controllers/router.d.ts +172 -0
  53. package/dist/controllers/router.d.ts.map +1 -0
  54. package/dist/controllers/router.js +569 -0
  55. package/dist/controllers/router.js.map +1 -0
  56. package/dist/index.d.ts +72 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +61 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/log/api-logger.d.ts +55 -0
  61. package/dist/log/api-logger.d.ts.map +1 -0
  62. package/dist/log/api-logger.js +264 -0
  63. package/dist/log/api-logger.js.map +1 -0
  64. package/dist/log/debug-logger.d.ts +49 -0
  65. package/dist/log/debug-logger.d.ts.map +1 -0
  66. package/dist/log/debug-logger.js +285 -0
  67. package/dist/log/debug-logger.js.map +1 -0
  68. package/dist/log/logger.d.ts +16 -0
  69. package/dist/log/logger.d.ts.map +1 -0
  70. package/dist/log/logger.js +35 -0
  71. package/dist/log/logger.js.map +1 -0
  72. package/dist/postinstall.d.ts +3 -0
  73. package/dist/postinstall.d.ts.map +1 -0
  74. package/dist/postinstall.js +90 -0
  75. package/dist/postinstall.js.map +1 -0
  76. package/dist/providers/base.d.ts +83 -0
  77. package/dist/providers/base.d.ts.map +1 -0
  78. package/dist/providers/base.js +51 -0
  79. package/dist/providers/base.js.map +1 -0
  80. package/dist/providers/chatglm-dom-extract.d.ts +24 -0
  81. package/dist/providers/chatglm-dom-extract.d.ts.map +1 -0
  82. package/dist/providers/chatglm-dom-extract.js +175 -0
  83. package/dist/providers/chatglm-dom-extract.js.map +1 -0
  84. package/dist/providers/chatglm-dom.d.ts +110 -0
  85. package/dist/providers/chatglm-dom.d.ts.map +1 -0
  86. package/dist/providers/chatglm-dom.js +384 -0
  87. package/dist/providers/chatglm-dom.js.map +1 -0
  88. package/dist/providers/chatglm-sse.d.ts +119 -0
  89. package/dist/providers/chatglm-sse.d.ts.map +1 -0
  90. package/dist/providers/chatglm-sse.js +241 -0
  91. package/dist/providers/chatglm-sse.js.map +1 -0
  92. package/dist/providers/chatglm.d.ts +288 -0
  93. package/dist/providers/chatglm.d.ts.map +1 -0
  94. package/dist/providers/chatglm.js +1631 -0
  95. package/dist/providers/chatglm.js.map +1 -0
  96. package/dist/routes/chat.d.ts +117 -0
  97. package/dist/routes/chat.d.ts.map +1 -0
  98. package/dist/routes/chat.js +1346 -0
  99. package/dist/routes/chat.js.map +1 -0
  100. package/dist/routes/compress.d.ts +142 -0
  101. package/dist/routes/compress.d.ts.map +1 -0
  102. package/dist/routes/compress.js +551 -0
  103. package/dist/routes/compress.js.map +1 -0
  104. package/dist/routes/failover.d.ts +34 -0
  105. package/dist/routes/failover.d.ts.map +1 -0
  106. package/dist/routes/failover.js +221 -0
  107. package/dist/routes/failover.js.map +1 -0
  108. package/dist/routes/helpers.d.ts +174 -0
  109. package/dist/routes/helpers.d.ts.map +1 -0
  110. package/dist/routes/helpers.js +525 -0
  111. package/dist/routes/helpers.js.map +1 -0
  112. package/dist/routes/meta.d.ts +31 -0
  113. package/dist/routes/meta.d.ts.map +1 -0
  114. package/dist/routes/meta.js +184 -0
  115. package/dist/routes/meta.js.map +1 -0
  116. package/dist/routes/sse.d.ts +82 -0
  117. package/dist/routes/sse.d.ts.map +1 -0
  118. package/dist/routes/sse.js +77 -0
  119. package/dist/routes/sse.js.map +1 -0
  120. package/dist/server/app.d.ts +24 -0
  121. package/dist/server/app.d.ts.map +1 -0
  122. package/dist/server/app.js +292 -0
  123. package/dist/server/app.js.map +1 -0
  124. package/dist/server/middleware/api-key.d.ts +61 -0
  125. package/dist/server/middleware/api-key.d.ts.map +1 -0
  126. package/dist/server/middleware/api-key.js +95 -0
  127. package/dist/server/middleware/api-key.js.map +1 -0
  128. package/dist/server/middleware/rate-limit.d.ts +67 -0
  129. package/dist/server/middleware/rate-limit.d.ts.map +1 -0
  130. package/dist/server/middleware/rate-limit.js +134 -0
  131. package/dist/server/middleware/rate-limit.js.map +1 -0
  132. package/dist/server/middleware/timeout.d.ts +34 -0
  133. package/dist/server/middleware/timeout.d.ts.map +1 -0
  134. package/dist/server/middleware/timeout.js +64 -0
  135. package/dist/server/middleware/timeout.js.map +1 -0
  136. package/dist/server/types.d.ts +20 -0
  137. package/dist/server/types.d.ts.map +1 -0
  138. package/dist/server/types.js +2 -0
  139. package/dist/server/types.js.map +1 -0
  140. package/dist/tools/build.d.ts +14 -0
  141. package/dist/tools/build.d.ts.map +1 -0
  142. package/dist/tools/build.js +105 -0
  143. package/dist/tools/build.js.map +1 -0
  144. package/dist/tools/clean.d.ts +32 -0
  145. package/dist/tools/clean.d.ts.map +1 -0
  146. package/dist/tools/clean.js +65 -0
  147. package/dist/tools/clean.js.map +1 -0
  148. package/dist/tools/convert.d.ts +50 -0
  149. package/dist/tools/convert.d.ts.map +1 -0
  150. package/dist/tools/convert.js +289 -0
  151. package/dist/tools/convert.js.map +1 -0
  152. package/dist/tools/names.d.ts +138 -0
  153. package/dist/tools/names.d.ts.map +1 -0
  154. package/dist/tools/names.js +578 -0
  155. package/dist/tools/names.js.map +1 -0
  156. package/dist/tools/parse.d.ts +31 -0
  157. package/dist/tools/parse.d.ts.map +1 -0
  158. package/dist/tools/parse.js +273 -0
  159. package/dist/tools/parse.js.map +1 -0
  160. package/dist/tools/placeholder.d.ts +21 -0
  161. package/dist/tools/placeholder.d.ts.map +1 -0
  162. package/dist/tools/placeholder.js +135 -0
  163. package/dist/tools/placeholder.js.map +1 -0
  164. package/dist/tools/prompts.d.ts +42 -0
  165. package/dist/tools/prompts.d.ts.map +1 -0
  166. package/dist/tools/prompts.js +69 -0
  167. package/dist/tools/prompts.js.map +1 -0
  168. package/dist/tools/protocol.d.ts +58 -0
  169. package/dist/tools/protocol.d.ts.map +1 -0
  170. package/dist/tools/protocol.js +287 -0
  171. package/dist/tools/protocol.js.map +1 -0
  172. package/dist/tools/repair.d.ts +83 -0
  173. package/dist/tools/repair.d.ts.map +1 -0
  174. package/dist/tools/repair.js +510 -0
  175. package/dist/tools/repair.js.map +1 -0
  176. package/dist/tools/workspace.d.ts +40 -0
  177. package/dist/tools/workspace.d.ts.map +1 -0
  178. package/dist/tools/workspace.js +224 -0
  179. package/dist/tools/workspace.js.map +1 -0
  180. package/dist/types/message.d.ts +87 -0
  181. package/dist/types/message.d.ts.map +1 -0
  182. package/dist/types/message.js +85 -0
  183. package/dist/types/message.js.map +1 -0
  184. package/dist/types/openai.d.ts +100 -0
  185. package/dist/types/openai.d.ts.map +1 -0
  186. package/dist/types/openai.js +66 -0
  187. package/dist/types/openai.js.map +1 -0
  188. package/dist/utils/errors.d.ts +82 -0
  189. package/dist/utils/errors.d.ts.map +1 -0
  190. package/dist/utils/errors.js +115 -0
  191. package/dist/utils/errors.js.map +1 -0
  192. package/dist/utils/mutex.d.ts +31 -0
  193. package/dist/utils/mutex.d.ts.map +1 -0
  194. package/dist/utils/mutex.js +61 -0
  195. package/dist/utils/mutex.js.map +1 -0
  196. package/dist/utils/prompt.d.ts +150 -0
  197. package/dist/utils/prompt.d.ts.map +1 -0
  198. package/dist/utils/prompt.js +514 -0
  199. package/dist/utils/prompt.js.map +1 -0
  200. package/dist/utils/text.d.ts +30 -0
  201. package/dist/utils/text.d.ts.map +1 -0
  202. package/dist/utils/text.js +70 -0
  203. package/dist/utils/text.js.map +1 -0
  204. package/package.json +67 -4
  205. package/postinstall.mjs +34 -0
@@ -0,0 +1,273 @@
1
+ /**
2
+ * 从 AI 文本里解析工具调用 —— `legacy-python/src/utils/tool_calls.py` 的 `parse_tool_calls_from_text`。
3
+ *
4
+ * 一共 7 层 Pattern,一层比一层宽容(都是被真实输出逼出来的):
5
+ * 1. `<tool_call>{...}</tool_call>`(我们注入的标准格式)
6
+ * 2. `<tool_call name="X">{...}</tool_call`(模型把名字写成 XML 属性)
7
+ * 3. `{"name":"X","arguments":{...}}</tool_call`(名字在 JSON 里,闭合标签残缺)
8
+ * 4. `tool_call>{...}</tool_call`(少了开头的 `<`)
9
+ * 5. `tool_call>{...}`(完全没有闭合标签)
10
+ * 6. 标签全碎:直接在正文里扫 `{"name": ...}` 并 raw_decode
11
+ * 7. 超级兜底:`<tool_call>` 被当 HTML 消费、内部 JSON 被渲染破坏 → 先修复再扫
12
+ *
13
+ * 返回值与原实现的 Tuple 不同:改为 `{ text, toolCalls }` 对象,避免调用方解构时写错顺序。
14
+ */
15
+ import { logger } from '../log/logger.js';
16
+ import { buildToolCall } from './build.js';
17
+ import { normalizeToolCallTags, stripLeftoverToolTags } from './clean.js';
18
+ import { EMPTY_TOOL_MAPS } from './names.js';
19
+ import { BROKEN_TAG_INDICATOR, DOM_CORRUPTION_INDICATOR, DOM_PREVIEW_KEY_INDICATOR, hasSmartQuotes, repairDomCorruptedJson, tryParseJson, } from './repair.js';
20
+ /**
21
+ * Pattern 1:`<tool_call>{...}</tool_call>`(全局版,DOTALL)
22
+ *
23
+ * ⚠️ 结尾必须带 `>`。Python 原版是 `re.escape("</tool_call>")`,
24
+ * 漏掉 `>` 会导致删除工具调用块后正文里残留一个孤立的 `>`。
25
+ */
26
+ const P1_TOOL_CALL_PATTERN = /<tool_call>\s*(.*?)\s*<\/tool_call>/gsu;
27
+ /** Pattern 2:`<tool_call name="X">{...}</tool_call` */
28
+ const XML_TOOL_CALL_PATTERN = /<tool_call\s+name\s*=\s*["']([^"']+)["']\s*>(.*?)<\/tool_call/gsu;
29
+ /** Pattern 3:`{...}</tool_call`(名字在 JSON 内部) */
30
+ const JSON_TOOL_CALL_PATTERN = /(\{.*?\})\s*<\/tool_call/gsu;
31
+ /** Pattern 4:宽容版,`tool_call>` 前没有 `<` */
32
+ const LENIENT_TOOL_PATTERN = /tool_call>\s*(.*?)\s*<\/tool_call/gsu;
33
+ /** Pattern 5:极宽容,`tool_call>` + JSON 且**完全没有闭合标签** */
34
+ const NO_CLOSE_TOOL_PATTERN = /<?>?tool_call>\s*(\{)/gsu;
35
+ /** 扫描 `{"name": ...}` 起点用的正则(Pattern 6/7)。 */
36
+ const JSON_NAME_START = /\{\s*"name"\s*:\s*"/gu;
37
+ /**
38
+ * 等价于 Python `json.JSONDecoder().raw_decode(text, pos)`。
39
+ *
40
+ * 从 `text[pos]` 开始解析**第一个完整的 JSON 值**,返回其结束位置(**绝对下标**)。
41
+ * Python 的 `raw_decode` 允许后面还有别的内容,JS 的 `JSON.parse` 不允许,
42
+ * 所以这里自己扫括号配平(正确处理字符串与转义),再对切片做 `JSON.parse`。
43
+ *
44
+ * @param pos 起始下标;ChatGLM 的 SSE 报文会把多个 JSON 直接拼在一行,
45
+ * 需要从任意位置连续往后扫(`pos` 让调用方免于反复 `slice`,避免 O(n²))。
46
+ */
47
+ export function rawDecodeJson(text, pos = 0) {
48
+ let i = pos;
49
+ while (i < text.length && /\s/.test(text[i]))
50
+ i += 1;
51
+ const first = text[i];
52
+ if (first !== '{' && first !== '[')
53
+ return undefined;
54
+ let depth = 0;
55
+ let inString = false;
56
+ let escaped = false;
57
+ for (let j = i; j < text.length; j += 1) {
58
+ const ch = text[j];
59
+ if (inString) {
60
+ if (escaped)
61
+ escaped = false;
62
+ else if (ch === '\\')
63
+ escaped = true;
64
+ else if (ch === '"')
65
+ inString = false;
66
+ continue;
67
+ }
68
+ if (ch === '"') {
69
+ inString = true;
70
+ continue;
71
+ }
72
+ if (ch === '{' || ch === '[') {
73
+ depth += 1;
74
+ continue;
75
+ }
76
+ if (ch === '}' || ch === ']') {
77
+ depth -= 1;
78
+ if (depth === 0) {
79
+ try {
80
+ return { value: JSON.parse(text.slice(i, j + 1)), end: j + 1 };
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ }
87
+ }
88
+ return undefined;
89
+ }
90
+ function spansOverlap(start, end, spans) {
91
+ return spans.some(([s, e]) => start < e && end > s);
92
+ }
93
+ /**
94
+ * 从 AI 回复文本中解析工具调用。
95
+ *
96
+ * @param text AI 完整回复
97
+ * @param maps 本请求的工具映射表(决定了标准名会映射到哪个客户端真实工具名)
98
+ */
99
+ export function parseToolCallsFromText(text, maps = EMPTY_TOOL_MAPS) {
100
+ // === 预处理:修复 DOM 提取导致的标签破碎 ===
101
+ const normalized = normalizeToolCallTags(text);
102
+ const toolCalls = [];
103
+ const removalSpans = [];
104
+ let repaired = '';
105
+ /** 统一的「从 JSON 对象构造调用」步骤,成功才登记待删除区间。 */
106
+ const tryAdd = (data, start, end) => {
107
+ if (!data)
108
+ return false;
109
+ const tc = buildToolCall(data['name'], data['arguments'] ?? {}, maps);
110
+ if (!tc)
111
+ return false;
112
+ toolCalls.push(tc);
113
+ removalSpans.push([start, end]);
114
+ return true;
115
+ };
116
+ // --- Pattern 1 ---
117
+ for (const match of normalized.matchAll(P1_TOOL_CALL_PATTERN)) {
118
+ const raw = (match[1] ?? '').trim();
119
+ if (!raw)
120
+ continue;
121
+ // 有 DOM 损坏特征就跳过,交给 Pattern 7;否则 tryParseJson 的正则兜底会拿到短预览值
122
+ if (DOM_PREVIEW_KEY_INDICATOR.test(raw) ||
123
+ DOM_CORRUPTION_INDICATOR.test(raw) ||
124
+ hasSmartQuotes(raw)) {
125
+ continue;
126
+ }
127
+ const start = match.index ?? 0;
128
+ tryAdd(tryParseJson(raw), start, start + match[0].length);
129
+ }
130
+ // --- Pattern 2 ---
131
+ for (const match of normalized.matchAll(new RegExp(XML_TOOL_CALL_PATTERN.source, 'gsu'))) {
132
+ const start = match.index ?? 0;
133
+ const end = start + match[0].length;
134
+ if (spansOverlap(start, end, removalSpans))
135
+ continue;
136
+ const name = (match[1] ?? '').trim();
137
+ const rawArgs = (match[2] ?? '').trim();
138
+ const parsed = rawArgs ? tryParseJson(rawArgs) : undefined;
139
+ const args = parsed && typeof parsed === 'object' ? parsed : {};
140
+ const tc = buildToolCall(name, args, maps);
141
+ if (tc) {
142
+ toolCalls.push(tc);
143
+ removalSpans.push([start, end]);
144
+ }
145
+ }
146
+ // --- Pattern 4 ---
147
+ // ⚠️ 与原设计不同处:这里**先跑 Pattern 4 再跑 Pattern 3**。
148
+ // Pattern 4 的匹配区间包含开头的 `tool_call>`,区间更大,
149
+ // 先注册它就能把整段(含破碎标签)一次删干净;
150
+ // 若按 Python 的顺序先跑 Pattern 3(只从 `{` 开始),
151
+ // 残留的 `tool_call>` 会被 stripLeftoverToolTags 清掉、但最后会多留一个 `>` 在正文里。
152
+ for (const match of normalized.matchAll(new RegExp(LENIENT_TOOL_PATTERN.source, 'gsu'))) {
153
+ const start = match.index ?? 0;
154
+ const end = start + match[0].length;
155
+ if (spansOverlap(start, end, removalSpans))
156
+ continue;
157
+ const raw = (match[1] ?? '').trim();
158
+ if (!raw)
159
+ continue;
160
+ const data = tryParseJson(raw);
161
+ if (!data)
162
+ continue;
163
+ tryAdd(data, start, end);
164
+ }
165
+ // --- Pattern 3 ---
166
+ for (const match of normalized.matchAll(new RegExp(JSON_TOOL_CALL_PATTERN.source, 'gsu'))) {
167
+ const start = match.index ?? 0;
168
+ const end = start + match[0].length;
169
+ if (spansOverlap(start, end, removalSpans))
170
+ continue;
171
+ const raw = (match[1] ?? '').trim();
172
+ if (!raw)
173
+ continue;
174
+ const data = tryParseJson(raw);
175
+ if (!data)
176
+ continue;
177
+ tryAdd(data, start, end);
178
+ }
179
+ // --- Pattern 5 ---
180
+ for (const match of normalized.matchAll(new RegExp(NO_CLOSE_TOOL_PATTERN.source, 'gsu'))) {
181
+ const start = match.index ?? 0;
182
+ const end = start + match[0].length;
183
+ if (spansOverlap(start, end, removalSpans))
184
+ continue;
185
+ const jsonStart = start + match[0].length - 1; // 指向 "{"
186
+ const decoded = rawDecodeJson(normalized.slice(jsonStart));
187
+ if (!decoded)
188
+ continue;
189
+ const data = decoded.value;
190
+ if (!data || typeof data !== 'object')
191
+ continue;
192
+ const tc = buildToolCall(data['name'], data['arguments'] ?? {}, maps);
193
+ if (tc) {
194
+ toolCalls.push(tc);
195
+ removalSpans.push([start, jsonStart + decoded.end]);
196
+ }
197
+ }
198
+ // --- Pattern 6:标签全碎时从正文里扫 JSON ---
199
+ if (toolCalls.length === 0 && BROKEN_TAG_INDICATOR.test(normalized)) {
200
+ logger.info('[tool_calls] 标签破碎但未提取到工具调用,启用 Pattern 6 兜底扫描');
201
+ scanStandaloneJson(normalized, toolCalls, removalSpans, maps);
202
+ }
203
+ // --- Pattern 7:修复被 DOM 破坏的 JSON 后再扫 ---
204
+ if (toolCalls.length === 0 &&
205
+ (BROKEN_TAG_INDICATOR.test(normalized) ||
206
+ DOM_CORRUPTION_INDICATOR.test(normalized) ||
207
+ DOM_PREVIEW_KEY_INDICATOR.test(normalized))) {
208
+ repaired = repairDomCorruptedJson(normalized);
209
+ if (repaired && repaired !== normalized) {
210
+ logger.info({ from: normalized.length, to: repaired.length }, '[tool_calls] Pattern 7 DOM 损坏修复');
211
+ const before = toolCalls.length;
212
+ scanStandaloneJson(repaired, toolCalls, removalSpans, maps);
213
+ for (const tc of toolCalls.slice(before)) {
214
+ const name = tc.function.name;
215
+ let argKeys = [];
216
+ try {
217
+ const parsed = JSON.parse(tc.function.arguments);
218
+ if (parsed && typeof parsed === 'object')
219
+ argKeys = Object.keys(parsed);
220
+ }
221
+ catch {
222
+ // 忽略:只为日志
223
+ }
224
+ logger.info({ name, argKeys }, '[tool_calls] Pattern 7 修复后提取');
225
+ if (name === 'SearchReplace') {
226
+ try {
227
+ const parsed = JSON.parse(tc.function.arguments);
228
+ logger.info({
229
+ filePath: parsed['file_path'],
230
+ oldStrLen: String(parsed['old_str'] ?? '').length,
231
+ newStrLen: String(parsed['new_str'] ?? '').length,
232
+ }, '[tool_calls] SearchReplace 参数');
233
+ }
234
+ catch {
235
+ // 忽略
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
241
+ // === 移除所有命中的区间(从后往前,避免位置失效) ===
242
+ let remaining = toolCalls.length > 0 && repaired && repaired !== normalized ? repaired : normalized;
243
+ for (const [start, end] of [...removalSpans].sort((a, b) => b[0] - a[0])) {
244
+ remaining = remaining.slice(0, start) + remaining.slice(end);
245
+ }
246
+ return { text: stripLeftoverToolTags(remaining).trim(), toolCalls };
247
+ }
248
+ /**
249
+ * 扫描形如 `{"name": "...", "arguments": {...}}` 的独立 JSON 对象。
250
+ * Pattern 6 / Pattern 7 共用。
251
+ */
252
+ function scanStandaloneJson(source, toolCalls, removalSpans, maps) {
253
+ for (const match of source.matchAll(new RegExp(JSON_NAME_START.source, 'gu'))) {
254
+ const jsonStart = match.index ?? 0;
255
+ if (spansOverlap(jsonStart, jsonStart + match[0].length, removalSpans))
256
+ continue;
257
+ const decoded = rawDecodeJson(source.slice(jsonStart));
258
+ if (!decoded)
259
+ continue;
260
+ const data = decoded.value;
261
+ if (!data || typeof data !== 'object')
262
+ continue;
263
+ if (!('name' in data) || !('arguments' in data))
264
+ continue;
265
+ const tc = buildToolCall(data['name'], data['arguments'], maps);
266
+ if (tc) {
267
+ toolCalls.push(tc);
268
+ removalSpans.push([jsonStart, jsonStart + decoded.end]);
269
+ logger.info({ name: data['name'] }, '[tool_calls] 独立 JSON 兜底提取');
270
+ }
271
+ }
272
+ }
273
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/tools/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ToolCallPayload } from '../types/message.js';
2
+ /** 占位符「整值」集合:仅当参数值**整体等于**其中之一时才判定为占位符。 */
3
+ export declare const PLACEHOLDER_VALUES: ReadonlyArray<string>;
4
+ /** 只有这些「路径类」字段才做占位符判定。 */
5
+ export declare const PLACEHOLDER_PATH_KEYS: ReadonlyArray<string>;
6
+ /** 占位符工具名。 */
7
+ export declare const PLACEHOLDER_TOOL_NAMES: ReadonlySet<string>;
8
+ /**
9
+ * 判断工具调用是否为「示例占位符」而非真实调用。
10
+ *
11
+ * 两种情况都应丢弃:
12
+ * 1. **工具名本身是占位符**(如 `工具名称`),或含未填充的尖括号
13
+ * 2. **参数值是占位符**(如 `真实文件路径` / `文件内容`)
14
+ */
15
+ export declare function isPlaceholderToolCall(toolCall: ToolCallPayload): boolean;
16
+ /** 过滤掉占位符工具调用,返回 `[有效, 被丢弃]`。 */
17
+ export declare function filterPlaceholderToolCalls(toolCalls: ReadonlyArray<ToolCallPayload> | null | undefined): {
18
+ valid: ToolCallPayload[];
19
+ dropped: ToolCallPayload[];
20
+ };
21
+ //# sourceMappingURL=placeholder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholder.d.ts","sourceRoot":"","sources":["../../src/tools/placeholder.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,2CAA2C;AAC3C,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC,MAAM,CAcpD,CAAC;AAEF,0BAA0B;AAC1B,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,CAMvD,CAAC;AAEF,cAAc;AACd,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAWrD,CAAC;AAsBH;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAkCxE;AAED,iCAAiC;AACjC,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3D;IAAE,KAAK,EAAE,eAAe,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,CAsB1D"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * 占位符工具调用过滤 —— `legacy-python/src/utils/tool_calls.py` 的一部分。
3
+ *
4
+ * AI 有时会把提示词里的**格式示例**原样抄出来:
5
+ * `{"name": "工具名称", "arguments": {"参数1": "值1"}}`,
6
+ * IDE 会去执行一个不存在的工具并报错,必须在返回前拦截。
7
+ *
8
+ * ⚠️ **判定必须从严**:只认「整值就是占位符」,**绝不做子串包含判断**。
9
+ * 真实文件内容里出现「新代码」「文件内容」等词完全正常,
10
+ * 子串判断会把合法的 `write_to_file` 误杀(曾导致工具调用被整体丢弃,
11
+ * 客户端只收到纯文本而不再继续执行工具)。
12
+ */
13
+ import { logger } from '../log/logger.js';
14
+ /** 占位符「整值」集合:仅当参数值**整体等于**其中之一时才判定为占位符。 */
15
+ export const PLACEHOLDER_VALUES = [
16
+ '真实文件路径',
17
+ '文件内容',
18
+ '要替换的代码',
19
+ '新代码',
20
+ 'your_file_path',
21
+ 'your_file',
22
+ 'path/to/file',
23
+ 'path/to/your/file',
24
+ 'example.com/path',
25
+ '参数1',
26
+ '参数2',
27
+ '值1',
28
+ '值2',
29
+ ];
30
+ /** 只有这些「路径类」字段才做占位符判定。 */
31
+ export const PLACEHOLDER_PATH_KEYS = [
32
+ 'file_path',
33
+ 'filepath',
34
+ 'path',
35
+ 'filename',
36
+ 'file',
37
+ ];
38
+ /** 占位符工具名。 */
39
+ export const PLACEHOLDER_TOOL_NAMES = new Set([
40
+ '工具名称',
41
+ '工具名',
42
+ '工具',
43
+ '参数1',
44
+ '<工具名>',
45
+ 'tool_name',
46
+ 'toolname',
47
+ 'your_tool',
48
+ 'tool',
49
+ 'function_name',
50
+ ]);
51
+ /** 纯尖括号模板,如 `<file_path>` / `<此处填写真实文件路径>`。 */
52
+ const ANGLE_PLACEHOLDER = /^<[^<>]{1,50}>$/;
53
+ function parseArguments(raw) {
54
+ if (typeof raw === 'string') {
55
+ try {
56
+ const parsed = JSON.parse(raw);
57
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
58
+ ? parsed
59
+ : undefined;
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ }
65
+ if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
66
+ return raw;
67
+ }
68
+ return undefined;
69
+ }
70
+ /**
71
+ * 判断工具调用是否为「示例占位符」而非真实调用。
72
+ *
73
+ * 两种情况都应丢弃:
74
+ * 1. **工具名本身是占位符**(如 `工具名称`),或含未填充的尖括号
75
+ * 2. **参数值是占位符**(如 `真实文件路径` / `文件内容`)
76
+ */
77
+ export function isPlaceholderToolCall(toolCall) {
78
+ let name = '';
79
+ let rawArgs = '{}';
80
+ try {
81
+ name = String(toolCall?.function?.name ?? '');
82
+ rawArgs = toolCall?.function?.arguments ?? '{}';
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ const nameStripped = name.trim();
88
+ if (PLACEHOLDER_TOOL_NAMES.has(nameStripped))
89
+ return true;
90
+ if (nameStripped.includes('<') || nameStripped.includes('>'))
91
+ return true;
92
+ const args = parseArguments(rawArgs);
93
+ if (!args)
94
+ return false; // 解析不了就不判定,宁可放过
95
+ for (const [key, val] of Object.entries(args)) {
96
+ if (typeof val !== 'string')
97
+ continue;
98
+ const v = val.trim();
99
+ if (!v)
100
+ continue;
101
+ // 纯尖括号模板
102
+ if (v.length <= 60 && ANGLE_PLACEHOLDER.test(v))
103
+ return true;
104
+ // 路径类字段:整值等于示例词,或明显是示例路径
105
+ if (PLACEHOLDER_PATH_KEYS.includes(key.toLowerCase())) {
106
+ if (PLACEHOLDER_VALUES.includes(v))
107
+ return true;
108
+ if (v.startsWith('your_file') || v.startsWith('example.com'))
109
+ return true;
110
+ }
111
+ }
112
+ return false;
113
+ }
114
+ /** 过滤掉占位符工具调用,返回 `[有效, 被丢弃]`。 */
115
+ export function filterPlaceholderToolCalls(toolCalls) {
116
+ const valid = [];
117
+ const dropped = [];
118
+ for (const tc of toolCalls ?? []) {
119
+ if (isPlaceholderToolCall(tc))
120
+ dropped.push(tc);
121
+ else
122
+ valid.push(tc);
123
+ }
124
+ if (dropped.length > 0) {
125
+ const detail = dropped.map((tc) => {
126
+ let args = tc.function?.arguments ?? '';
127
+ if (typeof args === 'string' && args.length > 200)
128
+ args = `${args.slice(0, 200)}...`;
129
+ return `${tc.function?.name}(${String(args)})`;
130
+ });
131
+ logger.warn({ count: dropped.length }, `[tool_calls] 丢弃 ${dropped.length} 个占位符工具调用(参数整值为示例文本):${detail.join(' | ')}`);
132
+ }
133
+ return { valid, dropped };
134
+ }
135
+ //# sourceMappingURL=placeholder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholder.js","sourceRoot":"","sources":["../../src/tools/placeholder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,2CAA2C;AAC3C,MAAM,CAAC,MAAM,kBAAkB,GAA0B;IACvD,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,KAAK;IACL,gBAAgB;IAChB,WAAW;IACX,cAAc;IACd,mBAAmB;IACnB,kBAAkB;IAClB,KAAK;IACL,KAAK;IACL,IAAI;IACJ,IAAI;CACL,CAAC;AAEF,0BAA0B;AAC1B,MAAM,CAAC,MAAM,qBAAqB,GAA0B;IAC1D,WAAW;IACX,UAAU;IACV,MAAM;IACN,UAAU;IACV,MAAM;CACP,CAAC;AAEF,cAAc;AACd,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC;IACjE,MAAM;IACN,KAAK;IACL,IAAI;IACJ,KAAK;IACL,OAAO;IACP,WAAW;IACX,UAAU;IACV,WAAW;IACX,MAAM;IACN,eAAe;CAChB,CAAC,CAAC;AAEH,+CAA+C;AAC/C,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAE5C,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBACnE,CAAC,CAAE,MAAkC;gBACrC,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,GAA8B,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAyB;IAC7D,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,OAAO,GAAY,IAAI,CAAC;IAC5B,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,GAAG,QAAQ,EAAE,QAAQ,EAAE,SAAS,IAAI,IAAI,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,sBAAsB,CAAC,GAAG,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1E,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC,CAAC,gBAAgB;IAEzC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,SAAS;QAEtC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC;YAAE,SAAS;QAEjB,SAAS;QACT,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAE7D,yBAAyB;QACzB,IAAI,qBAAqB,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACtD,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YAChD,IAAI,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,0BAA0B,CACxC,SAA4D;IAE5D,MAAM,KAAK,GAAsB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,MAAM,EAAE,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,qBAAqB,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;YAChC,IAAI,IAAI,GAAqB,EAAE,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,CAAC;YAC1D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;gBAAE,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC;YACrF,OAAO,GAAG,EAAE,CAAC,QAAQ,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACjD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CACT,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,EACzB,mBAAmB,OAAO,CAAC,MAAM,wBAAwB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAC9E,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 兜底轮的提示词 —— 原来是「两轮策略转换器」(`build_reparse_prompt`),
3
+ * 2026-10-14 与「自驱动续跑」「工具名纠正轮」合并成**唯一一层**动作恢复轮
4
+ * (见 `docs/native-parity.md`)。
5
+ *
6
+ * ⚠️ 关键踩坑(2026-09-2x):工具名**必须取自客户端真实 tools**,绝不能硬编码
7
+ * `Write` / `SearchReplace` / `Read`。实测客户端只提供 `list_dir`/`read_file`/`search_content`
8
+ * 时,旧提示词却写着「工具名必须严格使用以下名称:read_file, Write, SearchReplace」,
9
+ * 转换器照着输出 → 客户端没有这些工具 → 被 `filterUnknownToolCalls` 全部丢弃,
10
+ * 表现为「转换成功但 IDE 不执行」。
11
+ */
12
+ import type { ToolDefinition } from '../types/message.js';
13
+ /** 恢复轮里回放「上一轮回复」的长度上限。 */
14
+ export declare const RECOVERY_ANSWER_MAX_LEN = 4000;
15
+ export interface BuildActionRecoveryPromptOptions {
16
+ /** 上一轮的回复/思考正文(可能为空 —— 整轮只输出了一段 `<tool_call>` 块)。 */
17
+ answer?: string;
18
+ /** 上一轮里「客户端没有这个工具」的调用名(空数组表示「压根没给出调用」)。 */
19
+ invalidNames?: ReadonlyArray<string>;
20
+ /** 上一轮这些调用的原文(`name(arguments)`),让模型看清自己原本想调什么。 */
21
+ invalidCalls?: ReadonlyArray<string>;
22
+ /** 「最近进展」文本(`formatRecentProgress()` 的产出)。 */
23
+ recentProgress?: string;
24
+ /** 当前工作目录;默认取 `process.cwd()`(对应 Python 的 `os.getcwd()`)。 */
25
+ currentWorkingDir?: string;
26
+ }
27
+ /**
28
+ * 构造**唯一一层**兜底的提示词:逼模型把「下一步」变成真实的工具调用。
29
+ *
30
+ * ## 为什么只有一层(2026-10-14 重构)
31
+ * 原来有**三套**独立兜底,最坏会串起来跑 2~3 轮额外对话(每轮实测 30~98s):
32
+ * - 「两轮策略 reparse」:本轮没有任何工具调用 → 让模型把文字转成调用;
33
+ * - 「自驱动续跑」:回答像计划书(只说不做)→ 再驱动一轮;
34
+ * - 「工具名纠正轮」:调了客户端没有的工具(如平台自带的 `execute_sandbox_code`)→ 纠正。
35
+ * 三者的**触发条件互斥、提示词高度重叠**,合并成一个 directive 提示词即可,
36
+ * 且总成本封顶为**一轮**(见 `docs/native-parity.md` 的「取舍与代价」)。
37
+ *
38
+ * ⚠️ 与 `buildReparsePrompt` 同样的铁律:**工具名/参数名只能取自客户端真实 tools**,
39
+ * 绝不在提示词里硬编码任何工具名。
40
+ */
41
+ export declare function buildActionRecoveryPrompt(tools: ReadonlyArray<ToolDefinition>, options?: BuildActionRecoveryPromptOptions): string;
42
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/tools/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAQ1D,0BAA0B;AAC1B,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,MAAM,WAAW,gCAAgC;IAC/C,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,mDAAmD;IACnD,YAAY,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,EACpC,OAAO,GAAE,gCAAqC,GAC7C,MAAM,CAyDR"}
@@ -0,0 +1,69 @@
1
+ import { toolNameOf, toolParamNames } from '../types/message.js';
2
+ import { TOOL_CALL_CLOSE, TOOL_CALL_OPEN } from './protocol.js';
3
+ /* ==================================================================== */
4
+ /* 动作恢复轮(**唯一一层兜底**) */
5
+ /* ==================================================================== */
6
+ /** 恢复轮里回放「上一轮回复」的长度上限。 */
7
+ export const RECOVERY_ANSWER_MAX_LEN = 4000;
8
+ /**
9
+ * 构造**唯一一层**兜底的提示词:逼模型把「下一步」变成真实的工具调用。
10
+ *
11
+ * ## 为什么只有一层(2026-10-14 重构)
12
+ * 原来有**三套**独立兜底,最坏会串起来跑 2~3 轮额外对话(每轮实测 30~98s):
13
+ * - 「两轮策略 reparse」:本轮没有任何工具调用 → 让模型把文字转成调用;
14
+ * - 「自驱动续跑」:回答像计划书(只说不做)→ 再驱动一轮;
15
+ * - 「工具名纠正轮」:调了客户端没有的工具(如平台自带的 `execute_sandbox_code`)→ 纠正。
16
+ * 三者的**触发条件互斥、提示词高度重叠**,合并成一个 directive 提示词即可,
17
+ * 且总成本封顶为**一轮**(见 `docs/native-parity.md` 的「取舍与代价」)。
18
+ *
19
+ * ⚠️ 与 `buildReparsePrompt` 同样的铁律:**工具名/参数名只能取自客户端真实 tools**,
20
+ * 绝不在提示词里硬编码任何工具名。
21
+ */
22
+ export function buildActionRecoveryPrompt(tools, options = {}) {
23
+ const { answer = '', invalidNames = [], invalidCalls = [], recentProgress = '', currentWorkingDir = process.cwd(), } = options;
24
+ const names = [...new Set(invalidNames.map((n) => (n ?? '').trim()).filter(Boolean))];
25
+ const namesText = names.map((n) => `\`${n}\``).join(', ');
26
+ // 问题定性:调错名字 vs 压根没动手(两者的「必须做的事」是一样的)
27
+ const problem = names.length
28
+ ? `你调用了**本环境不存在的工具**:${namesText}。\n` +
29
+ '那些名字属于网页平台自带的工具(代码沙箱 / 联网搜索之类),本地客户端**没有提供**,' +
30
+ '调用无效 —— 那一轮什么都不会被执行。'
31
+ : '你上一轮**没有给出可执行的工具调用**(只有文字/计划),这在当前环境下是无效回复。';
32
+ // 工具清单只列名称与参数名(长描述会干扰这一轮)
33
+ const toolLines = tools.map((tool) => {
34
+ const name = toolNameOf(tool);
35
+ const params = toolParamNames(tool).join(', ');
36
+ const desc = tool?.function?.description ?? '';
37
+ const shortDesc = desc.length > 60 ? `${desc.slice(0, 60)}...` : desc;
38
+ return `- ${name}(${params}): ${shortDesc}`;
39
+ });
40
+ const trimmedAnswer = answer.trim();
41
+ let shownAnswer = trimmedAnswer.slice(0, RECOVERY_ANSWER_MAX_LEN);
42
+ if (trimmedAnswer.length > RECOVERY_ANSWER_MAX_LEN) {
43
+ shownAnswer += '\n\n[... 内容已截断 ...]';
44
+ }
45
+ const answerBlock = shownAnswer ? `\n[你上一轮的回复]\n${shownAnswer}\n` : '';
46
+ const callsBlock = invalidCalls.length > 0 ? `\n[你上一轮实际输出的调用]\n${invalidCalls.join('\n')}\n` : '';
47
+ const progressBlock = recentProgress ? `\n# 最近进展(对话尾部)\n${recentProgress}\n` : '';
48
+ return `你上一轮没有推进任务。${problem}
49
+
50
+ [现在必须做的事]
51
+ 1. **只输出工具调用**(${TOOL_CALL_OPEN}...${TOOL_CALL_CLOSE}),不要任何解释、计划、清单、总结,
52
+ 也不要复述本段文字。
53
+ 2. 把「下一步」换成下方清单里的**真实工具**:要执行代码/命令 → 用命令执行类工具;
54
+ 要读文件 → 用读取类工具;要改文件 → 用修改/写入类工具。
55
+ 3. **禁止**输出清单以外的工具名${namesText ? `(尤其禁止 ${namesText})` : ''};
56
+ **禁止占位符**(如「真实文件路径」「文件内容」「<...>」),file_path 用真实绝对路径。
57
+ 4. 不需要再问、不要再确认——直接调用。
58
+ 5. **不要重复已经执行过的同一条调用**(同工具 + 同参数);
59
+ 如果事实上已经没有新动作可做,就只输出一行文字:\`任务已完成。\`
60
+
61
+ # 本次可用的真实工具(只有这些可用)
62
+ ${toolLines.join('\n')}
63
+
64
+ # 当前工作目录
65
+ \`${currentWorkingDir}\`
66
+ ${progressBlock}${answerBlock}${callsBlock}
67
+ 现在输出工具调用:`;
68
+ }
69
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/tools/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { ChatMessage, MessageDict, ToolDefinition } from '../types/message.js';
2
+ import { toolParamNames } from '../types/message.js';
3
+ import { type ToolMaps } from './names.js';
4
+ /** 工具调用的 XML 标签。 */
5
+ export declare const TOOL_CALL_OPEN = "<tool_call>";
6
+ export declare const TOOL_CALL_CLOSE = "</tool_call>";
7
+ /** 匹配 `<tool_call>...</tool_call>` 块。 */
8
+ export declare const TOOL_CALL_PATTERN: RegExp;
9
+ /**
10
+ * 工具说明在提示词中的最大长度。
11
+ *
12
+ * 客户端的工具说明常常很长(含 Usage/Examples),全部注入会吃掉输入框额度,
13
+ * 且**提示词越长模型越容易「只描述不调用」**。截断成一句话足够选对工具。
14
+ */
15
+ export declare const TOOL_DESC_MAX_LEN = 80;
16
+ export interface FormatToolsOptions {
17
+ /** 用户项目/工作目录(用于防止模型编造路径)。 */
18
+ workspacePath?: string;
19
+ /** 对话中已出现过的真实文件路径。 */
20
+ knownFilePaths?: readonly string[];
21
+ }
22
+ /**
23
+ * 把 OpenAI `tools` 定义渲染成注入用的文本块。
24
+ *
25
+ * 返回的文本会被追加到系统提示里,告诉模型用 `<tool_call>` 标签输出调用。
26
+ *
27
+ * 工具列表用**紧凑格式**:`名称(必填*,可选):说明`。
28
+ * 27 个工具实测从 11,892 字符降到 3,462 字符(-71%)。
29
+ */
30
+ export declare function formatToolsAsText(tools: ReadonlyArray<ToolDefinition>, options?: FormatToolsOptions): string;
31
+ /** `formatToolsAsText` + 映射表的组合结果。 */
32
+ export interface ToolProtocol {
33
+ /** 要注入提示词的文本。 */
34
+ text: string;
35
+ /** 本请求专用的映射表(替代 Python 版的全局变量)。 */
36
+ maps: ToolMaps;
37
+ }
38
+ /**
39
+ * 一次算出「注入文本 + 映射表」。
40
+ *
41
+ * 路由层应该用这个函数而不是分别调用 `formatToolsAsText` / `createToolMaps`,
42
+ * 避免映射表与提示词里的工具列表不一致。
43
+ */
44
+ export declare function buildToolProtocol(tools: ReadonlyArray<ToolDefinition>, options?: FormatToolsOptions): ToolProtocol;
45
+ /**
46
+ * 把所有消息拍平成一段文本(等价于 `format_messages_as_text`)。
47
+ *
48
+ * 目的:让网页版模型在**一次提示**里看到完整对话上下文。
49
+ *
50
+ * 截断策略(这里是**唯一会丢内容**的地方):
51
+ * - tool_call 参数 > 3000 字符 → 截断
52
+ * - assistant 文本 > 3000 字符 → 截断
53
+ * - tool 结果 > 5000 字符 → 截断(Read 类例外,保留全文)
54
+ */
55
+ export declare function formatMessagesAsText(messages: ReadonlyArray<ChatMessage | MessageDict>): string;
56
+ /** 便捷:取工具的参数名列表(供 reparse 提示词等使用)。 */
57
+ export { toolParamNames };
58
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/tools/protocol.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAGL,cAAc,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAmC,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5E,oBAAoB;AACpB,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAC5C,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAE9C,yCAAyC;AACzC,eAAO,MAAM,iBAAiB,QAG7B,CAAC;AAMF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAKpC,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,EACpC,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAiHR;AAED,sCAAsC;AACtC,MAAM,WAAW,YAAY;IAC3B,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,EACpC,OAAO,GAAE,kBAAuB,GAC/B,YAAY,CAKd;AAcD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,MAAM,CA8F/F;AAsBD,sCAAsC;AACtC,OAAO,EAAE,cAAc,EAAE,CAAC"}