@code-yeongyu/senpi-ai 2026.10.10 → 2026.10.11

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 (58) hide show
  1. package/dist/api/anthropic-messages.js +101 -38
  2. package/dist/api/anthropic-tool-references.js +24 -18
  3. package/dist/api/bedrock-converse-stream.js +5 -1
  4. package/dist/api/google-shared.js +101 -21
  5. package/dist/api/lazy.js +13 -0
  6. package/dist/api/mistral-conversations.js +18 -3
  7. package/dist/api/openai-codex-responses.js +2 -2
  8. package/dist/api/openai-completions.js +26 -2
  9. package/dist/api/openai-responses-allowed-tools.d.ts +33 -0
  10. package/dist/api/openai-responses-allowed-tools.js +108 -0
  11. package/dist/api/openai-responses.js +43 -58
  12. package/dist/auth/oauth/anthropic.js +4 -3
  13. package/dist/auth/oauth/chatgpt-subscription.js +3 -2
  14. package/dist/auth/oauth/cursor.js +3 -2
  15. package/dist/auth/oauth/devin-token.js +2 -1
  16. package/dist/auth/oauth/github-copilot.js +3 -2
  17. package/dist/auth/oauth/kimi-coding.js +5 -4
  18. package/dist/auth/oauth/openai-chatgpt.js +2 -1
  19. package/dist/auth/oauth/openrouter.js +2 -1
  20. package/dist/auth/oauth/radius.js +5 -5
  21. package/dist/auth/oauth/xai.js +7 -4
  22. package/dist/auth/oauth-refresh.js +10 -0
  23. package/dist/auth/resolve.js +5 -0
  24. package/dist/openai-responses-compat.d.ts +7 -2
  25. package/dist/openai-responses-compat.js +15 -2
  26. package/dist/providers/all.d.ts +1 -1
  27. package/dist/providers/data/.manifest.json +1 -1
  28. package/dist/providers/data/amazon-bedrock.json +1 -1
  29. package/dist/providers/data/anthropic.json +1 -1
  30. package/dist/providers/data/baseten.json +1 -1
  31. package/dist/providers/data/chatgpt-subscription.json +1 -1
  32. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  33. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  34. package/dist/providers/data/github-copilot.json +1 -1
  35. package/dist/providers/data/google-vertex.json +1 -1
  36. package/dist/providers/data/huggingface.json +1 -1
  37. package/dist/providers/data/mistral.json +1 -1
  38. package/dist/providers/data/moonshotai-cn.json +1 -1
  39. package/dist/providers/data/moonshotai.json +1 -1
  40. package/dist/providers/data/opencode-go.json +1 -1
  41. package/dist/providers/data/opencode.json +1 -1
  42. package/dist/providers/data/opengateway.json +1 -1
  43. package/dist/providers/data/openrouter.json +1 -1
  44. package/dist/providers/data/radius.json +1 -1
  45. package/dist/providers/data/venice.json +1 -1
  46. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  47. package/dist/providers/kimi-coding.models.d.ts +1 -1
  48. package/dist/providers/kimi-coding.models.js +1 -1
  49. package/dist/providers/opengateway-refresh.js +2 -1
  50. package/dist/types.d.ts +3 -2
  51. package/dist/utils/oauth-refresh-error.d.ts +16 -0
  52. package/dist/utils/oauth-refresh-error.js +67 -0
  53. package/dist/utils/prompt-cache-ttl.js +3 -1
  54. package/dist/utils/retry.d.ts +6 -0
  55. package/dist/utils/retry.js +10 -0
  56. package/dist/utils/tool-choice-fallback.d.ts +11 -0
  57. package/dist/utils/tool-choice-fallback.js +69 -2
  58. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * xAI OAuth device-code flow.
3
3
  */
4
+ import { OAuthTokenEndpointError } from "../../utils/oauth-refresh-error.js";
4
5
  import { pollOAuthDeviceCodeFlow } from "./device-code.js";
5
6
  const XAI_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
