@kenkaiiii/gg-agent 5.64.0 → 5.64.1

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/dist/index.cjs CHANGED
@@ -1215,7 +1215,8 @@ async function* agentLoop(messages, options) {
1215
1215
  maxTurnToolResultChars: options.maxTurnToolResultChars,
1216
1216
  toolMap,
1217
1217
  invalidToolArgumentCounts,
1218
- markFatalToolArgumentError
1218
+ markFatalToolArgumentError,
1219
+ seenToolCalls: /* @__PURE__ */ new Set()
1219
1220
  };
1220
1221
  const hasSequentialToolCall = toolCalls.some(
1221
1222
  (toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
@@ -1336,6 +1337,15 @@ async function* agentLoop(messages, options) {
1336
1337
  totalUsage: { ...totalUsage }
1337
1338
  };
1338
1339
  }
1340
+ function canonicalToolArgs(value) {
1341
+ if (Array.isArray(value)) return value.map(canonicalToolArgs);
1342
+ if (value !== null && typeof value === "object") {
1343
+ return Object.fromEntries(
1344
+ Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, canonicalToolArgs(v)])
1345
+ );
1346
+ }
1347
+ return value;
1348
+ }
1339
1349
  function pushToolEvent(eventStream, state, event) {
1340
1350
  if (!state.finalized) eventStream.push(event);
1341
1351
  }
@@ -1352,6 +1362,21 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1352
1362
  let isError = false;
1353
1363
  let invalidArgAttempt;
1354
1364
  const tool = options.toolMap.get(toolCall.name);
1365
+ if (tool) {
1366
+ const signature = JSON.stringify([toolCall.name, canonicalToolArgs(toolCall.args)]);
1367
+ if (options.seenToolCalls.has(signature)) {
1368
+ const content = "Tool call cancelled: an identical call already appeared in this response; this call was not executed.";
1369
+ pushEvent({
1370
+ type: "tool_call_end",
1371
+ toolCallId: toolCall.id,
1372
+ result: content,
1373
+ isError: true,
1374
+ durationMs: Date.now() - startTime
1375
+ });
1376
+ return { toolCallId: toolCall.id, content, isError: true };
1377
+ }
1378
+ options.seenToolCalls.add(signature);
1379
+ }
1355
1380
  if (!tool) {
1356
1381
  resultContent = `Unknown tool: ${toolCall.name}`;
1357
1382
  isError = true;
@@ -1463,6 +1488,11 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
1463
1488
  for (const phase of phases) {
1464
1489
  if (options.signal?.aborted) break;
1465
1490
  if (phase.sequential) {
1491
+ const signature = JSON.stringify([
1492
+ phase.sequential.name,
1493
+ canonicalToolArgs(phase.sequential.args)
1494
+ ]);
1495
+ if (!options.seenToolCalls.has(signature)) options.seenToolCalls.clear();
1466
1496
  dispatchedIds.add(phase.sequential.id);
1467
1497
  const record = await executeSingleToolCall(
1468
1498
  phase.sequential,