Merge remote-tracking branch 'origin/main' into add-kimi-deferred-tools
This commit is contained in:
@@ -282,6 +282,7 @@ function buildParams(model: Model<"openai-responses">, context: Context, options
|
||||
effort: (model.thinkingLevelMap?.off ?? "none") as NonNullable<typeof params.reasoning>["effort"],
|
||||
};
|
||||
}
|
||||
if (model.provider === "xai") params.include = ["reasoning.encrypted_content"];
|
||||
}
|
||||
|
||||
return params;
|
||||
|
||||
@@ -11,18 +11,46 @@ const importOAuthModule = (specifier: string): Promise<unknown> => {
|
||||
return import(runtimeSpecifier);
|
||||
};
|
||||
|
||||
export const loadAnthropicOAuth = async (): Promise<OAuthAuth> =>
|
||||
((await importOAuthModule("./anthropic.ts")) as { anthropicOAuth: OAuthAuth }).anthropicOAuth;
|
||||
type OAuthFlowLoaders = {
|
||||
anthropic: () => OAuthAuth | Promise<OAuthAuth>;
|
||||
openaiCodex: () => OAuthAuth | Promise<OAuthAuth>;
|
||||
githubCopilot: () => OAuthAuth | Promise<OAuthAuth>;
|
||||
xai: () => OAuthAuth | Promise<OAuthAuth>;
|
||||
radius: (options: { name: string; gateway: string }) => OAuthAuth | Promise<OAuthAuth>;
|
||||
};
|
||||
|
||||
export const loadOpenAICodexOAuth = async (): Promise<OAuthAuth> =>
|
||||
((await importOAuthModule("./openai-codex.ts")) as { openaiCodexOAuth: OAuthAuth }).openaiCodexOAuth;
|
||||
let bundledLoaders: OAuthFlowLoaders | undefined;
|
||||
|
||||
export const loadGitHubCopilotOAuth = async (): Promise<OAuthAuth> =>
|
||||
((await importOAuthModule("./github-copilot.ts")) as { githubCopilotOAuth: OAuthAuth }).githubCopilotOAuth;
|
||||
/** Registers statically bundled OAuth flows for standalone Bun binaries. */
|
||||
export function registerBundledOAuthFlowLoaders(loaders: OAuthFlowLoaders): void {
|
||||
bundledLoaders = loaders;
|
||||
}
|
||||
|
||||
export const loadRadiusOAuth = async (options: { name: string; gateway: string }): Promise<OAuthAuth> =>
|
||||
(
|
||||
export const loadAnthropicOAuth = async (): Promise<OAuthAuth> => {
|
||||
if (bundledLoaders) return bundledLoaders.anthropic();
|
||||
return ((await importOAuthModule("./anthropic.ts")) as { anthropicOAuth: OAuthAuth }).anthropicOAuth;
|
||||
};
|
||||
|
||||
export const loadOpenAICodexOAuth = async (): Promise<OAuthAuth> => {
|
||||
if (bundledLoaders) return bundledLoaders.openaiCodex();
|
||||
return ((await importOAuthModule("./openai-codex.ts")) as { openaiCodexOAuth: OAuthAuth }).openaiCodexOAuth;
|
||||
};
|
||||
|
||||
export const loadGitHubCopilotOAuth = async (): Promise<OAuthAuth> => {
|
||||
if (bundledLoaders) return bundledLoaders.githubCopilot();
|
||||
return ((await importOAuthModule("./github-copilot.ts")) as { githubCopilotOAuth: OAuthAuth }).githubCopilotOAuth;
|
||||
};
|
||||
|
||||
export const loadXaiOAuth = async (): Promise<OAuthAuth> => {
|
||||
if (bundledLoaders) return bundledLoaders.xai();
|
||||
return ((await importOAuthModule("./xai.ts")) as { xaiOAuth: OAuthAuth }).xaiOAuth;
|
||||
};
|
||||
|
||||
export const loadRadiusOAuth = async (options: { name: string; gateway: string }): Promise<OAuthAuth> => {
|
||||
if (bundledLoaders) return bundledLoaders.radius(options);
|
||||
return (
|
||||
(await importOAuthModule("./radius.ts")) as {
|
||||
createRadiusOAuth: (input: { name: string; gateway: string }) => OAuthAuth;
|
||||
}
|
||||
).createRadiusOAuth(options);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* xAI OAuth device-code flow.
|
||||
*/
|
||||
|
||||
import type { AuthInteraction, OAuthAuth, OAuthCredential } from "../types.ts";
|
||||
import { pollOAuthDeviceCodeFlow } from "./device-code.ts";
|
||||
|
||||
const XAI_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
|
||||
const XAI_SCOPE = "openid profile email offline_access grok-cli:access api:access";
|
||||
const XAI_DEVICE_CODE_URL = "https://auth.x.ai/oauth2/device/code";
|
||||
const XAI_TOKEN_URL = "https://auth.x.ai/oauth2/token";
|
||||
// Refresh slightly before the reported expiry to avoid using a token that dies mid-request.
|
||||
const REFRESH_SKEW_MS = 5 * 60 * 1000;
|
||||
const DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;
|
||||
|
||||
type JsonObject = Record<string, unknown>;
|
||||
|
||||
type OAuthHttpResponse = {
|
||||
ok: boolean;
|
||||
status: number;
|
||||
body: JsonObject;
|
||||
};
|
||||
|
||||
type XaiDeviceCode = {
|
||||
deviceCode: string;
|
||||
userCode: string;
|
||||
verificationUri: string;
|
||||
intervalSeconds?: number;
|
||||
expiresInSeconds: number;
|
||||
};
|
||||
|
||||
function requiredString(body: JsonObject, field: string): string {
|
||||
const value = body[field];
|
||||
if (typeof value !== "string" || value.length === 0) {
|
||||
throw new Error(`Invalid xAI OAuth response field: ${field}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function positiveNumber(body: JsonObject, field: string): number {
|
||||
const value = body[field];
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
||||
throw new Error(`Invalid xAI OAuth response field: ${field}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// The verification URI is opened in the user's browser; force it to be an https URL
|
||||
// so a malicious response cannot make `open` launch something else.
|
||||
function validateVerificationUri(raw: string): string {
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(raw);
|
||||
} catch {
|
||||
throw new Error("Untrusted verification URI in xAI OAuth response");
|
||||
}
|
||||
if (url.protocol !== "https:") {
|
||||
throw new Error("Untrusted verification URI in xAI OAuth response");
|
||||
}
|
||||
return url.href;
|
||||
}
|
||||
|
||||
async function postForm(url: string, fields: Record<string, string>, signal?: AbortSignal): Promise<OAuthHttpResponse> {
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: new URLSearchParams(fields),
|
||||
signal,
|
||||
});
|
||||
} catch (error) {
|
||||
if (signal?.aborted) {
|
||||
throw new Error("Login cancelled");
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
let body: JsonObject;
|
||||
try {
|
||||
const parsed = (await response.json()) as unknown;
|
||||
body = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? (parsed as JsonObject) : {};
|
||||
} catch {
|
||||
if (signal?.aborted) {
|
||||
throw new Error("Login cancelled");
|
||||
}
|
||||
throw new Error(`xAI OAuth returned invalid JSON (HTTP ${response.status})`);
|
||||
}
|
||||
return {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
body,
|
||||
};
|
||||
}
|
||||
|
||||
function requestFailure(action: string, response: OAuthHttpResponse): Error {
|
||||
const error = typeof response.body.error === "string" ? response.body.error : undefined;
|
||||
const description =
|
||||
typeof response.body.error_description === "string" ? response.body.error_description : undefined;
|
||||
const detail = [error, description].filter(Boolean).join(": ");
|
||||
return new Error(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : ""}`);
|
||||
}
|
||||
|
||||
function parseDeviceCode(body: JsonObject): XaiDeviceCode {
|
||||
// RFC 8628 allows interval 0 (no minimum wait); fall back to the poller's
|
||||
// default instead of failing on non-positive or malformed values.
|
||||
const interval = body.interval;
|
||||
const intervalSeconds =
|
||||
typeof interval === "number" && Number.isFinite(interval) && interval > 0 ? interval : undefined;
|
||||
return {
|
||||
deviceCode: requiredString(body, "device_code"),
|
||||
userCode: requiredString(body, "user_code"),
|
||||
verificationUri: validateVerificationUri(requiredString(body, "verification_uri")),
|
||||
intervalSeconds,
|
||||
expiresInSeconds: positiveNumber(body, "expires_in"),
|
||||
};
|
||||
}
|
||||
|
||||
function credentialsFromTokenResponse(body: JsonObject, previousRefreshToken?: string): OAuthCredential {
|
||||
const access = requiredString(body, "access_token");
|
||||
// xAI may omit refresh_token on refresh when the token is not rotated.
|
||||
const refresh =
|
||||
body.refresh_token === undefined && previousRefreshToken
|
||||
? previousRefreshToken
|
||||
: requiredString(body, "refresh_token");
|
||||
const expiresInSeconds =
|
||||
body.expires_in === undefined ? DEFAULT_TOKEN_LIFETIME_SECONDS : positiveNumber(body, "expires_in");
|
||||
return {
|
||||
type: "oauth",
|
||||
access,
|
||||
refresh,
|
||||
expires: Date.now() + expiresInSeconds * 1000 - REFRESH_SKEW_MS,
|
||||
};
|
||||
}
|
||||
|
||||
async function requestDeviceCode(signal?: AbortSignal): Promise<XaiDeviceCode> {
|
||||
const response = await postForm(
|
||||
XAI_DEVICE_CODE_URL,
|
||||
{
|
||||
client_id: XAI_CLIENT_ID,
|
||||
scope: XAI_SCOPE,
|
||||
referrer: "pi",
|
||||
},
|
||||
signal,
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw requestFailure("device authorization", response);
|
||||
}
|
||||
return parseDeviceCode(response.body);
|
||||
}
|
||||
|
||||
async function pollForTokens(device: XaiDeviceCode, signal?: AbortSignal): Promise<OAuthCredential> {
|
||||
return pollOAuthDeviceCodeFlow<OAuthCredential>({
|
||||
intervalSeconds: device.intervalSeconds,
|
||||
expiresInSeconds: device.expiresInSeconds,
|
||||
waitBeforeFirstPoll: true,
|
||||
signal,
|
||||
poll: async () => {
|
||||
const response = await postForm(
|
||||
XAI_TOKEN_URL,
|
||||
{
|
||||
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
||||
client_id: XAI_CLIENT_ID,
|
||||
device_code: device.deviceCode,
|
||||
},
|
||||
signal,
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
return { status: "complete", value: credentialsFromTokenResponse(response.body) };
|
||||
}
|
||||
|
||||
const error = response.body.error;
|
||||
if (error === "authorization_pending") {
|
||||
return { status: "pending" };
|
||||
}
|
||||
if (error === "slow_down") {
|
||||
const interval = response.body.interval;
|
||||
return { status: "slow_down", intervalSeconds: typeof interval === "number" ? interval : undefined };
|
||||
}
|
||||
if (error === "access_denied" || error === "authorization_denied") {
|
||||
return { status: "failed", message: "xAI device authorization was denied" };
|
||||
}
|
||||
if (error === "expired_token") {
|
||||
return { status: "failed", message: "xAI device code expired" };
|
||||
}
|
||||
return { status: "failed", message: requestFailure("device token polling", response).message };
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function loginXai(interaction: AuthInteraction): Promise<OAuthCredential> {
|
||||
const device = await requestDeviceCode(interaction.signal);
|
||||
interaction.notify({
|
||||
type: "device_code",
|
||||
userCode: device.userCode,
|
||||
verificationUri: device.verificationUri,
|
||||
intervalSeconds: device.intervalSeconds,
|
||||
expiresInSeconds: device.expiresInSeconds,
|
||||
});
|
||||
return pollForTokens(device, interaction.signal);
|
||||
}
|
||||
|
||||
async function refreshXaiToken(refreshToken: string, signal?: AbortSignal): Promise<OAuthCredential> {
|
||||
const response = await postForm(
|
||||
XAI_TOKEN_URL,
|
||||
{
|
||||
grant_type: "refresh_token",
|
||||
client_id: XAI_CLIENT_ID,
|
||||
refresh_token: refreshToken,
|
||||
},
|
||||
signal,
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw requestFailure("token refresh", response);
|
||||
}
|
||||
return credentialsFromTokenResponse(response.body, refreshToken);
|
||||
}
|
||||
|
||||
export const xaiOAuth: OAuthAuth = {
|
||||
name: "xAI (Grok/X subscription)",
|
||||
login: loginXai,
|
||||
refresh: (credential, signal) => refreshXaiToken(credential.refresh, signal),
|
||||
|
||||
async toAuth(credential) {
|
||||
return { apiKey: credential.access };
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { anthropicOAuth } from "./auth/oauth/anthropic.ts";
|
||||
import { githubCopilotOAuth } from "./auth/oauth/github-copilot.ts";
|
||||
import { registerBundledOAuthFlowLoaders } from "./auth/oauth/load.ts";
|
||||
import { openaiCodexOAuth } from "./auth/oauth/openai-codex.ts";
|
||||
import { createRadiusOAuth } from "./auth/oauth/radius.ts";
|
||||
import { xaiOAuth } from "./auth/oauth/xai.ts";
|
||||
|
||||
/** Register OAuth flows statically embedded in the standalone Bun binary. */
|
||||
export function registerBunOAuthFlows(): void {
|
||||
registerBundledOAuthFlowLoaders({
|
||||
anthropic: () => anthropicOAuth,
|
||||
openaiCodex: () => openaiCodexOAuth,
|
||||
githubCopilot: () => githubCopilotOAuth,
|
||||
xai: () => xaiOAuth,
|
||||
radius: createRadiusOAuth,
|
||||
});
|
||||
}
|
||||
@@ -38,11 +38,15 @@ export interface RefreshModelsContext {
|
||||
store: ProviderModelsStore;
|
||||
/** False during offline/cache-only initialization. */
|
||||
allowNetwork: boolean;
|
||||
/** Bypass provider freshness checks and fetch immediately when network access is allowed. */
|
||||
force?: boolean;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
export interface ModelsRefreshOptions {
|
||||
allowNetwork?: boolean;
|
||||
/** Bypass provider freshness checks and fetch immediately when network access is allowed. */
|
||||
force?: boolean;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
@@ -290,7 +294,13 @@ class ModelsImpl implements MutableModels {
|
||||
stored = await this.readCredential(provider.id);
|
||||
const credential = await this.resolveRefreshCredential(provider, stored, allowNetwork, options.signal);
|
||||
if (!credential) return;
|
||||
await provider.refreshModels({ credential, store, allowNetwork, signal: options.signal });
|
||||
await provider.refreshModels({
|
||||
credential,
|
||||
store,
|
||||
allowNetwork,
|
||||
force: options.force,
|
||||
signal: options.signal,
|
||||
});
|
||||
} catch (error) {
|
||||
if (!options.signal?.aborted) {
|
||||
errors.set(
|
||||
|
||||
@@ -22,6 +22,24 @@ export const KIMI_CODING_MODELS = {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"k3": {
|
||||
id: "k3",
|
||||
name: "Kimi K3",
|
||||
api: "anthropic-messages",
|
||||
provider: "kimi-coding",
|
||||
baseUrl: "https://api.kimi.com/coding",
|
||||
headers: {"User-Agent":"KimiCLI/1.5"},
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"kimi-for-coding": {
|
||||
id: "kimi-for-coding",
|
||||
name: "Kimi For Coding",
|
||||
@@ -40,6 +58,24 @@ export const KIMI_CODING_MODELS = {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"kimi-for-coding-highspeed": {
|
||||
id: "kimi-for-coding-highspeed",
|
||||
name: "Kimi For Coding HighSpeed",
|
||||
api: "anthropic-messages",
|
||||
provider: "kimi-coding",
|
||||
baseUrl: "https://api.kimi.com/coding",
|
||||
headers: {"User-Agent":"KimiCLI/1.5"},
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"kimi-k2-thinking": {
|
||||
id: "kimi-k2-thinking",
|
||||
name: "Kimi K2 Thinking",
|
||||
|
||||
@@ -168,4 +168,23 @@ export const MOONSHOTAI_CN_MODELS = {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"kimi-k3": {
|
||||
id: "kimi-k3",
|
||||
name: "Kimi K3",
|
||||
api: "openai-completions",
|
||||
provider: "moonshotai-cn",
|
||||
baseUrl: "https://api.moonshot.cn/v1",
|
||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"deepseek","requiresReasoningContentOnAssistantMessages":true},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
} as const;
|
||||
|
||||
@@ -168,4 +168,23 @@ export const MOONSHOTAI_MODELS = {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"kimi-k3": {
|
||||
id: "kimi-k3",
|
||||
name: "Kimi K3",
|
||||
api: "openai-completions",
|
||||
provider: "moonshotai",
|
||||
baseUrl: "https://api.moonshot.ai/v1",
|
||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"deepseek","requiresReasoningContentOnAssistantMessages":true},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
} as const;
|
||||
|
||||
@@ -385,7 +385,7 @@ export const OPENROUTER_MODELS = {
|
||||
cacheRead: 0.3,
|
||||
cacheWrite: 3.75,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
contextWindow: 200000,
|
||||
maxTokens: 64000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"anthropic/claude-sonnet-4.5": {
|
||||
@@ -652,13 +652,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.24,
|
||||
output: 0.9,
|
||||
input: 0.27,
|
||||
output: 1.12,
|
||||
cacheRead: 0.135,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 163840,
|
||||
maxTokens: 16384,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"deepseek/deepseek-chat-v3.1": {
|
||||
id: "deepseek/deepseek-chat-v3.1",
|
||||
@@ -725,11 +725,11 @@ export const OPENROUTER_MODELS = {
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.27,
|
||||
output: 0.95,
|
||||
cacheRead: 0.13,
|
||||
output: 1,
|
||||
cacheRead: 0.135,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 163840,
|
||||
contextWindow: 131072,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"deepseek/deepseek-v3.2": {
|
||||
@@ -742,13 +742,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.2145,
|
||||
output: 0.32175,
|
||||
cacheRead: 0.02145,
|
||||
input: 0.269,
|
||||
output: 0.4,
|
||||
cacheRead: 0.1345,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 64000,
|
||||
contextWindow: 163840,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"deepseek/deepseek-v3.2-exp": {
|
||||
id: "deepseek/deepseek-v3.2-exp",
|
||||
@@ -779,13 +779,13 @@ export const OPENROUTER_MODELS = {
|
||||
thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":null,"xhigh":"xhigh"},
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.09,
|
||||
output: 0.18,
|
||||
cacheRead: 0.018,
|
||||
input: 0.098,
|
||||
output: 0.196,
|
||||
cacheRead: 0.02,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 65536,
|
||||
contextWindow: 1048575,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"deepseek/deepseek-v4-pro": {
|
||||
id: "deepseek/deepseek-v4-pro",
|
||||
@@ -1051,12 +1051,12 @@ export const OPENROUTER_MODELS = {
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.08,
|
||||
output: 0.16,
|
||||
cacheRead: 0,
|
||||
output: 0.45,
|
||||
cacheRead: 0.04,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 16384,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"google/gemma-4-26b-a4b-it": {
|
||||
id: "google/gemma-4-26b-a4b-it",
|
||||
@@ -1068,13 +1068,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.06,
|
||||
output: 0.33,
|
||||
input: 0.1,
|
||||
output: 0.3,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 4096,
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"google/gemma-4-26b-a4b-it:free": {
|
||||
id: "google/gemma-4-26b-a4b-it:free",
|
||||
@@ -1104,13 +1104,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.06,
|
||||
output: 0.35,
|
||||
cacheRead: 0,
|
||||
input: 0.22,
|
||||
output: 0.55,
|
||||
cacheRead: 0.12,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 8192,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"google/gemma-4-31b-it:free": {
|
||||
id: "google/gemma-4-31b-it:free",
|
||||
@@ -1303,13 +1303,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.02,
|
||||
output: 0.03,
|
||||
cacheRead: 0,
|
||||
input: 0.05,
|
||||
output: 0.08,
|
||||
cacheRead: 0.025,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 16384,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.3-70b-instruct": {
|
||||
id: "meta-llama/llama-3.3-70b-instruct",
|
||||
@@ -1321,13 +1321,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.1,
|
||||
output: 0.32,
|
||||
input: 0.13,
|
||||
output: 0.4,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 16384,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.3-70b-instruct:free": {
|
||||
id: "meta-llama/llama-3.3-70b-instruct:free",
|
||||
@@ -1383,6 +1383,24 @@ export const OPENROUTER_MODELS = {
|
||||
contextWindow: 327680,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta/muse-spark-1.1": {
|
||||
id: "meta/muse-spark-1.1",
|
||||
name: "Meta: Muse Spark 1.1",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"},
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 4.25,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"minimax/minimax-m1": {
|
||||
id: "minimax/minimax-m1",
|
||||
name: "MiniMax: MiniMax M1",
|
||||
@@ -1393,7 +1411,7 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.4,
|
||||
input: 0.55,
|
||||
output: 2.2,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
@@ -1465,13 +1483,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.24,
|
||||
output: 0.96,
|
||||
cacheRead: 0,
|
||||
input: 0.3,
|
||||
output: 1.2,
|
||||
cacheRead: 0.06,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 196608,
|
||||
maxTokens: 196608,
|
||||
contextWindow: 204800,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"minimax/minimax-m3": {
|
||||
id: "minimax/minimax-m3",
|
||||
@@ -1488,8 +1506,8 @@ export const OPENROUTER_MODELS = {
|
||||
cacheRead: 0.06,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 131072,
|
||||
contextWindow: 524288,
|
||||
maxTokens: 512000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mistralai/codestral-2508": {
|
||||
id: "mistralai/codestral-2508",
|
||||
@@ -1700,12 +1718,12 @@ export const OPENROUTER_MODELS = {
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.02,
|
||||
output: 0.03,
|
||||
output: 0.04,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mistralai/mistral-saba": {
|
||||
id: "mistralai/mistral-saba",
|
||||
@@ -1753,13 +1771,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.075,
|
||||
output: 0.2,
|
||||
cacheRead: 0,
|
||||
input: 0.1,
|
||||
output: 0.3,
|
||||
cacheRead: 0.01,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 16384,
|
||||
contextWindow: 131072,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mistralai/mixtral-8x22b-instruct": {
|
||||
id: "mistralai/mixtral-8x22b-instruct",
|
||||
@@ -1845,11 +1863,11 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 0.6,
|
||||
output: 2.5,
|
||||
cacheRead: 0.15,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 100352,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"moonshotai/kimi-k2.5": {
|
||||
id: "moonshotai/kimi-k2.5",
|
||||
@@ -1879,13 +1897,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.66,
|
||||
output: 3.41,
|
||||
cacheRead: 0.15,
|
||||
input: 0.95,
|
||||
output: 4,
|
||||
cacheRead: 0.16,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"moonshotai/kimi-k2.7-code": {
|
||||
id: "moonshotai/kimi-k2.7-code",
|
||||
@@ -1897,9 +1915,9 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.719,
|
||||
output: 3.49,
|
||||
cacheRead: 0.149,
|
||||
input: 0.75,
|
||||
output: 3.5,
|
||||
cacheRead: 0.16,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
@@ -2023,12 +2041,12 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.08,
|
||||
output: 0.45,
|
||||
cacheRead: 0,
|
||||
input: 0.21,
|
||||
output: 0.455,
|
||||
cacheRead: 0.06,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"nvidia/nemotron-3-super-120b-a12b:free": {
|
||||
@@ -2059,13 +2077,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.5,
|
||||
output: 2.2,
|
||||
cacheRead: 0.1,
|
||||
input: 0.6,
|
||||
output: 3.6,
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 16384,
|
||||
contextWindow: 512288,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"nvidia/nemotron-3-ultra-550b-a55b:free": {
|
||||
id: "nvidia/nemotron-3-ultra-550b-a55b:free",
|
||||
@@ -2245,7 +2263,7 @@ export const OPENROUTER_MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1047576,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-4.1-mini": {
|
||||
id: "openai/gpt-4.1-mini",
|
||||
@@ -2295,7 +2313,7 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 2.5,
|
||||
output: 10,
|
||||
cacheRead: 0,
|
||||
cacheRead: 1.25,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
@@ -2511,11 +2529,11 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 10,
|
||||
cacheRead: 0.13,
|
||||
cacheRead: 0.125,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 32000,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-5.1-codex": {
|
||||
id: "openai/gpt-5.1-codex",
|
||||
@@ -2529,7 +2547,7 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 10,
|
||||
cacheRead: 0.13,
|
||||
cacheRead: 0.125,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 400000,
|
||||
@@ -2977,8 +2995,8 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.03,
|
||||
output: 0.15,
|
||||
input: 0.037,
|
||||
output: 0.17,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -2995,13 +3013,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.029,
|
||||
output: 0.14,
|
||||
cacheRead: 0,
|
||||
input: 0.03,
|
||||
output: 0.13,
|
||||
cacheRead: 0.03,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-oss-20b:free": {
|
||||
id: "openai/gpt-oss-20b:free",
|
||||
@@ -3517,13 +3535,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.04815,
|
||||
output: 0.19305,
|
||||
input: 0.1,
|
||||
output: 0.3,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 32000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3-30b-a3b-thinking-2507": {
|
||||
id: "qwen/qwen3-30b-a3b-thinking-2507",
|
||||
@@ -3589,9 +3607,9 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.22,
|
||||
output: 1.8,
|
||||
cacheRead: 0,
|
||||
input: 0.3,
|
||||
output: 1,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
@@ -3733,13 +3751,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.09,
|
||||
input: 0.1,
|
||||
output: 1.1,
|
||||
cacheRead: 0,
|
||||
cacheRead: 0.07,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 16384,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3-next-80b-a3b-instruct:free": {
|
||||
id: "qwen/qwen3-next-80b-a3b-instruct:free",
|
||||
@@ -3787,13 +3805,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.2,
|
||||
output: 0.88,
|
||||
cacheRead: 0.11,
|
||||
input: 0.21,
|
||||
output: 1.9,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 16384,
|
||||
contextWindow: 131072,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3-vl-235b-a22b-thinking": {
|
||||
id: "qwen/qwen3-vl-235b-a22b-thinking",
|
||||
@@ -3919,7 +3937,7 @@ export const OPENROUTER_MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.5-27b": {
|
||||
id: "qwen/qwen3.5-27b",
|
||||
@@ -3951,11 +3969,11 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 0.14,
|
||||
output: 1,
|
||||
cacheRead: 0.05,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 81920,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.5-397b-a17b": {
|
||||
id: "qwen/qwen3.5-397b-a17b",
|
||||
@@ -3967,13 +3985,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.385,
|
||||
output: 2.45,
|
||||
cacheRead: 0.111,
|
||||
input: 0.45,
|
||||
output: 3,
|
||||
cacheRead: 0.225,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 4096,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.5-9b": {
|
||||
id: "qwen/qwen3.5-9b",
|
||||
@@ -4057,13 +4075,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.289,
|
||||
output: 2.4,
|
||||
input: 0.45,
|
||||
output: 2.7,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.6-35b-a3b": {
|
||||
id: "qwen/qwen3.6-35b-a3b",
|
||||
@@ -4147,10 +4165,10 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 3.75,
|
||||
cacheRead: 0.25,
|
||||
cacheWrite: 1.5625,
|
||||
input: 1.475,
|
||||
output: 4.425,
|
||||
cacheRead: 0.295,
|
||||
cacheWrite: 1.84375,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 65536,
|
||||
@@ -4291,13 +4309,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.14,
|
||||
output: 0.58,
|
||||
cacheRead: 0.035,
|
||||
input: 0.2,
|
||||
output: 0.8,
|
||||
cacheRead: 0.05,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"tencent/hy3-preview": {
|
||||
id: "tencent/hy3-preview",
|
||||
@@ -4453,13 +4471,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.105,
|
||||
input: 0.14,
|
||||
output: 0.28,
|
||||
cacheRead: 0.028,
|
||||
cacheRead: 0.0028,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 4096,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"xiaomi/mimo-v2.5-pro": {
|
||||
id: "xiaomi/mimo-v2.5-pro",
|
||||
@@ -4543,13 +4561,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.43,
|
||||
output: 1.75,
|
||||
cacheRead: 0.08,
|
||||
input: 0.5,
|
||||
output: 2,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 198000,
|
||||
maxTokens: 16384,
|
||||
contextWindow: 202752,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-4.6v": {
|
||||
id: "z-ai/glm-4.6v",
|
||||
@@ -4597,13 +4615,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.06,
|
||||
input: 0.0605,
|
||||
output: 0.4,
|
||||
cacheRead: 0.01,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 202752,
|
||||
maxTokens: 16384,
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5": {
|
||||
id: "z-ai/glm-5",
|
||||
@@ -4620,8 +4638,8 @@ export const OPENROUTER_MODELS = {
|
||||
cacheRead: 0.119,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 198000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 202752,
|
||||
maxTokens: 202752,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5-turbo": {
|
||||
id: "z-ai/glm-5-turbo",
|
||||
@@ -4638,7 +4656,7 @@ export const OPENROUTER_MODELS = {
|
||||
cacheRead: 0.24,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
contextWindow: 202752,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5.1": {
|
||||
@@ -4670,13 +4688,13 @@ export const OPENROUTER_MODELS = {
|
||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.924,
|
||||
output: 2.904,
|
||||
cacheRead: 0.1716,
|
||||
input: 0.9366,
|
||||
output: 2.9436,
|
||||
cacheRead: 0.17394,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1024000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5v-turbo": {
|
||||
id: "z-ai/glm-5v-turbo",
|
||||
|
||||
@@ -622,6 +622,25 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-opus-4.7-fast": {
|
||||
id: "anthropic/claude-opus-4.7-fast",
|
||||
name: "Claude Opus 4.7 (Fast)",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 30,
|
||||
output: 150,
|
||||
cacheRead: 3,
|
||||
cacheWrite: 37.5,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-opus-4.8": {
|
||||
id: "anthropic/claude-opus-4.8",
|
||||
name: "Claude Opus 4.8",
|
||||
@@ -641,6 +660,25 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-opus-4.8-fast": {
|
||||
id: "anthropic/claude-opus-4.8-fast",
|
||||
name: "Claude Opus 4.8 (Fast)",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 10,
|
||||
output: 50,
|
||||
cacheRead: 1,
|
||||
cacheWrite: 12.5,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-sonnet-4": {
|
||||
id: "anthropic/claude-sonnet-4",
|
||||
name: "Claude Sonnet 4",
|
||||
@@ -841,8 +879,8 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.21,
|
||||
output: 0.79,
|
||||
input: 0.25,
|
||||
output: 0.95,
|
||||
cacheRead: 0.13,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -2717,6 +2755,23 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"thinkingmachines/inkling": {
|
||||
id: "thinkingmachines/inkling",
|
||||
name: "Inkling",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 4.05,
|
||||
cacheRead: 0.17,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"xai/grok-4.1-fast-non-reasoning": {
|
||||
id: "xai/grok-4.1-fast-non-reasoning",
|
||||
name: "Grok 4.1 Fast Non-Reasoning",
|
||||
|
||||
@@ -97,11 +97,12 @@ export const XAI_MODELS = {
|
||||
"grok-4.5": {
|
||||
id: "grok-4.5",
|
||||
name: "Grok 4.5",
|
||||
api: "openai-completions",
|
||||
api: "openai-responses",
|
||||
provider: "xai",
|
||||
baseUrl: "https://api.x.ai/v1",
|
||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false},
|
||||
compat: {"supportsLongCacheRetention":false},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"minimal":null},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
@@ -111,7 +112,7 @@ export const XAI_MODELS = {
|
||||
},
|
||||
contextWindow: 500000,
|
||||
maxTokens: 500000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"grok-build-0.1": {
|
||||
id: "grok-build-0.1",
|
||||
name: "Grok Build 0.1",
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadXaiOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { XAI_MODELS } from "./xai.models.ts";
|
||||
|
||||
export function xaiProvider(): Provider<"openai-completions"> {
|
||||
export function xaiProvider(): Provider<"openai-completions" | "openai-responses"> {
|
||||
return createProvider({
|
||||
id: "xai",
|
||||
name: "xAI",
|
||||
baseUrl: "https://api.x.ai/v1",
|
||||
auth: { apiKey: envApiKeyAuth("xAI API key", ["XAI_API_KEY"]) },
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("xAI API key", ["XAI_API_KEY"]),
|
||||
oauth: lazyOAuth({ name: "xAI (Grok/X subscription)", load: loadXaiOAuth }),
|
||||
},
|
||||
models: Object.values(XAI_MODELS),
|
||||
api: openAICompletionsApi(),
|
||||
api: {
|
||||
"openai-completions": openAICompletionsApi(),
|
||||
"openai-responses": openAIResponsesApi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user