6
7
  const XAI_SCOPE = "openid profile email offline_access grok-cli:access api:access";
@@ -53,7 +54,7 @@ async function postForm(url, fields, signal) {
53
54
  }
54
55
  catch (error) {
55
56
  if (signal.aborted) {
56
- throw new Error("Login cancelled");
57
+ throw new Error("Login cancelled", { cause: signal.reason });
57
58
  }
58
59
  throw error;
59
60
  }
@@ -64,9 +65,11 @@ async function postForm(url, fields, signal) {
64
65
  }
65
66
  catch {
66
67
  if (signal.aborted) {
67
- throw new Error("Login cancelled");
68
+ throw new Error("Login cancelled", { cause: signal.reason });
68
69
  }
69
- throw new Error(`xAI OAuth returned invalid JSON (HTTP ${response.status})`);
70
+ const message = `xAI OAuth returned invalid JSON (HTTP ${response.status})`;
71
+ // An error page (an HTML 503 from a proxy, say) still carries the status the retry decision needs.
72
+ throw response.ok ? new Error(message) : new OAuthTokenEndpointError(message, response.status);
70
73
  }
71
74
  return {
72
75
  ok: response.ok,
@@ -78,7 +81,7 @@ function requestFailure(action, response) {
78
81
  const error = typeof response.body.error === "string" ? response.body.error : undefined;
79
82
  const description = typeof response.body.error_description === "string" ? response.body.error_description : undefined;
80
83
  const detail = [error, description].filter(Boolean).join(": ");
81
- return new Error(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : ""}`);
84
+ return new OAuthTokenEndpointError(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : ""}`, response.status);
82
85
  }
