@kenkaiiii/gg-agent 5.22.2 → 5.22.4

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
@@ -227,6 +227,7 @@ async function* agentLoop(messages, options) {
227
227
  let overloadRetries = 0;
228
228
  let emptyResponseRetries = 0;
229
229
  let stallRetries = 0;
230
+ let runawayToolcallRetries = 0;
230
231
  let overflowCompactionAttempts = 0;
231
232
  let toolResultTruncationAttempted = false;
232
233
  const invalidToolArgumentCounts = /* @__PURE__ */ new Map();
@@ -235,6 +236,8 @@ async function* agentLoop(messages, options) {
235
236
  const MAX_OVERLOAD_RETRIES = 10;
236
237
  const MAX_EMPTY_RESPONSE_RETRIES = 2;
237
238
  const MAX_STALL_RETRIES = 5;
239
+ const MAX_RUNAWAY_TOOLCALL_RETRIES = 2;
240
+ const RUNAWAY_TOOLCALL_RETRY_DELAY_MS = 1e3;
238
241
  const MAX_OVERFLOW_COMPACTIONS = 2;
239
242
  const STALL_RETRIES_BEFORE_NON_STREAMING = 2;
240
243
  const STALL_DELAY_MS = 1e3;
@@ -252,9 +255,9 @@ async function* agentLoop(messages, options) {
252
255
  const STREAM_THINKING_IDLE_TIMEOUT_MS = 3e5;
253
256
  const STREAM_THINKING_HARD_TIMEOUT_MS = 6e5;
254
257
  const NON_STREAMING_HARD_TIMEOUT_MS = 3e5;
255
- const isSakana = options.provider === "sakana";
256
- const firstEventTimeoutMs = isSakana ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
257
- const initialHardTimeoutMs = isSakana ? STREAM_THINKING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
258
+ const usesSilentReasoningBudget = options.provider === "sakana" || options.provider === "openai" && options.thinking != null;
259
+ const firstEventTimeoutMs = usesSilentReasoningBudget ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
260
+ const initialHardTimeoutMs = usesSilentReasoningBudget ? STREAM_THINKING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
258
261
  const MAX_TOOLCALL_DELTA_CHARS = 1e6;
259
262
  const MAX_TOOLCALL_DELTA_EVENTS = 2e4;
260
263
  let logicalTurnStartedAt = 0;
@@ -282,7 +285,10 @@ async function* agentLoop(messages, options) {
282
285
  messages: messages.length,
283
286
  chars: msgChars,
284
287
  provider: options.provider,
285
- model: options.model
288
+ model: options.model,
289
+ thinking: options.thinking ?? "off",
290
+ firstEventTimeoutMs,
291
+ initialHardTimeoutMs
286
292
  });
287
293
  }
288
294
  if (firstTurn && options.getSteeringMessages) {
@@ -639,11 +645,33 @@ async function* agentLoop(messages, options) {
639
645
  provider: options.provider,
640
646
  model: options.model
641
647
  });
648
+ if (runawayToolcallRetries < MAX_RUNAWAY_TOOLCALL_RETRIES) {
649
+ runawayToolcallRetries++;
650
+ const delayMs = RUNAWAY_TOOLCALL_RETRY_DELAY_MS * runawayToolcallRetries;
651
+ diag("retry", {
652
+ reason: "runaway_toolcall",
653
+ attempt: runawayToolcallRetries,
654
+ maxAttempts: MAX_RUNAWAY_TOOLCALL_RETRIES,
655
+ delayMs,
656
+ ...runawayDetected
657
+ });
658
+ yield {
659
+ type: "retry",
660
+ reason: "runaway_toolcall",
661
+ attempt: runawayToolcallRetries,
662
+ maxAttempts: MAX_RUNAWAY_TOOLCALL_RETRIES,
663
+ delayMs,
664
+ silent: true
665
+ };
666
+ await abortableSleep(delayMs, options.signal);
667
+ turn--;
668
+ continue;
669
+ }
642
670
  const detail = runawayDetected.kind === "chars" ? `${(runawayDetected.chars / 1024).toFixed(0)} KB of tool-call arguments` : `${runawayDetected.events} tool-call delta events`;
643
671
  yield {
644
672
  type: "error",
645
673
  error: new Error(
646
- `The model glitched mid-tool-call and produced ${detail} without closing the call. This is usually an upstream model bug \u2014 try the same request again or switch models. Your conversation is preserved.`
674
+ `The model repeatedly failed to close a tool call after ${MAX_RUNAWAY_TOOLCALL_RETRIES} automatic retries (${detail}). Switch models and retry; your conversation is preserved.`
647
675
  )
648
676
  };
649
677
  break;
@@ -696,15 +724,29 @@ async function* agentLoop(messages, options) {
696
724
  continue;
697
725
  }
698
726
  if (transportFailure) {
727
+ const cause = malformed ? "malformed_stream" : socketDrop ? "socket_drop" : "stream_stall";
699
728
  diag("stall_exhausted", {
700
729
  stallRetries: MAX_STALL_RETRIES,
701
730
  provider: options.provider,
702
- model: options.model
731
+ model: options.model,
732
+ cause,
733
+ nonStreaming: useNonStreamingFallback,
734
+ events: streamEventCount,
735
+ eventTypes: eventTypeCounts,
736
+ lastEventType,
737
+ sinceLastEventMs: Date.now() - lastEventTime,
738
+ attemptDurationMs: Date.now() - streamCallStart,
739
+ maxConsumerLagMs
703
740
  });
704
741
  yield {
705
742
  type: "error",
706
- error: new Error(
707
- `The API provider's stream stalled ${MAX_STALL_RETRIES} times \u2014 the provider may be experiencing capacity issues. Your conversation is preserved. Send another message to retry.`
743
+ error: new import_gg_ai.GGAIError(
744
+ `The connection to the API provider stopped responding after ${MAX_STALL_RETRIES} automatic retries. Your conversation is preserved.`,
745
+ {
746
+ source: "network",
747
+ hint: "Retry once. If it keeps happening on this device, disable any VPN or proxy and allow GG Coder through firewall or antivirus web protection.",
748
+ cause: err
749
+ }
708
750
  )
709
751
  };
710
752
  break;
@@ -744,6 +786,7 @@ async function* agentLoop(messages, options) {
744
786
  }
745
787
  overloadRetries = 0;
746
788
  stallRetries = 0;
789
+ runawayToolcallRetries = 0;
747
790
  const contentArr = Array.isArray(response.message.content) ? response.message.content : null;
748
791
  const hasActionableContent = response.message.content !== "" && contentArr !== null && contentArr.some(
749
792
  (p) => p.type === "text" || p.type === "tool_call" || p.type === "server_tool_call"