feat(coding-agent): replace model registry with model runtime
Move provider auth and OAuth flows onto pi-ai Models, compose models.json and extension overlays through ModelRuntime, and retain ModelRegistry as an extension compatibility facade.
This commit is contained in:
@@ -1290,6 +1290,60 @@ export const AMAZON_BEDROCK_MODELS = {
|
||||
contextWindow: 272000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"bedrock-converse-stream">,
|
||||
"openai.gpt-5.6-luna": {
|
||||
id: "openai.gpt-5.6-luna",
|
||||
name: "GPT-5.6 Luna",
|
||||
api: "bedrock-converse-stream",
|
||||
provider: "amazon-bedrock",
|
||||
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 6,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 1.25,
|
||||
},
|
||||
contextWindow: 272000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"bedrock-converse-stream">,
|
||||
"openai.gpt-5.6-sol": {
|
||||
id: "openai.gpt-5.6-sol",
|
||||
name: "GPT-5.6 Sol",
|
||||
api: "bedrock-converse-stream",
|
||||
provider: "amazon-bedrock",
|
||||
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 5,
|
||||
output: 30,
|
||||
cacheRead: 0.5,
|
||||
cacheWrite: 6.25,
|
||||
},
|
||||
contextWindow: 272000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"bedrock-converse-stream">,
|
||||
"openai.gpt-5.6-terra": {
|
||||
id: "openai.gpt-5.6-terra",
|
||||
name: "GPT-5.6 Terra",
|
||||
api: "bedrock-converse-stream",
|
||||
provider: "amazon-bedrock",
|
||||
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cacheRead: 0.25,
|
||||
cacheWrite: 3.125,
|
||||
},
|
||||
contextWindow: 272000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"bedrock-converse-stream">,
|
||||
"openai.gpt-oss-120b": {
|
||||
id: "openai.gpt-oss-120b",
|
||||
name: "gpt-oss-120b",
|
||||
|
||||
@@ -4,16 +4,61 @@ import { createProvider, type Provider } from "../models.ts";
|
||||
import { AMAZON_BEDROCK_MODELS } from "./amazon-bedrock.models.ts";
|
||||
|
||||
/**
|
||||
* Bedrock auth is ambient: the AWS SDK's default credential chain handles the
|
||||
* actual signing, so `resolve` only reports whether the provider is
|
||||
* configured. A stored credential key is surfaced as the bearer token.
|
||||
* Bedrock accepts a bearer token or the AWS SDK's default credential chain.
|
||||
* The login flow can store a token/profile choice; resolve also detects ambient
|
||||
* AWS credentials without copying them into pi's credential store.
|
||||
*/
|
||||
const bedrockAuth: ApiKeyAuth = {
|
||||
name: "AWS credentials",
|
||||
name: "AWS credentials or bearer token",
|
||||
login: async (interaction) => {
|
||||
const method = await interaction.prompt({
|
||||
type: "select",
|
||||
message: "Select Amazon Bedrock authentication method:",
|
||||
options: [
|
||||
{ id: "bearer-token", label: "Bearer token" },
|
||||
{ id: "aws-profile", label: "AWS profile" },
|
||||
{ id: "credential-chain", label: "Existing AWS credential chain" },
|
||||
],
|
||||
});
|
||||
if (method === "bearer-token") {
|
||||
return {
|
||||
type: "api_key",
|
||||
key: await interaction.prompt({ type: "secret", message: "Enter Amazon Bedrock bearer token" }),
|
||||
};
|
||||
}
|
||||
interaction.notify({
|
||||
type: "info",
|
||||
message: "Amazon Bedrock supports AWS profiles, IAM credentials, and role-based credentials.",
|
||||
links: [
|
||||
{
|
||||
label: "AWS credential provider chain",
|
||||
url: "https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html",
|
||||
},
|
||||
],
|
||||
});
|
||||
if (method === "aws-profile") {
|
||||
return {
|
||||
type: "api_key",
|
||||
env: { AWS_PROFILE: await interaction.prompt({ type: "text", message: "Enter AWS profile name" }) },
|
||||
};
|
||||
}
|
||||
if (method !== "credential-chain") throw new Error(`Unknown Amazon Bedrock auth method: ${method}`);
|
||||
await interaction.prompt({
|
||||
type: "text",
|
||||
message: "Configure AWS credentials, then press Enter to continue",
|
||||
});
|
||||
return { type: "api_key" };
|
||||
},
|
||||
resolve: async ({ ctx, credential }) => {
|
||||
if (credential?.key) return { auth: { apiKey: credential.key }, source: "stored credential" };
|
||||
if (await ctx.env("AWS_BEARER_TOKEN_BEDROCK")) return { auth: {}, source: "AWS_BEARER_TOKEN_BEDROCK" };
|
||||
if (await ctx.env("AWS_PROFILE")) return { auth: {}, source: "AWS_PROFILE" };
|
||||
if (credential?.env?.AWS_PROFILE ?? (await ctx.env("AWS_PROFILE"))) {
|
||||
return {
|
||||
auth: {},
|
||||
env: credential?.env,
|
||||
source: credential?.env?.AWS_PROFILE ? "stored credential" : "AWS_PROFILE",
|
||||
};
|
||||
}
|
||||
if ((await ctx.env("AWS_ACCESS_KEY_ID")) && (await ctx.env("AWS_SECRET_ACCESS_KEY"))) {
|
||||
return { auth: {}, source: "AWS access keys" };
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadAnthropicOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { loadAnthropicOAuth } from "../utils/oauth/load.ts";
|
||||
import { ANTHROPIC_MODELS } from "./anthropic.models.ts";
|
||||
|
||||
export function anthropicProvider(): Provider<"anthropic-messages"> {
|
||||
|
||||
@@ -660,6 +660,23 @@ export const AZURE_OPENAI_RESPONSES_MODELS = {
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"azure-openai-responses">,
|
||||
"gpt-realtime-2.1": {
|
||||
id: "gpt-realtime-2.1",
|
||||
name: "GPT-Realtime-2.1",
|
||||
api: "azure-openai-responses",
|
||||
provider: "azure-openai-responses",
|
||||
baseUrl: "",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 4,
|
||||
output: 24,
|
||||
cacheRead: 0.4,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 32000,
|
||||
} satisfies Model<"azure-openai-responses">,
|
||||
"o1": {
|
||||
id: "o1",
|
||||
name: "o1",
|
||||
|
||||
@@ -52,7 +52,7 @@ export const CEREBRAS_MODELS = {
|
||||
cost: {
|
||||
input: 2.25,
|
||||
output: 2.75,
|
||||
cacheRead: 0,
|
||||
cacheRead: 2.25,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
|
||||
@@ -528,6 +528,60 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-luna": {
|
||||
id: "gpt-5.6-luna",
|
||||
name: "GPT-5.6 Luna",
|
||||
api: "openai-responses",
|
||||
provider: "cloudflare-ai-gateway",
|
||||
baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 6,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-sol": {
|
||||
id: "gpt-5.6-sol",
|
||||
name: "GPT-5.6 Sol",
|
||||
api: "openai-responses",
|
||||
provider: "cloudflare-ai-gateway",
|
||||
baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 5,
|
||||
output: 30,
|
||||
cacheRead: 0.5,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-terra": {
|
||||
id: "gpt-5.6-terra",
|
||||
name: "GPT-5.6 Terra",
|
||||
api: "openai-responses",
|
||||
provider: "cloudflare-ai-gateway",
|
||||
baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cacheRead: 0.25,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"o1": {
|
||||
id: "o1",
|
||||
name: "o1",
|
||||
@@ -685,4 +739,22 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"workers-ai/@cf/zai-org/glm-5.2": {
|
||||
id: "workers-ai/@cf/zai-org/glm-5.2",
|
||||
name: "Glm 5.2",
|
||||
api: "openai-completions",
|
||||
provider: "cloudflare-ai-gateway",
|
||||
baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat",
|
||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"supportsLongCacheRetention":false,"sendSessionAffinityHeaders":true},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1.4,
|
||||
output: 4.4,
|
||||
cacheRead: 0.26,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">,
|
||||
} as const;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { CLOUDFLARE_AI_GATEWAY_MODELS } from "./cloudflare-ai-gateway.models.ts";
|
||||
import { cloudflareAIGatewayAuth } from "./cloudflare-auth.ts";
|
||||
import { cloudflareStreams } from "./cloudflare-stream.ts";
|
||||
|
||||
export function cloudflareAIGatewayProvider(): Provider<
|
||||
"anthropic-messages" | "openai-completions" | "openai-responses"
|
||||
@@ -14,9 +15,9 @@ export function cloudflareAIGatewayProvider(): Provider<
|
||||
auth: { apiKey: cloudflareAIGatewayAuth() },
|
||||
models: Object.values(CLOUDFLARE_AI_GATEWAY_MODELS),
|
||||
api: {
|
||||
"anthropic-messages": anthropicMessagesApi(),
|
||||
"openai-completions": openAICompletionsApi(),
|
||||
"openai-responses": openAIResponsesApi(),
|
||||
"anthropic-messages": cloudflareStreams(anthropicMessagesApi()),
|
||||
"openai-completions": cloudflareStreams(openAICompletionsApi()),
|
||||
"openai-responses": cloudflareStreams(openAIResponsesApi()),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ApiKeyAuth, ApiKeyCredential, AuthContext } from "../auth/types.ts";
|
||||
import type { Api, ImagesApi, ImagesModel, Model, ProviderEnv } from "../types.ts";
|
||||
import type { ProviderEnv } from "../types.ts";
|
||||
|
||||
const CLOUDFLARE_API_KEY = "CLOUDFLARE_API_KEY";
|
||||
const CLOUDFLARE_ACCOUNT_ID = "CLOUDFLARE_ACCOUNT_ID";
|
||||
@@ -19,22 +19,11 @@ async function resolveValue(
|
||||
return ctx.env(name);
|
||||
}
|
||||
|
||||
function resolveCloudflareBaseUrl(
|
||||
model: Model<Api> | ImagesModel<ImagesApi>,
|
||||
accountId: string,
|
||||
gatewayId: string | undefined,
|
||||
): string {
|
||||
return model.baseUrl
|
||||
.replaceAll(`{${CLOUDFLARE_ACCOUNT_ID}}`, accountId)
|
||||
.replaceAll(`{${CLOUDFLARE_GATEWAY_ID}}`, gatewayId ?? "");
|
||||
}
|
||||
|
||||
async function resolveCloudflareEnv(
|
||||
kind: CloudflareAuthKind,
|
||||
model: Model<Api> | ImagesModel<ImagesApi>,
|
||||
ctx: AuthContext,
|
||||
credential: ApiKeyCredential | undefined,
|
||||
): Promise<{ apiKey: string; env: ProviderEnv; baseUrl: string; source: string } | undefined> {
|
||||
): Promise<{ apiKey: string; env: ProviderEnv; source: string } | undefined> {
|
||||
const apiKey = await resolveValue(CLOUDFLARE_API_KEY, ctx, credential);
|
||||
const accountId = await resolveValue(CLOUDFLARE_ACCOUNT_ID, ctx, credential);
|
||||
const gatewayId = kind === "ai-gateway" ? await resolveValue(CLOUDFLARE_GATEWAY_ID, ctx, credential) : undefined;
|
||||
@@ -47,7 +36,6 @@ async function resolveCloudflareEnv(
|
||||
CLOUDFLARE_ACCOUNT_ID: accountId,
|
||||
...(gatewayId ? { CLOUDFLARE_GATEWAY_ID: gatewayId } : {}),
|
||||
},
|
||||
baseUrl: resolveCloudflareBaseUrl(model, accountId, gatewayId),
|
||||
source: credential ? "stored credential" : CLOUDFLARE_API_KEY,
|
||||
};
|
||||
}
|
||||
@@ -55,16 +43,16 @@ async function resolveCloudflareEnv(
|
||||
export function cloudflareWorkersAIAuth(): ApiKeyAuth {
|
||||
return {
|
||||
name: "Cloudflare API key",
|
||||
login: async (callbacks) => {
|
||||
const key = await callbacks.prompt({ type: "secret", message: "Enter Cloudflare API key" });
|
||||
const accountId = await callbacks.prompt({ type: "text", message: "Enter Cloudflare account ID" });
|
||||
login: async (interaction) => {
|
||||
const key = await interaction.prompt({ type: "secret", message: "Enter Cloudflare API key" });
|
||||
const accountId = await interaction.prompt({ type: "text", message: "Enter Cloudflare account ID" });
|
||||
return { type: "api_key", key, env: { CLOUDFLARE_ACCOUNT_ID: accountId } };
|
||||
},
|
||||
resolve: async ({ model, ctx, credential }) => {
|
||||
const resolved = await resolveCloudflareEnv("workers-ai", model, ctx, credential);
|
||||
resolve: async ({ ctx, credential }) => {
|
||||
const resolved = await resolveCloudflareEnv("workers-ai", ctx, credential);
|
||||
if (!resolved) return undefined;
|
||||
return {
|
||||
auth: { apiKey: resolved.apiKey, baseUrl: resolved.baseUrl },
|
||||
auth: { apiKey: resolved.apiKey },
|
||||
env: resolved.env,
|
||||
source: resolved.source,
|
||||
};
|
||||
@@ -75,18 +63,18 @@ export function cloudflareWorkersAIAuth(): ApiKeyAuth {
|
||||
export function cloudflareAIGatewayAuth(): ApiKeyAuth {
|
||||
return {
|
||||
name: "Cloudflare API key",
|
||||
login: async (callbacks) => {
|
||||
const key = await callbacks.prompt({ type: "secret", message: "Enter Cloudflare API key" });
|
||||
const accountId = await callbacks.prompt({ type: "text", message: "Enter Cloudflare account ID" });
|
||||
const gatewayId = await callbacks.prompt({ type: "text", message: "Enter Cloudflare AI Gateway ID" });
|
||||
login: async (interaction) => {
|
||||
const key = await interaction.prompt({ type: "secret", message: "Enter Cloudflare API key" });
|
||||
const accountId = await interaction.prompt({ type: "text", message: "Enter Cloudflare account ID" });
|
||||
const gatewayId = await interaction.prompt({ type: "text", message: "Enter Cloudflare AI Gateway ID" });
|
||||
return {
|
||||
type: "api_key",
|
||||
key,
|
||||
env: { CLOUDFLARE_ACCOUNT_ID: accountId, CLOUDFLARE_GATEWAY_ID: gatewayId },
|
||||
};
|
||||
},
|
||||
resolve: async ({ model, ctx, credential }) => {
|
||||
const resolved = await resolveCloudflareEnv("ai-gateway", model, ctx, credential);
|
||||
resolve: async ({ ctx, credential }) => {
|
||||
const resolved = await resolveCloudflareEnv("ai-gateway", ctx, credential);
|
||||
if (!resolved) return undefined;
|
||||
return {
|
||||
auth: {
|
||||
@@ -95,7 +83,6 @@ export function cloudflareAIGatewayAuth(): ApiKeyAuth {
|
||||
Authorization: null,
|
||||
"x-api-key": null,
|
||||
},
|
||||
baseUrl: resolved.baseUrl,
|
||||
},
|
||||
env: resolved.env,
|
||||
source: resolved.source,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Api, Model, ProviderEnv, ProviderStreams } from "../types.ts";
|
||||
|
||||
const CLOUDFLARE_ACCOUNT_ID = "CLOUDFLARE_ACCOUNT_ID";
|
||||
const CLOUDFLARE_GATEWAY_ID = "CLOUDFLARE_GATEWAY_ID";
|
||||
|
||||
export function resolveCloudflareModel<TApi extends Api>(
|
||||
model: Model<TApi>,
|
||||
env: ProviderEnv | undefined,
|
||||
): Model<TApi> {
|
||||
if (!env) return model;
|
||||
const baseUrl = model.baseUrl
|
||||
.replaceAll(`{${CLOUDFLARE_ACCOUNT_ID}}`, env[CLOUDFLARE_ACCOUNT_ID] ?? `{${CLOUDFLARE_ACCOUNT_ID}}`)
|
||||
.replaceAll(`{${CLOUDFLARE_GATEWAY_ID}}`, env[CLOUDFLARE_GATEWAY_ID] ?? `{${CLOUDFLARE_GATEWAY_ID}}`);
|
||||
return baseUrl === model.baseUrl ? model : { ...model, baseUrl };
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an API implementation so Cloudflare account/gateway endpoint
|
||||
* placeholders materialize from the resolved provider env before dispatch.
|
||||
*/
|
||||
export function cloudflareStreams(streams: ProviderStreams): ProviderStreams {
|
||||
return {
|
||||
stream: (model, context, options) =>
|
||||
streams.stream(resolveCloudflareModel(model, options?.env), context, options),
|
||||
streamSimple: (model, context, options) =>
|
||||
streams.streamSimple(resolveCloudflareModel(model, options?.env), context, options),
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { cloudflareWorkersAIAuth } from "./cloudflare-auth.ts";
|
||||
import { cloudflareStreams } from "./cloudflare-stream.ts";
|
||||
import { CLOUDFLARE_WORKERS_AI_MODELS } from "./cloudflare-workers-ai.models.ts";
|
||||
|
||||
export function cloudflareWorkersAIProvider(): Provider<"openai-completions"> {
|
||||
@@ -9,6 +10,6 @@ export function cloudflareWorkersAIProvider(): Provider<"openai-completions"> {
|
||||
name: "Cloudflare Workers AI",
|
||||
auth: { apiKey: cloudflareWorkersAIAuth() },
|
||||
models: Object.values(CLOUDFLARE_WORKERS_AI_MODELS),
|
||||
api: openAICompletionsApi(),
|
||||
api: cloudflareStreams(openAICompletionsApi()),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ export const GITHUB_COPILOT_MODELS = {
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 200000,
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 64000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"gemini-3.5-flash": {
|
||||
@@ -445,6 +445,63 @@ export const GITHUB_COPILOT_MODELS = {
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-luna": {
|
||||
id: "gpt-5.6-luna",
|
||||
name: "GPT-5.6 Luna",
|
||||
api: "openai-responses",
|
||||
provider: "github-copilot",
|
||||
baseUrl: "https://api.individual.githubcopilot.com",
|
||||
headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"minimal":"low","xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 6,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-sol": {
|
||||
id: "gpt-5.6-sol",
|
||||
name: "GPT-5.6 Sol",
|
||||
api: "openai-responses",
|
||||
provider: "github-copilot",
|
||||
baseUrl: "https://api.individual.githubcopilot.com",
|
||||
headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"minimal":"low","xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 5,
|
||||
output: 30,
|
||||
cacheRead: 0.5,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-terra": {
|
||||
id: "gpt-5.6-terra",
|
||||
name: "GPT-5.6 Terra",
|
||||
api: "openai-responses",
|
||||
provider: "github-copilot",
|
||||
baseUrl: "https://api.individual.githubcopilot.com",
|
||||
headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"},
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"minimal":"low","xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cacheRead: 0.25,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"kimi-k2.7-code": {
|
||||
id: "kimi-k2.7-code",
|
||||
name: "Kimi K2.7 Code",
|
||||
|
||||
@@ -2,8 +2,8 @@ import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadGitHubCopilotOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { loadGitHubCopilotOAuth } from "../utils/oauth/load.ts";
|
||||
import { GITHUB_COPILOT_MODELS } from "./github-copilot.models.ts";
|
||||
|
||||
export function githubCopilotProvider(): Provider<"anthropic-messages" | "openai-completions" | "openai-responses"> {
|
||||
@@ -16,6 +16,15 @@ export function githubCopilotProvider(): Provider<"anthropic-messages" | "openai
|
||||
oauth: lazyOAuth({ name: "GitHub Copilot", load: loadGitHubCopilotOAuth }),
|
||||
},
|
||||
models: Object.values(GITHUB_COPILOT_MODELS),
|
||||
filterModels: (models, credential) => {
|
||||
if (credential?.type !== "oauth") return models;
|
||||
const availableModelIds = credential.availableModelIds;
|
||||
if (!Array.isArray(availableModelIds) || !availableModelIds.every((id) => typeof id === "string")) {
|
||||
return models;
|
||||
}
|
||||
const available = new Set(availableModelIds);
|
||||
return models.filter((model) => available.has(model.id));
|
||||
},
|
||||
api: {
|
||||
"anthropic-messages": anthropicMessagesApi(),
|
||||
"openai-completions": openAICompletionsApi(),
|
||||
|
||||
@@ -12,16 +12,71 @@ const VERTEX_ADC_PATH = "~/.config/gcloud/application_default_credentials.json";
|
||||
*/
|
||||
const vertexAuth: ApiKeyAuth = {
|
||||
name: "Google Cloud credentials",
|
||||
login: async (interaction) => {
|
||||
const method = await interaction.prompt({
|
||||
type: "select",
|
||||
message: "Select Google Vertex AI authentication method:",
|
||||
options: [
|
||||
{ id: "api-key", label: "Google Cloud API key" },
|
||||
{ id: "adc", label: "Application Default Credentials" },
|
||||
{ id: "service-account", label: "Service account credentials file" },
|
||||
],
|
||||
});
|
||||
if (method === "api-key") {
|
||||
return {
|
||||
type: "api_key",
|
||||
key: await interaction.prompt({ type: "secret", message: "Enter Google Cloud API key" }),
|
||||
};
|
||||
}
|
||||
if (method !== "adc" && method !== "service-account") {
|
||||
throw new Error(`Unknown Google Vertex AI auth method: ${method}`);
|
||||
}
|
||||
interaction.notify({
|
||||
type: "info",
|
||||
message:
|
||||
method === "adc"
|
||||
? "Run `gcloud auth application-default login`, then provide the project and location."
|
||||
: "Provide a service account credentials file, project, and location.",
|
||||
links: [
|
||||
{
|
||||
label: "Application Default Credentials",
|
||||
url: "https://cloud.google.com/docs/authentication/provide-credentials-adc",
|
||||
},
|
||||
],
|
||||
});
|
||||
const project = await interaction.prompt({ type: "text", message: "Enter Google Cloud project ID" });
|
||||
const location = await interaction.prompt({ type: "text", message: "Enter Google Cloud location" });
|
||||
const credentialsPath =
|
||||
method === "service-account"
|
||||
? await interaction.prompt({ type: "text", message: "Enter service account credentials file path" })
|
||||
: undefined;
|
||||
return {
|
||||
type: "api_key",
|
||||
env: {
|
||||
GOOGLE_CLOUD_PROJECT: project,
|
||||
GOOGLE_CLOUD_LOCATION: location,
|
||||
...(credentialsPath ? { GOOGLE_APPLICATION_CREDENTIALS: credentialsPath } : {}),
|
||||
},
|
||||
};
|
||||
},
|
||||
resolve: async ({ ctx, credential }) => {
|
||||
const key = credential?.key ?? (await ctx.env("GOOGLE_CLOUD_API_KEY"));
|
||||
if (key) return { auth: { apiKey: key }, source: credential?.key ? "stored credential" : "GOOGLE_CLOUD_API_KEY" };
|
||||
|
||||
const adcPath = await ctx.env("GOOGLE_APPLICATION_CREDENTIALS");
|
||||
const adcPath =
|
||||
credential?.env?.GOOGLE_APPLICATION_CREDENTIALS ?? (await ctx.env("GOOGLE_APPLICATION_CREDENTIALS"));
|
||||
const hasCredentials = await ctx.fileExists(adcPath ?? VERTEX_ADC_PATH);
|
||||
const hasProject = Boolean((await ctx.env("GOOGLE_CLOUD_PROJECT")) ?? (await ctx.env("GCLOUD_PROJECT")));
|
||||
const hasLocation = Boolean(await ctx.env("GOOGLE_CLOUD_LOCATION"));
|
||||
if (hasCredentials && hasProject && hasLocation) {
|
||||
return { auth: {}, source: "gcloud application default credentials" };
|
||||
const project =
|
||||
credential?.env?.GOOGLE_CLOUD_PROJECT ??
|
||||
(await ctx.env("GOOGLE_CLOUD_PROJECT")) ??
|
||||
(await ctx.env("GCLOUD_PROJECT"));
|
||||
const location = credential?.env?.GOOGLE_CLOUD_LOCATION ?? (await ctx.env("GOOGLE_CLOUD_LOCATION"));
|
||||
if (hasCredentials && project && location) {
|
||||
return {
|
||||
auth: {},
|
||||
env: credential?.env,
|
||||
source: credential ? "stored credential" : "gcloud application default credentials",
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { openAICodexResponsesApi } from "../api/openai-codex-responses.lazy.ts";
|
||||
import { lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadOpenAICodexOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { loadOpenAICodexOAuth } from "../utils/oauth/load.ts";
|
||||
import { OPENAI_CODEX_MODELS } from "./openai-codex.models.ts";
|
||||
|
||||
export function openaiCodexProvider(): Provider<"openai-codex-responses"> {
|
||||
|
||||
@@ -667,6 +667,23 @@ export const OPENAI_MODELS = {
|
||||
contextWindow: 272000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-realtime-2.1": {
|
||||
id: "gpt-realtime-2.1",
|
||||
name: "GPT-Realtime-2.1",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 4,
|
||||
output: 24,
|
||||
cacheRead: 0.4,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 32000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"o1": {
|
||||
id: "o1",
|
||||
name: "o1",
|
||||
|
||||
@@ -674,6 +674,60 @@ export const OPENCODE_MODELS = {
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-luna": {
|
||||
id: "gpt-5.6-luna",
|
||||
name: "GPT-5.6 Luna",
|
||||
api: "openai-responses",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 6,
|
||||
cacheRead: 0.1,
|
||||
cacheWrite: 1.25,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-sol": {
|
||||
id: "gpt-5.6-sol",
|
||||
name: "GPT-5.6 Sol",
|
||||
api: "openai-responses",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 5,
|
||||
output: 30,
|
||||
cacheRead: 0.5,
|
||||
cacheWrite: 6.25,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"gpt-5.6-terra": {
|
||||
id: "gpt-5.6-terra",
|
||||
name: "GPT-5.6 Terra",
|
||||
api: "openai-responses",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
reasoning: true,
|
||||
thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2.5,
|
||||
output: 15,
|
||||
cacheRead: 0.25,
|
||||
cacheWrite: 3.125,
|
||||
},
|
||||
contextWindow: 1050000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-responses">,
|
||||
"grok-4.5": {
|
||||
id: "grok-4.5",
|
||||
name: "Grok 4.5",
|
||||
@@ -726,7 +780,7 @@ export const OPENCODE_MODELS = {
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
contextWindow: 190000,
|
||||
maxTokens: 64000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"kimi-k2.5": {
|
||||
|
||||
@@ -461,24 +461,6 @@ export const OPENROUTER_MODELS = {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"arcee-ai/trinity-mini": {
|
||||
id: "arcee-ai/trinity-mini",
|
||||
name: "Arcee AI: Trinity Mini",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.045,
|
||||
output: 0.15,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"arcee-ai/virtuoso-large": {
|
||||
id: "arcee-ai/virtuoso-large",
|
||||
name: "Arcee AI: Virtuoso Large",
|
||||
@@ -687,8 +669,8 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.21,
|
||||
output: 0.79,
|
||||
input: 0.25,
|
||||
output: 0.95,
|
||||
cacheRead: 0.13,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -759,9 +741,9 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.2288,
|
||||
output: 0.3432,
|
||||
cacheRead: 0.02288,
|
||||
input: 0.2145,
|
||||
output: 0.32175,
|
||||
cacheRead: 0.02145,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
@@ -1121,13 +1103,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.12,
|
||||
input: 0.06,
|
||||
output: 0.35,
|
||||
cacheRead: 0.09,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
maxTokens: 8192,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"google/gemma-4-31b-it:free": {
|
||||
id: "google/gemma-4-31b-it:free",
|
||||
@@ -1145,7 +1127,7 @@ export const OPENROUTER_MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 8192,
|
||||
maxTokens: 32768,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"ibm-granite/granite-4.1-8b": {
|
||||
id: "ibm-granite/granite-4.1-8b",
|
||||
@@ -1238,6 +1220,24 @@ export const OPENROUTER_MODELS = {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"kwaipilot/kat-coder-air-v2.5": {
|
||||
id: "kwaipilot/kat-coder-air-v2.5",
|
||||
name: "Kwaipilot: KAT-Coder-Air V2.5",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"},
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.15,
|
||||
output: 0.6,
|
||||
cacheRead: 0.03,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"kwaipilot/kat-coder-pro-v2": {
|
||||
id: "kwaipilot/kat-coder-pro-v2",
|
||||
name: "Kwaipilot: KAT-Coder-Pro V2",
|
||||
@@ -1256,23 +1256,23 @@ export const OPENROUTER_MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"liquid/lfm-2.5-1.2b-thinking:free": {
|
||||
id: "liquid/lfm-2.5-1.2b-thinking:free",
|
||||
name: "LiquidAI: LFM2.5-1.2B-Thinking (free)",
|
||||
"kwaipilot/kat-coder-pro-v2.5": {
|
||||
id: "kwaipilot/kat-coder-pro-v2.5",
|
||||
name: "Kwaipilot: KAT-Coder-Pro V2.5",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter"},
|
||||
reasoning: true,
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
input: 0.74,
|
||||
output: 2.96,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 32768,
|
||||
maxTokens: 4096,
|
||||
contextWindow: 256000,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.1-70b-instruct": {
|
||||
id: "meta-llama/llama-3.1-70b-instruct",
|
||||
@@ -1356,8 +1356,8 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.15,
|
||||
output: 0.6,
|
||||
input: 0.2,
|
||||
output: 0.8,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -1878,9 +1878,9 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.65,
|
||||
input: 0.66,
|
||||
output: 3.41,
|
||||
cacheRead: 0.14,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
@@ -1896,9 +1896,9 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.72,
|
||||
input: 0.719,
|
||||
output: 3.49,
|
||||
cacheRead: 0.159,
|
||||
cacheRead: 0.149,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
@@ -2456,11 +2456,11 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 0.05,
|
||||
output: 0.4,
|
||||
cacheRead: 0.01,
|
||||
cacheRead: 0.005,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 400000,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-5-pro": {
|
||||
id: "openai/gpt-5-pro",
|
||||
@@ -2492,7 +2492,7 @@ export const OPENROUTER_MODELS = {
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 10,
|
||||
cacheRead: 0.13,
|
||||
cacheRead: 0.125,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 400000,
|
||||
@@ -2976,26 +2976,8 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.036,
|
||||
output: 0.18,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-oss-120b:free": {
|
||||
id: "openai/gpt-oss-120b:free",
|
||||
name: "OpenAI: gpt-oss-120b (free)",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
compat: {"thinkingFormat":"openrouter"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
input: 0.03,
|
||||
output: 0.15,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -3481,7 +3463,7 @@ export const OPENROUTER_MODELS = {
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.09,
|
||||
output: 0.1,
|
||||
output: 0.55,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -4074,13 +4056,13 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.285,
|
||||
input: 0.289,
|
||||
output: 2.4,
|
||||
cacheRead: 0.15,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262140,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.6-35b-a3b": {
|
||||
id: "qwen/qwen3.6-35b-a3b",
|
||||
@@ -4561,12 +4543,12 @@ export const OPENROUTER_MODELS = {
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.43,
|
||||
output: 1.74,
|
||||
output: 1.75,
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 202752,
|
||||
maxTokens: 131072,
|
||||
contextWindow: 200000,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-4.6v": {
|
||||
id: "z-ai/glm-4.6v",
|
||||
@@ -4638,7 +4620,7 @@ export const OPENROUTER_MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 202752,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5-turbo": {
|
||||
id: "z-ai/glm-5-turbo",
|
||||
@@ -4687,13 +4669,13 @@ export const OPENROUTER_MODELS = {
|
||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.54,
|
||||
output: 1.76,
|
||||
cacheRead: 0.1,
|
||||
input: 0.924,
|
||||
output: 2.904,
|
||||
cacheRead: 0.1716,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 101376,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5v-turbo": {
|
||||
id: "z-ai/glm-5v-turbo",
|
||||
@@ -4831,9 +4813,9 @@ export const OPENROUTER_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.65,
|
||||
input: 0.66,
|
||||
output: 3.41,
|
||||
cacheRead: 0.14,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
|
||||
@@ -497,23 +497,6 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 200000,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-3.5-haiku": {
|
||||
id: "anthropic/claude-3.5-haiku",
|
||||
name: "Claude 3.5 Haiku",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.8,
|
||||
output: 4,
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 1,
|
||||
},
|
||||
contextWindow: 200000,
|
||||
maxTokens: 8192,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-fable-5": {
|
||||
id: "anthropic/claude-fable-5",
|
||||
name: "Claude Fable 5",
|
||||
@@ -565,7 +548,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
cacheWrite: 18.75,
|
||||
},
|
||||
contextWindow: 200000,
|
||||
maxTokens: 32000,
|
||||
maxTokens: 8192,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-opus-4.1": {
|
||||
id: "anthropic/claude-opus-4.1",
|
||||
@@ -673,7 +656,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
cacheWrite: 3.75,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 64000,
|
||||
maxTokens: 8192,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"anthropic/claude-sonnet-4.5": {
|
||||
id: "anthropic/claude-sonnet-4.5",
|
||||
@@ -730,23 +713,6 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"arcee-ai/trinity-large-preview": {
|
||||
id: "arcee-ai/trinity-large-preview",
|
||||
name: "Trinity Large Preview",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.25,
|
||||
output: 1,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131000,
|
||||
maxTokens: 131000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"arcee-ai/trinity-large-thinking": {
|
||||
id: "arcee-ai/trinity-large-thinking",
|
||||
name: "Trinity Large Thinking",
|
||||
@@ -875,12 +841,12 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.6,
|
||||
output: 1.7,
|
||||
cacheRead: 0,
|
||||
input: 0.21,
|
||||
output: 0.79,
|
||||
cacheRead: 0.13,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
contextWindow: 163840,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"deepseek/deepseek-v3.1-terminus": {
|
||||
@@ -945,7 +911,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
cost: {
|
||||
input: 0.14,
|
||||
output: 0.28,
|
||||
cacheRead: 0.0028,
|
||||
cacheRead: 0.028,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
@@ -1206,6 +1172,23 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 32000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"kwaipilot/kat-coder-air-v2.5": {
|
||||
id: "kwaipilot/kat-coder-air-v2.5",
|
||||
name: "Kat Coder Air V2.5",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.15,
|
||||
output: 0.6,
|
||||
cacheRead: 0.03,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"kwaipilot/kat-coder-pro-v1": {
|
||||
id: "kwaipilot/kat-coder-pro-v1",
|
||||
name: "KAT-Coder-Pro V1",
|
||||
@@ -1240,39 +1223,22 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"meituan/longcat-flash-chat": {
|
||||
id: "meituan/longcat-flash-chat",
|
||||
name: "LongCat Flash Chat",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 100000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"meituan/longcat-flash-thinking-2601": {
|
||||
id: "meituan/longcat-flash-thinking-2601",
|
||||
name: "LongCat Flash Thinking 2601",
|
||||
"kwaipilot/kat-coder-pro-v2.5": {
|
||||
id: "kwaipilot/kat-coder-pro-v2.5",
|
||||
name: "Kat Coder Pro V2.5",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
input: 0.74,
|
||||
output: 2.96,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 32768,
|
||||
maxTokens: 32768,
|
||||
contextWindow: 256000,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"meta/llama-3.1-70b": {
|
||||
id: "meta/llama-3.1-70b",
|
||||
@@ -1400,7 +1366,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1.25,
|
||||
output: 4.25,
|
||||
@@ -1580,23 +1546,6 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mistral/devstral-small": {
|
||||
id: "mistral/devstral-small",
|
||||
name: "Devstral Small 1.1",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.1,
|
||||
output: 0.3,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 64000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mistral/devstral-small-2": {
|
||||
id: "mistral/devstral-small-2",
|
||||
name: "Devstral Small 2",
|
||||
@@ -1801,23 +1750,6 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 128000,
|
||||
maxTokens: 4000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mistral/pixtral-large": {
|
||||
id: "mistral/pixtral-large",
|
||||
name: "Pixtral Large",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 128000,
|
||||
maxTokens: 4000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"moonshotai/kimi-k2": {
|
||||
id: "moonshotai/kimi-k2",
|
||||
name: "Kimi K2 Instruct",
|
||||
@@ -2972,40 +2904,6 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"xiaomi/mimo-v2-flash": {
|
||||
id: "xiaomi/mimo-v2-flash",
|
||||
name: "MiMo V2 Flash",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.1,
|
||||
output: 0.3,
|
||||
cacheRead: 0.01,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"xiaomi/mimo-v2-pro": {
|
||||
id: "xiaomi/mimo-v2-pro",
|
||||
name: "MiMo V2 Pro",
|
||||
api: "anthropic-messages",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 3,
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"xiaomi/mimo-v2.5": {
|
||||
id: "xiaomi/mimo-v2.5",
|
||||
name: "MiMo M2.5",
|
||||
@@ -3270,9 +3168,9 @@ export const VERCEL_AI_GATEWAY_MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 3,
|
||||
output: 10.25,
|
||||
cacheRead: 0.5,
|
||||
input: 2.1,
|
||||
output: 6.6,
|
||||
cacheRead: 0.21,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
|
||||
Reference in New Issue
Block a user