@kenkaiiii/gg-ai 4.6.0 → 4.6.2

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
@@ -328,21 +328,21 @@ var StreamResult = class {
328
328
  resolveResponse;
329
329
  rejectResponse;
330
330
  resolveWait = null;
331
- constructor(generator) {
331
+ constructor(generator, signal) {
332
332
  this.response = new Promise((resolve, reject) => {
333
333
  this.resolveResponse = resolve;
334
334
  this.rejectResponse = reject;
335
335
  });
336
- this.pump(generator);
336
+ this.pump(generator, signal);
337
337
  }
338
- async pump(generator) {
338
+ async pump(generator, signal) {
339
339
  try {
340
- let next = await generator.next();
340
+ let next = await this._nextWithAbort(generator, signal);
341
341
  while (!next.done) {
342
342
  this.buffer.push(next.value);
343
343
  this.resolveWait?.();
344
344
  this.resolveWait = null;
345
- next = await generator.next();
345
+ next = await this._nextWithAbort(generator, signal);
346
346
  }
347
347
  this.done = true;
348
348
  this.resolveResponse(next.value);
@@ -357,6 +357,28 @@ var StreamResult = class {
357
357
  this.resolveWait = null;
358
358
  }
359
359
  }
360
+ async _nextWithAbort(generator, signal) {
361
+ if (!signal) {
362
+ return generator.next();
363
+ }
364
+ if (signal.aborted) {
365
+ return Promise.reject(new DOMException("Aborted", "AbortError"));
366
+ }
367
+ let onAbort;
368
+ const abortPromise = new Promise((_, reject) => {
369
+ onAbort = () => {
370
+ generator.return?.(void 0).catch(() => {
371
+ });
372
+ reject(new DOMException("Aborted", "AbortError"));
373
+ };
374
+ signal.addEventListener("abort", onAbort, { once: true });
375
+ });
376
+ try {
377
+ return await Promise.race([generator.next(), abortPromise]);
378
+ } finally {
379
+ if (onAbort) signal.removeEventListener("abort", onAbort);
380
+ }
381
+ }
360
382
  async *[Symbol.asyncIterator]() {
361
383
  let index = 0;
362
384
  while (true) {
@@ -973,10 +995,10 @@ function createClient(options) {
973
995
  ...isOAuth ? { apiKey: null, authToken: options.apiKey } : { apiKey: options.apiKey },
974
996
  ...options.baseUrl ? { baseURL: options.baseUrl } : {},
975
997
  ...options.fetch ? { fetch: options.fetch } : {},
976
- // Allow SDK retries for connection-level failures (socket hang up, 500s,
977
- // connection refused). Our stall detection handles abort-initiated retries
978
- // separately SDK retries only fire on genuine transport errors.
979
- maxRetries: 2,
998
+ // Disable SDK retries the agent loop has its own stall/overload retry
999
+ // logic that surfaces errors properly. SDK retries on 429s can cause
1000
+ // multi-minute hangs when the provider stops responding mid-retry.
1001
+ maxRetries: 0,
980
1002
  ...isOAuth ? {
981
1003
  defaultHeaders: {
982
1004
  // Anthropic's OAuth edge validates the claude-cli version. Callers
@@ -989,7 +1011,7 @@ function createClient(options) {
989
1011
  });
990
1012
  }
991
1013
  function streamAnthropic(options) {
992
- return new StreamResult(runStream(options));
1014
+ return new StreamResult(runStream(options), options.signal);
993
1015
  }
994
1016
  async function* runStream(options) {
995
1017
  const client = createClient(options);
@@ -1084,7 +1106,6 @@ async function* runStream(options) {
1084
1106
  throw toError(err);
1085
1107
  }
1086
1108
  }
1087
- const stream2 = client.messages.stream(params, requestOptions);
1088
1109
  const contentParts = [];
1089
1110
  const blocks = /* @__PURE__ */ new Map();
1090
1111
  let inputTokens = 0;
@@ -1093,8 +1114,14 @@ async function* runStream(options) {
1093
1114
  let cacheWrite;
1094
1115
  let stopReason = null;
1095
1116
  const keepalive = { type: "keepalive" };
1117
+ let receivedAnyEvent = false;
1096
1118
  try {
1119
+ const stream2 = await client.messages.create(
1120
+ params,
1121
+ requestOptions
1122
+ );
1097
1123
  for await (const event of stream2) {
1124
+ receivedAnyEvent = true;
1098
1125
  switch (event.type) {
1099
1126
  case "message_start": {
1100
1127
  const usage = event.message.usage;
@@ -1131,7 +1158,7 @@ async function* runStream(options) {
1131
1158
  accum.toolId = block.id;
1132
1159
  accum.toolName = block.name;
1133
1160
  accum.input = block.input;
1134
- } else if (block.type === "redacted_thinking") {
1161
+ } else if (block.type !== "text" && block.type !== "thinking") {
1135
1162
  accum.raw = block;
1136
1163
  }
1137
1164
  blocks.set(idx, accum);
@@ -1228,8 +1255,7 @@ async function* runStream(options) {
1228
1255
  contentParts.push({ type: "raw", data: accum.raw });
1229
1256
  yield keepalive;
1230
1257
  } else {
1231
- const msg = stream2.currentMessage;
1232
- const rawBlock = msg?.content[event.index];
1258
+ const rawBlock = accum.raw;
1233
1259
  if (rawBlock) {
1234
1260
  const blockType = rawBlock.type;
1235
1261
  if (blockType === "web_search_tool_result") {
@@ -1275,6 +1301,11 @@ async function* runStream(options) {
1275
1301
  } catch (err) {
1276
1302
  throw toError(err);
1277
1303
  }
1304
+ if (!receivedAnyEvent) {
1305
+ throw new ProviderError("anthropic", "Stream ended without producing any events.", {
1306
+ statusCode: 504
1307
+ });
1308
+ }
1278
1309
  const normalizedStop = normalizeAnthropicStopReason(stopReason);
1279
1310
  const response = {
1280
1311
  message: {
@@ -1566,7 +1597,7 @@ function createClient2(options) {
1566
1597
  });
1567
1598
  }
1568
1599
  function streamOpenAI(options) {
1569
- return new StreamResult(runStream2(options));
1600
+ return new StreamResult(runStream2(options), options.signal);
1570
1601
  }
1571
1602
  async function* runStream2(options) {
1572
1603
  const providerName = options.provider ?? "openai";
@@ -1658,51 +1689,62 @@ async function* runStream2(options) {
1658
1689
  let outputTokens = 0;
1659
1690
  let cacheRead = 0;
1660
1691
  let finishReason = null;
1661
- for await (const chunk of stream2) {
1662
- const choice = chunk.choices?.[0];
1663
- if (chunk.usage) {
1664
- ({ inputTokens, outputTokens, cacheRead } = extractOpenAIUsage(chunk.usage));
1665
- }
1666
- if (!choice) continue;
1667
- if (choice.finish_reason) {
1668
- finishReason = choice.finish_reason;
1669
- }
1670
- const delta = choice.delta;
1671
- const reasoningContent = delta.reasoning_content;
1672
- if (typeof reasoningContent === "string" && reasoningContent) {
1673
- thinkingAccum += reasoningContent;
1674
- if (options.thinking) {
1675
- yield { type: "thinking_delta", text: reasoningContent };
1692
+ let receivedAnyChunk = false;
1693
+ try {
1694
+ for await (const chunk of stream2) {
1695
+ receivedAnyChunk = true;
1696
+ const choice = chunk.choices?.[0];
1697
+ if (chunk.usage) {
1698
+ ({ inputTokens, outputTokens, cacheRead } = extractOpenAIUsage(chunk.usage));
1676
1699
  }
1677
- }
1678
- if (delta.content) {
1679
- textAccum += delta.content;
1680
- yield { type: "text_delta", text: delta.content };
1681
- }
1682
- if (delta.tool_calls) {
1683
- for (const tc of delta.tool_calls) {
1684
- let accum = toolCallAccum.get(tc.index);
1685
- if (!accum) {
1686
- accum = {
1687
- id: tc.id ?? "",
1688
- name: tc.function?.name ?? "",
1689
- argsJson: ""
1690
- };
1691
- toolCallAccum.set(tc.index, accum);
1700
+ if (!choice) continue;
1701
+ if (choice.finish_reason) {
1702
+ finishReason = choice.finish_reason;
1703
+ }
1704
+ const delta = choice.delta;
1705
+ const reasoningContent = delta.reasoning_content;
1706
+ if (typeof reasoningContent === "string" && reasoningContent) {
1707
+ thinkingAccum += reasoningContent;
1708
+ if (options.thinking) {
1709
+ yield { type: "thinking_delta", text: reasoningContent };
1692
1710
  }
1693
- if (tc.id) accum.id = tc.id;
1694
- if (tc.function?.name) accum.name = tc.function.name;
1695
- if (tc.function?.arguments) {
1696
- accum.argsJson += tc.function.arguments;
1697
- yield {
1698
- type: "toolcall_delta",
1699
- id: accum.id,
1700
- name: accum.name,
1701
- argsJson: tc.function.arguments
1702
- };
1711
+ }
1712
+ if (delta.content) {
1713
+ textAccum += delta.content;
1714
+ yield { type: "text_delta", text: delta.content };
1715
+ }
1716
+ if (delta.tool_calls) {
1717
+ for (const tc of delta.tool_calls) {
1718
+ let accum = toolCallAccum.get(tc.index);
1719
+ if (!accum) {
1720
+ accum = {
1721
+ id: tc.id ?? "",
1722
+ name: tc.function?.name ?? "",
1723
+ argsJson: ""
1724
+ };
1725
+ toolCallAccum.set(tc.index, accum);
1726
+ }
1727
+ if (tc.id) accum.id = tc.id;
1728
+ if (tc.function?.name) accum.name = tc.function.name;
1729
+ if (tc.function?.arguments) {
1730
+ accum.argsJson += tc.function.arguments;
1731
+ yield {
1732
+ type: "toolcall_delta",
1733
+ id: accum.id,
1734
+ name: accum.name,
1735
+ argsJson: tc.function.arguments
1736
+ };
1737
+ }
1703
1738
  }
1704
1739
  }
1705
1740
  }
1741
+ } catch (err) {
1742
+ throw toError2(err, providerName);
1743
+ }
1744
+ if (!receivedAnyChunk) {
1745
+ throw new ProviderError(providerName, "Stream ended without producing any chunks.", {
1746
+ statusCode: 504
1747
+ });
1706
1748
  }
1707
1749
  if (thinkingAccum) {
1708
1750
  contentParts.push({ type: "thinking", text: thinkingAccum });
@@ -1945,7 +1987,7 @@ function isVisibleOutputItem(itemType) {
1945
1987
  return itemType === "message";
1946
1988
  }
1947
1989
  function streamOpenAICodex(options) {
1948
- return new StreamResult(runStream3(options));
1990
+ return new StreamResult(runStream3(options), options.signal);
1949
1991
  }
1950
1992
  async function* runStream3(options) {
1951
1993
  const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
@@ -2275,10 +2317,16 @@ async function* parseSSE(body) {
2275
2317
  }
2276
2318
  }
2277
2319
  function remapCodexId(id, idMap) {
2278
- if (id.startsWith("fc_") || id.startsWith("fc-")) return id;
2279
2320
  const existing = idMap.get(id);
2280
2321
  if (existing) return existing;
2281
- const mapped = `fc_${id.replace(/^toolu_/, "")}`;
2322
+ const withPrefix = id.startsWith("fc_") || id.startsWith("fc-") ? id : `fc_${id.replace(/^toolu_/, "")}`;
2323
+ const sanitized = withPrefix.replace(/[^A-Za-z0-9_-]/g, "_");
2324
+ let mapped = sanitized;
2325
+ let suffix = 2;
2326
+ const used = new Set(idMap.values());
2327
+ while (used.has(mapped)) {
2328
+ mapped = `${sanitized}_${suffix++}`;
2329
+ }
2282
2330
  idMap.set(id, mapped);
2283
2331
  return mapped;
2284
2332
  }
@@ -2801,7 +2849,7 @@ async function fetchCodeAssistWithRetry(plan, options) {
2801
2849
  throw lastError ?? new ProviderError("gemini", "Gemini Code Assist request failed.");
2802
2850
  }
2803
2851
  function streamGemini(options) {
2804
- return new StreamResult(runStream4(options));
2852
+ return new StreamResult(runStream4(options), options.signal);
2805
2853
  }
2806
2854
  async function* runStream4(options) {
2807
2855
  const useStreaming = options.streaming !== false;
@@ -3257,7 +3305,7 @@ function registerPalsuProvider(config) {
3257
3305
  const stopReason = explicitStop ?? (hasToolCalls ? "tool_use" : "end_turn");
3258
3306
  return yield* simulateStream(message, stopReason, options.signal, cacheUsage);
3259
3307
  })();
3260
- return new StreamResult(gen);
3308
+ return new StreamResult(gen, options.signal);
3261
3309
  }
3262
3310
  });
3263
3311
  return handle;