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,525 @@
1
+ /**
2
+ * 路由层公共工具 —— `legacy-python/src/api/routes.py` 第 78~497 行的移植。
3
+ *
4
+ * 这里放的都是**纯函数与常量**,不依赖 Fastify / Provider,便于单测。
5
+ * 预算相关的常量集中在这里,因为它们互相之间有约束关系(见各条注释)。
6
+ */
7
+ import { createHash } from 'node:crypto';
8
+ import { logger } from '../log/logger.js';
9
+ import { getTextContent, messageToDict } from '../types/message.js';
10
+ /* ==================================================================== */
11
+ /* token 估算 / usage / 错误体 */
12
+ /* ==================================================================== */
13
+ /**
14
+ * 估算文本的 token 数。
15
+ *
16
+ * 启发式(与原实现一致):中文约 0.5 token/字,英文约 0.25 token/词。
17
+ * 仅用于 OpenAI 兼容响应的 `usage` 字段,不参与任何决策。
18
+ */
19
+ export function estimateTokens(text) {
20
+ if (!text)
21
+ return 0;
22
+ const chineseCount = (text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) ?? []).length;
23
+ const englishCount = (text.match(/[a-zA-Z]+/g) ?? []).length;
24
+ const other = text.length - chineseCount - englishCount;
25
+ return Math.trunc(chineseCount * 0.5 + englishCount * 0.25 + other * 0.3);
26
+ }
27
+ /** 构建 OpenAI 兼容的 usage 对象。 */
28
+ export function buildUsage(promptText, completionText) {
29
+ const promptTokens = estimateTokens(promptText);
30
+ const completionTokens = estimateTokens(completionText);
31
+ return {
32
+ prompt_tokens: promptTokens,
33
+ completion_tokens: completionTokens,
34
+ total_tokens: promptTokens + completionTokens,
35
+ };
36
+ }
37
+ /** 构建 OpenAI 兼容的错误响应体。 */
38
+ export function openaiErrorResponse(message, errorType = 'invalid_request_error', code) {
39
+ const error = { message, type: errorType };
40
+ if (code != null)
41
+ error['code'] = code;
42
+ return { error };
43
+ }
44
+ /* ==================================================================== */
45
+ /* 上下文 / 用户提问提取 */
46
+ /* ==================================================================== */
47
+ /**
48
+ * 把历史消息格式化为上下文字符串(跨平台切换时注入,保持对话连续性)。
49
+ */
50
+ export function formatHistoryContext(history) {
51
+ const lines = ['[以下是之前的对话历史,请基于此上下文回答最新问题]'];
52
+ for (const msg of history) {
53
+ const role = msg['role'] === 'user' ? 'User' : 'Assistant';
54
+ const content = msg['content'];
55
+ if (content)
56
+ lines.push(`${role}: ${String(content)}`);
57
+ }
58
+ return lines.join('\n');
59
+ }
60
+ /**
61
+ * 从消息列表里提取用户**真正的问题**。
62
+ *
63
+ * ⚠️ 多轮工具调用场景下,`messages` 的最后一条往往是 tool 结果或
64
+ * `<system-reminder>`,**不能直接取 `messages[-1]`**。
65
+ *
66
+ * 优先级:
67
+ * 1. 最后一条含 `<user_query>...</user_query>` 的用户消息里的 query 内容;
68
+ * 2. 最后一条 role=user 且不以 `<system-reminder>` 开头的消息(完整内容);
69
+ * 3. 兜底:最后一条 role=user 的消息。
70
+ */
71
+ export function extractUserQuestion(messages) {
72
+ if (messages.length === 0)
73
+ return '';
74
+ const userMessages = [];
75
+ for (const m of messages) {
76
+ const md = messageToDict(m);
77
+ if (md.role !== 'user')
78
+ continue;
79
+ let text = md.content;
80
+ if (Array.isArray(text)) {
81
+ text = text
82
+ .filter((p) => p && typeof p === 'object' && p['type'] === 'text')
83
+ .map((p) => String(p['text'] ?? ''))
84
+ .join('\n');
85
+ }
86
+ userMessages.push(typeof text === 'string' ? text : getTextContent(text));
87
+ }
88
+ if (userMessages.length === 0)
89
+ return '';
90
+ // 1) 优先取带 <user_query> 的(从后往前)
91
+ for (let i = userMessages.length - 1; i >= 0; i -= 1) {
92
+ const text = userMessages[i];
93
+ // ⚠️ Python 用 re.DOTALL(`.` 匹配换行),TS 对应 `s` 标志
94
+ const m = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(text);
95
+ if (m?.[1] !== undefined)
96
+ return m[1].trim();
97
+ }
98
+ // 2) 最后一条非 system-reminder 的用户消息
99
+ for (let i = userMessages.length - 1; i >= 0; i -= 1) {
100
+ const stripped = userMessages[i].trim();
101
+ if (stripped.startsWith('<system-reminder>'))
102
+ continue;
103
+ return stripped;
104
+ }
105
+ // 3) 兜底
106
+ return userMessages[userMessages.length - 1].trim();
107
+ }
108
+ /* ==================================================================== */
109
+ /* 转换轮 / 续跑轮的材料准备 */
110
+ /* ==================================================================== */
111
+ /**
112
+ * 模型对「网页平台自带工具」的自我纠结 —— 出现在材料里只会把转换轮带沟里。
113
+ *
114
+ * ⚠️ 2026-10-14 实测:主轮被平台 `open`/`search` 劫持后(单轮调 `open` 52 次),
115
+ * 回答与思考里全是这类句子:
116
+ * 「浏览器工具已确认不可用」「open 工具已达到上限,应该停止调用」「已严格遵守系统指令,
117
+ * 停止 search 调用」「搜索结果与本任务无关,忽略」。把它们原样交给转换轮,
118
+ * **同一个 ChatGLM** 会跟着再去调 open/search,又白烧掉 90s(实测 0 工具调用)。
119
+ */
120
+ const PLATFORM_TOOL_NOISE_RE = /(浏览器工具|open\s*工具|search\s*工具|搜索结果|联网搜索|停止调用|停止\s*(?:search|open)|(?:已达|达到|超过)\s*上限|严格遵守系统指令|系统提醒|本任务是纯本地工程任务|立即用\s*bash\s*推进|直接用\s*bash\s*完成|改用\s*bash)/i;
121
+ /**
122
+ * 剔掉「平台自带工具」的议论句,保留模型真正想做的事。
123
+ *
124
+ * 粒度是**句子**而不是整行:同一行里既有议论又有实质(例如「浏览器工具不可用;用 bash 删除
125
+ * /a/b」)时,只丢议论那一句,绝不整行丢 —— 否则会连着真命令一起丢掉。
126
+ */
127
+ export function stripPlatformToolNoise(text) {
128
+ if (!text)
129
+ return '';
130
+ const out = [];
131
+ for (const rawLine of text.split('\n')) {
132
+ const line = rawLine.trim();
133
+ if (!line) {
134
+ out.push('');
135
+ continue;
136
+ }
137
+ // 按句末标点切分(保留标点),只剔除命中的句子
138
+ const kept = line
139
+ .split(/(?<=[。!?!?;;])/)
140
+ .filter((sentence) => sentence.trim() && !PLATFORM_TOOL_NOISE_RE.test(sentence))
141
+ .join('')
142
+ .trim();
143
+ if (kept)
144
+ out.push(kept);
145
+ }
146
+ return out.join('\n').replace(/\n{3,}/g, '\n\n').trim();
147
+ }
148
+ /** 单条进展的截断长度。 */
149
+ function clip(text, maxLen) {
150
+ return text.length > maxLen ? `${text.slice(0, maxLen)}…` : text;
151
+ }
152
+ /**
153
+ * 从消息列表**尾部**抽取「最近进展」,给转换轮当上下文。
154
+ *
155
+ * ⚠️ 2026-10-14:转换轮原来只有「模型自己的自言自语 + 一个取错的用户请求」,
156
+ * 完全不知道进行到哪了(上一轮写了哪个文件、跑过什么命令),自然转不出正确的下一步。
157
+ * `buildReparsePrompt` 的 `conversationHistory` 只被用来**抽文件路径**,从没展示给模型。
158
+ *
159
+ * @param messages 完整消息列表(越靠后越新)
160
+ * @returns 形如 `用户: …` / `AI 调用工具: write_file` / `工具结果: 已写入 …` 的多行文本
161
+ */
162
+ export function formatRecentProgress(messages, options = {}) {
163
+ const { maxEntries = 8, maxCharsPerEntry = 240, maxTotalChars = 1600 } = options;
164
+ const lines = [];
165
+ for (let i = messages.length - 1; i >= 0 && lines.length < maxEntries; i -= 1) {
166
+ const md = messageToDict(messages[i]);
167
+ const role = md.role;
168
+ const text = getTextContent(md.content).replace(/\s+/g, ' ').trim();
169
+ const rawToolCalls = md.tool_calls;
170
+ const names = Array.isArray(rawToolCalls)
171
+ ? rawToolCalls.map((tc) => tc?.function?.name ?? '?')
172
+ : [];
173
+ if (role === 'user' && text) {
174
+ lines.push(`用户: ${clip(text, maxCharsPerEntry)}`);
175
+ }
176
+ else if (role === 'assistant' && names.length > 0) {
177
+ const note = text ? `(旁白: ${clip(text, 80)})` : '';
178
+ lines.push(`AI 调用工具: ${names.join(', ')}${note}`);
179
+ }
180
+ else if (role === 'assistant' && text) {
181
+ lines.push(`AI: ${clip(text, maxCharsPerEntry)}`);
182
+ }
183
+ else if ((role === 'tool' || role === 'function') && text) {
184
+ lines.push(`工具结果: ${clip(text, maxCharsPerEntry)}`);
185
+ }
186
+ }
187
+ const ordered = lines.reverse().join('\n');
188
+ // 超出总预算时只保留**最近**的部分
189
+ return ordered.length > maxTotalChars ? ordered.slice(-maxTotalChars) : ordered;
190
+ }
191
+ /* ==================================================================== */
192
+ /* 预算常量(互相有约束关系,改前务必读完注释) */
193
+ /* ==================================================================== */
194
+ /**
195
+ * 网页端输入框长度上限(实测)。
196
+ *
197
+ * ChatGLM 输入框填 8.2 万字符时:`textarea.value` 正常写入,但按 Enter
198
+ * **不会提交**(不报错、不产生新对话轮次),表现为「模型未返回任何内容」。
199
+ * 实测 7 万字符仍可发送;这里取 64K(留安全余量,同时尽量保留上下文)。
200
+ */
201
+ export const BROWSER_PROMPT_MAX_LEN = 64000;
202
+ /**
203
+ * 整个 HTTP 请求的时间预算(秒)。
204
+ *
205
+ * 必须 < 超时中间件的 300s,并留出把 `[DONE]` 写回客户端的时间。
206
+ *
207
+ * 为什么要设总预算:一次请求内部可能串起**多个完整对话往返** ——
208
+ * 首轮对话 + 两轮策略的 reparse。各轮在 provider 内部各自有 240s 硬超时,
209
+ * 不设总预算则合计必然超 300s:实测首轮 176s + reparse 114s,
210
+ * 被中间件在 300s 处掐断 → 客户端拿到 504,连首轮已经拿到的文本都没有。
211
+ */
212
+ export const TOTAL_TIME_BUDGET = 270.0;
213
+ /**
214
+ * 历史压缩的预算门槛(秒)。
215
+ *
216
+ * 「压缩历史」不是免费的:一份 8 万字符的提示词要压缩 2 次,每次都是一轮完整对话,
217
+ * 实测烧掉 117s,剩下的 150s 只够主对话跑一次 → 「两轮策略」因剩余时间不足被跳过,
218
+ * 模型只交一份计划书就结束回合 → 用户看到「读了半天、一个文件都没改、任务终止」。
219
+ *
220
+ * 对策:剩余预算低于本值就不压缩,改用快速中间截断,把时间留给真正干活的环节。
221
+ */
222
+ export const COMPRESS_MIN_BUDGET = 170.0;
223
+ /** 单块压缩的时间上限(秒),避免无限等待。 */
224
+ export const COMPRESS_CHUNK_MAX_SECONDS = 60.0;
225
+ /**
226
+ * 动作恢复轮(**唯一一层兜底**)的预算:至少要留多少剩余时间才值得启动,以及它自己的上限。
227
+ *
228
+ * 实测一轮完整对话要 20~120s:门槛设得太低会启动一个**注定跑不完**的恢复轮
229
+ * (2026-10-14 实测:首轮烧掉 210s 后只剩 60s,恢复轮一直转到 270s 总预算耗尽,
230
+ * 客户端既没拿到工具调用还多等了 60s)。
231
+ */
232
+ export const CONTINUE_MIN_BUDGET = 80.0;
233
+ export const CONTINUE_MAX_BUDGET = 100.0;
234
+ /**
235
+ * 同一用户请求下允许的最大工具调用轮数。
236
+ *
237
+ * ⚠️ 旧值 8 太小:模型一次想读 4 个文件时我们**只下发第一个**,
238
+ * 8 轮就被截停,然后回一句「操作已完成。」—— 实测用户「帮我修复这几处」,
239
+ * 读了 8 个文件后就被截停,**一个文件都没改**。
240
+ */
241
+ export const TOOL_ROUND_LIMIT = 24;
242
+ /* ==================================================================== */
243
+ /* 只读工具判定 */
244
+ /* ==================================================================== */
245
+ /**
246
+ * 「只读」工具名(归一化后比对:去掉非字母并小写)。
247
+ *
248
+ * 这些调用不改任何状态,同一条回复里的多个调用可以**一起下发**,
249
+ * 由客户端并行执行 —— 省下大量轮次(读取 6 个文件从 6 轮降到 1 轮)。
250
+ */
251
+ export const READ_ONLY_TOOLS = new Set([
252
+ 'read', 'readfile', 'readfiles', 'getfilecontent', 'getfilecontents',
253
+ 'listdir', 'listfiles', 'listdirectory', 'ls', 'glob', 'findfile', 'findfiles',
254
+ 'searchfile', 'searchfiles', 'searchcontent', 'searchcodebase', 'grep',
255
+ 'codesearch', 'readlints', 'view', 'cat', 'stat', 'diff',
256
+ ]);
257
+ /** 工具名是否属于「只读」类(可安全地在同一轮里批量下发)。 */
258
+ export function isReadOnlyTool(name) {
259
+ const n = String(name ?? '').toLowerCase().replace(/[^a-z]/g, '');
260
+ return READ_ONLY_TOOLS.has(n);
261
+ }
262
+ /* ==================================================================== */
263
+ /* 动作恢复轮的触发信号 */
264
+ /* ==================================================================== */
265
+ /**
266
+ * 识别「只给计划、没有动手」的未完成回答。
267
+ *
268
+ * 实测:模型读了 7 轮文件后,最后的回答是一段**计划书** ——
269
+ * 「仍有三处关键文件内容未知…需先补读」—— 里面没有任何工具调用。
270
+ * 客户端收到纯文本即结束回合,用户看到「读了半天、一个文件都没改、任务终止」。
271
+ * 模型还自认为「工具轮数已达上限(8/8)」(这句是它自己脑补的),
272
+ * 于是主动放弃动手改成写计划。
273
+ *
274
+ * 现在它是「动作恢复轮」的触发信号之一(提示词见
275
+ * `tools/prompts.ts::buildActionRecoveryPrompt`,原 `CONTINUE_PROMPT` 已并入)。
276
+ */
277
+ export const UNFINISHED_MARKERS = [
278
+ '需先补读', '需要先补读', '还需补读', '需补读', '补读',
279
+ '无法直接生成', '无法生成编辑', '待下一轮', '下一轮执行', '下一轮再',
280
+ '轮数已达上限', '已达上限', '额度已用尽',
281
+ '尚未修改', '还未修改', '尚未完成', '还没修改', '没有做任何修改',
282
+ '接下来我将', '接下来我会', '下一步将', '下一步我会',
283
+ ];
284
+ /** 回答是否是「只说计划、没有动手」的未完成态。 */
285
+ export function looksUnfinishedAnswer(text) {
286
+ if (!text)
287
+ return false;
288
+ return UNFINISHED_MARKERS.some((m) => text.includes(m));
289
+ }
290
+ /* ==================================================================== */
291
+ /* 回答跑偏检测 */
292
+ /* ==================================================================== */
293
+ /** 项目根路径识别:`/home/<user>/<a>/<b>`(macOS 同理 `/Users/...`)。 */
294
+ export const PROJECT_ROOT_RE = /\/(?:home|Users)\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)/g;
295
+ /**
296
+ * 模型「自认读不到本地文件」的话术:出现这些短语说明它整轮没真正用我们的工具,
297
+ * 而是在跟网页端自带能力(联网搜索等)较劲,回答通常与本项目无关。
298
+ */
299
+ export const SELF_ADMISSION_PHRASES = [
300
+ '工具不可用',
301
+ '工具实际不可用',
302
+ '无法读取文件系统',
303
+ '无法直接访问本地文件',
304
+ '无法直接读取文件',
305
+ '读不到本地文件',
306
+ '从未真正读到',
307
+ '没有 read_file',
308
+ '缺少文件工具',
309
+ '只有 search',
310
+ ];
311
+ /**
312
+ * 检测「回答与本项目无关」的迹象,返回要追加到正文前的提示(无异常返回空串)。
313
+ *
314
+ * 两类信号(实测的跑偏方式):
315
+ * 1. 回答里出现**其他项目根目录**(如 `/home/amble/project/ai-api`),
316
+ * 而当前工作目录是 `/home/amble/object/biga` —— 模型读/聊的是别的项目;
317
+ * 2. 回答自认「工具不可用 / 读不到本地文件」—— 说明它整轮在跟网页端自带的
318
+ * 联网搜索较劲,没真正读本项目代码。
319
+ *
320
+ * 这类回答看起来很自信但与本项目无关,直接把原文给用户是误导,
321
+ * 因此在正文前加一行明确提示(同时打 WARN 便于统计频率)。
322
+ */
323
+ export function detectMismatchedAnswer(text, workspacePath) {
324
+ if (!text || !workspacePath)
325
+ return '';
326
+ const ws = workspacePath.replace(/\/+$/, '');
327
+ if (!ws)
328
+ return '';
329
+ const others = new Set();
330
+ // ⚠️ 正则带 `g` 标志,`exec` 会记住 lastIndex → 必须每次重置
331
+ PROJECT_ROOT_RE.lastIndex = 0;
332
+ let m;
333
+ while ((m = PROJECT_ROOT_RE.exec(text)) !== null) {
334
+ const root = m[0].replace(/\/+$/, '');
335
+ // 互为前缀视为同一个项目(工作目录可能是项目子目录,反之亦然)
336
+ if (ws.startsWith(root) || root.startsWith(ws))
337
+ continue;
338
+ others.add(root);
339
+ }
340
+ const wsBase = ws.split('/').pop() ?? '';
341
+ const wsMentions = countOccurrences(text, ws) + (wsBase.length > 3 ? countOccurrences(text, wsBase) : 0);
342
+ if (others.size > 0 && wsMentions === 0) {
343
+ const listed = [...others].sort().slice(0, 2);
344
+ return (`[提示] 本次回答可能与本项目无关:回答里出现了其他项目路径 ` +
345
+ `${JSON.stringify(listed)},而当前工作目录是 \`${ws}\`。` +
346
+ '模型可能使用了网页端自带的联网搜索或读到了其他项目的记忆,建议重发一次请求。\n\n');
347
+ }
348
+ const hit = SELF_ADMISSION_PHRASES.find((p) => text.includes(p));
349
+ if (hit) {
350
+ return (`[提示] 模型自述「${hit}」:本次回答很可能**不是**基于本项目代码` +
351
+ `(当前工作目录 \`${ws}\`),建议重发一次请求。\n\n`);
352
+ }
353
+ return '';
354
+ }
355
+ /** 统计子串出现次数(Python `str.count`)。 */
356
+ function countOccurrences(haystack, needle) {
357
+ if (!needle)
358
+ return 0;
359
+ let count = 0;
360
+ let idx = haystack.indexOf(needle);
361
+ while (idx !== -1) {
362
+ count += 1;
363
+ idx = haystack.indexOf(needle, idx + needle.length);
364
+ }
365
+ return count;
366
+ }
367
+ /* ==================================================================== */
368
+ /* 提示词截断 */
369
+ /* ==================================================================== */
370
+ /**
371
+ * 截断注入给网页端的 prompt,防止超过输入框上限导致消息发不出去。
372
+ *
373
+ * 截断策略:保留头部(工具调用协议 + 工具列表,决定能否产出工具调用)
374
+ * 与尾部(最近的对话内容,含 `<user_query>`),仅丢弃中间部分。
375
+ */
376
+ export function truncatePromptForBrowser(text, maxLen = BROWSER_PROMPT_MAX_LEN) {
377
+ if (!text || text.length <= maxLen)
378
+ return text;
379
+ const marker = `\n\n... [上下文过长,已省略中间 ${text.length - maxLen} 字符] ...\n\n`;
380
+ const headLen = Math.trunc(maxLen * 0.45);
381
+ const tailLen = maxLen - headLen - marker.length;
382
+ if (tailLen <= 0)
383
+ return text.slice(0, maxLen);
384
+ const truncated = text.slice(0, headLen) + marker + text.slice(-tailLen);
385
+ logger.warn(`[prompt] 注入内容过长(${text.length} 字符),已截断至 ${truncated.length} 字符` +
386
+ `(保留头部 ${headLen} + 尾部 ${tailLen})`);
387
+ return truncated;
388
+ }
389
+ const SESSION_SEND_STATE = new Map();
390
+ /** 最多记住多少个会话。 */
391
+ const SESSION_STATE_MAX = 50;
392
+ /** 30 分钟没再用的记录视为过期(网页会话多半也没了)。 */
393
+ const SESSION_STATE_TTL = 1800.0;
394
+ /**
395
+ * 只有 ChatGLM 用「网页对话」承载上下文。
396
+ *
397
+ * 其他平台即使共用同一个浏览器页面也不能套用增量协议
398
+ * (它们各自会导航到自己的站点,会话互不相通)。
399
+ */
400
+ const SESSION_REUSE_PLATFORMS = new Set(['chatglm']);
401
+ /** 把 `provider.platform` 归一成站点名(`chatglm-browser` → `chatglm`)。 */
402
+ export function platformOf(platformName) {
403
+ if (!platformName)
404
+ return '';
405
+ let name = extractPlatformName(platformName).trim().toLowerCase();
406
+ for (const suffix of ['-browser', '_browser', '-web', '_web']) {
407
+ if (name.endsWith(suffix)) {
408
+ name = name.slice(0, -suffix.length);
409
+ break;
410
+ }
411
+ }
412
+ return name;
413
+ }
414
+ /** 从 provider 的 platform 名里取平台名(目前是直通,保留钩子)。 */
415
+ export function extractPlatformName(providerPlatform) {
416
+ return providerPlatform;
417
+ }
418
+ /**
419
+ * 规范化 JSON(键排序),等价于 Python `json.dumps(sort_keys=True, ensure_ascii=False)`。
420
+ *
421
+ * ⚠️ 仅在**本进程内**用于比对指纹,不与其他语言的实现互通,
422
+ * 因此不需要和 Python 的字节序列完全一致。
423
+ */
424
+ function canonicalJson(value) {
425
+ if (value === null || value === undefined)
426
+ return 'null';
427
+ if (typeof value === 'string')
428
+ return JSON.stringify(value);
429
+ if (typeof value === 'number' || typeof value === 'boolean')
430
+ return JSON.stringify(value);
431
+ if (Array.isArray(value))
432
+ return `[${value.map(canonicalJson).join(', ')}]`;
433
+ if (typeof value === 'object') {
434
+ const rec = value;
435
+ const keys = Object.keys(rec).sort();
436
+ return `{${keys.map((k) => `${JSON.stringify(k)}: ${canonicalJson(rec[k])}`).join(', ')}}`;
437
+ }
438
+ return JSON.stringify(String(value));
439
+ }
440
+ /** 单条消息的指纹(用于逐条比对历史是否被改写)。 */
441
+ export function msgFingerprint(msg) {
442
+ let body;
443
+ try {
444
+ body = canonicalJson(messageToDict(msg));
445
+ }
446
+ catch {
447
+ body = String(msg);
448
+ }
449
+ return createHash('md5').update(body, 'utf8').digest('hex');
450
+ }
451
+ /**
452
+ * 若这个会话的历史是上次的延续,返回「本次新增消息」的列表。
453
+ *
454
+ * @returns 新增消息;不可复用(无记录 / 历史被改写 / 无新增)时返回 `[]`。
455
+ */
456
+ export function getSessionDelta(messages, conversationId) {
457
+ if (!conversationId)
458
+ return [];
459
+ const rec = SESSION_SEND_STATE.get(conversationId);
460
+ if (!rec)
461
+ return [];
462
+ const now = Date.now() / 1000;
463
+ if (now - rec.ts > SESSION_STATE_TTL) {
464
+ SESSION_SEND_STATE.delete(conversationId);
465
+ return [];
466
+ }
467
+ const count = Math.trunc(rec.count || 0);
468
+ if (count <= 0 || count >= messages.length)
469
+ return [];
470
+ // 逐条比对:客户端可能改写历史(编辑消息 / 上下文压缩 / 换工作区),
471
+ // 也可能只是 system 提示词里带了变化的环境信息。
472
+ // 任何一条不一致都不能只发增量(否则网页会话里的上下文与真实历史不符)。
473
+ const prevFps = rec.fps ?? [];
474
+ for (let i = 0; i < Math.min(count, prevFps.length); i += 1) {
475
+ const cur = msgFingerprint(messages[i]);
476
+ if (cur !== prevFps[i]) {
477
+ const role = messageToDict(messages[i]).role;
478
+ logger.info(`[session] 会话 ${conversationId} 的第 ${i} 条消息(${role})与上次不同` +
479
+ '(历史被改写或环境信息变化),本轮发完整提示词');
480
+ SESSION_SEND_STATE.delete(conversationId);
481
+ return [];
482
+ }
483
+ }
484
+ return messages.slice(count);
485
+ }
486
+ /** 记录「这批消息已经发进 platform 的网页会话」,供下次算增量。 */
487
+ export function rememberSessionSend(conversationId, messages, platform) {
488
+ if (!conversationId)
489
+ return;
490
+ const site = platformOf(platform);
491
+ if (!SESSION_REUSE_PLATFORMS.has(site)) {
492
+ SESSION_SEND_STATE.delete(conversationId);
493
+ return;
494
+ }
495
+ // 过期清理 + 容量控制(简单 LRU:按 ts 丢最旧)
496
+ const now = Date.now() / 1000;
497
+ for (const [k, v] of SESSION_SEND_STATE) {
498
+ if (now - v.ts > SESSION_STATE_TTL)
499
+ SESSION_SEND_STATE.delete(k);
500
+ }
501
+ if (SESSION_SEND_STATE.size >= SESSION_STATE_MAX) {
502
+ let oldestKey = null;
503
+ let oldestTs = Number.POSITIVE_INFINITY;
504
+ for (const [k, v] of SESSION_SEND_STATE) {
505
+ if (v.ts < oldestTs) {
506
+ oldestTs = v.ts;
507
+ oldestKey = k;
508
+ }
509
+ }
510
+ if (oldestKey !== null)
511
+ SESSION_SEND_STATE.delete(oldestKey);
512
+ }
513
+ SESSION_SEND_STATE.set(conversationId, {
514
+ count: messages.length,
515
+ fps: messages.map((m) => msgFingerprint(m)),
516
+ platform: site,
517
+ ts: now,
518
+ });
519
+ logger.info(`[session] 已记录会话 ${conversationId} 的发送进度: ${messages.length} 条消息(平台 ${site})`);
520
+ }
521
+ /** 清空会话发送记录(测试用)。 */
522
+ export function __clearSessionSendState() {
523
+ SESSION_SEND_STATE.clear();
524
+ }
525
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/routes/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 元信息路由 —— `/v1/models`、`/v1/health`、`/v1/status` 的移植
3
+ * (`legacy-python/src/api/routes.py` 第 1266~1305、3025~3104 行)。
4
+ */
5
+ import type { FastifyInstance } from 'fastify';
6
+ /**
7
+ * 注册元信息路由。
8
+ *
9
+ * ⚠️ 路由前缀由调用方在 Fastify 注册时给出(`settings.apiPrefix`,
10
+ * 默认 `/v1`),所以这里的路径都不带 `/v1`。
11
+ */
12
+ export declare function registerMetaRoutes(app: FastifyInstance): void;
13
+ /**
14
+ * 启动时的日志重置与历史库自检。
15
+ *
16
+ * ⚠️ 与原实现的差异:Python 是**覆盖写** `logs/api_requests.log` 并写入一行
17
+ * `# API 请求日志 - <时间> 启动`;TS 侧由 `resetApiLog()` 清空(保持「原样记录、
18
+ * 不加工」的契约 —— 头部注释会干扰对日志的 `grep`)。
19
+ *
20
+ * 历史库清理是**异步**的,日志里会带上统计数字。
21
+ */
22
+ export declare function runStartupTasks(): Promise<void>;
23
+ /**
24
+ * 后台定期清理历史消息(每 1 小时一次)。
25
+ *
26
+ * 返回一个可取消的句柄(关服时调用 `stop()`)。
27
+ */
28
+ export declare function startPeriodicHistoryCleanup(intervalMs?: number): {
29
+ stop: () => void;
30
+ };
31
+ //# sourceMappingURL=meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/routes/meta.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA2B/C;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CA4H7D;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBrD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,SAAW,GAAG;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAwBvF"}