@kenkaiiii/gg-agent 5.83.2 → 5.83.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
@@ -638,6 +638,9 @@ async function* agentLoop(messages, options) {
638
638
  let overloadRetries = 0;
639
639
  let emptyResponseRetries = 0;
640
640
  let stallRetries = 0;
641
+ let splitToolCallHintAdded = false;
642
+ let stalledInToolCall = false;
643
+ let stalledAfterConnecting = false;
641
644
  let runawayToolcallRetries = 0;
642
645
  let overflowCompactionAttempts = 0;
643
646
  let toolResultTruncationAttempted = false;
@@ -655,6 +658,7 @@ async function* agentLoop(messages, options) {
655
658
  const STALL_DELAY_MS = 1e3;
656
659
  const MIN_PARTIAL_PRESERVE_CHARS = 200;
657
660
  const PARTIAL_CONTINUATION_PROMPT = "[Your previous response was cut off by a connection failure. The text above is what was already delivered to the user. Continue exactly from where it stopped \u2014 do not repeat or restart it.]";
661
+ const SPLIT_TOOL_CALL_PROMPT = "[Your previous response was cut off while you were still writing a tool call's arguments, after minutes without data from the provider. None of that call was applied. Do not resend it as one large call: split the work into smaller pieces (e.g. a shorter first version, then further edits, or one file per call).]";
658
662
  const MAX_OUTPUT_CONTINUATIONS = 2;
659
663
  const MAX_TOKENS_CONTINUATION_PROMPT = "[Your previous response hit the output-token limit and was cut off. The text above is what was already delivered to the user. Continue exactly from where it stopped \u2014 do not repeat or restart it.]";
660
664
  let maxTokensContinuations = 0;
@@ -680,7 +684,7 @@ async function* agentLoop(messages, options) {
680
684
  const NON_STREAMING_HARD_TIMEOUT_MS = 3e5;
681
685
  const nonStreamingHardTimeoutMs = options.thinking != null ? STREAM_THINKING_HARD_TIMEOUT_MS : NON_STREAMING_HARD_TIMEOUT_MS;
682
686
  const VISIBLE_STALL_AFTER_MS = 6e4;
683
- const usesSilentReasoningBudget = options.provider === "sakana" || options.provider === "openai" && options.thinking != null;
687
+ const usesSilentReasoningBudget = options.provider === "sakana" || options.provider === "xai" || options.provider === "openai" && options.thinking != null;
684
688
  const localBackend = isLocalBackendUrl(options.baseUrl);
685
689
  const baseFirstEventTimeoutMs = localBackend ? Number.POSITIVE_INFINITY : usesSilentReasoningBudget ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
686
690
  const baseHardTimeoutMs = localBackend || usesSilentReasoningBudget ? STREAM_THINKING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
@@ -902,7 +906,7 @@ async function* agentLoop(messages, options) {
902
906
  }, hardTimeoutMs);
903
907
  }
904
908
  }
905
- if (event.type === "thinking_delta" && !hasReceivedThinking) {
909
+ if ((event.type === "thinking_delta" || event.type === "keepalive" && event.reasoning === true) && !hasReceivedThinking) {
906
910
  hasReceivedThinking = true;
907
911
  if (hardTimer) clearTimeout(hardTimer);
908
912
  hardTimeoutMs = STREAM_THINKING_HARD_TIMEOUT_MS;
@@ -1231,6 +1235,9 @@ async function* agentLoop(messages, options) {
1231
1235
  const malformed = isMalformedStream(err);
1232
1236
  const socketDrop = isTransportFailure(err);
1233
1237
  const transportFailure = (idleTimedOut || malformed || socketDrop) && !options.signal?.aborted;
1238
+ const attemptMs = Date.now() - streamCallStart;
1239
+ if (transportFailure && toolInputOpen) stalledInToolCall = true;
1240
+ if (transportFailure && streamEventCount > 0) stalledAfterConnecting = true;
1234
1241
  if (transportFailure && stallRetries < MAX_STALL_RETRIES) {
1235
1242
  stallRetries++;
1236
1243
  const cause = malformed ? "malformed_stream" : socketDrop ? "socket_drop" : "stream_stall";
@@ -1261,6 +1268,20 @@ async function* agentLoop(messages, options) {
1261
1268
  });
1262
1269
  preservedChars = attemptText.length;
1263
1270
  }
1271
+ let splitHint = false;
1272
+ if (toolInputOpen && attemptMs >= VISIBLE_STALL_AFTER_MS && !splitToolCallHintAdded) {
1273
+ splitToolCallHintAdded = true;
1274
+ splitHint = true;
1275
+ messages.push({
1276
+ role: "user",
1277
+ content: SPLIT_TOOL_CALL_PROMPT,
1278
+ provenance: {
1279
+ source: "runtime",
1280
+ kind: "continuation",
1281
+ visibility: "hidden"
1282
+ }
1283
+ });
1284
+ }
1264
1285
  diag("retry", {
1265
1286
  reason: cause,
1266
1287
  attempt: stallRetries,
@@ -1268,7 +1289,8 @@ async function* agentLoop(messages, options) {
1268
1289
  delayMs,
1269
1290
  events: streamEventCount,
1270
1291
  nonStreaming: useNonStreamingFallback,
1271
- preservedChars
1292
+ preservedChars,
1293
+ splitHint
1272
1294
  });
1273
1295
  yield {
1274
1296
  type: "retry",
@@ -1295,9 +1317,25 @@ async function* agentLoop(messages, options) {
1295
1317
  eventTypes: eventTypeCounts,
1296
1318
  lastEventType,
1297
1319
  sinceLastEventMs: Date.now() - lastEventTime,
1298
- attemptDurationMs: Date.now() - streamCallStart,
1299
- maxConsumerLagMs
1320
+ attemptDurationMs: attemptMs,
1321
+ maxConsumerLagMs,
1322
+ stalledAfterConnecting,
1323
+ stalledInToolCall
1300
1324
  });
1325
+ if (stalledAfterConnecting) {
1326
+ yield {
1327
+ type: "error",
1328
+ error: new import_gg_ai2.ResponseStalledError(
1329
+ `The provider stopped sending data before the response finished, ${MAX_STALL_RETRIES} automatic retries in a row. Your conversation is preserved.`,
1330
+ {
1331
+ inToolCall: stalledInToolCall,
1332
+ hint: stalledInToolCall ? "The model was writing one very large tool call each time. Ask it to make the change in smaller pieces (shorter files or several edits), then retry." : "Retry once. If it keeps happening, choose another model or lower the thinking level, and disable any VPN or proxy that may buffer streamed responses.",
1333
+ cause: err
1334
+ }
1335
+ )
1336
+ };
1337
+ break;
1338
+ }
1301
1339
  yield {
1302
1340
  type: "error",
1303
1341
  error: new import_gg_ai2.GGAIError(
@@ -1346,6 +1384,9 @@ async function* agentLoop(messages, options) {
1346
1384
  }
1347
1385
  overloadRetries = 0;
1348
1386
  stallRetries = 0;
1387
+ splitToolCallHintAdded = false;
1388
+ stalledInToolCall = false;
1389
+ stalledAfterConnecting = false;
1349
1390
  runawayToolcallRetries = 0;
1350
1391
  const contentArr = Array.isArray(response.message.content) ? response.message.content : null;
1351
1392
  const hasActionableContent = response.message.content !== "" && contentArr !== null && contentArr.some(