@bolloon/bolloon-agent 0.2.1 → 0.2.3

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 (118) hide show
  1. package/bin/ipfs +0 -0
  2. package/dist/agents/judgment-protocol.js +479 -0
  3. package/dist/agents/parse-tool-call.js +304 -0
  4. package/dist/agents/pi-sdk.js +190 -267
  5. package/dist/agents/react-loop.js +86 -0
  6. package/dist/agents/session-store.js +157 -0
  7. package/dist/agents/tool-registry.js +136 -0
  8. package/dist/agents/workflow-pivot-loop.js +40 -0
  9. package/dist/bollharness/src/index.js +5 -0
  10. package/dist/bollharness/src/scripts/checks/check_adr_plan_numbering.js +6 -0
  11. package/dist/bollharness/src/scripts/checks/check_api_types.js +45 -0
  12. package/dist/bollharness/src/scripts/checks/check_artifact_link.js +146 -0
  13. package/dist/bollharness/src/scripts/checks/check_bridge_deps.js +6 -0
  14. package/dist/bollharness/src/scripts/checks/check_bugfix_binding.js +6 -0
  15. package/dist/bollharness/src/scripts/checks/check_bugfix_binding_ci.js +6 -0
  16. package/dist/bollharness/src/scripts/checks/check_doc_file_references.js +6 -0
  17. package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +135 -0
  18. package/dist/bollharness/src/scripts/checks/check_doc_links.js +31 -0
  19. package/dist/bollharness/src/scripts/checks/check_file_existence_claims.js +6 -0
  20. package/dist/bollharness/src/scripts/checks/check_fragment_integrity.js +34 -0
  21. package/dist/bollharness/src/scripts/checks/check_hook_installed.js +63 -0
  22. package/dist/bollharness/src/scripts/checks/check_issue_closure.js +41 -0
  23. package/dist/bollharness/src/scripts/checks/check_mcp_parity.js +6 -0
  24. package/dist/bollharness/src/scripts/checks/check_security.js +48 -0
  25. package/dist/bollharness/src/scripts/checks/check_skill_parity.js +6 -0
  26. package/dist/bollharness/src/scripts/checks/check_versions.js +6 -0
  27. package/dist/bollharness/src/scripts/checks/finding.js +13 -0
  28. package/dist/bollharness/src/scripts/checks/next_decision_number.js +20 -0
  29. package/dist/bollharness/src/scripts/checks/regenerate_magic_docs.js +6 -0
  30. package/dist/bollharness/src/scripts/ci/detect_rebaseline_triggers.js +8 -0
  31. package/dist/bollharness/src/scripts/ci/scan_subprocess_cfg.js +8 -0
  32. package/dist/bollharness/src/scripts/ci/scan_verify_artifacts.js +8 -0
  33. package/dist/bollharness/src/scripts/ci/scan_yaml_schema.js +8 -0
  34. package/dist/bollharness/src/scripts/context_router.js +67 -0
  35. package/dist/bollharness/src/scripts/deploy-guard.js +157 -0
  36. package/dist/bollharness/src/scripts/guard-feedback.js +192 -0
  37. package/dist/bollharness/src/scripts/guard_router.js +158 -0
  38. package/dist/bollharness/src/scripts/hooks/_hook_output.js +6 -0
  39. package/dist/bollharness/src/scripts/hooks/auto-python3.js +6 -0
  40. package/dist/bollharness/src/scripts/hooks/deploy-progress-on-session-end.js +6 -0
  41. package/dist/bollharness/src/scripts/hooks/failure-analyzer.js +6 -0
  42. package/dist/bollharness/src/scripts/hooks/gate-judgment-inject.js +92 -0
  43. package/dist/bollharness/src/scripts/hooks/gate-transition-judgment.js +63 -0
  44. package/dist/bollharness/src/scripts/hooks/inbox-ack.js +6 -0
  45. package/dist/bollharness/src/scripts/hooks/inbox-inject-on-start.js +6 -0
  46. package/dist/bollharness/src/scripts/hooks/inbox-validate.js +6 -0
  47. package/dist/bollharness/src/scripts/hooks/inbox-write-ledger.js +6 -0
  48. package/dist/bollharness/src/scripts/hooks/initializer-agent.js +6 -0
  49. package/dist/bollharness/src/scripts/hooks/loop-detection.js +73 -0
  50. package/dist/bollharness/src/scripts/hooks/owner-guard.js +6 -0
  51. package/dist/bollharness/src/scripts/hooks/precompact.js +6 -0
  52. package/dist/bollharness/src/scripts/hooks/review-agent-gatekeeper.js +6 -0
  53. package/dist/bollharness/src/scripts/hooks/risk-tracker.js +108 -0
  54. package/dist/bollharness/src/scripts/hooks/sanitize-on-read.js +6 -0
  55. package/dist/bollharness/src/scripts/hooks/session-reflection.js +7 -0
  56. package/dist/bollharness/src/scripts/hooks/session-start-magic-docs.js +7 -0
  57. package/dist/bollharness/src/scripts/hooks/session-start-reset-risk.js +7 -0
  58. package/dist/bollharness/src/scripts/hooks/session-start-toolkit-reminder.js +7 -0
  59. package/dist/bollharness/src/scripts/hooks/stop-evaluator.js +157 -0
  60. package/dist/bollharness/src/scripts/hooks/tool-call-counter.js +6 -0
  61. package/dist/bollharness/src/scripts/hooks/trace-analyzer.js +10 -0
  62. package/dist/bollharness/src/scripts/install/install-trust-token.js +7 -0
  63. package/dist/bollharness/src/scripts/install/multi_project_registry.js +9 -0
  64. package/dist/bollharness/src/scripts/install/phase2_auto.js +21 -0
  65. package/dist/bollharness/src/scripts/install/pre_commit_installer.js +6 -0
  66. package/dist/bollharness/src/scripts/install/tier_selector.js +7 -0
  67. package/dist/bollharness/src/scripts/install/transcript_miner.js +7 -0
  68. package/dist/bollharness/src/scripts/lib/claim_patterns.js +10 -0
  69. package/dist/bollharness/src/scripts/lib/sanitize_patterns.js +12 -0
  70. package/dist/bollharness/src/scripts/sanitize.js +6 -0
  71. package/dist/constraint-runtime/src/tools/PolymarketSDK/cancelOrder.js +6 -0
  72. package/dist/constraint-runtime/src/tools/PolymarketSDK/createOrder.js +6 -0
  73. package/dist/constraint-runtime/src/tools/PolymarketSDK/getMarket.js +5 -0
  74. package/dist/constraint-runtime/src/tools/PolymarketSDK/getOrders.js +6 -0
  75. package/dist/constraint-runtime/src/tools/PolymarketSDK/listMarkets.js +4 -0
  76. package/dist/constraint-runtime/src/tools/SafeSDK/deploySafe.js +6 -0
  77. package/dist/constraint-runtime/src/tools/WalletTools/autoPay.js +29 -0
  78. package/dist/constraint-runtime/src/tools/WalletTools/createWallet.js +10 -0
  79. package/dist/constraint-runtime/src/tools/WalletTools/getBalance.js +13 -0
  80. package/dist/constraint-runtime/src/tools/WalletTools/importWallet.js +22 -0
  81. package/dist/constraint-runtime/src/tools/WalletTools/sendTransaction.js +25 -0
  82. package/dist/constraint-runtime/src/tools/WalletTools/signMessage.js +10 -0
  83. package/dist/constraint-runtime/src/tools/WalletTools/transferToken.js +25 -0
  84. package/dist/electron/config.js.map +1 -0
  85. package/dist/electron/dialogs.js.map +1 -0
  86. package/dist/electron/first-run.js.map +1 -0
  87. package/dist/electron/ipc.js.map +1 -0
  88. package/dist/electron/logger.js.map +1 -0
  89. package/dist/electron/main.js.map +1 -0
  90. package/dist/electron/menu.js.map +1 -0
  91. package/dist/electron/paths.js.map +1 -0
  92. package/dist/electron/server.js +2 -1
  93. package/dist/electron/server.js.map +1 -0
  94. package/dist/electron/tray.js.map +1 -0
  95. package/dist/electron/window.js.map +1 -0
  96. package/dist/electron-preload.js +29 -0
  97. package/dist/electron-preload.js.map +1 -0
  98. package/dist/electron.js +5 -0
  99. package/dist/electron.js.map +1 -0
  100. package/dist/llm/config-store.js +24 -8
  101. package/dist/llm/pi-ai.js +33 -19
  102. package/dist/workflows/collaboration.js +374 -0
  103. package/dist/workflows/index.js +54 -0
  104. package/package.json +18 -4
  105. package/.comm/README.md +0 -21
  106. package/.comm/default/2026-06-17T08-23-00-017Z-8a735de8.md +0 -7
  107. package/CLAUDE.md +0 -3
  108. package/build/icon.icns +0 -0
  109. package/build/icon.ico +0 -0
  110. package/build/icon.png +0 -0
  111. package/build/tray.png +0 -0
  112. package/build/trayTemplate.png +0 -0
  113. package/scripts/auto-evolve-oneshot.sh +0 -155
  114. package/scripts/auto-evolve-snapshot.sh +0 -136
  115. package/scripts/build-cli.js +0 -216
  116. package/scripts/detect-schema-changes.sh +0 -48
  117. package/scripts/lefthook-helper.sh +0 -69
  118. package/scripts/postinstall.js +0 -153
