@code-yeongyu/senpi-ai 2026.8.1 → 2026.8.3

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.
Files changed (96) hide show
  1. package/README.md +2 -1
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +46 -10
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/anthropic-tool-pairs.d.ts +3 -0
  6. package/dist/api/anthropic-tool-pairs.d.ts.map +1 -0
  7. package/dist/api/anthropic-tool-pairs.js +134 -0
  8. package/dist/api/anthropic-tool-pairs.js.map +1 -0
  9. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  10. package/dist/api/azure-openai-responses.js +5 -1
  11. package/dist/api/azure-openai-responses.js.map +1 -1
  12. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  13. package/dist/api/bedrock-converse-stream.js +64 -4
  14. package/dist/api/bedrock-converse-stream.js.map +1 -1
  15. package/dist/api/google-generative-ai.d.ts.map +1 -1
  16. package/dist/api/google-generative-ai.js +12 -2
  17. package/dist/api/google-generative-ai.js.map +1 -1
  18. package/dist/api/google-shared.d.ts.map +1 -1
  19. package/dist/api/google-shared.js +13 -6
  20. package/dist/api/google-shared.js.map +1 -1
  21. package/dist/api/google-vertex.d.ts.map +1 -1
  22. package/dist/api/google-vertex.js +12 -2
  23. package/dist/api/google-vertex.js.map +1 -1
  24. package/dist/api/mistral-conversations.d.ts.map +1 -1
  25. package/dist/api/mistral-conversations.js +19 -10
  26. package/dist/api/mistral-conversations.js.map +1 -1
  27. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  28. package/dist/api/openai-codex-responses.js +84 -47
  29. package/dist/api/openai-codex-responses.js.map +1 -1
  30. package/dist/api/openai-completions.d.ts.map +1 -1
  31. package/dist/api/openai-completions.js +17 -8
  32. package/dist/api/openai-completions.js.map +1 -1
  33. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  34. package/dist/api/openai-responses-shared.js +11 -1
  35. package/dist/api/openai-responses-shared.js.map +1 -1
  36. package/dist/api/openai-responses.d.ts.map +1 -1
  37. package/dist/api/openai-responses.js +7 -3
  38. package/dist/api/openai-responses.js.map +1 -1
  39. package/dist/api/openrouter-images.js +3 -2
  40. package/dist/api/openrouter-images.js.map +1 -1
  41. package/dist/api/pi-messages.js +2 -2
  42. package/dist/api/pi-messages.js.map +1 -1
  43. package/dist/api/simple-options.d.ts.map +1 -1
  44. package/dist/api/simple-options.js +1 -0
  45. package/dist/api/simple-options.js.map +1 -1
  46. package/dist/auth/oauth/openrouter.d.ts +3 -1
  47. package/dist/auth/oauth/openrouter.d.ts.map +1 -1
  48. package/dist/auth/oauth/openrouter.js +81 -26
  49. package/dist/auth/oauth/openrouter.js.map +1 -1
  50. package/dist/auth/resolve.d.ts +2 -0
  51. package/dist/auth/resolve.d.ts.map +1 -1
  52. package/dist/auth/resolve.js +16 -8
  53. package/dist/auth/resolve.js.map +1 -1
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +1 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/providers/data/.manifest.json +1 -1
  59. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  60. package/dist/providers/data/fireworks.json +1 -1
  61. package/dist/providers/data/github-copilot.json +1 -1
  62. package/dist/providers/data/huggingface.json +1 -1
  63. package/dist/providers/data/mistral.json +1 -1
  64. package/dist/providers/data/openai-codex.json +1 -1
  65. package/dist/providers/data/openai.json +1 -1
  66. package/dist/providers/data/opencode.json +1 -1
  67. package/dist/providers/data/openrouter.json +1 -1
  68. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  69. package/dist/providers/data/qwen-token-plan.json +1 -1
  70. package/dist/providers/data/together.json +1 -1
  71. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  72. package/dist/providers/data/zai-coding-cn.json +1 -1
  73. package/dist/providers/data/zai.json +1 -1
  74. package/dist/providers/faux.d.ts.map +1 -1
  75. package/dist/providers/faux.js +4 -1
  76. package/dist/providers/faux.js.map +1 -1
  77. package/dist/providers/opencode-go.js +1 -1
  78. package/dist/providers/opencode-go.js.map +1 -1
  79. package/dist/types.d.ts +13 -1
  80. package/dist/types.d.ts.map +1 -1
  81. package/dist/types.js.map +1 -1
  82. package/dist/utils/error-body.d.ts.map +1 -1
  83. package/dist/utils/error-body.js +23 -4
  84. package/dist/utils/error-body.js.map +1 -1
  85. package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  86. package/dist/utils/prompt-cache-ttl.js +10 -1
  87. package/dist/utils/prompt-cache-ttl.js.map +1 -1
  88. package/dist/utils/provider-retry.d.ts +3 -0
  89. package/dist/utils/provider-retry.d.ts.map +1 -1
  90. package/dist/utils/provider-retry.js +13 -12
  91. package/dist/utils/provider-retry.js.map +1 -1
  92. package/dist/utils/retry-hint.d.ts +24 -0
  93. package/dist/utils/retry-hint.d.ts.map +1 -0
  94. package/dist/utils/retry-hint.js +233 -0
  95. package/dist/utils/retry-hint.js.map +1 -0
  96. package/package.json +10 -6
