@code-yeongyu/senpi-ai 2026.11.3-2 → 2026.11.3-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/anthropic-messages.js +5 -5
- package/dist/api/lazy.js +3 -0
- package/dist/api/simple-options.js +1 -0
- package/dist/auth/oauth/openai-chatgpt.d.ts +26 -2
- package/dist/auth/oauth/openai-chatgpt.js +37 -18
- package/dist/auth/oauth-refresh.d.ts +3 -1
- package/dist/auth/oauth-refresh.js +49 -11
- package/dist/auth/types.d.ts +12 -3
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/radius.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 +6 -0
- package/dist/utils/provider-diagnostic-vocabulary.d.ts +4 -0
- package/dist/utils/provider-diagnostic-vocabulary.js +14 -0
- package/dist/utils/provider-failure-description.d.ts +2 -0
- package/dist/utils/provider-failure-description.js +1 -1
- package/package.json +2 -2
|
@@ -952,11 +952,11 @@ export const stream = (model, context, options) => {
|
|
|
952
952
|
});
|
|
953
953
|
}
|
|
954
954
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention ?? model.cacheRetention, options?.env, "short");
|
|
955
|
-
const
|
|
955
|
+
const affinityKey = cacheRetention === "none" ? undefined : (options?.sessionAffinityKey ?? options?.sessionId);
|
|
956
956
|
openClient = () => {
|
|
957
957
|
client = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, normalizedContext), options?.refusalFallbacks !== undefined && configuredBetaHeader(model, options) !== null, optionsHeaders, getAnthropicCompat(model).supportsGzipRequestBody
|
|
958
958
|
? withGzipRequestBodies(options?.fetch)
|
|
959
|
-
: options?.fetch, copilotDynamicHeaders,
|
|
959
|
+
: options?.fetch, copilotDynamicHeaders, affinityKey, options?.env, federation);
|
|
960
960
|
};
|
|
961
961
|
openClient();
|
|
962
962
|
}
|
|
@@ -1602,7 +1602,7 @@ export const streamSimple = (model, context, options) => {
|
|
|
1602
1602
|
thinkingBudgetTokens: Math.min(adjusted.thinkingBudget, Math.max(0, maxTokens - 1024)),
|
|
1603
1603
|
});
|
|
1604
1604
|
};
|
|
1605
|
-
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, useServerSideFallbackBeta, optionsHeaders, fetch, dynamicHeaders,
|
|
1605
|
+
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, useServerSideFallbackBeta, optionsHeaders, fetch, dynamicHeaders, affinityKey, env, federation) {
|
|
1606
1606
|
// Adaptive thinking models have interleaved thinking built in, so skip the beta header.
|
|
1607
1607
|
const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model);
|
|
1608
1608
|
const betaFeatures = [];
|
|
@@ -1652,11 +1652,11 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
1652
1652
|
// API key, header-owned auth, or workload identity federation.
|
|
1653
1653
|
const affinityCompat = getAnthropicCompat(model);
|
|
1654
1654
|
const sessionAffinityHeaders = {};
|
|
1655
|
-
if (
|
|
1655
|
+
if (affinityKey && affinityCompat.sendSessionAffinityHeaders) {
|
|
1656
1656
|
// OpenRouter routes prompt-cache affinity through its own header name and
|
|
1657
1657
|
// rejects x-session-affinity (earendil-works/pi#9102).
|
|
1658
1658
|
const header = affinityCompat.sessionAffinityFormat === "openrouter" ? "x-session-id" : "x-session-affinity";
|
|
1659
|
-
sessionAffinityHeaders[header] =
|
|
1659
|
+
sessionAffinityHeaders[header] = affinityKey;
|
|
1660
1660
|
}
|
|
1661
1661
|
const defaultHeaders = sanitizeAdaptiveThinkingHeaders(model, mergeClientHeaders(model, {
|
|
1662
1662
|
accept: "application/json",
|
package/dist/api/lazy.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { readProviderDiagnostic } from "../provider-diagnostic.js";
|
|
1
2
|
import { assistantEvents, pushAssistantProgress, setAssistantReader } from "../utils/assistant-capture.js";
|
|
2
3
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
3
4
|
import { isOAuthRefreshUnavailableError } from "../utils/oauth-refresh-error.js";
|
|
4
5
|
import { describeReplacedInstall } from "../utils/provider-failure-description.js";
|
|
5
6
|
import { OAUTH_REFRESH_UNAVAILABLE_DIAGNOSTIC } from "../utils/retry.js";
|
|
6
7
|
function createSetupErrorMessage(model, error) {
|
|
8
|
+
const providerDiagnostic = readProviderDiagnostic(error);
|
|
7
9
|
return {
|
|
8
10
|
role: "assistant",
|
|
9
11
|
content: [],
|
|
@@ -20,6 +22,7 @@ function createSetupErrorMessage(model, error) {
|
|
|
20
22
|
},
|
|
21
23
|
stopReason: "error",
|
|
22
24
|
errorMessage: describeReplacedInstall(error) ?? (error instanceof Error ? error.message : String(error)),
|
|
25
|
+
...(providerDiagnostic === undefined ? {} : { providerDiagnostic }),
|
|
23
26
|
...(isOAuthRefreshUnavailableError(error)
|
|
24
27
|
? {
|
|
25
28
|
diagnostics: [
|
|
@@ -118,6 +118,7 @@ export function buildBaseOptions(model, context, options, apiKey) {
|
|
|
118
118
|
transport: options?.transport,
|
|
119
119
|
cacheRetention: options?.cacheRetention ?? model.cacheRetention,
|
|
120
120
|
sessionId: options?.sessionId,
|
|
121
|
+
sessionAffinityKey: options?.sessionAffinityKey,
|
|
121
122
|
headers: options?.headers,
|
|
122
123
|
extraBody: options?.extraBody,
|
|
123
124
|
onPayload: options?.onPayload,
|
|
@@ -4,6 +4,30 @@
|
|
|
4
4
|
* This public-client flow uses no client secret and sends the resulting user
|
|
5
5
|
* access token directly to api.openai.com.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
8
|
-
|
|
7
|
+
import type { LoginOptions, LogoutOptions, OAuthCredential, OAuthRevocationResult, ProviderAuthInteraction } from "../types.ts";
|
|
8
|
+
declare function refreshAccessToken(credential: OAuthCredential, signal: AbortSignal): Promise<OAuthCredential>;
|
|
9
|
+
declare function revokeSession(credential: OAuthCredential, options?: LogoutOptions): Promise<OAuthRevocationResult>;
|
|
10
|
+
declare function loginOpenAIChatGPT(interaction: ProviderAuthInteraction, options?: LoginOptions & {
|
|
11
|
+
readonly preferredCallbackPort?: number;
|
|
12
|
+
}): Promise<OAuthCredential>;
|
|
13
|
+
export declare const openaiChatGPTOAuth: {
|
|
14
|
+
name: string;
|
|
15
|
+
isSubscription: true;
|
|
16
|
+
loginLabel: string;
|
|
17
|
+
login: typeof loginOpenAIChatGPT;
|
|
18
|
+
refresh: typeof refreshAccessToken;
|
|
19
|
+
revoke: typeof revokeSession;
|
|
20
|
+
check({ credential }: {
|
|
21
|
+
ctx: import("../types.ts").AuthContext;
|
|
22
|
+
credential?: OAuthCredential;
|
|
23
|
+
signal: AbortSignal;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
type: "oauth";
|
|
26
|
+
source: string;
|
|
27
|
+
} | undefined>;
|
|
28
|
+
toAuth(credential: OAuthCredential): Promise<{
|
|
29
|
+
apiKey: string;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
export {};
|
|
9
33
|
//# sourceMappingURL=openai-chatgpt.d.ts.map
|
|
@@ -8,7 +8,6 @@ import { randomBytes } from "node:crypto";
|
|
|
8
8
|
import { createServer } from "node:http";
|
|
9
9
|
import { configuredOAuthBrandName, oauthErrorHtml, oauthSuccessHtml } from "../../utils/oauth-page.js";
|
|
10
10
|
import { OAuthTokenEndpointError } from "../../utils/oauth-refresh-error.js";
|
|
11
|
-
import { getProviderEnvValue } from "../../utils/provider-env.js";
|
|
12
11
|
import { getWireIdentity } from "../../wire-identity.js";
|
|
13
12
|
import { generatePKCE } from "./pkce.js";
|
|
14
13
|
// every login registers a new client with this ID; OpenAI returns the issued client ID in the callback
|
|
@@ -18,7 +17,7 @@ const AUTHORIZE_URL = "https://auth.openai.com/api/accounts/authorize";
|
|
|
18
17
|
const TOKEN_URL = "https://auth.openai.com/api/accounts/oauth/token";
|
|
19
18
|
const DISCOVERY_URL = "https://auth.openai.com/.well-known/openid-configuration";
|
|
20
19
|
const RESOURCE = "https://api.openai.com/v1";
|
|
21
|
-
const CALLBACK_HOST =
|
|
20
|
+
const CALLBACK_HOST = "127.0.0.1";
|
|
22
21
|
const CALLBACK_PORT = 1455;
|
|
23
22
|
const CALLBACK_PATH = "/auth/callback";
|
|
24
23
|
const REDIRECT_URI = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
@@ -43,7 +42,7 @@ function authorizationResultFromCallback(url, expectedState) {
|
|
|
43
42
|
throw new Error("OpenAI OAuth registration callback did not contain an issued client ID");
|
|
44
43
|
return { code, clientId };
|
|
45
44
|
}
|
|
46
|
-
function authorizationResultFromManualInput(input, expectedState) {
|
|
45
|
+
function authorizationResultFromManualInput(input, expectedState, redirectUri) {
|
|
47
46
|
let url;
|
|
48
47
|
try {
|
|
49
48
|
url = new URL(input.trim());
|
|
@@ -51,9 +50,9 @@ function authorizationResultFromManualInput(input, expectedState) {
|
|
|
51
50
|
catch {
|
|
52
51
|
throw new Error("Paste the full callback URL from the browser");
|
|
53
52
|
}
|
|
54
|
-
const expected = new URL(
|
|
53
|
+
const expected = new URL(redirectUri);
|
|
55
54
|
if (url.origin !== expected.origin || url.pathname !== expected.pathname) {
|
|
56
|
-
throw new Error(`The pasted callback URL must start with ${
|
|
55
|
+
throw new Error(`The pasted callback URL must start with ${redirectUri}`);
|
|
57
56
|
}
|
|
58
57
|
const error = url.searchParams.get("error");
|
|
59
58
|
if (error)
|
|
@@ -64,8 +63,9 @@ function sendHtml(response, status, body) {
|
|
|
64
63
|
response.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
|
|
65
64
|
response.end(body);
|
|
66
65
|
}
|
|
67
|
-
function startCallbackServer(expectedState) {
|
|
66
|
+
function startCallbackServer(expectedState, preferredPort) {
|
|
68
67
|
return new Promise((resolve, reject) => {
|
|
68
|
+
let redirectUri = REDIRECT_URI;
|
|
69
69
|
let resolveResult;
|
|
70
70
|
let rejectResult;
|
|
71
71
|
const result = new Promise((resolveAuthorization, rejectAuthorization) => {
|
|
@@ -74,7 +74,7 @@ function startCallbackServer(expectedState) {
|
|
|
74
74
|
});
|
|
75
75
|
const server = createServer((request, response) => {
|
|
76
76
|
try {
|
|
77
|
-
const url = new URL(request.url || "",
|
|
77
|
+
const url = new URL(request.url || "", redirectUri);
|
|
78
78
|
if (url.pathname !== CALLBACK_PATH) {
|
|
79
79
|
sendHtml(response, 404, oauthErrorHtml("Callback route not found."));
|
|
80
80
|
return;
|
|
@@ -101,12 +101,30 @@ function startCallbackServer(expectedState) {
|
|
|
101
101
|
sendHtml(response, 500, oauthErrorHtml("Internal error while processing the callback."));
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const onListening = () => {
|
|
105
|
+
server.removeListener("error", onBindError);
|
|
106
106
|
server.removeListener("error", reject);
|
|
107
|
+
const address = server.address();
|
|
108
|
+
if (!address || typeof address === "string") {
|
|
109
|
+
server.close();
|
|
110
|
+
reject(new Error("OpenAI OAuth callback server did not bind to TCP"));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
redirectUri = `http://${CALLBACK_HOST}:${address.port}${CALLBACK_PATH}`;
|
|
107
114
|
server.on("error", rejectResult);
|
|
108
|
-
resolve({ server, result });
|
|
109
|
-
}
|
|
115
|
+
resolve({ server, result, redirectUri });
|
|
116
|
+
};
|
|
117
|
+
const onBindError = (error) => {
|
|
118
|
+
server.removeListener("listening", onListening);
|
|
119
|
+
if (error.code !== "EADDRINUSE") {
|
|
120
|
+
reject(error);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
server.once("error", reject);
|
|
124
|
+
server.listen(0, CALLBACK_HOST, onListening);
|
|
125
|
+
};
|
|
126
|
+
server.once("error", onBindError);
|
|
127
|
+
server.listen(preferredPort, CALLBACK_HOST, onListening);
|
|
110
128
|
});
|
|
111
129
|
}
|
|
112
130
|
async function requestToken(body, signal) {
|
|
@@ -155,13 +173,13 @@ function credentialFromTokenResponse(token, clientId) {
|
|
|
155
173
|
scopes,
|
|
156
174
|
};
|
|
157
175
|
}
|
|
158
|
-
async function exchangeAuthorizationCode(code, verifier, clientId, signal) {
|
|
176
|
+
async function exchangeAuthorizationCode(code, verifier, clientId, redirectUri, signal) {
|
|
159
177
|
const token = await requestToken(new URLSearchParams({
|
|
160
178
|
grant_type: "authorization_code",
|
|
161
179
|
client_id: clientId,
|
|
162
180
|
code,
|
|
163
181
|
code_verifier: verifier,
|
|
164
|
-
redirect_uri:
|
|
182
|
+
redirect_uri: redirectUri,
|
|
165
183
|
resource: RESOURCE,
|
|
166
184
|
}), signal);
|
|
167
185
|
// Pi does not use the ID token to identify the user or read profile data.
|
|
@@ -267,7 +285,7 @@ async function loginOpenAIChatGPT(interaction, options) {
|
|
|
267
285
|
const nonce = randomValue();
|
|
268
286
|
let callback;
|
|
269
287
|
try {
|
|
270
|
-
callback = await startCallbackServer(state);
|
|
288
|
+
callback = await startCallbackServer(state, options?.preferredCallbackPort ?? CALLBACK_PORT);
|
|
271
289
|
}
|
|
272
290
|
catch (error) {
|
|
273
291
|
interaction.notify({
|
|
@@ -275,6 +293,7 @@ async function loginOpenAIChatGPT(interaction, options) {
|
|
|
275
293
|
message: `Could not listen on ${REDIRECT_URI}; paste the final redirect URL to continue. ${error instanceof Error ? error.message : String(error)}`,
|
|
276
294
|
});
|
|
277
295
|
}
|
|
296
|
+
const redirectUri = callback?.redirectUri ?? REDIRECT_URI;
|
|
278
297
|
const authorizationUrl = new URL(AUTHORIZE_URL);
|
|
279
298
|
authorizationUrl.search = new URLSearchParams({
|
|
280
299
|
client_id: DYNAMIC_CLIENT_ID,
|
|
@@ -282,7 +301,7 @@ async function loginOpenAIChatGPT(interaction, options) {
|
|
|
282
301
|
agent_name_hint: options?.appName ?? configuredOAuthBrandName() ?? getWireIdentity(),
|
|
283
302
|
ext_agent_host_id: hostId,
|
|
284
303
|
response_type: "code",
|
|
285
|
-
redirect_uri:
|
|
304
|
+
redirect_uri: redirectUri,
|
|
286
305
|
resource: RESOURCE,
|
|
287
306
|
scope: SCOPE,
|
|
288
307
|
state,
|
|
@@ -300,14 +319,14 @@ async function loginOpenAIChatGPT(interaction, options) {
|
|
|
300
319
|
.prompt({
|
|
301
320
|
type: "manual_code",
|
|
302
321
|
message: "Complete login in your browser, or paste the final redirect URL here:",
|
|
303
|
-
placeholder:
|
|
322
|
+
placeholder: redirectUri,
|
|
304
323
|
signal: AbortSignal.any([manualAbort.signal, interaction.signal]),
|
|
305
324
|
})
|
|
306
|
-
.then((input) => authorizationResultFromManualInput(input, state));
|
|
325
|
+
.then((input) => authorizationResultFromManualInput(input, state, redirectUri));
|
|
307
326
|
try {
|
|
308
327
|
const result = await (callback ? Promise.race([callback.result, manualCode]) : manualCode);
|
|
309
328
|
interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
|
|
310
|
-
return await exchangeAuthorizationCode(result.code, verifier, result.clientId, interaction.signal);
|
|
329
|
+
return await exchangeAuthorizationCode(result.code, verifier, result.clientId, redirectUri, interaction.signal);
|
|
311
330
|
}
|
|
312
331
|
catch (error) {
|
|
313
332
|
if (interaction.signal.aborted)
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
* re-acquires the lock and compare-and-swaps on the slot's refresh token, so a
|
|
10
10
|
* slot rotated meanwhile by another process is adopted instead of overwritten.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* Persistent stores inject a session-scoped lock around read/exchange/write so
|
|
13
|
+
* two processes cannot consume the same rotating token. Within a process,
|
|
14
|
+
* concurrent refreshes of the same slot join one exchange.
|
|
13
15
|
* Waiters that own the exchange (per-request resolution) cancel it once none of
|
|
14
16
|
* them is waiting; the catalog-refresh lane joins without owning it, so a
|
|
15
17
|
* superseded catalog refresh stops waiting but never aborts the exchange.
|
|
@@ -9,14 +9,16 @@
|
|
|
9
9
|
* re-acquires the lock and compare-and-swaps on the slot's refresh token, so a
|
|
10
10
|
* slot rotated meanwhile by another process is adopted instead of overwritten.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* Persistent stores inject a session-scoped lock around read/exchange/write so
|
|
13
|
+
* two processes cannot consume the same rotating token. Within a process,
|
|
14
|
+
* concurrent refreshes of the same slot join one exchange.
|
|
13
15
|
* Waiters that own the exchange (per-request resolution) cancel it once none of
|
|
14
16
|
* them is waiting; the catalog-refresh lane joins without owning it, so a
|
|
15
17
|
* superseded catalog refresh stops waiting but never aborts the exchange.
|
|
16
18
|
*/
|
|
17
19
|
import { raceWithAbortSignal } from "../utils/abort.js";
|
|
18
20
|
import { oauthRefreshFailureCause } from "../utils/oauth-refresh-error.js";
|
|
19
|
-
import { mergeRefreshed, mergeRefreshedSlot, projectSlot } from "./pool/slots.js";
|
|
21
|
+
import { DEFAULT_SLOT_NAME, listSlots, mergeRefreshed, mergeRefreshedSlot, projectSlot } from "./pool/slots.js";
|
|
20
22
|
export const DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15_000;
|
|
21
23
|
/** The provider rejected or timed out the token exchange. */
|
|
22
24
|
export class OAuthRefreshExchangeError extends Error {
|
|
@@ -78,7 +80,7 @@ export function refreshOAuthCredential(request) {
|
|
|
78
80
|
if (!inflight) {
|
|
79
81
|
const controller = new AbortController();
|
|
80
82
|
const created = { controller, waiters: 0, owned: false, promise: Promise.resolve(undefined) };
|
|
81
|
-
created.promise =
|
|
83
|
+
created.promise = serializeExchange(request, controller.signal).finally(() => {
|
|
82
84
|
if (registry.get(key) === created)
|
|
83
85
|
registry.delete(key);
|
|
84
86
|
});
|
|
@@ -105,7 +107,50 @@ function join(inflight, signal, owning) {
|
|
|
105
107
|
else
|
|
106
108
|
signal.addEventListener("abort", leave, { once: true });
|
|
107
109
|
}
|
|
108
|
-
|
|
110
|
+
function refreshSlotName(credential, slotName) {
|
|
111
|
+
// Flat/catalog resolution and named resolution of its mirrored slot must
|
|
112
|
+
// acquire the same lock. Token equality locates the stable ID; it is not the key.
|
|
113
|
+
return (slotName ??
|
|
114
|
+
listSlots(credential).find((slot) => slot.refresh === credential.refresh || slot.access === credential.access)
|
|
115
|
+
?.name ??
|
|
116
|
+
DEFAULT_SLOT_NAME);
|
|
117
|
+
}
|
|
118
|
+
async function serializeExchange(request, signal) {
|
|
119
|
+
const { credentials, providerId, slotName } = request;
|
|
120
|
+
let identity = refreshSlotName(request.stale, slotName);
|
|
121
|
+
let retry;
|
|
122
|
+
do {
|
|
123
|
+
retry = false;
|
|
124
|
+
const run = async (lockSignal) => {
|
|
125
|
+
const latest = await credentials.read(providerId, { signal: lockSignal });
|
|
126
|
+
if (credentials.withRefreshLock && latest?.type === "oauth") {
|
|
127
|
+
const currentIdentity = refreshSlotName(latest, slotName);
|
|
128
|
+
if (currentIdentity !== identity) {
|
|
129
|
+
// A login/removal changed the flat projection while we waited.
|
|
130
|
+
// Release before acquiring that account's lock; never nest locks.
|
|
131
|
+
identity = currentIdentity;
|
|
132
|
+
retry = true;
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return exchangeAndStore(request, lockSignal, latest);
|
|
137
|
+
};
|
|
138
|
+
try {
|
|
139
|
+
const result = credentials.withRefreshLock
|
|
140
|
+
? await credentials.withRefreshLock(providerId, identity, run, { signal })
|
|
141
|
+
: await run(signal);
|
|
142
|
+
if (!retry)
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (error instanceof OAuthRefreshExchangeError || error instanceof OAuthRefreshStoreError)
|
|
147
|
+
throw error;
|
|
148
|
+
throw new OAuthRefreshStoreError(error);
|
|
149
|
+
}
|
|
150
|
+
} while (retry);
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
async function exchangeAndStore(request, signal, latest) {
|
|
109
154
|
const { credentials, providerId, oauth, slotName } = request;
|
|
110
155
|
const view = (credential) => {
|
|
111
156
|
if (credential?.type !== "oauth")
|
|
@@ -115,13 +160,6 @@ async function exchangeAndStore(request, signal) {
|
|
|
115
160
|
return undefined;
|
|
116
161
|
return projected;
|
|
117
162
|
};
|
|
118
|
-
let latest;
|
|
119
|
-
try {
|
|
120
|
-
latest = await credentials.read(providerId, { signal });
|
|
121
|
-
}
|
|
122
|
-
catch (error) {
|
|
123
|
-
throw new OAuthRefreshStoreError(error);
|
|
124
|
-
}
|
|
125
163
|
const current = view(latest);
|
|
126
164
|
if (!current)
|
|
127
165
|
return undefined; // logged out or slot removed meanwhile
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -56,8 +56,8 @@ export interface LogoutOptions extends AuthOperationOptions {
|
|
|
56
56
|
* App-owned credential storage, keyed by `Provider.id`, one entry per
|
|
57
57
|
* provider; an entry may pool sibling slots under `accounts` while its flat
|
|
58
58
|
* fields remain a valid credential. `modify` is the only write path, so every mutation is a
|
|
59
|
-
* serialized read-modify-write
|
|
60
|
-
*
|
|
59
|
+
* serialized read-modify-write. Persistent stores inject `withRefreshLock` to
|
|
60
|
+
* serialize a session's exchange without holding the global write lock. The
|
|
61
61
|
* app persists a credential after login via
|
|
62
62
|
* `modify(provider.id, async () => credential)`. Login/logout orchestration
|
|
63
63
|
* is app-owned.
|
|
@@ -81,6 +81,14 @@ export interface CredentialStore {
|
|
|
81
81
|
* resolves only the selected slot, never the flat key or a sibling.
|
|
82
82
|
*/
|
|
83
83
|
readSlot?(providerId: string, slotName: string, options?: AuthOperationOptions): Promise<Credential | undefined>;
|
|
84
|
+
/**
|
|
85
|
+
* Optional session-scoped exclusion around read-latest -> exchange -> persist.
|
|
86
|
+
* Persistent stores serialize across processes, separately from `modify`, so
|
|
87
|
+
* unrelated accounts stay concurrent. The key is the provider and stable slot
|
|
88
|
+
* name, never token material. The callback's signal also aborts on lock loss;
|
|
89
|
+
* the lock stays held until the callback settles, including its final write.
|
|
90
|
+
*/
|
|
91
|
+
withRefreshLock?<T>(providerId: string, slotName: string, fn: (signal: AbortSignal) => Promise<T>, options?: AuthOperationOptions): Promise<T>;
|
|
84
92
|
/**
|
|
85
93
|
* List stored credential metadata without resolving or exposing secrets.
|
|
86
94
|
* Implementations must not execute configured API-key commands while listing.
|
|
@@ -279,7 +287,8 @@ export interface OAuthAuth {
|
|
|
279
287
|
accountIdentity?(credential: Pick<OAuthCredential, "access">): string | undefined;
|
|
280
288
|
/**
|
|
281
289
|
* Exchange the refresh token. Network call; throws on failure
|
|
282
|
-
* (invalid_grant etc.). `Models`
|
|
290
|
+
* (invalid_grant etc.). `Models` uses the injected session refresh lock,
|
|
291
|
+
* never the store's global write lock.
|
|
283
292
|
*/
|
|
284
293
|
refresh(credential: OAuthCredential, signal: AbortSignal): Promise<OAuthCredential>;
|
|
285
294
|
/** End the renewable session before the caller clears local tokens. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schemaVersion":6,"generatedAt":"2026-11-
|
|
1
|
+
{"schemaVersion":6,"generatedAt":"2026-11-03T19:25:26.151Z","structureHash":"f02e0f2116db88980085dffcee84b272042fef2eaff3e6648bf05b485f18502d","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":"5bd3c98c61769388b3724368ef964d16b7a58e41a6edcf4ebceb9d4ac0a21d3b","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":"0e45bcd4d5a897f6f6785c0e257a9fb03691cef3ff87d9254da5daa5075468da","openai.json":"d61200cdd22d931dfff8181a5ed8d636c89fb34637dcec80f07ec24f8c2ef5c6","opencode-go.json":"de809e50975183fc8da3afb29a74bcf9164b6893271484588166a38b9930513f","opencode.json":"52786b917e5207c7b720e3c466b6c517e0cc57c58632c7f1ebf5e68b8fefeece","opengateway.json":"c39301d5db2d88aee71705143a6039ebfce2513ef4648979125def43ef409d49","openrouter.json":"455d8785b312d22cc0e789a6ecce18315bf30399b102b17b8297a38a60d716c8","qwen-token-plan-cn.json":"751b18bd443fceb16659ea33013fed90fbf3bbdb4e0ffd7607c93cee2b4cf40d","qwen-token-plan-individual.json":"35ffb0ba1a1ce3f68fc73262dd5e07fbcb5bf5911ad1e6e17bc0621e2894676a","qwen-token-plan.json":"e59b0a45e238578f80d0eea937a093b9cec7cb93751ae20a9e88b16c09eb5cdd","radius.json":"1e4868b8cef7b63d822584e7b8634111891fd6746983a758660ee8f44fad3400","together.json":"a68b8386a2f28f9e1570d296223fdbdc0ebcca8a322ade5b999212c0e60b772c","typesafe.json":"83409437dbf4c353ac413c0db4e7cf29902fc35e0e0197bdb4eeda2d7f3b07cd","venice.json":"cf6b67c0e15d62a126317e92897634c394f7aeefb5f6c5f99f7c885dbe963aab","vercel-ai-gateway.json":"1b6e25a28fa6b6d229c2c340edb5a850a6f944fa8db272efec7997b6b0fe6dc9","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
|
-
{"anthropic-messages":{"chat:claude-haiku-5-5":{"id":"claude-haiku-5-5","name":"Claude Haiku 5.5","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.5,"cacheRead":0.01,"cacheWrite":0.125,"tiers":[{"inputTokensAbove":100000,"input":0.5,"output":2.5,"cacheRead":0.05,"cacheWrite":0.625}]},"contextWindow":100000,"maxTokens":32000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"supportsDisabledThinking":false,"forceAdaptiveThinking":true,"supportsTemperature":false},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.4,"output":1.6,"cacheRead":0.04,"cacheWrite":0.5},"contextWindow":1000000,"maxTokens":65536,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.47,"cacheRead":0.016,"cacheWrite":0.2},"contextWindow":1000000,"maxTokens":131072,"compat":{"allowEmptySignature":true},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.25,"cacheWrite":2.5},"contextWindow":1000000,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}},"google-generative-ai":{"chat:gemini-4-argon":{"id":"gemini-4-argon","name":"Gemini 4 Argon","api":"google-generative-ai","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null},"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.1,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:gemini-4-argon-contributor":{"id":"gemini-4-argon-contributor","name":"Gemini 4 Argon Contributor","api":"google-generative-ai","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null},"input":["text","image"],"cost":{"input":4,"output":20,"cacheRead":0.2,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"deprecated":true,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}},"openai-completions":{"chat:beam-free":{"id":"beam-free","name":"Beam Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"type":"chat"},"chat:deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro (New)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.66,"output":1.98,"cacheRead":0.022,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"},"type":"chat"},"chat:deepseek-v4.1-flash":{"id":"deepseek-v4.1-flash","name":"DeepSeek V4.1 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/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.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"type":"chat"},"chat:glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"type":"chat"},"chat:glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:hy3":{"id":"hy3","name":"Hy3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.58,"cacheRead":0.035,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":256000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null},"type":"chat"},"chat:hy4-preview":{"id":"hy4-preview","name":"Hy4 preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.834,"output":2.501,"cacheRead":0.042,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1024000,"maxTokens":64000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null},"type":"chat"},"chat:iceman-contributor-free":{"id":"iceman-contributor-free","name":"Iceman Contributor Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":131072,"type":"chat"},"chat:kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens","supportsMidConvoSystemMessages":true,"supportsMidConvoToolAdditions":true},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:kimi-k3.1-pro":{"id":"kimi-k3.1-pro","name":"Kimi K3.1 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":2},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:longcat-2.0":{"id":"longcat-2.0","name":"LongCat-2.0","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.006,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"type":"chat"},"chat:longcat-2.5-preview-free":{"id":"longcat-2.5-preview-free","name":"LongCat 2.5 Preview Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"deprecated":true,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo V2.5","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo V2.5 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":128000,"type":"chat"},"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:minimax-m3.1-flash":{"id":"minimax-m3.1-flash","name":"MiniMax M3.1 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":512000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:minimax-m3.1-flash-free":{"id":"minimax-m3.1-flash-free","name":"MiniMax M3.1 Flash Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":512000,"deprecated":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:step-5-preview":{"id":"step-5-preview","name":"Step 5 Preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":1,"output":2.7,"cacheRead":0.1,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}},"openai-responses":{"chat:gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession","supportsMidConvoSystemMessages":true,"supportsAdditionalTools":true},"contextWindow":922000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:gpt-6-luna":{"id":"gpt-6-luna","name":"GPT-6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.5,"cacheRead":0.01,"cacheWrite":0.125},"compat":{"sessionAffinityFormat":"openai-nosession","supportsMidConvoSystemMessages":true,"supportsAdditionalTools":true},"contextWindow":922000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:grok-4.7":{"id":"grok-4.7","name":"Grok 4.7","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:muse-spark-1.2-contributor":{"id":"muse-spark-1.2-contributor","name":"Muse Spark 1.2 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:muse-spark-1.3-contributor":{"id":"muse-spark-1.3-contributor","name":"Muse Spark 1.3 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
|
|
1
|
+
{"anthropic-messages":{"chat:claude-haiku-5-5":{"id":"claude-haiku-5-5","name":"Claude Haiku 5.5","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.5,"cacheRead":0.01,"cacheWrite":0.125,"tiers":[{"inputTokensAbove":100000,"input":0.5,"output":2.5,"cacheRead":0.05,"cacheWrite":0.625}]},"contextWindow":100000,"maxTokens":32000,"thinkingLevelMap":{"xhigh":"xhigh","max":"max"},"compat":{"supportsDisabledThinking":false,"forceAdaptiveThinking":true,"supportsTemperature":false},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.4,"output":1.6,"cacheRead":0.04,"cacheWrite":0.5},"contextWindow":1000000,"maxTokens":65536,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.47,"cacheRead":0.016,"cacheWrite":0.2},"contextWindow":1000000,"maxTokens":131072,"compat":{"allowEmptySignature":true},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.25,"cacheWrite":2.5},"contextWindow":1000000,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}},"google-generative-ai":{"chat:gemini-4-argon":{"id":"gemini-4-argon","name":"Gemini 4 Argon","api":"google-generative-ai","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null},"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.1,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:gemini-4-argon-contributor":{"id":"gemini-4-argon-contributor","name":"Gemini 4 Argon Contributor","api":"google-generative-ai","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null},"input":["text","image"],"cost":{"input":4,"output":20,"cacheRead":0.2,"cacheWrite":0},"contextWindow":1048576,"maxTokens":65536,"deprecated":true,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}},"openai-completions":{"chat:beam-free":{"id":"beam-free","name":"Beam Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"type":"chat"},"chat:deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.66,"output":1.98,"cacheRead":0.022,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"},"type":"chat"},"chat:deepseek-v4.1-flash":{"id":"deepseek-v4.1-flash","name":"DeepSeek V4.1 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/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.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"type":"chat"},"chat:glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"},"type":"chat"},"chat:glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:hy3":{"id":"hy3","name":"Hy3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.58,"cacheRead":0.035,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":256000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null},"type":"chat"},"chat:hy4-preview":{"id":"hy4-preview","name":"Hy4 preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.834,"output":2.501,"cacheRead":0.042,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1024000,"maxTokens":64000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null},"type":"chat"},"chat:iceman-contributor-free":{"id":"iceman-contributor-free","name":"Iceman Contributor Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":131072,"type":"chat"},"chat:kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":3},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens","supportsMidConvoSystemMessages":true,"supportsMidConvoToolAdditions":true},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:kimi-k3.1-pro":{"id":"kimi-k3.1-pro","name":"Kimi K3.1 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":10,"cacheRead":0.2,"cacheWrite":2},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:longcat-2.0":{"id":"longcat-2.0","name":"LongCat-2.0","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.006,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"type":"chat"},"chat:longcat-2.5-preview-free":{"id":"longcat-2.5-preview-free","name":"LongCat 2.5 Preview Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"deprecated":true,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo V2.5","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo V2.5 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":128000,"type":"chat"},"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:minimax-m3.1-flash":{"id":"minimax-m3.1-flash","name":"MiniMax M3.1 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.015,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":512000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:minimax-m3.1-flash-free":{"id":"minimax-m3.1-flash-free","name":"MiniMax M3.1 Flash Free","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":512000,"deprecated":true,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:step-5-preview":{"id":"step-5-preview","name":"Step 5 Preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":1,"output":2.7,"cacheRead":0.1,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsStrictMode":true,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":null,"max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}},"openai-responses":{"chat:gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession","supportsMidConvoSystemMessages":true,"supportsAdditionalTools":true},"contextWindow":922000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:gpt-6-luna":{"id":"gpt-6-luna","name":"GPT-6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.5,"cacheRead":0.01,"cacheWrite":0.125},"compat":{"sessionAffinityFormat":"openai-nosession","supportsMidConvoSystemMessages":true,"supportsAdditionalTools":true},"contextWindow":922000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:grok-4.7":{"id":"grok-4.7","name":"Grok 4.7","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:muse-spark-1.2-contributor":{"id":"muse-spark-1.2-contributor","name":"Muse Spark 1.2 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:muse-spark-1.3-contributor":{"id":"muse-spark-1.3-contributor","name":"Muse Spark 1.3 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/inference/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null},"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
|