@@ -0,0 +1,304 @@
1
+ /**
2
+ * parseToolCall — 从 LLM 输出 (minimax / Hermes / Qwen / GLM / Anthropic 等)
3
+ * 中提取 tool_call { name, args }.
4
+ *
5
+ * 2026-06-30 抽出: 原先作为 PiAgentSession 的 private 方法藏在 4522 行类里,
6
+ * 测试只能复刻逻辑不能 import 真源 = 测试通过 ≠ 实际工作. 现在抽出为纯函数,
7
+ * 接受 ctx.tools (可用工具名集合) + 可选 ctx.resolveAlias (别名 → 真实工具名).
8
+ *
9
+ * 用法:
10
+ * import { parseToolCall } from './parse-tool-call';
11
+ * const r = parseToolCall(content, { tools: new Set(['shell_exec', 'read_file']) });
12
+ * if (r) tool.execute(r.args);
13
+ */
14
+ const SHELL_KEYWORDS = ['git', 'npx', 'npm', 'tsx', 'tsc', 'vitest', 'node', 'mkdir', 'touch', 'ls', 'echo', 'cat', 'head', 'tail', 'wc', 'pwd', 'date'];
15
+ /**
16
+ * 默认的 alias resolver — Claude Code 风格 → bolloon 工具名
17
+ * 当 ctx.resolveAlias 缺失时使用.
18
+ */
19
+ function defaultResolveAlias(name, tools) {
20
+ if (tools.has(name))
21
+ return name;
22
+ const lower = name.toLowerCase();
23
+ const aliasMap = {
24
+ read: 'read_file',
25
+ edit: 'edit_file',
26
+ write: 'write_file',
27
+ rm: 'delete_file',
28
+ mv: 'move_file',
29
+ bash: 'shell_exec',
30
+ shell: 'shell_exec',
31
+ sh: 'shell_exec',
32
+ cat: 'read_file',
33
+ test: 'vitest_run',
34
+ vitest: 'vitest_run',
35
+ typecheck: 'tsc_check',
36
+ tsc: 'tsc_check',
37
+ log: 'git_log',
38
+ show: 'git_show',
39
+ diff: 'git_diff',
40
+ commit: 'git_commit',
41
+ push: 'git_push',
42
+ branch: 'git_branch',
43
+ checkout: 'git_branch',
44
+ stash: 'git_stash',
45
+ todo_write: 'create_task',
46
+ todowrite: 'create_task',
47
+ task: 'create_task',
48
+ };
49
+ const aliased = aliasMap[lower];
50
+ if (aliased && tools.has(aliased))
51
+ return aliased;
52
+ if (tools.has(lower))
53
+ return lower;
54
+ return null;
55
+ }
56
+ /** 拆分 args.command: "git status" → { command: "git", args: "status" } */
57
+ function autoSplitCommand(args) {
58
+ if (typeof args.command === 'string' && args.command.includes(' ') && !args.args) {
59
+ const parts = args.command.split(/\s+/);
60
+ args.command = parts[0];
61
+ args.args = parts.slice(1).join(' ');
62
+ }
63
+ }
64
+ /** 用 resolver 解析工具名 — 接受任意 resolver (默认或自定义). */
65
+ function resolve(ctx, name) {
66
+ if (ctx.resolveAlias)
67
+ return ctx.resolveAlias(name);
68
+ return defaultResolveAlias(name, ctx.tools);
69
+ }
70
+ export function parseToolCall(content, ctx) {
71
+ if (!content)
72
+ return null;
73
+ // === 0. 剥离 思考块 — 必须先做, 否则旧 regex `<(\w+)>...</\1>` 会先匹配 想想标签 ===
74
+ const strippedContent = content.replace(/<think[\s\S]*?<\/think/g, '');
75
+ // === 1. JSON function-call (OpenAI / Anthropic / Minimax-style) ===
76
+ const jsonPatterns = [
77
+ // markdown json code block + OpenAI 块, 同时匹配 arguments/input 字段
78
+ /(?:```(?:json|json5)?\s*\n?)?\{[\s\S]*?"name"\s*:\s*["'](\w+)["']\s*,\s*["']?(?:arguments|input)["']?\s*:\s*(\{[\s\S]*?\})\s*\}/,
79
+ ];
80
+ for (const p of jsonPatterns) {
81
+ const m = content.match(p);
82
+ if (m) {
83
+ const name = m[1];
84
+ let args = {};
85
+ try {
86
+ const parsed = JSON.parse(m[2]);
87
+ if (parsed && typeof parsed === 'object') {
88
+ args = Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, String(v)]));
89
+ }
90
+ }
91
+ catch {
92
+ /* 解析失败保持 args={} */
93
+ }
94
+ autoSplitCommand(args);
95
+ const resolved = resolve(ctx, name);
96
+ if (resolved) {
97
+ return { name: resolved, args };
98
+ }
99
+ }
100
+ }
101
+ // === 2. <tools:call name="X">...</tools:call> 嵌套格式 ===
102
+ const toolsCallMatch = content.match(/<tools:call\s+name=["'](\w+)["']>([\s\S]*?)<\/tools:call>/);
103
+ if (toolsCallMatch) {
104
+ const name = toolsCallMatch[1];
105
+ const inner = toolsCallMatch[2];
106
+ const args = {};
107
+ const argTags = inner.matchAll(/<tools:call\s+name=["'](\w+)["']>([\s\S]*?)<\/tools:call>/g);
108
+ for (const m of argTags) {
109
+ args[m[1]] = m[2].trim();
110
+ }
111
+ const resolved = resolve(ctx, name);
112
+ if (resolved) {
113
+ return { name: resolved, args };
114
+ }
115
+ // 兜底: 外层 tool name 不在 tools, 但内层有 command, 推断 shell_exec
116
+ if (args.command) {
117
+ const cmdFirst = args.command.split(/\s+/)[0];
118
+ if (SHELL_KEYWORDS.includes(cmdFirst)) {
119
+ return { name: 'shell_exec', args };
120
+ }
121
+ }
122
+ }
123
+ // === 3. XML 格式 (陆续检测多个 pattern) ===
124
+ const patterns = [
125
+ // minimax/Hermes 自闭合 XML 格式 <invoke name="X">...</invoke>
126
+ new RegExp('<invoke\\s+name=["\']([\\w]+)["\']>([\\s\\S]*?)</invoke>'),
127
+ // <function_calls> 包裹
128
+ new RegExp('<function_calls>[\\s\\S]*?<invoke\\s+name=["\']([\\w]+)["\']>([\\s\\S]*?)</invoke>[\\s\\S]*?</function_calls>'),
129
+ // <function_calls><tool name="X"><param name="Y">value</param></tool></function_calls>
130
+ new RegExp('<function_calls>[\\s\\S]*?<tool\\s+name=["\']([\\w]+)["\']>([\\s\\S]*?)</tool>[\\s\\S]*?</function_calls>'),
131
+ /调用工具[::]\s*(\w+)\s*\(([^)]*)\)/,
132
+ /使用工具[::]\s*(\w+)\s*\(([^)]*)\)/,
133
+ /tool[_\w]*[::]\s*(\w+)\s*\(([^)]*)\)/i,
134
+ /(\w+)\s*\(\s*([^)]*)\s*\)/,
135
+ // 对象字面量格式 {tool => "get_identity", args => {...}}
136
+ /\{\s*tool\s*=>\s*["'](\w+)["']\s*(?:,\s*args\s*=>\s*(\{[\s\S]*?\}))?\s*\}/,
137
+ // tool => "get_identity" (无 args 包裹)
138
+ /\btool\s*=>\s*["'](\w+)["']/,
139
+ // [TOOL_CALL] 块内 JSON 形式 {"name": "x", "args": {...}}
140
+ /\[TOOL_CALL\][\s\S]*?\{\s*"name"\s*:\s*"(\w+)"\s*,\s*"args"\s*:\s*(\{[\s\S]*?\})/i,
141
+ // "tool_name {json_args}" 形式 (单行, 无 name 字段)
142
+ /(?:^|\n)(\w+)\s+(\{[\s\S]*?\})(?=\n|$)/,
143
+ // XML 格式 <tool_name>...<arg>value</arg>...</tool_name>
144
+ /<(\w+)>([\s\S]*?)<\/\1>/,
145
+ ];
146
+ for (const pattern of patterns) {
147
+ const match = strippedContent.match(pattern);
148
+ if (!match)
149
+ continue;
150
+ const name = match[1];
151
+ let args = {};
152
+ const rawArgs = match[2] || '';
153
+ if (rawArgs && rawArgs.trim().startsWith('{')) {
154
+ // JSON 形式, 尝试解析
155
+ try {
156
+ const parsed = JSON.parse(rawArgs);
157
+ if (parsed && typeof parsed === 'object') {
158
+ args = Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, String(v)]));
159
+ }
160
+ }
161
+ catch {
162
+ // 解析失败就当字符串处理
163
+ const argPairs = rawArgs.split(',').map(s => s.trim()).filter(Boolean);
164
+ for (const pair of argPairs) {
165
+ const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
166
+ if (key)
167
+ args[key] = valueParts.join(':') || '';
168
+ }
169
+ }
170
+ }
171
+ else if (rawArgs && /<[\w]/.test(rawArgs) && /<\/\w+>/.test(rawArgs)) {
172
+ // 2026-06-30 修: 检测 XML 子标签 (含带属性的 <parameter name="X"> 形式)
173
+ // 原文用 /<\w+>[\s\S]*<\/\w+>/ 检测, 但是 <parameter name="command"> 形式
174
+ // 首标签是 <parameter, 不是简单的 <command 所以原检测会 false,
175
+ // 路由错误走 key:value 路径. 这里放宽到任何 <...>...content...</...>
176
+ const paramRe = /<parameter\s+name=["'](\w+)["']>([\s\S]*?)<\/parameter>/g;
177
+ const paramReShort = /<param\s+name=["'](\w+)["']>([\s\S]*?)<\/param>/g;
178
+ let pMatch;
179
+ while ((pMatch = paramRe.exec(rawArgs)) !== null) {
180
+ const argName = pMatch[1];
181
+ const argValue = pMatch[2].trim();
182
+ if (argName && argValue) {
183
+ args[argName] = argValue;
184
+ }
185
+ }
186
+ if (Object.keys(args).length === 0) {
187
+ let sMatch;
188
+ paramReShort.lastIndex = 0;
189
+ while ((sMatch = paramReShort.exec(rawArgs)) !== null) {
190
+ const argName = sMatch[1];
191
+ const argValue = sMatch[2].trim().replace(/^["']|["']$/g, '');
192
+ if (argName && argValue) {
193
+ args[argName] = argValue;
194
+ }
195
+ }
196
+ }
197
+ if (Object.keys(args).length === 0) {
198
+ const xmlArgPattern = /<(\w+)>([\s\S]*?)<\/\1>/g;
199
+ let xmlMatch;
200
+ while ((xmlMatch = xmlArgPattern.exec(rawArgs)) !== null) {
201
+ const argName = xmlMatch[1];
202
+ const argValue = xmlMatch[2].trim();
203
+ if (argName && argValue) {
204
+ args[argName] = argValue;
205
+ }
206
+ }
207
+ }
208
+ }
209
+ else if (rawArgs) {
210
+ // 形参串 key: value
211
+ const argPairs = rawArgs.split(',').map(s => s.trim()).filter(Boolean);
212
+ for (const pair of argPairs) {
213
+ const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
214
+ if (key)
215
+ args[key] = valueParts.join(':') || '';
216
+ }
217
+ }
218
+ // 名字 resolve: 优先 this.tools.has, 然后 alias resolver
219
+ const resolved = ctx.tools.has(name) ? name : resolve(ctx, name);
220
+ if (resolved) {
221
+ autoSplitCommand(args);
222
+ return { name: resolved, args };
223
+ }
224
+ // 名字未识别但 rawArgs 含 <command> 子标签 → 跳出, 走 fallback 按 command 推断 shell_exec
225
+ if (rawArgs && /<\w+>[\s\S]*<\/\w+>/.test(strippedContent)) {
226
+ break;
227
+ }
228
+ }
229
+ // === 4. Fallback: 任意 <tag><command>...</command></tag> 按 cmdFirst 推断 shell_exec ===
230
+ const xmlTagMatch = strippedContent.match(/<(\w+)>([\s\S]*?)<\/\1>/);
231
+ if (xmlTagMatch) {
232
+ const outerTag = xmlTagMatch[1];
233
+ const inner = xmlTagMatch[2];
234
+ if (!resolve(ctx, outerTag)) {
235
+ const cmdMatch = inner.match(/<command>([\s\S]*?)<\/command>/);
236
+ if (cmdMatch) {
237
+ const cmd = cmdMatch[1].trim();
238
+ const cmdFirst = cmd.split(/\s+/)[0];
239
+ if (SHELL_KEYWORDS.includes(cmdFirst)) {
240
+ const args = {};
241
+ const remaining = cmd.slice(cmdFirst.length).trim();
242
+ if (remaining) {
243
+ args.command = cmdFirst;
244
+ args.args = remaining;
245
+ }
246
+ else {
247
+ args.command = cmd;
248
+ }
249
+ const argsM = inner.match(/<args>([\s\S]*?)<\/args>/);
250
+ if (argsM && argsM[1].trim()) {
251
+ args.args = argsM[1].trim();
252
+ }
253
+ return { name: 'shell_exec', args };
254
+ }
255
+ }
256
+ }
257
+ }
258
+ return null;
259
+ }
260
+ /**
261
+ * isFinalResponse — 临时判断 LLM 是否已完结 (含 <final gen>)
262
+ * 2026-06-19/06-30 修: 先剥离 think, 避免思考块中提及 <final gen> 误杀
263
+ * 含可解析 tool_call 则优先执行工具, 不算 final
264
+ */
265
+ export function isFinalResponse(content, ctx) {
266
+ const stripped = content.replace(/<think[\s\S]*?<\/think/g, '');
267
+ if (!stripped.includes('<final gen>'))
268
+ return false;
269
+ // 用默认 ctx (无需 tool 名解析, 只看能否 parse 出来) - 但 isFinalResponse 不需要 tools 列表上下文.
270
+ // 如果没有传 ctx, 使用 empty set (只解析不 resolve).
271
+ if (ctx && parseToolCall(stripped, ctx))
272
+ return false;
273
+ if (!ctx) {
274
+ // 试探性 parse (不 resolve name) — 如果至少能提取 name+args 模式, 就不是 final.
275
+ // 这里粗略检测: stripped 中含 json "name": 或 <invoke name= 或 <function_calls> 任一
276
+ if (/\{[\s\S]*?"name"\s*:/.test(stripped))
277
+ return false;
278
+ if (/<invoke\s+name=/.test(stripped))
279
+ return false;
280
+ if (/<function_calls>/.test(stripped))
281
+ return false;
282
+ }
283
+ return true;
284
+ }
285
+ /** extractFinalAnswer: 去除 <final gen> 标记 + tool call 噪声. */
286
+ export function extractFinalAnswer(content) {
287
+ const marker = '<final gen>';
288
+ const markerIndex = content.indexOf(marker);
289
+ if (markerIndex !== -1) {
290
+ const after = content.substring(markerIndex + marker.length).trim();
291
+ if (after) {
292
+ content = after;
293
+ }
294
+ else {
295
+ content = content.substring(0, markerIndex).trim();
296
+ }
297
+ }
298
+ let cleaned = content
299
+ .replace(/调用工具[::]\s*\w+\s*\([^)]*\)/g, '')
300
+ .replace(/使用工具[::]\s*\w+\s*\([^)]*\)/g, '')
301
+ .replace(/tool[_\w]*[::]\s*\w+\s*\([^)]*\)/gi, '')
302
+ .trim();
303
+ return cleaned;
304
+ }