package/README.md CHANGED
@@ -874,7 +874,8 @@ for await (const event of s) {
874
874
 
875
875
  Every `AssistantMessage` includes a `stopReason` field that indicates how the generation ended:
876
876
 
877
- - `"stop"` - Normal completion, the model finished its response
877
+ - `"pending"` - Only present in partial messages when we do not know what the stop reason will be
878
+ - `"stop"` - This is the final message the model will produce this turn
878
879
  - `"length"` - Output hit the maximum token limit
879
880
  - `"toolUse"` - Model is calling tools and expects tool results
880
881
  - `"error"` - An error occurred during generation
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAU1C,OAAO,KAAK,EAWX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAgCrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA6JlE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAoEhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AAuzBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAqYzE,CAAC;AA0FF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA2ClF,CAAC"}
1
+ {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAU1C,OAAO,KAAK,EAWX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAiCrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA6JlE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAoEhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AA4zBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CA6ZzE,CAAC;AA0FF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA2ClF,CAAC"}
@@ -9,11 +9,13 @@ import { parseJsonWithRepair, parseStreamingJson } from "../utils/json-parse.js"
9
9
  import { getAnthropicCompat, isAnthropicApiBaseUrl } from "../utils/prompt-cache-ttl.js";
10
10
  import { getProviderEnvValue } from "../utils/provider-env.js";
11
11
  import { retryProviderRequest } from "../utils/provider-retry.js";
12
+ import { appendRetryAfterMsMarker, extract429RetryAfterMs } from "../utils/retry-hint.js";
12
13
  import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
13
14
  import { applyServerFallbackAbort, parseServerFallbackReceipt, parseStickyFallbackReceipt, } from "../utils/server-fallback-receipt.js";
14
15
  import { normalizeToolCallId } from "../utils/tool-call-id.js";
15
16
  import { isForcedToolChoiceUnsupportedError, omitToolChoiceParam } from "../utils/tool-choice-fallback.js";
16
17
  import { demotedToolCallText, demotedToolResultText } from "../utils/unavailable-tool-text.js";
18
+ import { sanitizeAnthropicToolPairs } from "./anthropic-tool-pairs.js";
17
19
  import { resolveCloudflareBaseUrl } from "./cloudflare.js";
18
20
  import { resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
19
21
  import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
@@ -835,7 +837,12 @@ async function* iterateAnthropicEvents(response, signal) {
835
837
  let sawMessageEnd = false;
836
838
  for await (const sse of iterateSseMessages(response.body, signal)) {
837
839
  if (sse.event === "error") {
838
- throw new Error(sse.data);
840
+ let errorText = sse.data;
841
+ const hintMs = extract429RetryAfterMs({ bodyText: sse.data });
842
+ if (hintMs !== undefined) {
843
+ errorText = appendRetryAfterMsMarker(errorText, hintMs);
844
+ }
845
+ throw new Error(errorText);
839
846
  }
840
847
  if (!ANTHROPIC_MESSAGE_EVENTS.has(sse.event ?? "")) {
841
848
  continue;
@@ -876,7 +883,7 @@ export const stream = (model, context, options) => {
876
883
  totalTokens: 0,
877
884
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
878
885
  },
879
- stopReason: "stop",
886
+ stopReason: "pending",
880
887
  timestamp: Date.now(),
881
888
  };
882
889
  const serverFallbackAbort = new AbortController();
@@ -906,7 +913,7 @@ export const stream = (model, context, options) => {
906
913
  }
907
914
  const cacheRetention = resolveCacheRetention(options?.cacheRetention ?? model.cacheRetention, options?.env, "long");
908
915
  const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
909
- const created = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), optionsHeaders, copilotDynamicHeaders, cacheSessionId, options?.env);
916
+ const created = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), optionsHeaders, options?.fetch, copilotDynamicHeaders, cacheSessionId, options?.env);
910
917
  client = created.client;
911
918
  isOAuth = created.isOAuthToken;
912
919
  }
