fix(ai,coding-agent): drop models retired upstream

models.dev deprecated several Baseten, GitHub Copilot, and Together models,
which broke type checks and the default-model test.

- Default GitHub Copilot model: gpt-5.4 -> gpt-6.1-sol
- Move Copilot live tests to gpt-6-luna/gpt-6-sol
- Remove tests and generator entries for retired models, including the
  Together reasoning-only model list
This commit is contained in:
David Brailovsky 2026-10-21 10:10:55 +02:00
parent 16f5f0af4d
commit e5fe9777b9
11 changed files with 14 additions and 93 deletions

View file

@ -189,18 +189,8 @@ const TOGETHER_TOGGLE_REASONING_EFFORT_COMPAT: OpenAICompletionsCompat = {
...TOGETHER_TOGGLE_REASONING_COMPAT,
supportsReasoningEffort: true,
};
const TOGETHER_REASONING_ONLY_MODELS = new Set([
"deepseek-ai/DeepSeek-R1",
"MiniMaxAI/MiniMax-M2.7",
]);
const TOGETHER_REASONING_EFFORT_MODELS = new Set(["openai/gpt-oss-20b", "openai/gpt-oss-120b"]);
const TOGETHER_TOGGLE_REASONING_EFFORT_MODELS = new Set(["deepseek-ai/DeepSeek-V4-Pro-0813"]);
const TOGETHER_FIXED_REASONING_LEVEL_MAP = {
off: null,
minimal: null,
low: null,
medium: null,
} as const;
const TOGETHER_REASONING_EFFORT_LEVEL_MAP = {
off: null,
minimal: null,
@ -502,16 +492,12 @@ const OPENCODE_OPENAI_COMPLETIONS_LONG_CACHE_RETENTION_UNSUPPORTED_MODELS = new
// the extended 1 million token context window.
const GITHUB_COPILOT_EXTENDED_CONTEXT_MODELS = new Set([
"claude-fable-5",
"claude-opus-4.6",
"claude-opus-4.7",
"claude-opus-4.8",
"claude-opus-5",
"claude-opus-5.5",
"claude-sonnet-4.6",
"claude-sonnet-5",
"gpt-5.3-codex",
"gpt-5.4",
"gpt-5.5",
"gpt-6-astra",
"gpt-6-luna",
"gpt-6-sol",
@ -520,7 +506,6 @@ const GITHUB_COPILOT_EXTENDED_CONTEXT_MODELS = new Set([
// Checked manually against the authenticated GitHub Copilot /models endpoint on 2026-06-15.
// Keep this to narrow corrections over models.dev metadata instead of snapshotting Copilot's catalog.
const GITHUB_COPILOT_THINKING_LEVEL_OVERRIDES = {
"claude-opus-4.7": { minimal: "low" },
"claude-opus-4.8": { minimal: "low" },
"claude-opus-5": { minimal: "low" },
"claude-sonnet-4.6": { minimal: "low", max: "max" },
@ -571,7 +556,6 @@ function getTogetherCompat(modelId: string, reasoning: boolean): OpenAICompletio
if (!reasoning) return TOGETHER_BASE_COMPAT;
if (TOGETHER_REASONING_EFFORT_MODELS.has(modelId)) return TOGETHER_REASONING_EFFORT_COMPAT;
if (TOGETHER_TOGGLE_REASONING_EFFORT_MODELS.has(modelId)) return TOGETHER_TOGGLE_REASONING_EFFORT_COMPAT;
if (TOGETHER_REASONING_ONLY_MODELS.has(modelId)) return TOGETHER_BASE_COMPAT;
return TOGETHER_TOGGLE_REASONING_COMPAT;
}
@ -582,7 +566,6 @@ function getTogetherThinkingLevelMap(
if (!reasoning) return undefined;
if (TOGETHER_REASONING_EFFORT_MODELS.has(modelId)) return { ...TOGETHER_REASONING_EFFORT_LEVEL_MAP };
if (TOGETHER_TOGGLE_REASONING_EFFORT_MODELS.has(modelId)) return { ...TOGETHER_DEEPSEEK_V4_THINKING_LEVEL_MAP };
if (TOGETHER_REASONING_ONLY_MODELS.has(modelId)) return { ...TOGETHER_FIXED_REASONING_LEVEL_MAP };
return { ...TOGETHER_TOGGLE_REASONING_LEVEL_MAP };
}
@ -739,7 +722,6 @@ function detectOpenAICompletionsCompat(model: Model<"openai-completions">): Open
const isNvidia = provider === "nvidia" || baseUrl.includes("integrate.api.nvidia.com");
const isAntLing = provider === "ant-ling" || baseUrl.includes("api.ant-ling.com");
const isCerebras = provider === "cerebras" || baseUrl.includes("cerebras.ai");
const isTogetherReasoningOnly = isTogether && TOGETHER_REASONING_ONLY_MODELS.has(model.id);
const isDeepSeek = provider === "deepseek" || baseUrl.toLowerCase().includes("deepseek.com");
const isNonStandard =
@ -790,7 +772,7 @@ function detectOpenAICompletionsCompat(model: Model<"openai-completions">): Open
? "deepseek"
: isZai
? "zai"
: isTogether && !isTogetherReasoningOnly
: isTogether
? "together"
: isAntLing
? "ant-ling"

View file

@ -1,7 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { getModel, streamSimple } from "../src/compat.ts";
import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.ts";
import { getSupportedThinkingLevels } from "../src/models.ts";
const originalBasetenApiKey = process.env.BASETEN_API_KEY;
@ -19,43 +18,6 @@ describe("Baseten models", () => {
expect(getModel("baseten", "zai-org/GLM-5.2-Fast").input).toEqual(["text"]);
});
it("models Kimi K2.6 reasoning as an explicit off/on toggle", async () => {
const model = getModel("baseten", "moonshotai/Kimi-K2.6");
let payload: Record<string, unknown> | undefined;
expect(model.thinkingLevelMap).toEqual({
off: "off",
minimal: null,
low: null,
medium: null,
high: "high",
xhigh: null,
max: null,
});
expect(model.compat).toMatchObject({
supportsReasoningEffort: false,
thinkingFormat: "baseten",
chatTemplateArgs: { enable_thinking: { $var: "thinking.enabled" } },
});
expect(getSupportedThinkingLevels(model)).toEqual(["off", "high"]);
await streamSimple(
model,
{ messages: [{ role: "user", content: "test", timestamp: 0 }] },
{
apiKey: "test-baseten-key",
reasoning: "high",
onPayload: (value) => {
payload = value as Record<string, unknown>;
throw new Error("payload captured");
},
},
).result();
expect(payload?.chat_template_args).toEqual({ enable_thinking: true });
expect(payload?.reasoning_effort).toBeUndefined();
});
it("sends Baseten chat_template_args with reasoning effort", async () => {
const model = getModel("baseten", "zai-org/GLM-5.2");
let payload: Record<string, unknown> | undefined;

View file

@ -57,11 +57,6 @@ describe("Copilot Claude via Anthropic Messages", () => {
});
it("applies Copilot-specific adaptive thinking effort overrides", () => {
const opus47 = getModel("github-copilot", "claude-opus-4.7");
expect(opus47.thinkingLevelMap).toMatchObject({ minimal: "low", xhigh: "xhigh", max: "max" });
expect(getSupportedThinkingLevels(opus47)).toContain("xhigh");
expect(getSupportedThinkingLevels(opus47)).toContain("max");
const opus5 = getModel("github-copilot", "claude-opus-5");
expect(opus5.api).toBe("anthropic-messages");
expect(opus5.contextWindow).toBe(1000000);

View file

@ -311,19 +311,6 @@ describe("Tool Results with Images", () => {
});
});
describe.skipIf(!process.env.BASETEN_API_KEY)("Baseten Provider (Kimi-K2.6)", () => {
const llm = getModel("baseten", "moonshotai/Kimi-K2.6");
const options = { reasoningEffort: "high" } satisfies StreamOptionsWithExtras;
it("should handle tool result with only image", { retry: 3, timeout: 30000 }, async () => {
await handleToolWithImageResult(llm, options);
});
it("should handle tool result with text and image", { retry: 3, timeout: 30000 }, async () => {
await handleToolWithTextAndImageResult(llm, options);
});
});
describe.skipIf(!process.env.XIAOMI_API_KEY)("Xiaomi MiMo (API billing) Provider (mimo-v2.6-pro)", () => {
const llm = getModel("xiaomi", "mimo-v2.6-pro");

View file

@ -72,8 +72,9 @@ describe("openai-responses provider defaults", () => {
vi.restoreAllMocks();
});
// #2567: Copilot rejected reasoning.effort "none". gpt-6-sol has off: "none", so this exercises the Copilot exception.
it("omits reasoning when no reasoning is requested", async () => {
const model = getModel("github-copilot", "gpt-5-mini");
const model = getModel("github-copilot", "gpt-6-sol");
let capturedPayload: unknown;
vi.spyOn(globalThis, "fetch").mockResolvedValue(

View file

@ -162,8 +162,8 @@ describe("Responses API tool result images", () => {
});
});
describe("GitHub Copilot Responses Provider (gpt-5-mini)", () => {
const model = getModel("github-copilot", "gpt-5-mini");
describe("GitHub Copilot Responses Provider (gpt-6-luna)", () => {
const model = getModel("github-copilot", "gpt-6-luna");
it.skipIf(!githubCopilotToken)(
"should send tool result images in function_call_output",

View file

@ -1395,8 +1395,8 @@ describe("Generate E2E Tests", () => {
});
});
describe("GitHub Copilot Provider (gpt-5.3-codex via OpenAI Completions)", () => {
const llm = getModel("github-copilot", "gpt-5.3-codex");
describe("GitHub Copilot Provider (gpt-6-luna via OpenAI Responses)", () => {
const llm = getModel("github-copilot", "gpt-6-luna");
it.skipIf(!githubCopilotToken)("should complete basic text generation", { retry: 3 }, async () => {
await basicTextGeneration(llm, { apiKey: githubCopilotToken });
@ -1411,13 +1411,11 @@ describe("Generate E2E Tests", () => {
});
it.skipIf(!githubCopilotToken)("should handle thinking", { retry: 2 }, async () => {
const thinkingModel = getModel("github-copilot", "gpt-5-mini");
await handleThinking(thinkingModel, { apiKey: githubCopilotToken, reasoningEffort: "high" });
await handleThinking(llm, { apiKey: githubCopilotToken, reasoningEffort: "high" });
});
it.skipIf(!githubCopilotToken)("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
const thinkingModel = getModel("github-copilot", "gpt-5-mini");
await multiTurn(thinkingModel, { apiKey: githubCopilotToken, reasoningEffort: "high" });
await multiTurn(llm, { apiKey: githubCopilotToken, reasoningEffort: "high" });
});
it.skipIf(!githubCopilotToken)("should handle image input", { retry: 3 }, async () => {

View file

@ -70,11 +70,6 @@ describe("Together models", () => {
supportsReasoningEffort: true,
thinkingFormat: "together",
});
const minimax = getModel("together", "MiniMaxAI/MiniMax-M2.7");
expect(minimax.thinkingLevelMap).toEqual({ off: null, minimal: null, low: null, medium: null });
expect(minimax.compat?.thinkingFormat).toBeUndefined();
expect(minimax.compat?.supportsReasoningEffort).toBe(false);
});
it("resolves TOGETHER_API_KEY from the environment", () => {

View file

@ -35,7 +35,7 @@ const echoTool: Tool<typeof echoToolSchema> = {
/**
* Test 1: Live cross-provider handoff
*
* 1. Use github-copilot gpt-5.5 to generate a tool call
* 1. Use github-copilot gpt-6-luna to generate a tool call
* 2. Switch to openrouter openai/gpt-5.5 and complete
* 3. Switch to openai-codex gpt-6.1-sol and complete
*
@ -45,7 +45,7 @@ describe("Tool Call ID Normalization - Live Handoff", () => {
it.skipIf(!copilotToken || !openrouterKey)(
"github-copilot -> openrouter should normalize pipe-separated IDs",
async () => {
const copilotModel = getModel("github-copilot", "gpt-5.5");
const copilotModel = getModel("github-copilot", "gpt-6-luna");
const openrouterModel = getModel("openrouter", "openai/gpt-5.5");
// Step 1: Generate tool call with github-copilot
@ -115,7 +115,7 @@ describe("Tool Call ID Normalization - Live Handoff", () => {
it.skipIf(!copilotToken || !codexToken)(
"github-copilot -> openai-codex should normalize pipe-separated IDs",
async () => {
const copilotModel = getModel("github-copilot", "gpt-5.5");
const copilotModel = getModel("github-copilot", "gpt-6-luna");
const codexModel = getModel("openai-codex", "gpt-6.1-sol");
// Step 1: Generate tool call with github-copilot

View file

@ -9,6 +9,7 @@
### Changed
- `generateSummary()` and `generateSummaryWithUsage()` now ignore their `reserveTokens` parameter. Summary requests use the model's output limit instead.
- Changed the default GitHub Copilot model from `gpt-5.4`, which Copilot retired, to `gpt-6.1-sol`.
### Fixed

View file

@ -29,7 +29,7 @@ export const defaultModelPerProvider: Partial<Record<KnownProvider, string>> = {
deepseek: "deepseek-v4-pro",
google: "gemini-3.1-pro-preview",
"google-vertex": "gemini-3.1-pro-preview",
"github-copilot": "gpt-5.4",
"github-copilot": "gpt-6.1-sol",
openrouter: "moonshotai/kimi-k2.6",
"vercel-ai-gateway": "zai/glm-5.1",
xai: "grok-4.7",