@code-yeongyu/senpi-ai 2026.10.16-2 → 2026.10.16-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.
- package/dist/api/google-vertex-adc.d.ts +20 -0
- package/dist/api/google-vertex-adc.js +38 -0
- package/dist/api/google-vertex-adc.lazy.d.ts +9 -0
- package/dist/api/google-vertex-adc.lazy.js +6 -0
- package/dist/api/google-vertex-env.d.ts +9 -0
- package/dist/api/google-vertex-env.js +11 -0
- package/dist/api/google-vertex.js +2 -7
- package/dist/api/openai-codex-responses/fallback-state.d.ts +17 -1
- package/dist/api/openai-codex-responses/fallback-state.js +31 -2
- package/dist/api/openai-codex-responses.js +5 -3
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/venice.json +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ProviderEnv } from "../types.ts";
|
|
2
|
+
export interface VertexAdcAccess {
|
|
3
|
+
accessToken: string;
|
|
4
|
+
/** Project whose Vertex endpoints the request targets. */
|
|
5
|
+
project: string;
|
|
6
|
+
/** Project billed for quota (`x-goog-user-project`); the ADC quota project when set. */
|
|
7
|
+
quotaProject: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolves an access token plus target and quota projects from Application
|
|
11
|
+
* Default Credentials, the same credential chain `@google/genai` uses for the
|
|
12
|
+
* google-vertex provider. Project precedence: explicit option, then
|
|
13
|
+
* GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT, then the ADC quota project, then the
|
|
14
|
+
* project google-auth-library discovers (gcloud config, metadata server).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getVertexAdcAccess(options?: {
|
|
17
|
+
project?: string;
|
|
18
|
+
env?: ProviderEnv;
|
|
19
|
+
}): Promise<VertexAdcAccess>;
|
|
20
|
+
//# sourceMappingURL=google-vertex-adc.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { GoogleAuth } from "google-auth-library";
|
|
2
|
+
import { buildGoogleAuthOptions, resolveVertexProjectFromEnv } from "./google-vertex-env.js";
|
|
3
|
+
const CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
|
|
4
|
+
const authByKey = new Map();
|
|
5
|
+
function getGoogleAuth(env) {
|
|
6
|
+
const authOptions = buildGoogleAuthOptions(env);
|
|
7
|
+
const key = authOptions?.keyFilename ?? "";
|
|
8
|
+
let auth = authByKey.get(key);
|
|
9
|
+
if (!auth) {
|
|
10
|
+
// One GoogleAuth per credential source so the library's token cache and refresh are reused.
|
|
11
|
+
auth = new GoogleAuth({ ...authOptions, scopes: [CLOUD_PLATFORM_SCOPE] });
|
|
12
|
+
authByKey.set(key, auth);
|
|
13
|
+
}
|
|
14
|
+
return auth;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolves an access token plus target and quota projects from Application
|
|
18
|
+
* Default Credentials, the same credential chain `@google/genai` uses for the
|
|
19
|
+
* google-vertex provider. Project precedence: explicit option, then
|
|
20
|
+
* GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT, then the ADC quota project, then the
|
|
21
|
+
* project google-auth-library discovers (gcloud config, metadata server).
|
|
22
|
+
*/
|
|
23
|
+
export async function getVertexAdcAccess(options) {
|
|
24
|
+
const auth = getGoogleAuth(options?.env);
|
|
25
|
+
const client = await auth.getClient();
|
|
26
|
+
const { token } = await client.getAccessToken();
|
|
27
|
+
if (!token)
|
|
28
|
+
throw new Error("Google Application Default Credentials returned no access token.");
|
|
29
|
+
const adcQuotaProject = client.quotaProjectId || undefined;
|
|
30
|
+
const project = resolveVertexProjectFromEnv(options) ??
|
|
31
|
+
adcQuotaProject ??
|
|
32
|
+
((await auth.getProjectId().catch(() => null)) || undefined);
|
|
33
|
+
if (!project) {
|
|
34
|
+
throw new Error("Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or a quota project in Application Default Credentials.");
|
|
35
|
+
}
|
|
36
|
+
return { accessToken: token, project, quotaProject: adcQuotaProject ?? project };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=google-vertex-adc.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProviderEnv } from "../types.ts";
|
|
2
|
+
import type { VertexAdcAccess } from "./google-vertex-adc.ts";
|
|
3
|
+
export type { VertexAdcAccess } from "./google-vertex-adc.ts";
|
|
4
|
+
/** Lazily loads google-auth-library so importing callers do not pay for it until a request is made. */
|
|
5
|
+
export declare function getVertexAdcAccess(options?: {
|
|
6
|
+
project?: string;
|
|
7
|
+
env?: ProviderEnv;
|
|
8
|
+
}): Promise<VertexAdcAccess>;
|
|
9
|
+
//# sourceMappingURL=google-vertex-adc.lazy.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Lazily loads google-auth-library so importing callers do not pay for it until a request is made. */
|
|
2
|
+
export async function getVertexAdcAccess(options) {
|
|
3
|
+
const module = await import("./google-vertex-adc.js");
|
|
4
|
+
return module.getVertexAdcAccess(options);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=google-vertex-adc.lazy.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProviderEnv } from "../types.ts";
|
|
2
|
+
export declare function resolveVertexProjectFromEnv(options?: {
|
|
3
|
+
project?: string;
|
|
4
|
+
env?: ProviderEnv;
|
|
5
|
+
}): string | undefined;
|
|
6
|
+
export declare function buildGoogleAuthOptions(env?: ProviderEnv): {
|
|
7
|
+
keyFilename: string;
|
|
8
|
+
} | undefined;
|
|
9
|
+
//# sourceMappingURL=google-vertex-env.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
2
|
+
export function resolveVertexProjectFromEnv(options) {
|
|
3
|
+
return (options?.project ||
|
|
4
|
+
getProviderEnvValue("GOOGLE_CLOUD_PROJECT", options?.env) ||
|
|
5
|
+
getProviderEnvValue("GCLOUD_PROJECT", options?.env));
|
|
6
|
+
}
|
|
7
|
+
export function buildGoogleAuthOptions(env) {
|
|
8
|
+
const keyFilename = getProviderEnvValue("GOOGLE_APPLICATION_CREDENTIALS", env);
|
|
9
|
+
return keyFilename ? { keyFilename } : undefined;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=google-vertex-env.js.map
|
|
@@ -9,6 +9,7 @@ import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
|
9
9
|
import { getSystemMessageText } from "../utils/text.js";
|
|
10
10
|
import { collapseSystemMessages, getCurrentTools, getInitialSystemMessage } from "../utils/transcript.js";
|
|
11
11
|
import { convertMessages, convertTools, getDisabledGoogleThinkingConfig, isThinkingPart, mapStopReason, resolveGoogleFunctionCallingMode, resolveGoogleThinkingLevel, retainThoughtSignature, retryGoogleRequest, supportsGoogleStrictToolSampling, toGoogleSdkThinkingLevel, toGoogleThinkingLevel, toProviderNativeContent, usesGoogleThinkingLevel, } from "./google-shared.js";
|
|
12
|
+
import { buildGoogleAuthOptions, resolveVertexProjectFromEnv } from "./google-vertex-env.js";
|
|
12
13
|
import { applyExtraBody, buildBaseOptions, GOOGLE_RESERVED_BODY_KEYS } from "./simple-options.js";
|
|
13
14
|
const API_VERSION = "v1";
|
|
14
15
|
const GCP_VERTEX_CREDENTIALS_MARKER = "gcp-vertex-credentials";
|
|
@@ -351,10 +352,6 @@ function baseUrlIncludesApiVersion(baseUrl) {
|
|
|
351
352
|
return /(?:^|\/)v\d+(?:beta\d*)?(?:\/|$)/.test(baseUrl);
|
|
352
353
|
}
|
|
353
354
|
}
|
|
354
|
-
function buildGoogleAuthOptions(env) {
|
|
355
|
-
const keyFilename = getProviderEnvValue("GOOGLE_APPLICATION_CREDENTIALS", env);
|
|
356
|
-
return keyFilename ? { keyFilename } : undefined;
|
|
357
|
-
}
|
|
358
355
|
function resolveApiKey(options) {
|
|
359
356
|
const apiKey = options?.apiKey?.trim();
|
|
360
357
|
if (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) {
|
|
@@ -366,9 +363,7 @@ function isPlaceholderApiKey(apiKey) {
|
|
|
366
363
|
return /^<[^>]+>$/.test(apiKey);
|
|
367
364
|
}
|
|
368
365
|
function resolveProject(options) {
|
|
369
|
-
const project = options
|
|
370
|
-
getProviderEnvValue("GOOGLE_CLOUD_PROJECT", options?.env) ||
|
|
371
|
-
getProviderEnvValue("GCLOUD_PROJECT", options?.env);
|
|
366
|
+
const project = resolveVertexProjectFromEnv(options);
|
|
372
367
|
if (!project) {
|
|
373
368
|
throw new Error("Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.");
|
|
374
369
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export declare const CODEX_WEBSOCKET_FALLBACK_COOLDOWN_MS = 60000;
|
|
2
|
+
/**
|
|
3
|
+
* Mid-stream WebSocket failures in a row, with no completed WebSocket response
|
|
4
|
+
* between them, before the session moves to SSE. One drop is transient: the
|
|
5
|
+
* retry opens a fresh WebSocket, as upstream Codex does (senpi#3442).
|
|
6
|
+
*/
|
|
7
|
+
export declare const CODEX_WEBSOCKET_MID_STREAM_FAILURES_BEFORE_FALLBACK = 2;
|
|
8
|
+
export type WebSocketFailurePhase = "before_message_stream_start" | "after_message_stream_start";
|
|
2
9
|
export interface ChatGptSubscriptionWebSocketDebugStats {
|
|
3
10
|
requests: number;
|
|
4
11
|
connectionsCreated: number;
|
|
@@ -20,5 +27,14 @@ export declare function getWebSocketDebugStats(sessionId: string): ChatGptSubscr
|
|
|
20
27
|
export declare function clearWebSocketFallbackState(sessionId?: string): void;
|
|
21
28
|
export declare function isWebSocketSseFallbackActive(sessionId: string | undefined): boolean;
|
|
22
29
|
export declare function recordWebSocketSseFallback(sessionId: string | undefined): void;
|
|
23
|
-
|
|
30
|
+
/**
|
|
31
|
+
* A failure before any output arms the SSE cooldown at once, because that same
|
|
32
|
+
* request is retried over SSE. A failure after output started is retried by the
|
|
33
|
+
* caller; it arms the cooldown only once it repeats without a completed
|
|
34
|
+
* WebSocket response in between. Aborts and non-transport errors never reach
|
|
35
|
+
* here, so they neither count nor reset the run.
|
|
36
|
+
*/
|
|
37
|
+
export declare function recordWebSocketFailure(sessionId: string | undefined, error: unknown, phase: WebSocketFailurePhase): void;
|
|
38
|
+
/** A completed WebSocket response ends a run of mid-stream failures. */
|
|
39
|
+
export declare function recordWebSocketSuccess(sessionId: string | undefined): void;
|
|
24
40
|
//# sourceMappingURL=fallback-state.d.ts.map
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { formatThrownValue } from "../../utils/diagnostics.js";
|
|
2
2
|
export const CODEX_WEBSOCKET_FALLBACK_COOLDOWN_MS = 60_000;
|
|
3
|
+
/**
|
|
4
|
+
* Mid-stream WebSocket failures in a row, with no completed WebSocket response
|
|
5
|
+
* between them, before the session moves to SSE. One drop is transient: the
|
|
6
|
+
* retry opens a fresh WebSocket, as upstream Codex does (senpi#3442).
|
|
7
|
+
*/
|
|
8
|
+
export const CODEX_WEBSOCKET_MID_STREAM_FAILURES_BEFORE_FALLBACK = 2;
|
|
3
9
|
const websocketDebugStats = new Map();
|
|
4
10
|
const websocketSseFallbackUntil = new Map();
|
|
11
|
+
const consecutiveMidStreamFailures = new Map();
|
|
5
12
|
export function getOrCreateWebSocketDebugStats(sessionId) {
|
|
6
13
|
let stats = websocketDebugStats.get(sessionId);
|
|
7
14
|
if (!stats) {
|
|
@@ -29,10 +36,12 @@ export function clearWebSocketFallbackState(sessionId) {
|
|
|
29
36
|
if (sessionId) {
|
|
30
37
|
websocketDebugStats.delete(sessionId);
|
|
31
38
|
websocketSseFallbackUntil.delete(sessionId);
|
|
39
|
+
consecutiveMidStreamFailures.delete(sessionId);
|
|
32
40
|
return;
|
|
33
41
|
}
|
|
34
42
|
websocketDebugStats.clear();
|
|
35
43
|
websocketSseFallbackUntil.clear();
|
|
44
|
+
consecutiveMidStreamFailures.clear();
|
|
36
45
|
}
|
|
37
46
|
export function isWebSocketSseFallbackActive(sessionId) {
|
|
38
47
|
if (!sessionId)
|
|
@@ -58,13 +67,33 @@ export function recordWebSocketSseFallback(sessionId) {
|
|
|
58
67
|
stats.sseFallbacks++;
|
|
59
68
|
stats.websocketFallbackActive = true;
|
|
60
69
|
}
|
|
61
|
-
|
|
70
|
+
/**
|
|
71
|
+
* A failure before any output arms the SSE cooldown at once, because that same
|
|
72
|
+
* request is retried over SSE. A failure after output started is retried by the
|
|
73
|
+
* caller; it arms the cooldown only once it repeats without a completed
|
|
74
|
+
* WebSocket response in between. Aborts and non-transport errors never reach
|
|
75
|
+
* here, so they neither count nor reset the run.
|
|
76
|
+
*/
|
|
77
|
+
export function recordWebSocketFailure(sessionId, error, phase) {
|
|
62
78
|
if (!sessionId)
|
|
63
79
|
return;
|
|
64
|
-
websocketSseFallbackUntil.set(sessionId, Date.now() + CODEX_WEBSOCKET_FALLBACK_COOLDOWN_MS);
|
|
65
80
|
const stats = getOrCreateWebSocketDebugStats(sessionId);
|
|
66
81
|
stats.websocketFailures++;
|
|
67
82
|
stats.lastWebSocketError = formatThrownValue(error);
|
|
83
|
+
if (phase === "after_message_stream_start") {
|
|
84
|
+
const failures = (consecutiveMidStreamFailures.get(sessionId) ?? 0) + 1;
|
|
85
|
+
if (failures < CODEX_WEBSOCKET_MID_STREAM_FAILURES_BEFORE_FALLBACK) {
|
|
86
|
+
consecutiveMidStreamFailures.set(sessionId, failures);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
consecutiveMidStreamFailures.delete(sessionId);
|
|
91
|
+
websocketSseFallbackUntil.set(sessionId, Date.now() + CODEX_WEBSOCKET_FALLBACK_COOLDOWN_MS);
|
|
68
92
|
stats.websocketFallbackActive = true;
|
|
69
93
|
}
|
|
94
|
+
/** A completed WebSocket response ends a run of mid-stream failures. */
|
|
95
|
+
export function recordWebSocketSuccess(sessionId) {
|
|
96
|
+
if (sessionId)
|
|
97
|
+
consecutiveMidStreamFailures.delete(sessionId);
|
|
98
|
+
}
|
|
70
99
|
//# sourceMappingURL=fallback-state.js.map
|
|
@@ -21,7 +21,7 @@ import { getSystemMessageText } from "../utils/text.js";
|
|
|
21
21
|
import { getDeclaredTools, getInitialSystemMessage, normalizeContext, resolveTranscript } from "../utils/transcript.js";
|
|
22
22
|
import { uuidv7 } from "../utils/uuid.js";
|
|
23
23
|
import { createGrammarToolInputProperties } from "./constrained-sampling.js";
|
|
24
|
-
import { clearWebSocketFallbackState, getOrCreateWebSocketDebugStats, getWebSocketDebugStats, isWebSocketSseFallbackActive, recordWebSocketFailure, recordWebSocketSseFallback, } from "./openai-codex-responses/fallback-state.js";
|
|
24
|
+
import { clearWebSocketFallbackState, getOrCreateWebSocketDebugStats, getWebSocketDebugStats, isWebSocketSseFallbackActive, recordWebSocketFailure, recordWebSocketSseFallback, recordWebSocketSuccess, } from "./openai-codex-responses/fallback-state.js";
|
|
25
25
|
import { buildCodexReasoning } from "./openai-codex-responses/reasoning.js";
|
|
26
26
|
import { applyChatGptSubscriptionCacheAffinityHeaders, clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
27
27
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream, resolveResponsesDeferredToolsMode, resolveResponsesToolPlacement, } from "./openai-responses-shared.js";
|
|
@@ -202,6 +202,7 @@ export const stream = (model, context, options) => {
|
|
|
202
202
|
throw new Error("Request was aborted");
|
|
203
203
|
}
|
|
204
204
|
assertSuccessfulOutput(output);
|
|
205
|
+
recordWebSocketSuccess(cacheSessionId);
|
|
205
206
|
stream.push({
|
|
206
207
|
type: "done",
|
|
207
208
|
reason: output.stopReason,
|
|
@@ -225,14 +226,15 @@ export const stream = (model, context, options) => {
|
|
|
225
226
|
if (aborted || (isCodexNonTransportError(error) && !connectionLimitBeforeStart)) {
|
|
226
227
|
throw error;
|
|
227
228
|
}
|
|
229
|
+
const phase = websocketStarted ? "after_message_stream_start" : "before_message_stream_start";
|
|
228
230
|
appendAssistantMessageDiagnostic(output, createAssistantMessageDiagnostic("provider_transport_failure", error, {
|
|
229
231
|
configuredTransport: transport,
|
|
230
232
|
...(websocketStarted ? {} : { fallbackTransport: "sse" }),
|
|
231
233
|
eventsEmitted: websocketStarted,
|
|
232
|
-
phase
|
|
234
|
+
phase,
|
|
233
235
|
requestBytes: new TextEncoder().encode(bodyJson).byteLength,
|
|
234
236
|
}));
|
|
235
|
-
recordWebSocketFailure(cacheSessionId, error);
|
|
237
|
+
recordWebSocketFailure(cacheSessionId, error, phase);
|
|
236
238
|
if (websocketStarted) {
|
|
237
239
|
throw error;
|
|
238
240
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schemaVersion":6,"generatedAt":"2026-10-
|
|
1
|
+
{"schemaVersion":6,"generatedAt":"2026-10-16T08:15:38.355Z","structureHash":"4b14b62036b26c05fb7e26d1b722135a8249b002d357c71bda326cfef4b2021e","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":"42b88c93d717b2a7469b71da7da5adf87347d0d9cc0f264b39117f0f940b51c0","cloudflare-ai-gateway.json":"673ac36e4531995c43e49e132577cdde18a0ba088648ecae5a904020f400abc2","cloudflare-workers-ai.json":"f351e80493dea7b7a2c31dceb086ee804a88d67c5f8a3c823ea907991fe5d659","deepseek.json":"10a296fb3e898f7715c80890c8af0af4f5fd58f22dbcd6612fdc5d762157ccdc","fireworks.json":"868f828365314089608e6d0d915076f6d3d4f67c305f824d47ba05e040897d39","github-copilot.json":"9a0a960b5978134bdd7a5e56928fb1985a10ce893fd31d93a272a4b38c413740","google-vertex.json":"8f986b4aca8c685b0f3481bd252bda21e4858bf9015ad37fc5bcc44b7f01d076","google.json":"fc06c3cd56c180d214612ce0ef72ea14734195de70ace47ef47f02199b053aae","groq.json":"910952ad9dad07856983459d63fce0148dba1203edd7b10d801a77c5824f3405","huggingface.json":"6399e958790a9d90c21fb55d1cbef8569427a1ceb28de86dadeb3b4454ecfade","meta.json":"563f5ec07973f52ab8c3eb26ef91a36ad8a79e950b37174935666cdcb624bf35","minimax-cn.json":"f962c20ee6a6a342820f778e9dc363a18a524bf11998f6e2c57f2989915d62e5","minimax.json":"17a432f80d0ea6dd26eade80a4314250d3a855678601728a5f70dd8fa0d21dd2","mistral.json":"27aa66c71a0504b53dc87ec194286fa7e70b99747fc8df9b709b23b3548afe50","moonshotai-cn.json":"18954b55dc5edecc174d8a07a2c5993416dd9d3ce52e411438035c16ee982e8e","moonshotai.json":"62d08fd5beead025a56d5f2e4227d8516b9c5034275b1b36d761a8625918f2b9","nvidia.json":"98b47c4da26c8e649f48a874602fd7e9dc8a54ee0bdb40e3d07fe49189a842d2","openai.json":"9104538118053eed57f90852332b6ad274a4e4792389bdbc9cfca1ae400c705a","opencode-go.json":"b78a595ce56b3da17d93d609e490eda7843e090cc7943f96423c108ca2abbbc9","opencode.json":"bba280a58b195539d45ebff7583b0211b8c4326bfae3e3cf5cc17dd1dde9dae6","opengateway.json":"41e04d37ca867d533349c4dd37c9cf7274f6321194a57bbaa5ef2386b0cb0bf0","openrouter.json":"54abb027f2185f5f9b084aef4da30f0483bcfa894f68a934d588f144baea85c8","qwen-token-plan-cn.json":"bd36a6d9cc2048deafacc85f7f0f2e51868c8b7aa09502e3e4e60e3e8b76f690","qwen-token-plan-individual.json":"35ffb0ba1a1ce3f68fc73262dd5e07fbcb5bf5911ad1e6e17bc0621e2894676a","qwen-token-plan.json":"ca27e49e62965221badead8e867b2007035c6b6a15a97c47219bd23d2c83c2b1","radius.json":"e33fab6aa5ac6c43ce26dc3680ea28f2d7d063a8dbca0360ee2b9c5676bc43a6","together.json":"bbd7fad86cacfefe3d3d61f6638f22e9b6f5d575722fd1112a16aafe0485c46d","typesafe.json":"a4429a2f696d5cc5273969af61a7310bda07d6bdcd27bf9ac9c76c534cc43716","venice.json":"7ccc4284bb1bdd458898bc64dc0c2f07b629dcfc6cda41b13d1dc35feba98190","vercel-ai-gateway.json":"aff3af2ac9f49338f733825f0e801acb96ab0196062dccedd543ad86ef702c7b","xai.json":"d7771a1450b21c1f6aee887ca6fea61b6e7b3fc13b4dee5cf72a71134fe623bc","xiaomi-token-plan-ams.json":"7fa339ba5675460b1ff4e5bca9e8ad0aa60b0277d75a989b1c196aa6ca2af34d","xiaomi-token-plan-cn.json":"ef7917c6ea0d3edc655c8a52082ee5f1330658aa6f10199d8f164eb4605ef0a0","xiaomi-token-plan-sgp.json":"addda93f6b70ba879db97e3cfd2e4f2efc7cda47d7daa78c23c5b0e51162de5c","xiaomi.json":"5a42caf49d3e4d7946d60386e9899c2146bf8e3cbaff4c576ee4f49b398cc11c","zai-coding-cn.json":"2a7f59d15f588a97d218997883f2506dfc52d3ee320697d39f14213a050fc912","zai.json":"e9cc408e1756de8abc70148d63d89d11a63c65b7ef06ad0661cd1328e4209ba3"}}
|