83
86
  function parseDeviceCode(body) {
84
87
  // RFC 8628 allows interval 0 (no minimum wait); fall back to the poller's
@@ -15,6 +15,7 @@
15
15
  * superseded catalog refresh stops waiting but never aborts the exchange.
16
16
  */
17
17
  import { raceWithAbortSignal } from "../utils/abort.js";
18
+ import { oauthRefreshFailureCause } from "../utils/oauth-refresh-error.js";
18
19
  import { mergeRefreshed, mergeRefreshedSlot, projectSlot } from "./pool/slots.js";
19
20
  export const DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15_000;
20
21
  /** The provider rejected or timed out the token exchange. */
@@ -103,6 +104,15 @@ async function exchangeAndStore(request, signal) {
103
104
  signal.throwIfAborted();
104
105
  }
105
106
  catch (error) {
107
+ signal.throwIfAborted();
108
+ const causeClass = oauthRefreshFailureCause(error);
109
+ if (causeClass !== undefined) {
110
+ console.warn("OAuth refresh unavailable", JSON.stringify({
111
+ provider: providerId,
112
+ ...(slotName ? { slot: slotName } : {}),
113
+ cause: causeClass,
114
+ }));
115
+ }
106
116
  throw new OAuthRefreshExchangeError(error);
107
117
  }
108
118
  try {
@@ -1,5 +1,6 @@
1
1
  import { operationSignal, raceWithAbortSignal } from "../utils/abort.js";
2
2
  import { ModelsError } from "../utils/models-error.js";
3
+ import { classifyOAuthRefreshFailure, OAuthRefreshUnavailableError } from "../utils/oauth-refresh-error.js";
3
4
  import { OAuthRefreshExchangeError, OAuthRefreshStoreError, projectOAuthSlot, refreshOAuthCredential, } from "./oauth-refresh.js";
4
5
  import { projectSlot } from "./pool/slots.js";
5
6
  export { ModelsError } from "../utils/models-error.js";
@@ -82,6 +83,9 @@ export function oauthRefreshModelsError(error, providerId) {
82
83
  if (error instanceof ModelsError)
83
84
  return error;
84
85
  if (error instanceof OAuthRefreshExchangeError) {
86
+ if (classifyOAuthRefreshFailure(error.cause) === "transient") {
87
+ return new OAuthRefreshUnavailableError(providerId, error.cause);
88
+ }
85
89
  return new ModelsError("oauth", `OAuth refresh failed for ${providerId}`, { cause: error.cause });
86
90
  }
87
91
  const cause = error instanceof OAuthRefreshStoreError ? error.cause : error;
@@ -112,6 +116,7 @@ async function resolveStoredOAuth(credentials, providerId, oauth, stored, authCo
112
116
  });
113
117
  }
114
118
  catch (error) {
119
+ signal.throwIfAborted();
115
120
  throw oauthRefreshModelsError(error, providerId);
116
121
  }
117
122
  if (post?.type !== "oauth")
@@ -42,10 +42,15 @@ export interface OpenAIResponsesCompat {
42
42
  * Whether the model accepts `tool_choice: { type: "allowed_tools" }`. When set, callers keep every
43
43
  * declared tool in `tools` and restrict the callable subset through `Context.activeToolNames`, so a
44
44
  * shrinking tool set does not rewrite the cached prompt prefix. Honored by the `openai-responses`
45
- * adapter. Default: false.
45
+ * adapter, and only on the native OpenAI API hosts (`api.openai.com` and its regional `*.api.openai.com`
46
+ * hosts): Responses-compatible gateways reject the choice (senpi#3080), and since a provider `baseUrl`
47
+ * override keeps the catalog compat, the flag cannot opt a gateway in. Default: false.
46
48
  */
47
49
  supportsAllowedTools?: boolean;
48
50
  }
49
- /** Whether a model's compat declares `allowed_tools` support (see {@link OpenAIResponsesCompat.supportsAllowedTools}). */
51
+ /**
52
+ * Whether requests to `model` restrict tools through `allowed_tools`: its compat declares support and it is
53
+ * served by the native OpenAI endpoint (see {@link OpenAIResponsesCompat.supportsAllowedTools}).
54
+ */
50
55
  export declare function supportsAllowedToolChoice(model: Model<Api>): boolean;
51
56
  //# sourceMappingURL=openai-responses-compat.d.ts.map
@@ -1,5 +1,18 @@
1
- /** Whether a model's compat declares `allowed_tools` support (see {@link OpenAIResponsesCompat.supportsAllowedTools}). */
1
+ function isNativeOpenAIEndpoint(baseUrl) {
2
+ try {
3
+ const { hostname } = new URL(baseUrl || "https://api.openai.com/v1");
4
+ return hostname === "api.openai.com" || hostname.endsWith(".api.openai.com");
5
+ }
6
+ catch {
7
+ return false;
8
+ }
9
+ }
10
+ /**
11
+ * Whether requests to `model` restrict tools through `allowed_tools`: its compat declares support and it is
12
+ * served by the native OpenAI endpoint (see {@link OpenAIResponsesCompat.supportsAllowedTools}).
13
+ */
2
14
  export function supportsAllowedToolChoice(model) {
3
- return model.compat?.supportsAllowedTools === true;
15
+ return (model.compat?.supportsAllowedTools === true &&
16
+ isNativeOpenAIEndpoint(model.baseUrl));
4
17
  }
5
18
  //# sourceMappingURL=openai-responses-compat.js.map
@@ -50,7 +50,7 @@ declare const FORK_OWNED_CATALOGS: {
50
50
  readonly input: 3;
51
51
  readonly output: 15;
52
52
  readonly cacheRead: 0.3;
53
- readonly cacheWrite: 0;
53
+ readonly cacheWrite: 3;
54
54
  };
55
55
  readonly contextWindow: 1048576;
56
56
  readonly maxTokens: 131072;
@@ -1 +1 @@
1
- {"schemaVersion":6,"generatedAt":"2026-10-05T00:22:16.949Z","structureHash":"ff5f1c5ea3d0a6d7d36208bac83298ca0f7762d9067e289536e1a1e02777e038","files":{"alibaba-token-plan.json":"16b3c6c78d72c73ca34a1e79ce71c0cf36ba409d02e83a17396ce0949a1d5363","amazon-bedrock.json":"e918146642945e9ef5f2ccc04f8de04d5a34b1cc32d0e1b0ddc231254263a656","ant-ling.json":"628feab3ef6c7d80ce96f75999804e1d9f05fec3851e5302e30fff3b69db90f6","anthropic.json":"2c0c4389cd71d21d4553075f399922892078192b0490fead423544e360af1a43","azure-openai-responses.json":"a3e52bd78f0220aa32bce519e13955b8e6e567860416343844cbe19902f4a682","bai.json":"7e6861aaf27d8af34e1771c6092602194fcec0a0046e6adfab9c3ee54d32b99f","baseten.json":"b04d1423d6958bec857ffccc36726f091ec1a8f3a09cf0836b64cc94b0ee697d","cerebras.json":"3eccb58c5de3d0dc7ba49dc6e477ba29f00cb3150ce0a35cc90d59e6b5ab368e","chatgpt-subscription.json":"08f365952647594f5b07337666255f8510ef2e09bfb704530843b63121ed07f4","cloudflare-ai-gateway.json":"2ba4b7f1b0ba8919760c2e9cbd994270edd179bc9d291f271eede738afcbf269","cloudflare-workers-ai.json":"4bf0b488460c2e6cb8a6615bb2f87ca2a31cd9597eb249d5b58cba251330a99a","deepseek.json":"10a296fb3e898f7715c80890c8af0af4f5fd58f22dbcd6612fdc5d762157ccdc","fireworks.json":"c3dc21dc2e95428fc9a38e3840c05bbf90f94e4c25dee0eedf0b385b49ff65a4","github-copilot.json":"9ed67e5c0104ec237e9befcb9a50a18bd7d65e1539cd9f0638d2bc20bd82ef60","google-vertex.json":"40090c680538bc867f2624d986a449f361be4dfa6ba96d7a27402050f036e009","google.json":"c0f5a633e5e5a5044432db3e537f4bc674d4de18df09325c6349547fcc13cabe","groq.json":"910952ad9dad07856983459d63fce0148dba1203edd7b10d801a77c5824f3405","huggingface.json":"1b8604bd31a5e05fe43a40ec1ec6dfc1a51a28b0b020151ef057fab43f57c923","meta.json":"0c7e9a370a7005c5a89dc94f0f93bc67b8935c3f802de324f11af6ff56fff429","minimax-cn.json":"f962c20ee6a6a342820f778e9dc363a18a524bf11998f6e2c57f2989915d62e5","minimax.json":"17a432f80d0ea6dd26eade80a4314250d3a855678601728a5f70dd8fa0d21dd2","mistral.json":"10f33bff9adf1248f7e6848e5890c265399f1f94e5b42cfdc28c109d547af98d","moonshotai-cn.json":"bfb0641eee9587118da525607d86e55840de13310cd934785bc3bdcfeb6f88e3","moonshotai.json":"79ac5b6861a10d592e884c05a546fdd0b58fe383ce3453ecdb32d43926cba9dd","nvidia.json":"a75e963dc81779e3eec01c051b12277c15ec37c5b94ab51ece9e9ccb3b16407c","openai.json":"9104538118053eed57f90852332b6ad274a4e4792389bdbc9cfca1ae400c705a","opencode-go.json":"ba0f2ac7ff7c85db2123979b69f3e58cf5f2c1d89f29c8c7eda8a067d9809481","opencode.json":"ae373c624a66b824f543ef76fb5f1849b4910390952e6ae18b13bdb3e2d63b37","opengateway.json":"2d4275641f1b1154dfc6ffb320bedc1bcb1e33a0d12a4e9fba147ee3edec7d64","openrouter.json":"f150723ee331c1112708e0990663acc34e989c591858bbeef96b42d420f71951","qwen-token-plan-cn.json":"bd36a6d9cc2048deafacc85f7f0f2e51868c8b7aa09502e3e4e60e3e8b76f690","qwen-token-plan-individual.json":"35ffb0ba1a1ce3f68fc73262dd5e07fbcb5bf5911ad1e6e17bc0621e2894676a","qwen-token-plan.json":"ca27e49e62965221badead8e867b2007035c6b6a15a97c47219bd23d2c83c2b1","radius.json":"a8cf2f2cc7dae90d8bbfdd8a2f8a0e058e7923dbdb3ba2cdaed7dd1aecd25a2a","together.json":"bbd7fad86cacfefe3d3d61f6638f22e9b6f5d575722fd1112a16aafe0485c46d","typesafe.json":"a4429a2f696d5cc5273969af61a7310bda07d6bdcd27bf9ac9c76c534cc43716","venice.json":"a5f06e8297561de8cfcce397f9609a804ec912af007ba7fdbdb1951f2ee97009","vercel-ai-gateway.json":"aa1eabd3ec0d8d7a0e783cd514c085b465a28503515cea6477f4880349d63f5c","xai.json":"d7771a1450b21c1f6aee887ca6fea61b6e7b3fc13b4dee5cf72a71134fe623bc","xiaomi-token-plan-ams.json":"4dd8f838e21d7aa7caf3122d0b0b1e5a02a33bc012b96e6a75bd119334152d7a","xiaomi-token-plan-cn.json":"46414ff49973b95a0c14bd33e8992cc1938a50ce2c7cea9e2e5cc02de8f1df31","xiaomi-token-plan-sgp.json":"f5b3f66bf7bb7238592d4a9667cad983a008d7539a66e9896b02422622800935","xiaomi.json":"8b62c158d55d5a165f35cd72c1fc82ab89ff8e73f08960105fc41b822f236f69","zai-coding-cn.json":"2a7f59d15f588a97d218997883f2506dfc52d3ee320697d39f14213a050fc912","zai.json":"e9cc408e1756de8abc70148d63d89d11a63c65b7ef06ad0661cd1328e4209ba3"}}
1
+ {"schemaVersion":6,"generatedAt":"2026-10-11T10:01:11.497Z","structureHash":"0989a1c88b40439cecf9d8a82fe466628aa29d2c7cc597ed79540d082d7890d6","files":{"alibaba-token-plan.json":"16b3c6c78d72c73ca34a1e79ce71c0cf36ba409d02e83a17396ce0949a1d5363","amazon-bedrock.json":"4a95e6bf974e5ca967d5c050df580262e13573e42b3186edb448fa11a302f09f","ant-ling.json":"628feab3ef6c7d80ce96f75999804e1d9f05fec3851e5302e30fff3b69db90f6","anthropic.json":"111384e9f5845e0247bd34edf2400ef7720fcbdac140b944cf8878192d8bd6ab","azure-openai-responses.json":"a3e52bd78f0220aa32bce519e13955b8e6e567860416343844cbe19902f4a682","bai.json":"7e6861aaf27d8af34e1771c6092602194fcec0a0046e6adfab9c3ee54d32b99f","baseten.json":"1fcdab8daf2881bd099eb08f9416f7df5bf39975937d2a63b841542bd032f2e6","cerebras.json":"3eccb58c5de3d0dc7ba49dc6e477ba29f00cb3150ce0a35cc90d59e6b5ab368e","chatgpt-subscription.json":"2fbeb0141b29c340542798bce53422b93bef026a13420986e87fca89353e0aa2","cloudflare-ai-gateway.json":"5c8782fdbf2477f620b238da4344b0bcc0948b8c177461e63e7e5ba256f769c7","cloudflare-workers-ai.json":"f351e80493dea7b7a2c31dceb086ee804a88d67c5f8a3c823ea907991fe5d659","deepseek.json":"10a296fb3e898f7715c80890c8af0af4f5fd58f22dbcd6612fdc5d762157ccdc","fireworks.json":"c3dc21dc2e95428fc9a38e3840c05bbf90f94e4c25dee0eedf0b385b49ff65a4","github-copilot.json":"2c5a84983477a7c4f6c001088a1e043ee959ce58c99fea6eb843e0286228664b","google-vertex.json":"96ecc19bf20a706f99ae658b021a0ee5438146119e1e99de5fd824a01fcfd81b","google.json":"c0f5a633e5e5a5044432db3e537f4bc674d4de18df09325c6349547fcc13cabe","groq.json":"910952ad9dad07856983459d63fce0148dba1203edd7b10d801a77c5824f3405","huggingface.json":"6399e958790a9d90c21fb55d1cbef8569427a1ceb28de86dadeb3b4454ecfade","meta.json":"0c7e9a370a7005c5a89dc94f0f93bc67b8935c3f802de324f11af6ff56fff429","minimax-cn.json":"f962c20ee6a6a342820f778e9dc363a18a524bf11998f6e2c57f2989915d62e5","minimax.json":"17a432f80d0ea6dd26eade80a4314250d3a855678601728a5f70dd8fa0d21dd2","mistral.json":"27aa66c71a0504b53dc87ec194286fa7e70b99747fc8df9b709b23b3548afe50","moonshotai-cn.json":"18954b55dc5edecc174d8a07a2c5993416dd9d3ce52e411438035c16ee982e8e","moonshotai.json":"62d08fd5beead025a56d5f2e4227d8516b9c5034275b1b36d761a8625918f2b9","nvidia.json":"a75e963dc81779e3eec01c051b12277c15ec37c5b94ab51ece9e9ccb3b16407c","openai.json":"9104538118053eed57f90852332b6ad274a4e4792389bdbc9cfca1ae400c705a","opencode-go.json":"48ff011f3e171f977cfed2928272667e9361f13a508e5994f00f2241f6a23419","opencode.json":"882b039f64ef266da7b02d30aee9255c191e16f0600ef5494022bc1ef746f749","opengateway.json":"dd4259885ea6045d723b3abaae06657dfcce07b9ce3c2b0300220ac661432859","openrouter.json":"9484c1583eb1d419e89ffe258cd4efb7bb793666ae09c94db545f400fe0d628e","qwen-token-plan-cn.json":"bd36a6d9cc2048deafacc85f7f0f2e51868c8b7aa09502e3e4e60e3e8b76f690","qwen-token-plan-individual.json":"35ffb0ba1a1ce3f68fc73262dd5e07fbcb5bf5911ad1e6e17bc0621e2894676a","qwen-token-plan.json":"ca27e49e62965221badead8e867b2007035c6b6a15a97c47219bd23d2c83c2b1","radius.json":"8214122385e8e4c4bc2e1d2a7d032f9e4c654da3bfd3ac8c5d4396e1b522e53a","together.json":"bbd7fad86cacfefe3d3d61f6638f22e9b6f5d575722fd1112a16aafe0485c46d","typesafe.json":"a4429a2f696d5cc5273969af61a7310bda07d6bdcd27bf9ac9c76c534cc43716","venice.json":"3604c88c46dd3e4151b833927c6f87bcc165d0999a4339b32db2ad74a9ff173f","vercel-ai-gateway.json":"9859481f690a9a9a8131af3abfadf5378b2d1ef51990041da4465de3f1e4ab78","xai.json":"d7771a1450b21c1f6aee887ca6fea61b6e7b3fc13b4dee5cf72a71134fe623bc","xiaomi-token-plan-ams.json":"4dd8f838e21d7aa7caf3122d0b0b1e5a02a33bc012b96e6a75bd119334152d7a","xiaomi-token-plan-cn.json":"46414ff49973b95a0c14bd33e8992cc1938a50ce2c7cea9e2e5cc02de8f1df31","xiaomi-token-plan-sgp.json":"f5b3f66bf7bb7238592d4a9667cad983a008d7539a66e9896b02422622800935","xiaomi.json":"8b62c158d55d5a165f35cd72c1fc82ab89ff8e73f08960105fc41b822f236f69","zai-coding-cn.json":"2a7f59d15f588a97d218997883f2506dfc52d3ee320697d39f14213a050fc912","zai.json":"e9cc408e1756de8abc70148d63d89d11a63c65b7ef06ad0661cd1328e4209ba3"}}