@@ -922,7 +929,7 @@ export const stream = (model, context, options) => {
922
929
  }
923
930
  params = sanitizeAdaptiveThinkingPayload(model, params, options);
924
931
  params = sanitizeUnsupportedNativeTools(model, params);
925
- params = demoteUnavailableToolReferences(params);
932
+ params = sanitizeAnthropicToolPairs(demoteUnavailableToolReferences(params));
926
933
  const payloadRequestMetadata = extractPayloadRequestMetadata(params);
927
934
  params = payloadRequestMetadata.params;
928
935
  const requestOptions = {
@@ -1002,7 +1009,7 @@ export const stream = (model, context, options) => {
1002
1009
  if (event.content_block.type === "text") {
1003
1010
  const block = {
1004
1011
  type: "text",
1005
- text: "",
1012
+ text: event.content_block.text ?? "",
1006
1013
  index: event.index,
1007
1014
  };
1008
1015
  output.content.push(block);
@@ -1011,8 +1018,8 @@ export const stream = (model, context, options) => {
1011
1018
  else if (event.content_block.type === "thinking") {
1012
1019
  const block = {
1013
1020
  type: "thinking",
1014
- thinking: "",
1015
- thinkingSignature: "",
1021
+ thinking: event.content_block.thinking ?? "",
1022
+ thinkingSignature: event.content_block.signature ?? "",
1016
1023
  index: event.index,
1017
1024
  };
1018
1025
  output.content.push(block);
@@ -1154,6 +1161,7 @@ export const stream = (model, context, options) => {
1154
1161
  }
1155
1162
  else if (event.type === "message_delta") {
1156
1163
  if (event.delta.stop_reason) {
1164
+ output.rawStopReason = event.delta.stop_reason;
1157
1165
  const stopReasonResult = mapStopReason(event.delta.stop_reason, event.delta.stop_details);
1158
1166
  output.stopReason = stopReasonResult.stopReason;
1159
1167
  if (stopReasonResult.errorMessage) {
@@ -1199,6 +1207,9 @@ export const stream = (model, context, options) => {
1199
1207
  if (serverFallbackReceipt !== undefined) {
1200
1208
  applyServerFallbackAbort(output, serverFallbackReceipt);
1201
1209
  }
1210
+ if (output.stopReason === "pending") {
1211
+ throw new Error("Anthropic stream ended without a stop reason");
1212
+ }
1202
1213
  if (output.stopReason === "aborted" || output.stopReason === "error") {
1203
1214
  throw new Error(output.errorMessage || "An unknown error occurred");
1204
1215
  }
@@ -1221,7 +1232,24 @@ export const stream = (model, context, options) => {
1221
1232
  delete block.partialJson;
1222
1233
  }
1223
1234
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
1224
- output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
1235
+ let errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
1236
+ // When a 429 SDK error carries response headers, extract the server's
1237
+ // retry-after hint and append the canonical marker so the orchestration
1238
+ // layer can recover the full delay.
1239
+ if (error instanceof Error && error.status === 429) {
1240
+ const sdkHeaders = error.headers;
1241
+ if (sdkHeaders instanceof Headers) {
1242
+ const hintMs = extract429RetryAfterMs({
1243
+ status: 429,
1244
+ headers: sdkHeaders,
1245
+ bodyText: errorMessage,
1246
+ });
1247
+ if (hintMs !== undefined) {
1248
+ errorMessage = appendRetryAfterMsMarker(errorMessage, hintMs);
1249
+ }
1250
+ }
1251
+ }
1252
+ output.errorMessage = errorMessage;
1225
1253
  stream.push({ type: "error", reason: output.stopReason, error: output });
1226
1254
  stream.end();
1227
1255
  }
@@ -1331,7 +1359,7 @@ export const streamSimple = (model, context, options) => {
1331
1359
  function isOAuthToken(apiKey) {
1332
1360
  return apiKey.includes("sk-ant-oat");
1333
1361
  }
1334
- function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, dynamicHeaders, sessionId, env) {
1362
+ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, fetch, dynamicHeaders, sessionId, env) {
1335
1363
  // Adaptive thinking models have interleaved thinking built in, so skip the beta header.
1336
1364
  const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model);
1337
1365
  const betaFeatures = [];
@@ -1347,6 +1375,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1347
1375
  authToken: null,
1348
1376
  baseURL: resolveCloudflareBaseUrl(model, env),
1349
1377
  dangerouslyAllowBrowser: true,
1378
+ fetch,
1350
1379
  defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1351
1380
  accept: "application/json",
1352
1381
  "anthropic-dangerous-direct-browser-access": "true",
@@ -1365,6 +1394,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1365
1394
  authToken: apiKey,
1366
1395
  baseURL: model.baseUrl,
1367
1396
  dangerouslyAllowBrowser: true,
1397
+ fetch,
1368
1398
  defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1369
1399
  accept: "application/json",
1370
1400
  "anthropic-dangerous-direct-browser-access": "true",
@@ -1380,6 +1410,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1380
1410
  authToken: apiKey,
1381
1411
  baseURL: model.baseUrl,
1382
1412
  dangerouslyAllowBrowser: true,
1413
+ fetch,
1383
1414
  defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1384
1415
  accept: "application/json",
1385
1416
  "anthropic-dangerous-direct-browser-access": "true",
@@ -1397,6 +1428,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1397
1428
  authToken: null,
1398
1429
  baseURL: model.baseUrl,
1399
1430
  dangerouslyAllowBrowser: true,
1431
+ fetch,
1400
1432
  defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1401
1433
  accept: "application/json",
1402
1434
  "anthropic-dangerous-direct-browser-access": "true",
@@ -1842,7 +1874,11 @@ function mapStopReason(reason, stopDetails) {
1842
1874
  case "stop_sequence":
1843
1875
  return { stopReason: "stop" }; // We don't supply stop sequences, so this should never happen
1844
1876
  case "sensitive": // Content flagged by safety filters (not yet in SDK types)
1845
- return { stopReason: "error", stopDetails: { type: "sensitive" } };
1877
+ return {
1878
+ stopReason: "error",
1879
+ errorMessage: "Provider stopped with: sensitive",
1880
+ stopDetails: { type: "sensitive" },
1881
+ };
1846
1882
  default:
1847
1883
  // Handle unknown stop reasons gracefully (API may add new values)
1848
1884
  throw new Error(`Unhandled stop reason: ${reason}`);