@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.js CHANGED
@@ -1188,7 +1188,8 @@ async function* agentLoop(messages, options) {
1188
1188
  maxTurnToolResultChars: options.maxTurnToolResultChars,
1189
1189
  toolMap,
1190
1190
  invalidToolArgumentCounts,
1191
- markFatalToolArgumentError
1191
+ markFatalToolArgumentError,
1192
+ seenToolCalls: /* @__PURE__ */ new Set()
1192
1193
  };
1193
1194
  const hasSequentialToolCall = toolCalls.some(
1194
1195
  (toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
@@ -1309,6 +1310,15 @@ async function* agentLoop(messages, options) {
1309
1310
  totalUsage: { ...totalUsage }
1310
1311
  };
1311
1312
  }
1313
+ function canonicalToolArgs(value) {
1314
+ if (Array.isArray(value)) return value.map(canonicalToolArgs);
1315
+ if (value !== null && typeof value === "object") {
1316
+ return Object.fromEntries(
1317
+ Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, canonicalToolArgs(v)])
1318
+ );
1319
+ }
1320
+ return value;
1321
+ }
1312
1322
  function pushToolEvent(eventStream, state, event) {
1313
1323
  if (!state.finalized) eventStream.push(event);
1314
1324
  }
@@ -1325,6 +1335,21 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1325
1335
  let isError = false;
1326
1336
  let invalidArgAttempt;
1327
1337
  const tool = options.toolMap.get(toolCall.name);
1338
+ if (tool) {
1339
+ const signature = JSON.stringify([toolCall.name, canonicalToolArgs(toolCall.args)]);
1340
+ if (options.seenToolCalls.has(signature)) {
1341
+ const content = "Tool call cancelled: an identical call already appeared in this response; this call was not executed.";
1342
+ pushEvent({
1343
+ type: "tool_call_end",
1344
+ toolCallId: toolCall.id,
1345
+ result: content,
1346
+ isError: true,
1347
+ durationMs: Date.now() - startTime
1348
+ });
1349
+ return { toolCallId: toolCall.id, content, isError: true };
1350
+ }
1351
+ options.seenToolCalls.add(signature);
1352
+ }
1328
1353
  if (!tool) {
1329
1354
  resultContent = `Unknown tool: ${toolCall.name}`;
1330
1355
  isError = true;
@@ -1436,6 +1461,11 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
1436
1461
  for (const phase of phases) {
1437
1462
  if (options.signal?.aborted) break;
1438
1463
  if (phase.sequential) {
1464
+ const signature = JSON.stringify([
1465
+ phase.sequential.name,
1466
+ canonicalToolArgs(phase.sequential.args)
1467
+ ]);
1468
+ if (!options.seenToolCalls.has(signature)) options.seenToolCalls.clear();
1439
1469
  dispatchedIds.add(phase.sequential.id);
1440
1470
  const record = await executeSingleToolCall(
1441
1471
  phase.sequential,