feat(ai): add github-copilot gpt-5.3-codex fallback closes #1853

This commit is contained in:
Mario Zechner 2026-03-05 21:47:52 +01:00
parent 8fc2b76827
commit 8f2af2ae7e
3 changed files with 145 additions and 48 deletions

View file

@ -844,6 +844,20 @@ async function generateModels() {
}); });
} }
// Add missing GitHub Copilot GPT-5.3 models until models.dev includes them.
const copilotBaseModel = allModels.find(
(m) => m.provider === "github-copilot" && m.id === "gpt-5.2-codex",
);
if (copilotBaseModel) {
if (!allModels.some((m) => m.provider === "github-copilot" && m.id === "gpt-5.3-codex")) {
allModels.push({
...copilotBaseModel,
id: "gpt-5.3-codex",
name: "GPT-5.3 Codex",
});
}
}
// OpenAI Codex (ChatGPT OAuth) models // OpenAI Codex (ChatGPT OAuth) models
// NOTE: These are not fetched from models.dev; we keep a small, explicit list to avoid aliases. // NOTE: These are not fetched from models.dev; we keep a small, explicit list to avoid aliases.
// Context window is based on observed server limits (400s above ~272k), not marketing numbers. // Context window is based on observed server limits (400s above ~272k), not marketing numbers.

View file

