| author | |
| committer | |
| log | fd25c42ae6e56a82be7219950a746572b1c4d0e9 |
| tree | 843cf5e9cfc7813ba0f939feadfbd5ee940583c5 |
| parent | 805967a878e6804d58c151f29d2a3d0a06828fd1 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>5 files changed, 59 insertions(+), 13 deletions(-)
apps/server/src/provider/Drivers/AntigravityDriver.test.ts+1-3| ... | ... | @@ -325,9 +325,7 @@ it.layer(layerTest)("AntigravityDriver", (it) => { |
| 325 | 325 | "gemini-test-high", |
| 326 | 326 | ]); |
| 327 | 327 | expect(snapshot.models[0]?.aliases).toContain(ANTIGRAVITY_DEFAULT_MODEL); |
| 328 | // The mock catalog is not in the manifest's current list, so it folds | |
| 329 | // under the legacy section like an old Codex model would. | |
| 330 | expect(snapshot.models.every((model) => model.isLegacy === true)).toBe(true); | |
| 328 | expect(snapshot.models.every((model) => model.isLegacy !== true)).toBe(true); | |
| 331 | 329 | expect(snapshot.slashCommands.map((command) => command.name)).toEqual(["plan", "logout"]); |
| 332 | 330 | expect(snapshot.supportsTextGeneration).toBe(true); |
| 333 | 331 | h.controls.selected = h.second; |
apps/server/src/provider/Drivers/AntigravityDriver.ts-3| ... | ... | @@ -150,9 +150,6 @@ export const AntigravityDriver: ProviderDriver<AntigravitySettings, AntigravityD |
| 150 | 150 | accentColor, |
| 151 | 151 | continuationGroupKey: continuationIdentity.continuationKey, |
| 152 | 152 | }); |
| 153 | // Google returns every model the account can use, including older | |
| 154 | // Gemini generations. The manifest names the current ones so the picker | |
| 155 | // folds the rest under its legacy section, as it does for Codex. | |
| 156 | 153 | const classifyModels = (draft: ServerProviderDraft) => |
| 157 | 154 | modelManifest.current.pipe( |
| 158 | 155 | Effect.map((manifest) => |
apps/server/src/provider/ModelManifest.test.ts+29-1| ... | ... | @@ -34,6 +34,12 @@ describe("classifyModels", () => { |
| 34 | 34 | const manifest: ModelManifest.ModelManifestData = { |
| 35 | 35 | version: 1, |
| 36 | 36 | currentModels: { codex: ["gpt-test"] }, |
| 37 | providers: { | |
| 38 | codex: { | |
| 39 | profiles: {}, | |
| 40 | models: [{ slug: "gpt-old", name: "Old", status: "legacy" }], | |
| 41 | }, | |
| 42 | }, | |
| 37 | 43 | }; |
| 38 | 44 | const models = [ |
| 39 | 45 | model({ slug: "openai.gpt-test", isLegacy: true }), |
| ... | ... | @@ -50,16 +56,23 @@ describe("classifyModels", () => { |
| 50 | 56 | ], |
| 51 | 57 | ); |
| 52 | 58 | }); |
| 53 | it("flags non-current models, clears stale flags, and skips custom models", () => { | |
| 59 | it("flags only known legacy models, clears stale flags, and skips custom models", () => { | |
| 54 | 60 | const manifest: ModelManifest.ModelManifestData = { |
| 55 | 61 | version: 1, |
| 56 | 62 | currentModels: { codex: ["current-a", "current-b"] }, |
| 63 | providers: { | |
| 64 | codex: { | |
| 65 | profiles: {}, | |
| 66 | models: [{ slug: "old-model", name: "Old", status: "legacy" }], | |
| 67 | }, | |
| 68 | }, | |
| 57 | 69 | }; |
| 58 | 70 | const models = [ |
| 59 | 71 | model({ slug: "current-a" }), |
| 60 | 72 | // Stale flag from a previous classification pass must be cleared. |
| 61 | 73 | model({ slug: "current-b", isLegacy: true }), |
| 62 | 74 | model({ slug: "old-model" }), |
| 75 | model({ slug: "new-release", isLegacy: true }), | |
| 63 | 76 | // Custom models are user-defined and never reclassified. |
| 64 | 77 | model({ slug: "my-own-model", isCustom: true }), |
| 65 | 78 | ]; |
| ... | ... | @@ -72,10 +85,25 @@ describe("classifyModels", () => { |
| 72 | 85 | ["current-a", false], |
| 73 | 86 | ["current-b", false], |
| 74 | 87 | ["old-model", true], |
| 88 | ["new-release", false], | |
| 75 | 89 | ["my-own-model", false], |
| 76 | 90 | ], |
| 77 | 91 | ); |
| 78 | 92 | }); |
| 93 | it.each(["codex", "antigravity"])( | |
| 94 | "keeps newly discovered %s models current when the manifest has no catalog", | |
| 95 | (driverKind) => { | |
| 96 | const models = [model({ slug: "new-release", isLegacy: true })]; | |
| 97 | assert.deepStrictEqual( | |
| 98 | ModelManifest.classifyModels( | |
| 99 | models, | |
| 100 | { version: 1, currentModels: { [driverKind]: ["known-current"] } }, | |
| 101 | ProviderDriverKind.make(driverKind), | |
| 102 | ), | |
| 103 | [model({ slug: "new-release" })], | |
| 104 | ); | |
| 105 | }, | |
| 106 | ); | |
| 79 | 107 | }); |
| 80 | 108 | |
| 81 | 109 | describe("applyManifestDefault", () => { |
apps/server/src/provider/ModelManifest.ts+1-4| ... | ... | @@ -221,10 +221,7 @@ function isLegacyModel( |
| 221 | 221 | const catalogModel = |
| 222 | 222 | catalog?.find((model) => model.slug === slug) ?? |
| 223 | 223 | catalog?.find((model) => model.slug === family); |
| 224 | if (catalogModel) return catalogModel.status === "legacy"; | |
| 225 | const currentModels = manifest.currentModels[driverKind]; | |
| 226 | if (!currentModels) return false; | |
| 227 | return !currentModels.includes(slug) && !currentModels.includes(family); | |
| 224 | return catalogModel?.status === "legacy"; | |
| 228 | 225 | } |
| 229 | 226 | |
| 230 | 227 | /** |
apps/server/src/provider/model-manifest.json+28-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | { |
| 2 | 2 | "version": 1, |
| 3 | "updatedAt": "2026-10-07T19:00:00Z", | |
| 3 | "updatedAt": "2026-10-08T14:44:57Z", | |
| 4 | 4 | "compatibility": [ |
| 5 | 5 | { |
| 6 | 6 | "driver": "codex", |
| ... | ... | @@ -109,6 +109,16 @@ |
| 109 | 109 | "antigravity": ["gemini-3.8-flash-high", "gemini-3.8-flash-medium", "gemini-3.8-flash-low"] |
| 110 | 110 | }, |
| 111 | 111 | "providers": { |
| 112 | "codex": { | |
| 113 | "profiles": {}, | |
| 114 | "models": [ | |
| 115 | { "slug": "gpt-6-sol", "name": "GPT-6 Sol", "status": "legacy" }, | |
| 116 | { "slug": "gpt-5.6-sol", "name": "GPT-5.6 Sol", "status": "legacy" }, | |
| 117 | { "slug": "gpt-5.6-terra", "name": "GPT-5.6 Terra", "status": "legacy" }, | |
| 118 | { "slug": "gpt-5.6-luna", "name": "GPT-5.6 Luna", "status": "legacy" }, | |
| 119 | { "slug": "gpt-5.5", "name": "GPT-5.5", "status": "legacy" } | |
| 120 | ] | |
| 121 | }, | |
| 112 | 122 | "claudeAgent": { |
| 113 | 123 | "defaults": { |
| 114 | 124 | "chat": "claude-fable-5-1" |
| ... | ... | @@ -777,7 +787,23 @@ |
| 777 | 787 | "slug": "gemini-3.8-flash-low", |
| 778 | 788 | "name": "Gemini 3.8 Flash (Low)", |
| 779 | 789 | "status": "current" |
| 780 | } | |
| 790 | }, | |
| 791 | { "slug": "gemini-3.7-flash-high", "name": "Gemini 3.7 Flash (High)", "status": "legacy" }, | |
| 792 | { | |
| 793 | "slug": "gemini-3.7-flash-medium", | |
| 794 | "name": "Gemini 3.7 Flash (Medium)", | |
| 795 | "status": "legacy" | |
| 796 | }, | |
| 797 | { "slug": "gemini-3.7-flash-low", "name": "Gemini 3.7 Flash (Low)", "status": "legacy" }, | |
| 798 | { "slug": "gemini-3.6-flash-high", "name": "Gemini 3.6 Flash (High)", "status": "legacy" }, | |
| 799 | { | |
| 800 | "slug": "gemini-3.6-flash-medium", | |
| 801 | "name": "Gemini 3.6 Flash (Medium)", | |
| 802 | "status": "legacy" | |
| 803 | }, | |
| 804 | { "slug": "gemini-3.6-flash-low", "name": "Gemini 3.6 Flash (Low)", "status": "legacy" }, | |
| 805 | { "slug": "gemini-pro-agent", "name": "Gemini 3.1 Pro (High)", "status": "legacy" }, | |
| 806 | { "slug": "gemini-3.1-pro-low", "name": "Gemini 3.1 Pro (Low)", "status": "legacy" } | |
| 781 | 807 | ] |
| 782 | 808 | } |
| 783 | 809 | } |