@code-yeongyu/senpi-ai 2026.11.3-3 → 2026.11.5-1
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/openai-completions.js +19 -4
- package/dist/api/openai-responses-prompt-cache.d.ts +2 -0
- package/dist/api/openai-responses-prompt-cache.js +6 -4
- package/dist/api/openai-responses-shared.d.ts +1 -0
- package/dist/api/openai-responses-shared.js +6 -1
- package/dist/api/openai-responses.js +75 -4
- package/dist/auth/oauth/openai-chatgpt.d.ts +26 -6
- package/dist/auth/oauth/openai-chatgpt.js +175 -62
- package/dist/auth/oauth/openai-id-token.d.ts +16 -0
- package/dist/auth/oauth/openai-id-token.js +105 -0
- package/dist/auth/pool/slots.d.ts +2 -2
- package/dist/auth/pool/slots.js +64 -14
- package/dist/auth/types.d.ts +29 -2
- package/dist/cli.js +2 -1
- package/dist/models.js +8 -1
- package/dist/providers/chatgpt-subscription.d.ts +1 -1
- package/dist/providers/chatgpt-subscription.js +57 -8
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/venice.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/types.d.ts +3 -2
- package/dist/utils/oauth-refresh-error.d.ts +11 -0
- package/dist/utils/oauth-refresh-error.js +18 -0
- package/dist/utils/oauth-url.d.ts +7 -0
- package/dist/utils/oauth-url.js +13 -0
- package/package.json +2 -2
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface OpenAIIdentity {
|
|
2
|
+
subject: string;
|
|
3
|
+
/** Display metadata only; never an account identity or workspace identifier. */
|
|
4
|
+
email?: string;
|
|
5
|
+
issuer: string;
|
|
6
|
+
}
|
|
7
|
+
export interface OpenAIIdTokenDependencies {
|
|
8
|
+
fetch: (url: string, init?: RequestInit) => Promise<Response>;
|
|
9
|
+
now: () => number;
|
|
10
|
+
}
|
|
11
|
+
export declare class OpenAIIdTokenValidationError extends Error {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
/** Each flow instance caches discovery and keys, without caching identity claims. */
|
|
15
|
+
export declare function createOpenAIIdTokenVerifier(deps: OpenAIIdTokenDependencies): (idToken: unknown, clientId: string, nonce: string, signal: AbortSignal) => Promise<OpenAIIdentity>;
|
|
16
|
+
//# sourceMappingURL=openai-id-token.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const ISSUER = "https://auth.openai.com";
|
|
2
|
+
const DISCOVERY_URL = `${ISSUER}/.well-known/openid-configuration`;
|
|
3
|
+
const CACHE_MS = 5 * 60 * 1000;
|
|
4
|
+
export class OpenAIIdTokenValidationError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(`OpenAI ID token validation failed: ${message}`);
|
|
7
|
+
this.name = "OpenAIIdTokenValidationError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function object(value) {
|
|
11
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
12
|
+
throw new OpenAIIdTokenValidationError("expected an object");
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function decode(value) {
|
|
17
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value))
|
|
18
|
+
throw new OpenAIIdTokenValidationError("invalid JWT encoding");
|
|
19
|
+
return Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/")), (char) => char.charCodeAt(0));
|
|
20
|
+
}
|
|
21
|
+
/** Each flow instance caches discovery and keys, without caching identity claims. */
|
|
22
|
+
export function createOpenAIIdTokenVerifier(deps) {
|
|
23
|
+
let discovery;
|
|
24
|
+
let jwks;
|
|
25
|
+
async function loadKeys(signal, force = false) {
|
|
26
|
+
if (!discovery || discovery.expires <= deps.now()) {
|
|
27
|
+
const response = await deps.fetch(DISCOVERY_URL, { signal });
|
|
28
|
+
if (!response.ok)
|
|
29
|
+
throw new OpenAIIdTokenValidationError("discovery request failed");
|
|
30
|
+
const config = object(await response.json());
|
|
31
|
+
if (typeof config.jwks_uri !== "string" || new URL(config.jwks_uri).protocol !== "https:") {
|
|
32
|
+
throw new OpenAIIdTokenValidationError("invalid discovery JWKS URI");
|
|
33
|
+
}
|
|
34
|
+
discovery = { jwksUri: config.jwks_uri, expires: deps.now() + CACHE_MS };
|
|
35
|
+
jwks = undefined;
|
|
36
|
+
}
|
|
37
|
+
if (force || !jwks || jwks.expires <= deps.now()) {
|
|
38
|
+
const response = await deps.fetch(discovery.jwksUri, { signal });
|
|
39
|
+
if (!response.ok)
|
|
40
|
+
throw new OpenAIIdTokenValidationError("JWKS request failed");
|
|
41
|
+
const data = object(await response.json());
|
|
42
|
+
if (!Array.isArray(data.keys))
|
|
43
|
+
throw new OpenAIIdTokenValidationError("invalid JWKS");
|
|
44
|
+
jwks = { keys: data.keys.map(object), expires: deps.now() + CACHE_MS };
|
|
45
|
+
}
|
|
46
|
+
return jwks.keys;
|
|
47
|
+
}
|
|
48
|
+
return async (idToken, clientId, nonce, signal) => {
|
|
49
|
+
try {
|
|
50
|
+
if (typeof idToken !== "string")
|
|
51
|
+
throw new OpenAIIdTokenValidationError("missing ID token");
|
|
52
|
+
const parts = idToken.split(".");
|
|
53
|
+
if (parts.length !== 3)
|
|
54
|
+
throw new OpenAIIdTokenValidationError("invalid JWT");
|
|
55
|
+
const [headerPart, payloadPart, signaturePart] = parts;
|
|
56
|
+
const header = object(JSON.parse(new TextDecoder().decode(decode(headerPart))));
|
|
57
|
+
if (header.alg !== "RS256" || typeof header.kid !== "string" || !header.kid || header.crit !== undefined) {
|
|
58
|
+
throw new OpenAIIdTokenValidationError("unsupported signing header");
|
|
59
|
+
}
|
|
60
|
+
const matchingKey = (key) => key.kid === header.kid &&
|
|
61
|
+
key.kty === "RSA" &&
|
|
62
|
+
(key.alg === undefined || key.alg === "RS256") &&
|
|
63
|
+
(key.use === undefined || key.use === "sig");
|
|
64
|
+
let keys = await loadKeys(signal);
|
|
65
|
+
if (!keys.some(matchingKey))
|
|
66
|
+
keys = await loadKeys(signal, true);
|
|
67
|
+
const matches = keys.filter(matchingKey);
|
|
68
|
+
if (matches.length !== 1)
|
|
69
|
+
throw new OpenAIIdTokenValidationError("signing key not found or ambiguous");
|
|
70
|
+
const key = await crypto.subtle.importKey("jwk", matches[0], { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"]);
|
|
71
|
+
const valid = await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key, decode(signaturePart), new TextEncoder().encode(`${headerPart}.${payloadPart}`));
|
|
72
|
+
if (!valid)
|
|
73
|
+
throw new OpenAIIdTokenValidationError("invalid signature");
|
|
74
|
+
const claims = object(JSON.parse(new TextDecoder().decode(decode(payloadPart))));
|
|
75
|
+
if (claims.iss !== ISSUER)
|
|
76
|
+
throw new OpenAIIdTokenValidationError("issuer mismatch");
|
|
77
|
+
const audiences = typeof claims.aud === "string" ? [claims.aud] : claims.aud;
|
|
78
|
+
if (!Array.isArray(audiences) ||
|
|
79
|
+
!audiences.every((aud) => typeof aud === "string") ||
|
|
80
|
+
!audiences.includes(clientId)) {
|
|
81
|
+
throw new OpenAIIdTokenValidationError("audience mismatch");
|
|
82
|
+
}
|
|
83
|
+
if (typeof claims.exp !== "number" || !Number.isFinite(claims.exp) || claims.exp <= deps.now() / 1000) {
|
|
84
|
+
throw new OpenAIIdTokenValidationError("expired or missing expiration");
|
|
85
|
+
}
|
|
86
|
+
if (claims.nonce !== nonce)
|
|
87
|
+
throw new OpenAIIdTokenValidationError("nonce mismatch");
|
|
88
|
+
if (typeof claims.sub !== "string" || !claims.sub.trim()) {
|
|
89
|
+
throw new OpenAIIdTokenValidationError("missing subject");
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
subject: claims.sub,
|
|
93
|
+
issuer: ISSUER,
|
|
94
|
+
...(typeof claims.email === "string" ? { email: claims.email } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error instanceof OpenAIIdTokenValidationError)
|
|
99
|
+
throw error;
|
|
100
|
+
// Do not expose tokens, key material, or remote response bodies in login errors.
|
|
101
|
+
throw new OpenAIIdTokenValidationError("could not verify ID token");
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=openai-id-token.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ProviderEnv } from "../../types.ts";
|
|
2
|
-
import type { Credential } from "../types.ts";
|
|
2
|
+
import type { Credential, OAuthCredentials } from "../types.ts";
|
|
3
3
|
export type { Credential };
|
|
4
4
|
export declare const DEFAULT_SLOT_NAME = "default";
|
|
5
5
|
export type CredentialSlotSource = "login" | "import" | "env";
|
|
6
|
-
export type CredentialSlot = {
|
|
6
|
+
export type CredentialSlot = Partial<OAuthCredentials> & {
|
|
7
7
|
/** Immutable operational identity. */
|
|
8
8
|
name: string;
|
|
9
9
|
/** Optional presentation metadata; never used for credential selection. */
|
package/dist/auth/pool/slots.js
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
import { LEGACY_PROVIDER_IDS } from "../../legacy-provider-ids.js";
|
|
2
2
|
export const DEFAULT_SLOT_NAME = "default";
|
|
3
|
+
const OAUTH_ACCOUNT_FIELDS = [
|
|
4
|
+
"route",
|
|
5
|
+
"issuer",
|
|
6
|
+
"subject",
|
|
7
|
+
"clientId",
|
|
8
|
+
"email",
|
|
9
|
+
"idToken",
|
|
10
|
+
"scopes",
|
|
11
|
+
"planUsageEnabled",
|
|
12
|
+
"signedOut",
|
|
13
|
+
];
|
|
14
|
+
/** Replace account metadata as a unit; an absent field must not inherit a sibling's identity. */
|
|
15
|
+
function withOAuthAccountFields(target, source) {
|
|
16
|
+
const next = { ...target };
|
|
17
|
+
for (const field of OAUTH_ACCOUNT_FIELDS) {
|
|
18
|
+
if (source[field] === undefined)
|
|
19
|
+
Reflect.deleteProperty(next, field);
|
|
20
|
+
else
|
|
21
|
+
Reflect.set(next, field, source[field]);
|
|
22
|
+
}
|
|
23
|
+
return next;
|
|
24
|
+
}
|
|
3
25
|
const SLOT_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
|
|
4
26
|
export function assertValidSlotName(name) {
|
|
5
27
|
if (!SLOT_NAME_PATTERN.test(name)) {
|
|
@@ -178,7 +200,7 @@ function projectFlatFields(credential, slot) {
|
|
|
178
200
|
if (credential.type === "oauth") {
|
|
179
201
|
if (slot.access === undefined || slot.refresh === undefined || slot.expires === undefined)
|
|
180
202
|
return credential;
|
|
181
|
-
return { ...credential, access: slot.access, refresh: slot.refresh, expires: slot.expires, ...env };
|
|
203
|
+
return withOAuthAccountFields({ ...credential, access: slot.access, refresh: slot.refresh, expires: slot.expires, ...env }, slot);
|
|
182
204
|
}
|
|
183
205
|
return { ...credential, key: slot.key, ...env };
|
|
184
206
|
}
|
|
@@ -228,20 +250,20 @@ export function projectSlot(credential, name) {
|
|
|
228
250
|
if (flat.type === "oauth") {
|
|
229
251
|
if (slot.access === undefined || slot.refresh === undefined || slot.expires === undefined)
|
|
230
252
|
return undefined;
|
|
231
|
-
return { ...flat, access: slot.access, refresh: slot.refresh, expires: slot.expires, ...env };
|
|
253
|
+
return withOAuthAccountFields({ ...flat, access: slot.access, refresh: slot.refresh, expires: slot.expires, ...env }, slot);
|
|
232
254
|
}
|
|
233
255
|
return { ...flat, key: slot.key, ...env };
|
|
234
256
|
}
|
|
235
257
|
function slotFromFlatCredentialNamed(credential, name) {
|
|
236
258
|
if (credential.type === "oauth") {
|
|
237
|
-
return {
|
|
259
|
+
return withOAuthAccountFields({
|
|
238
260
|
name,
|
|
239
261
|
source: "login",
|
|
240
262
|
access: credential.access,
|
|
241
263
|
refresh: credential.refresh,
|
|
242
264
|
expires: credential.expires,
|
|
243
265
|
...credentialSlotEnv(credential),
|
|
244
|
-
};
|
|
266
|
+
}, credential);
|
|
245
267
|
}
|
|
246
268
|
return { name, source: "login", key: credential.key, ...credentialSlotEnv(credential) };
|
|
247
269
|
}
|
|
@@ -374,7 +396,31 @@ export function appendLoginSlot(stored, flat, onAllocated, options) {
|
|
|
374
396
|
// shape because the provider's accounts already carry this login.
|
|
375
397
|
return storedAccounts ? mergeProvidedPool(current, storedAccounts, provided) : flat;
|
|
376
398
|
}
|
|
377
|
-
|
|
399
|
+
if (flat.type === "oauth" && flat.route === "siwc") {
|
|
400
|
+
const existing = listSlots(current);
|
|
401
|
+
const matched = existing.find((slot) => slot.route === "siwc" &&
|
|
402
|
+
["issuer", "subject", "clientId"].every((field) => typeof flat[field] === "string" && flat[field].trim() !== "" && flat[field] === slot[field]));
|
|
403
|
+
if (matched) {
|
|
404
|
+
const replacement = {
|
|
405
|
+
...slotFromFlatCredentialNamed(flat, matched.name),
|
|
406
|
+
...(matched.displayName === undefined ? {} : { displayName: matched.displayName }),
|
|
407
|
+
};
|
|
408
|
+
const next = slotMirrorsFlat(current, matched) ? projectFlatFields(current, replacement) : current;
|
|
409
|
+
onAllocated?.(matched.name, "generated");
|
|
410
|
+
if (!storedAccounts)
|
|
411
|
+
return next;
|
|
412
|
+
const pooled = {
|
|
413
|
+
...next,
|
|
414
|
+
accounts: existing.map((slot) => (slot === matched ? replacement : slot)),
|
|
415
|
+
};
|
|
416
|
+
return pooled;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// Sign in with ChatGPT names an account by its issuer, subject and issued client ID (matched above). Without
|
|
420
|
+
// that tuple, a shared ChatGPT token identity is not the same SIWC sign-in, so the login is appended.
|
|
421
|
+
const replaced = flat.type === "oauth" && flat.route === "siwc"
|
|
422
|
+
? undefined
|
|
423
|
+
: replaceSameAccount(current, flat, options?.accountIdentity, onAllocated);
|
|
378
424
|
if (replaced)
|
|
379
425
|
return replaced;
|
|
380
426
|
const name = nextLoginSlotName(current);
|
|
@@ -405,7 +451,13 @@ function replaceSameAccount(current, flat, accountIdentity, onAllocated) {
|
|
|
405
451
|
if (identity === undefined)
|
|
406
452
|
return undefined;
|
|
407
453
|
const slots = listSlots(current);
|
|
408
|
-
|
|
454
|
+
// A token identity names a ChatGPT account, not a sign-in: the legacy Codex route and Sign in with ChatGPT
|
|
455
|
+
// hold separate grants for one person, so a login replaces only a slot on its own route (#5003).
|
|
456
|
+
const route = flat.route ?? "codex";
|
|
457
|
+
const matches = slots.filter((slot) => slot.source !== "env" &&
|
|
458
|
+
(slot.route ?? "codex") === route &&
|
|
459
|
+
slot.access !== undefined &&
|
|
460
|
+
accountIdentity({ access: slot.access }) === identity);
|
|
409
461
|
const kept = matches[0];
|
|
410
462
|
if (!kept)
|
|
411
463
|
return undefined;
|
|
@@ -413,14 +465,12 @@ function replaceSameAccount(current, flat, accountIdentity, onAllocated) {
|
|
|
413
465
|
onAllocated?.(kept.name, "generated");
|
|
414
466
|
return flat;
|
|
415
467
|
}
|
|
468
|
+
// Built through the account-field projection so the login's route, issued client, issuer, subject, ID token
|
|
469
|
+
// and scopes reach the slot; a hand-copied token triple dropped them (#5003).
|
|
416
470
|
const fresh = {
|
|
417
|
-
|
|
471
|
+
...slotFromFlatCredentialNamed(flat, kept.name),
|
|
418
472
|
...(kept.displayName === undefined ? {} : { displayName: kept.displayName }),
|
|
419
473
|
...(kept.source === undefined ? {} : { source: kept.source }),
|
|
420
|
-
access: flat.access,
|
|
421
|
-
refresh: flat.refresh,
|
|
422
|
-
expires: flat.expires,
|
|
423
|
-
...credentialSlotEnv(flat),
|
|
424
474
|
};
|
|
425
475
|
const dropped = new Set(matches.slice(1).map((slot) => slot.name));
|
|
426
476
|
const accounts = slots.flatMap((slot) => (slot === kept ? [fresh] : dropped.has(slot.name) ? [] : [slot]));
|
|
@@ -510,7 +560,7 @@ export function mergeRefreshedSlot(current, name, refreshed) {
|
|
|
510
560
|
const target = current.accounts.find((slot) => slot.name === name);
|
|
511
561
|
if (!target)
|
|
512
562
|
return current;
|
|
513
|
-
const rotated = { access: refreshed.access, refresh: refreshed.refresh, expires: refreshed.expires };
|
|
563
|
+
const rotated = withOAuthAccountFields({ access: refreshed.access, refresh: refreshed.refresh, expires: refreshed.expires }, refreshed);
|
|
514
564
|
const accounts = current.accounts.map((slot) => (slot === target ? { ...slot, ...rotated } : slot));
|
|
515
565
|
const mirrorsFlat = target.access === current.access || target.refresh === current.refresh;
|
|
516
566
|
return mirrorsFlat ? { ...current, ...rotated, accounts } : { ...current, accounts };
|
|
@@ -522,11 +572,11 @@ export function mergeRefreshed(current, refreshed) {
|
|
|
522
572
|
if (refreshed.type !== "oauth" || current.type !== "oauth")
|
|
523
573
|
return refreshed;
|
|
524
574
|
const target = current.accounts.find((slot) => slot.access === current.access || slot.refresh === current.refresh);
|
|
525
|
-
const rotated = {
|
|
575
|
+
const rotated = withOAuthAccountFields({
|
|
526
576
|
access: refreshed.access,
|
|
527
577
|
refresh: refreshed.refresh,
|
|
528
578
|
expires: refreshed.expires,
|
|
529
|
-
};
|
|
579
|
+
}, refreshed);
|
|
530
580
|
const accounts = target
|
|
531
581
|
? current.accounts.map((slot) => (slot === target ? { ...slot, ...rotated } : slot))
|
|
532
582
|
: current.accounts;
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import type { ProviderEnv, ProviderHeaders } from "../types.ts";
|
|
1
|
+
import type { Api, Model, ProviderEnv, ProviderHeaders } from "../types.ts";
|
|
2
2
|
/**
|
|
3
3
|
* Request auth for a single model request. If a value cannot be expressed as
|
|
4
|
-
* `apiKey`, `headers`,
|
|
4
|
+
* `apiKey`, `headers`, `baseUrl`, or the credential's chat route, it is provider config, not auth.
|
|
5
5
|
*/
|
|
6
6
|
export interface ModelAuth {
|
|
7
7
|
apiKey?: string;
|
|
8
8
|
headers?: ProviderHeaders;
|
|
9
9
|
baseUrl?: string;
|
|
10
|
+
/** Credential-selected chat transport; absent preserves the selected model's API. */
|
|
11
|
+
api?: Api;
|
|
12
|
+
/** Request restrictions belonging to the selected credential's chat route. */
|
|
13
|
+
compat?: Model<Api>["compat"];
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* Stored api-key credential. `env` holds provider-scoped environment/config
|
|
@@ -24,11 +28,25 @@ export interface OAuthCredentials {
|
|
|
24
28
|
refresh: string;
|
|
25
29
|
access: string;
|
|
26
30
|
expires: number;
|
|
31
|
+
/** ChatGPT slots without a route retain the legacy Codex protocol. */
|
|
32
|
+
route?: "siwc" | "codex";
|
|
27
33
|
[key: string]: unknown;
|
|
28
34
|
}
|
|
29
35
|
/** Stored canonical OAuth credential. */
|
|
30
36
|
export interface OAuthCredential extends OAuthCredentials {
|
|
31
37
|
type: "oauth";
|
|
38
|
+
/** Verified account identity, retained only by flows that validate an ID token. */
|
|
39
|
+
subject?: string;
|
|
40
|
+
/** Display metadata only; not proof of identity or workspace membership. */
|
|
41
|
+
email?: string;
|
|
42
|
+
issuer?: string;
|
|
43
|
+
/** Issued OAuth client ID, not the dynamic registration entrypoint. */
|
|
44
|
+
clientId?: string;
|
|
45
|
+
/** Retained for a later id_token_hint; treat as secret credential material. */
|
|
46
|
+
idToken?: string;
|
|
47
|
+
scopes?: string[];
|
|
48
|
+
/** SIWC plan permission; absent on credentials saved before permission tracking. */
|
|
49
|
+
planUsageEnabled?: boolean;
|
|
32
50
|
/** Random id the last sign-in wrote (`stampLogin`); a refresh keeps or drops it, never mints one. Not key material. */
|
|
33
51
|
loginId?: string;
|
|
34
52
|
}
|
|
@@ -251,12 +269,21 @@ export interface ApiKeyAuth {
|
|
|
251
269
|
export interface LoginOptions {
|
|
252
270
|
/** Configured product display name, consistent across installations of this app. */
|
|
253
271
|
appName?: string;
|
|
272
|
+
/**
|
|
273
|
+
* The explicitly selected saved account for reauthorization. Omit when adding
|
|
274
|
+
* an account; callers must not infer this from the provider's active credential.
|
|
275
|
+
*/
|
|
276
|
+
reauthorize?: OAuthCredential;
|
|
254
277
|
/**
|
|
255
278
|
* Returns the stable ID of this app installation, e.g. sent to OpenAI as its
|
|
256
279
|
* agent host ID. Called only by login flows that need it, so apps can create
|
|
257
280
|
* the ID on first use and must return the same ID on every later call.
|
|
258
281
|
*/
|
|
259
282
|
getDeviceId?: () => string;
|
|
283
|
+
/** Explicitly enable ChatGPT plan usage for a saved SIWC registration. */
|
|
284
|
+
planUsageConsent?: {
|
|
285
|
+
clientId: string;
|
|
286
|
+
};
|
|
260
287
|
}
|
|
261
288
|
/**
|
|
262
289
|
* OAuth auth. The `refresh`/`toAuth` split lets `Models` own the locked
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { createInterface } from "node:readline";
|
|
7
7
|
import { builtinProviders } from "./providers/all.js";
|
|
8
|
+
import { redactOAuthUrl } from "./utils/oauth-url.js";
|
|
8
9
|
const AUTH_FILE = "auth.json";
|
|
9
10
|
const PROVIDERS = builtinProviders().filter((provider) => provider.auth.oauth !== undefined);
|
|
10
11
|
function prompt(rl, question) {
|
|
@@ -64,7 +65,7 @@ async function login(providerId) {
|
|
|
64
65
|
notify: (event) => {
|
|
65
66
|
switch (event.type) {
|
|
66
67
|
case "auth_url":
|
|
67
|
-
console.log(`\nOpen this URL in your browser:\n${event.url}`);
|
|
68
|
+
console.log(`\nOpen this URL in your browser:\n${redactOAuthUrl(event.url)}`);
|
|
68
69
|
if (event.instructions)
|
|
69
70
|
console.log(event.instructions);
|
|
70
71
|
break;
|
package/dist/models.js
CHANGED
|
@@ -496,7 +496,14 @@ class ModelsImpl {
|
|
|
496
496
|
if (options?.transformHeaders)
|
|
497
497
|
headers = await options.transformHeaders(headers ?? {});
|
|
498
498
|
const env = resolution.env || options?.env ? { ...(resolution.env ?? {}), ...(options?.env ?? {}) } : undefined;
|
|
499
|
-
const requestModel = auth.baseUrl
|
|
499
|
+
const requestModel = auth.baseUrl || ((auth.api || auth.compat) && isModelType(model, "chat"))
|
|
500
|
+
? {
|
|
501
|
+
...model,
|
|
502
|
+
...(auth.baseUrl ? { baseUrl: auth.baseUrl } : {}),
|
|
503
|
+
...(auth.api && isModelType(model, "chat") ? { api: auth.api } : {}),
|
|
504
|
+
...(auth.compat && isModelType(model, "chat") ? { compat: { ...model.compat, ...auth.compat } } : {}),
|
|
505
|
+
}
|
|
506
|
+
: model;
|
|
500
507
|
const { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {};
|
|
501
508
|
const requestOptions = { ...providerOptions, apiKey, headers, env };
|
|
502
509
|
return { requestModel, requestOptions };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type Provider } from "../models.ts";
|
|
2
|
-
export declare function chatgptSubscriptionProvider(): Provider<"openai-codex-responses">;
|
|
2
|
+
export declare function chatgptSubscriptionProvider(): Provider<"openai-codex-responses" | "openai-responses">;
|
|
3
3
|
//# sourceMappingURL=chatgpt-subscription.d.ts.map
|
|
@@ -1,24 +1,73 @@
|
|
|
1
1
|
import { openAICodexResponsesApi } from "../api/openai-codex-responses.lazy.js";
|
|
2
|
+
import { openAIResponsesApi } from "../api/openai-responses.lazy.js";
|
|
2
3
|
import { lazyOAuth } from "../auth/helpers.js";
|
|
3
|
-
import { loadChatGptSubscriptionOAuth } from "../auth/oauth/load.js";
|
|
4
|
+
import { loadChatGptSubscriptionOAuth, loadOpenAIChatGPTOAuth } from "../auth/oauth/load.js";
|
|
4
5
|
import { createProvider } from "../models.js";
|
|
5
6
|
import { extractChatGptSubscriptionIdentity } from "../utils/chatgpt-subscription-auth.js";
|
|
6
7
|
import { CHATGPT_SUBSCRIPTION_MODELS } from "./chatgpt-subscription.models.js";
|
|
7
8
|
export function chatgptSubscriptionProvider() {
|
|
9
|
+
const legacy = lazyOAuth({
|
|
10
|
+
name: "ChatGPT Subscription (Plus/Pro)",
|
|
11
|
+
isSubscription: true,
|
|
12
|
+
accountIdentity: (credential) => extractChatGptSubscriptionIdentity(credential.access),
|
|
13
|
+
load: loadChatGptSubscriptionOAuth,
|
|
14
|
+
});
|
|
15
|
+
const siwc = lazyOAuth({
|
|
16
|
+
name: "ChatGPT Subscription",
|
|
17
|
+
isSubscription: true,
|
|
18
|
+
load: loadOpenAIChatGPTOAuth,
|
|
19
|
+
});
|
|
20
|
+
const responses = openAIResponsesApi();
|
|
21
|
+
const siwcModel = (model) => ({
|
|
22
|
+
...model,
|
|
23
|
+
api: "openai-responses",
|
|
24
|
+
id: model.upstreamModelId ?? model.id,
|
|
25
|
+
compat: { ...model.compat, siwc: true, webSearchToolType: "web_search" },
|
|
26
|
+
});
|
|
8
27
|
return createProvider({
|
|
9
28
|
id: "chatgpt-subscription",
|
|
10
29
|
name: "ChatGPT Subscription",
|
|
11
30
|
baseUrl: "https://chatgpt.com/backend-api",
|
|
12
31
|
auth: {
|
|
13
|
-
oauth:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
oauth: {
|
|
33
|
+
...legacy,
|
|
34
|
+
loginLabel: "Continue with ChatGPT",
|
|
35
|
+
login: async (interaction, options) => {
|
|
36
|
+
const route = await interaction.prompt({
|
|
37
|
+
type: "select",
|
|
38
|
+
message: "Sign in to ChatGPT Subscription:",
|
|
39
|
+
options: [
|
|
40
|
+
{ id: "siwc", label: "Continue with ChatGPT" },
|
|
41
|
+
{ id: "legacy", label: "Legacy sign-in (existing users)" },
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
if (route === "legacy")
|
|
45
|
+
return legacy.login(interaction, options);
|
|
46
|
+
if (route !== "siwc")
|
|
47
|
+
throw new Error(`Unknown ChatGPT sign-in route: ${route}`);
|
|
48
|
+
return { ...(await siwc.login(interaction, options)), route: "siwc" };
|
|
49
|
+
},
|
|
50
|
+
refresh: async (credential, signal) => credential.route === "siwc"
|
|
51
|
+
? { ...credential, ...(await siwc.refresh(credential, signal)), route: "siwc" }
|
|
52
|
+
: legacy.refresh(credential, signal),
|
|
53
|
+
toAuth: async (credential) => credential.route === "siwc"
|
|
54
|
+
? {
|
|
55
|
+
...(await siwc.toAuth(credential)),
|
|
56
|
+
api: "openai-responses",
|
|
57
|
+
baseUrl: "https://api.openai.com/v1",
|
|
58
|
+
compat: { siwc: true, webSearchToolType: "web_search" },
|
|
59
|
+
}
|
|
60
|
+
: legacy.toAuth(credential),
|
|
61
|
+
},
|
|
19
62
|
},
|
|
20
63
|
models: Object.values(CHATGPT_SUBSCRIPTION_MODELS),
|
|
21
|
-
api:
|
|
64
|
+
api: {
|
|
65
|
+
"openai-codex-responses": openAICodexResponsesApi(),
|
|
66
|
+
"openai-responses": {
|
|
67
|
+
stream: (model, context, options) => responses.stream(siwcModel(model), context, options),
|
|
68
|
+
streamSimple: (model, context, options) => responses.streamSimple(siwcModel(model), context, options),
|
|
69
|
+
},
|
|
70
|
+
},
|
|
22
71
|
});
|
|
23
72
|
}
|
|
24
73
|
//# sourceMappingURL=chatgpt-subscription.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schemaVersion":6,"generatedAt":"2026-11-
|
|
1
|
+
{"schemaVersion":6,"generatedAt":"2026-11-05T15:53:47.603Z","structureHash":"10c238ccbbb6c7533c39e840770548c3d3eb1e510093c53c9feed0319e502344","files":{"alibaba-token-plan.json":"9f4d42cc765b2a875bcdcaa392bfdc1323c88968309baf9db9f611a26c595c73","amazon-bedrock.json":"a7e20838b095788cb9d5acbde49664b7f2868fad9b10fb4bbbd66635085bca2d","ant-ling.json":"628feab3ef6c7d80ce96f75999804e1d9f05fec3851e5302e30fff3b69db90f6","anthropic.json":"111384e9f5845e0247bd34edf2400ef7720fcbdac140b944cf8878192d8bd6ab","azure-openai-responses.json":"fd64c6a2a99fa87d768ed2f75f5c7813876df1dbe2f0d1776f7d9bd7ce2e61e4","bai.json":"7e6861aaf27d8af34e1771c6092602194fcec0a0046e6adfab9c3ee54d32b99f","baseten.json":"df8e6ea3c7bb4dfc08c234bbf42a0473cfb7985e0aee06ace4c77495547d98ab","cerebras.json":"2eb969b2956844f9a641d3de52c19f1791293c58f607282fb3b0ebfe85ff66f8","chatgpt-subscription.json":"98320f1d51709d26ca047b3d6e3191cfe2f192f1b27897cbb492f47b0e5a5030","cloudflare-ai-gateway.json":"ac281b8cc18eb84ba61f215eff3234d14732cd66239617fb59d6812b13d6473f","cloudflare-workers-ai.json":"1b9ad4360bde817f0ea358431020308f1052840e2278a57a93629f1790072d2e","deepseek.json":"10a296fb3e898f7715c80890c8af0af4f5fd58f22dbcd6612fdc5d762157ccdc","fireworks.json":"56c557eb97573028e871c211cb17e1d60665eb12d67a712615db4bb255bc9253","github-copilot.json":"474fa92eb88ef242208ca93709ebe6d7f21754917d0cad6210bd1edf2b99a87e","google-vertex.json":"8f986b4aca8c685b0f3481bd252bda21e4858bf9015ad37fc5bcc44b7f01d076","google.json":"d25613a7377e81d785d571be514d67b35436511ce6946247dc66f8674e2a5035","groq.json":"087df37206e9eed8b10f1e558e4c496289bef60074b7e8afba4f20fb102b4ec2","huggingface.json":"209cdcf205961ef2ff203486da614232a86a069ebe0e98266189a14a235fac8f","meta.json":"563f5ec07973f52ab8c3eb26ef91a36ad8a79e950b37174935666cdcb624bf35","minimax-cn.json":"70df757e95e9ea2275bf451956b58a746020835f6cbcbd1a644d7fad5b9941d3","minimax.json":"747038b05f4fc24e41405e8bc810f893d7d5121e214e35e6f812f775769a3806","mistral.json":"aafecc66686645b1baa8c90e81c02856115f09999ff507f9bee004d2e1c77a28","moonshotai-cn.json":"a953eace729ef96c91195d477c63c776a1c40aa36085b61236ca1be0fe5b9337","moonshotai.json":"0435f9dc4e532c0764b6d33d8dfa83ce5fccdbcab54224c5ae74ec2d965290f5","nvidia.json":"078fae404fc622ca6461f16a74791fedafe44976a6c3323b6ba779729823d4ff","openai.json":"d61200cdd22d931dfff8181a5ed8d636c89fb34637dcec80f07ec24f8c2ef5c6","opencode-go.json":"bff6f9062f046c04daf313ed7cf237cd211fe1650ed88eb374b320844ddd4a55","opencode.json":"ff443ac2d4230e4fb0694c827a08dcb63421ae46b8b708141c1609189af536f5","opengateway.json":"c39301d5db2d88aee71705143a6039ebfce2513ef4648979125def43ef409d49","openrouter.json":"7e0143b40e93ff0df86f2d27f02a60d5ff64f535c6fce0111ddcf31f60f3e547","qwen-token-plan-cn.json":"751b18bd443fceb16659ea33013fed90fbf3bbdb4e0ffd7607c93cee2b4cf40d","qwen-token-plan-individual.json":"35ffb0ba1a1ce3f68fc73262dd5e07fbcb5bf5911ad1e6e17bc0621e2894676a","qwen-token-plan.json":"e59b0a45e238578f80d0eea937a093b9cec7cb93751ae20a9e88b16c09eb5cdd","radius.json":"1e4868b8cef7b63d822584e7b8634111891fd6746983a758660ee8f44fad3400","together.json":"8b241bf22b25d8a4bf6d8effe45cebadd193a25a9f0ecc68039d395bf8c6e3bf","typesafe.json":"83409437dbf4c353ac413c0db4e7cf29902fc35e0e0197bdb4eeda2d7f3b07cd","venice.json":"ac2c830fd15de54d1b47e01d776f4032e897b4c13fc86fef44e915f5e03cb21b","vercel-ai-gateway.json":"eaad17194541263e2f0d7d7fbda22130bf848765fff943c7f2ea99e08ae231b3","xai.json":"cf3f475fe5a13625f858171900ba3456c4d95ebb0bac5060cc25e29bb31d3457","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":"2b6f85e04b5c568e320b1bde25b1c1614af9342e4c1ba0e1d5bb248aaf50cfe9","zai.json":"e9cc408e1756de8abc70148d63d89d11a63c65b7ef06ad0661cd1328e4209ba3"}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"openai-completions":{"chat:deepseek-ai/DeepSeek-V4-Flash-0731":{"id":"deepseek-ai/DeepSeek-V4-Flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0.13,"output":0.26,"cacheRead":0.028,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":384000,"type":"chat"},"chat:deepseek-ai/DeepSeek-V4-Pro-0813":{"id":"deepseek-ai/DeepSeek-V4-Pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.32,"output":3.96,"cacheRead":0.132,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash":{"id":"deepseek-ai/DeepSeek-V4.1-Flash","name":"DeepSeek V4.1 Flash","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":32768,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash-1017":{"id":"deepseek-ai/DeepSeek-V4.1-Flash-1017","name":"DeepSeek V4.1 Flash 1017","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash-1017-Fast":{"id":"deepseek-ai/DeepSeek-V4.1-Flash-1017-Fast","name":"DeepSeek V4.1 Flash 1017 Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.6,"output":2.4,"cacheRead":0.014,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash-Fast":{"id":"deepseek-ai/DeepSeek-V4.1-Flash-Fast","name":"DeepSeek V4.1 Flash Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.6,"output":2.4,"cacheRead":0.014,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":32768,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:moonshotai/Kimi-K3":{"id":"moonshotai/Kimi-K3","name":"Kimi K3","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B":{"id":"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B","name":"Nemotron Ultra","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null},"input":["text"],"cost":{"input":0.6,"output":2.4,"cacheRead":0.12,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":202800,"maxTokens":202800,"type":"chat"},"chat:openai/gpt-oss-120b":{"id":"openai/gpt-oss-120b","name":"OpenAI GPT 120B","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"input":["text"],"cost":{"input":0.1,"output":0.5,"cacheRead":0.1,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":128072,"maxTokens":128072,"type":"chat"},"chat:zai-org/GLM-5.2":{"id":"zai-org/GLM-5.2","name":"GLM 5.2","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.14,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"baseten","chatTemplateArgs":{"enable_thinking":{"$var":"thinking.enabled"}}},"contextWindow":1048576,"maxTokens":262144,"type":"chat"},"chat:zai-org/GLM-5.2-Fast":{"id":"zai-org/GLM-5.2-Fast","name":"GLM 5.2 Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":2.1,"output":6.6,"cacheRead":0.21,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"baseten","chatTemplateArgs":{"enable_thinking":{"$var":"thinking.enabled"}}},"contextWindow":1048576,"maxTokens":262144,"type":"chat"},"chat:zai-org/GLM-5.3":{"id":"zai-org/GLM-5.3","name":"GLM 5.3","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.14,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:zai-org/GLM-5.3-Fast":{"id":"zai-org/GLM-5.3-Fast","name":"GLM 5.3 Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":2.1,"output":6.6,"cacheRead":0.21,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:zai-org/GLM-5.3-Flash":{"id":"zai-org/GLM-5.3-Flash","name":"GLM 5.3 Flash","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
|
|
1
|
+
{"openai-completions":{"chat:deepseek-ai/DeepSeek-V4-Flash-0731":{"id":"deepseek-ai/DeepSeek-V4-Flash-0731","name":"DeepSeek V4 Flash 0731","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":0.13,"output":0.26,"cacheRead":0.028,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":384000,"type":"chat"},"chat:deepseek-ai/DeepSeek-V4-Pro-0813":{"id":"deepseek-ai/DeepSeek-V4-Pro-0813","name":"DeepSeek V4 Pro 0813","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.32,"output":3.96,"cacheRead":0.132,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash":{"id":"deepseek-ai/DeepSeek-V4.1-Flash","name":"DeepSeek V4.1 Flash","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":32768,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash-1017":{"id":"deepseek-ai/DeepSeek-V4.1-Flash-1017","name":"DeepSeek V4.1 Flash 1017","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.007,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash-1017-Fast":{"id":"deepseek-ai/DeepSeek-V4.1-Flash-1017-Fast","name":"DeepSeek V4.1 Flash 1017 Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.6,"output":2.4,"cacheRead":0.014,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:deepseek-ai/DeepSeek-V4.1-Flash-Fast":{"id":"deepseek-ai/DeepSeek-V4.1-Flash-Fast","name":"DeepSeek V4.1 Flash Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.6,"output":2.4,"cacheRead":0.014,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":32768,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:moonshotai/Kimi-K3":{"id":"moonshotai/Kimi-K3","name":"Kimi K3","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:moonshotai/Kimi-K3.1-Pro":{"id":"moonshotai/Kimi-K3.1-Pro","name":"Kimi K3.1 Pro","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false},"contextWindow":1000000,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B":{"id":"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B","name":"Nemotron Ultra","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null},"input":["text"],"cost":{"input":0.6,"output":2.4,"cacheRead":0.12,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":202800,"maxTokens":202800,"type":"chat"},"chat:openai/gpt-oss-120b":{"id":"openai/gpt-oss-120b","name":"OpenAI GPT 120B","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"input":["text"],"cost":{"input":0.1,"output":0.5,"cacheRead":0.1,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":128072,"maxTokens":128072,"type":"chat"},"chat:zai-org/GLM-5.2":{"id":"zai-org/GLM-5.2","name":"GLM 5.2","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.14,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"baseten","chatTemplateArgs":{"enable_thinking":{"$var":"thinking.enabled"}}},"contextWindow":1048576,"maxTokens":262144,"type":"chat"},"chat:zai-org/GLM-5.2-Fast":{"id":"zai-org/GLM-5.2-Fast","name":"GLM 5.2 Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text"],"cost":{"input":2.1,"output":6.6,"cacheRead":0.21,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"baseten","chatTemplateArgs":{"enable_thinking":{"$var":"thinking.enabled"}}},"contextWindow":1048576,"maxTokens":262144,"type":"chat"},"chat:zai-org/GLM-5.3":{"id":"zai-org/GLM-5.3","name":"GLM 5.3","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.14,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:zai-org/GLM-5.3-Fast":{"id":"zai-org/GLM-5.3-Fast","name":"GLM 5.3 Fast","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":2.1,"output":6.6,"cacheRead":0.21,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:zai-org/GLM-5.3-Flash":{"id":"zai-org/GLM-5.3-Flash","name":"GLM 5.3 Flash","api":"openai-completions","provider":"baseten","baseUrl":"https://inference.baseten.co/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStrictMode":true,"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"supportsUsageInStreaming":true,"maxTokensField":"max_tokens","sendSessionAffinityHeaders":true,"supportsLongCacheRetention":false,"thinkingFormat":"openai"},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
|