@ -2861,6 +2861,24 @@ export const MODELS = {
contextWindow: 272000, contextWindow: 272000,
maxTokens: 128000, maxTokens: 128000,
} satisfies Model<"openai-responses">, } satisfies Model<"openai-responses">,
"gpt-5.3-codex": {
id: "gpt-5.3-codex",
name: "GPT-5.3 Codex",
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,
input: ["text", "image"],
cost: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 272000,
maxTokens: 128000,
} satisfies Model<"openai-responses">,
"grok-code-fast-1": { "grok-code-fast-1": {
id: "grok-code-fast-1", id: "grok-code-fast-1",
name: "Grok Code Fast 1", name: "Grok Code Fast 1",
@ -6086,6 +6104,23 @@ export const MODELS = {
contextWindow: 400000, contextWindow: 400000,
maxTokens: 128000, maxTokens: 128000,
} satisfies Model<"openai-responses">, } satisfies Model<"openai-responses">,
"gpt-5.4": {
id: "gpt-5.4",
name: "GPT-5.4",
api: "openai-responses",
provider: "opencode",
baseUrl: "https://opencode.ai/zen/v1",
reasoning: true,
input: ["text", "image"],
cost: {
input: 2.5,
output: 15,
cacheRead: 0.25,
cacheWrite: 0,
},
contextWindow: 1050000,
maxTokens: 128000,
} satisfies Model<"openai-responses">,
"kimi-k2.5": { "kimi-k2.5": {
id: "kimi-k2.5", id: "kimi-k2.5",
name: "Kimi K2.5", name: "Kimi K2.5",
@ -6154,23 +6189,6 @@ export const MODELS = {
contextWindow: 204800, contextWindow: 204800,
maxTokens: 131072, maxTokens: 131072,
} satisfies Model<"anthropic-messages">, } satisfies Model<"anthropic-messages">,
"trinity-large-preview-free": {
id: "trinity-large-preview-free",
name: "Trinity Large Preview",
api: "openai-completions",
provider: "opencode",
baseUrl: "https://opencode.ai/zen/v1",
reasoning: false,
input: ["text"],
cost: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 131072,
maxTokens: 131072,
} satisfies Model<"openai-completions">,
}, },
"opencode-go": { "opencode-go": {
"glm-5": { "glm-5": {
@ -7227,7 +7245,24 @@ export const MODELS = {
cacheWrite: 0, cacheWrite: 0,
}, },
contextWindow: 128000, contextWindow: 128000,
maxTokens: 16384, maxTokens: 32000,
} satisfies Model<"openai-completions">,
"inception/mercury-2": {
id: "inception/mercury-2",
name: "Inception: Mercury 2",
api: "openai-completions",
provider: "openrouter",
baseUrl: "https://openrouter.ai/api/v1",
reasoning: true,
input: ["text"],
cost: {
input: 0.25,
output: 0.75,
cacheRead: 0.024999999999999998,
cacheWrite: 0,
},
contextWindow: 128000,
maxTokens: 50000,
} satisfies Model<"openai-completions">, } satisfies Model<"openai-completions">,
"inception/mercury-coder": { "inception/mercury-coder": {
id: "inception/mercury-coder", id: "inception/mercury-coder",
@ -7244,7 +7279,7 @@ export const MODELS = {
cacheWrite: 0, cacheWrite: 0,
}, },
contextWindow: 128000, contextWindow: 128000,
maxTokens: 16384, maxTokens: 32000,
} satisfies Model<"openai-completions">, } satisfies Model<"openai-completions">,
"kwaipilot/kat-coder-pro": { "kwaipilot/kat-coder-pro": {
id: "kwaipilot/kat-coder-pro", id: "kwaipilot/kat-coder-pro",
@ -7952,13 +7987,13 @@ export const MODELS = {
reasoning: true, reasoning: true,
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 0.44999999999999996, input: 0.41,
output: 2.2, output: 2.06,
cacheRead: 0.22499999999999998, cacheRead: 0.07,
cacheWrite: 0, cacheWrite: 0,
}, },
contextWindow: 262144, contextWindow: 262144,
maxTokens: 65535, maxTokens: 4096,
} satisfies Model<"openai-completions">, } satisfies Model<"openai-completions">,
"nex-agi/deepseek-v3.1-nex-n1": { "nex-agi/deepseek-v3.1-nex-n1": {
id: "nex-agi/deepseek-v3.1-nex-n1", id: "nex-agi/deepseek-v3.1-nex-n1",
@ -8725,6 +8760,40 @@ export const MODELS = {
contextWindow: 400000, contextWindow: 400000,
maxTokens: 128000, maxTokens: 128000,
} satisfies Model<"openai-completions">, } satisfies Model<"openai-completions">,
"openai/gpt-5.4": {
id: "openai/gpt-5.4",
name: "OpenAI: GPT-5.4",
api: "openai-completions",
provider: "openrouter",
baseUrl: "https://openrouter.ai/api/v1",
reasoning: true,
input: ["text", "image"],
cost: {
input: 2.5,
output: 15,
cacheRead: 0.25,
cacheWrite: 0,
},
contextWindow: 1050000,
maxTokens: 128000,
} satisfies Model<"openai-completions">,
"openai/gpt-5.4-pro": {
id: "openai/gpt-5.4-pro",
name: "OpenAI: GPT-5.4 Pro",
api: "openai-completions",
provider: "openrouter",
baseUrl: "https://openrouter.ai/api/v1",
reasoning: true,
input: ["text", "image"],
cost: {
input: 30,
output: 180,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 1050000,
maxTokens: 128000,
} satisfies Model<"openai-completions">,
"openai/gpt-oss-120b": { "openai/gpt-oss-120b": {
id: "openai/gpt-oss-120b", id: "openai/gpt-oss-120b",
name: "OpenAI: gpt-oss-120b", name: "OpenAI: gpt-oss-120b",
@ -10264,9 +10333,9 @@ export const MODELS = {
reasoning: true, reasoning: true,
input: ["text"], input: ["text"],
cost: { cost: {
input: 0.7999999999999999, input: 0.6,
output: 2.56, output: 1.9,
cacheRead: 0.16, cacheRead: 0.119,
cacheWrite: 0, cacheWrite: 0,
}, },
contextWindow: 202752, contextWindow: 202752,
@ -11974,6 +12043,40 @@ export const MODELS = {
contextWindow: 400000, contextWindow: 400000,
maxTokens: 128000, maxTokens: 128000,
} satisfies Model<"anthropic-messages">, } satisfies Model<"anthropic-messages">,
"openai/gpt-5.4": {
id: "openai/gpt-5.4",
name: "GPT 5.4",
api: "anthropic-messages",
provider: "vercel-ai-gateway",
baseUrl: "https://ai-gateway.vercel.sh",
reasoning: true,
input: ["text", "image"],
cost: {
input: 2.5,
output: 15,
cacheRead: 0.25,
cacheWrite: 0,
},
contextWindow: 1050000,
maxTokens: 128000,
} satisfies Model<"anthropic-messages">,
"openai/gpt-5.4-pro": {
id: "openai/gpt-5.4-pro",
name: "GPT 5.4 Pro",
api: "anthropic-messages",
provider: "vercel-ai-gateway",
baseUrl: "https://ai-gateway.vercel.sh",
reasoning: true,
input: ["text", "image"],
cost: {
input: 30,
output: 180,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 1050000,
maxTokens: 128000,
} satisfies Model<"anthropic-messages">,
"openai/gpt-oss-120b": { "openai/gpt-oss-120b": {
id: "openai/gpt-oss-120b", id: "openai/gpt-oss-120b",
name: "gpt-oss-120b", name: "gpt-oss-120b",

View file

@ -490,26 +490,6 @@ describe("Generate E2E Tests", () => {
}); });
}); });
describe.skipIf(!process.env.OPENAI_API_KEY)("OpenAI Responses Provider (gpt-5-mini)", () => {
const model = getModel("openai", "gpt-5-mini");
it("should complete basic text generation", { retry: 3 }, async () => {
await basicTextGeneration(model);
});
it("should handle tool calling", { retry: 3 }, async () => {
await handleToolCall(model);
});
it("should handle streaming", { retry: 3 }, async () => {
await handleStreaming(model);
});
it("should handle image input", { retry: 3 }, async () => {
await handleImage(model);
});
});
describe.skipIf(!hasAzureOpenAICredentials())("Azure OpenAI Responses Provider (gpt-4o-mini)", () => { describe.skipIf(!hasAzureOpenAICredentials())("Azure OpenAI Responses Provider (gpt-4o-mini)", () => {
const llm = getModel("azure-openai-responses", "gpt-4o-mini"); const llm = getModel("azure-openai-responses", "gpt-4o-mini");
const azureDeploymentName = resolveAzureDeploymentName(llm.id); const azureDeploymentName = resolveAzureDeploymentName(llm.id);
@ -934,8 +914,8 @@ describe("Generate E2E Tests", () => {
}); });
}); });
describe("GitHub Copilot Provider (gpt-4o via OpenAI Completions)", () => { describe("GitHub Copilot Provider (gpt-5.3-codex via OpenAI Completions)", () => {
const llm = getModel("github-copilot", "gpt-4o"); const llm = getModel("github-copilot", "gpt-5.3-codex");
it.skipIf(!githubCopilotToken)("should complete basic text generation", { retry: 3 }, async () => { it.skipIf(!githubCopilotToken)("should complete basic text generation", { retry: 3 }, async () => {
await basicTextGeneration(llm, { apiKey: githubCopilotToken }); await basicTextGeneration(llm, { apiKey: githubCopilotToken });