@bolloon/bolloon-agent 0.1.14 → 0.1.15

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.
@@ -1021,7 +1021,9 @@ ${toolDefs}
1021
1021
  // 检查是否需要继续循环处理
1022
1022
  // 更严格的判断:只有当回复明确表示需要更多信息时才继续
1023
1023
  const containsToolCallIntent = reply.includes('调用工具') || reply.includes('tool(') ||
1024
- reply.includes('使用工具') || reply.includes('需要获取') || reply.includes('需要查看');
1024
+ reply.includes('使用工具') || reply.includes('需要获取') || reply.includes('需要查看') ||
1025
+ // 兼容 LLM 用对象字面量输出 tool call (上轮没解析成功时, 至少要继续)
1026
+ reply.includes('tool =>') || reply.includes('[TOOL_CALL]');
1025
1027
  const hasError = ['不存在', '找不到', '无法找到', 'not found', 'does not exist',
1026
1028
  '错误', 'error', '失败', 'failed'].some(k => reply.includes(k));
1027
1029
  const isTooShort = reply.length < 50 && reply.length > 0;
@@ -1145,19 +1147,45 @@ Workspace root folder: ${this.cwd}
1145
1147
  /调用工具[::]\s*(\w+)\s*\(([^)]*)\)/,
1146
1148
  /使用工具[::]\s*(\w+)\s*\(([^)]*)\)/,
1147
1149
  /tool[_\w]*[::]\s*(\w+)\s*\(([^)]*)\)/i,
1148
- /(\w+)\s*\(\s*([^)]*)\s*\)/
1150
+ /(\w+)\s*\(\s*([^)]*)\s*\)/,
1151
+ // 兼容 LLM 输出的对象字面量格式: {tool => "get_identity", args => {...}}
1152
+ /\{\s*tool\s*=>\s*["'](\w+)["']\s*(?:,\s*args\s*=>\s*(\{[\s\S]*?\}))?\s*\}/,
1153
+ // 兼容: tool => "get_identity" (无 args 包裹)
1154
+ /\btool\s*=>\s*["'](\w+)["']/,
1155
+ // 兼容: [TOOL_CALL] 块内 JSON 形式 {"name": "x", "args": {...}}
1156
+ /\[TOOL_CALL\][\s\S]*?\{\s*"name"\s*:\s*"(\w+)"\s*,\s*"args"\s*:\s*(\{[\s\S]*?\})/i,
1149
1157
  ];
1150
1158
  for (const pattern of patterns) {
1151
1159
  const match = content.match(pattern);
1152
1160
  if (match) {
1153
1161
  const name = match[1];
1154
- const argsStr = match[2] || '';
1155
- const args = {};
1156
- const argPairs = argsStr.split(',').map(s => s.trim()).filter(Boolean);
1157
- for (const pair of argPairs) {
1158
- const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
1159
- if (key) {
1160
- args[key] = valueParts.join(':') || '';
1162
+ let args = {};
1163
+ const rawArgs = match[2] || '';
1164
+ if (rawArgs && rawArgs.trim().startsWith('{')) {
1165
+ // JSON 形式, 尝试解析
1166
+ try {
1167
+ const parsed = JSON.parse(rawArgs);
1168
+ if (parsed && typeof parsed === 'object') {
1169
+ args = Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, String(v)]));
1170
+ }
1171
+ }
1172
+ catch {
1173
+ // 解析失败就当字符串处理
1174
+ const argPairs = rawArgs.split(',').map(s => s.trim()).filter(Boolean);
1175
+ for (const pair of argPairs) {
1176
+ const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
1177
+ if (key)
1178
+ args[key] = valueParts.join(':') || '';
1179
+ }
1180
+ }
1181
+ }
1182
+ else if (rawArgs) {
1183
+ // 形参串, 形如 key: value, key2: value2
1184
+ const argPairs = rawArgs.split(',').map(s => s.trim()).filter(Boolean);
1185
+ for (const pair of argPairs) {
1186
+ const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
1187
+ if (key)
1188
+ args[key] = valueParts.join(':') || '';
1161
1189
  }
1162
1190
  }
1163
1191
  if (this.tools.has(name) || this.tools.has(name.replace(/_/g, '_'))) {
@@ -714,6 +714,8 @@ function addMessage(content, type, save = true, container) {
714
714
  .replace(/TOOL_CALL[\s\S]*?\/TOOL_CALL/g, '')
715
715
  .replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
716
716
  .replace(/{\s*"tool":[\s\S]*?}/g, '')
717
+ // 兼容 pi-sdk LLM 输出: {tool => "name", args => {...}}
718
+ .replace(/\{\s*tool\s*=>\s*["'][^"']+["']\s*(?:,\s*args\s*=>\s*\{[\s\S]*?\})?\s*\}/g, '')
717
719
  .replace(/\[Function[^\]]*\]\s*/g, '')
718
720
  .trim();
719
721