From 563b6569d302ff169cc756132a02db84ea851275 Mon Sep 17 00:00:00 2001 From: acamq <179265037+acamq@users.noreply.github.com> Date: Thu, 23 Apr 2026 20:37:06 -0600 Subject: [PATCH] refactor(agents): replace per-version GPT checks with regex pattern Replace isGpt5_4Model + isGpt5_5Model + OR-composed isGptNativeSisyphusModel with a single regex matching GPT-5.x where x >= 4. Automatically covers future versions (5.6, 5.7, 5.10+) without code changes. Constraint: Must continue to reject gpt-5.3-codex and gpt-5.x where x < 4 Rejected: Per-version functions | not scalable, each new version adds a function + OR clause Confidence: high Scope-risk: narrow --- src/agents/types.test.ts | 72 ++++++++++++++-------------------------- src/agents/types.ts | 13 ++------ 2 files changed, 27 insertions(+), 58 deletions(-) diff --git a/src/agents/types.test.ts b/src/agents/types.test.ts index 3491c46b8..13cb0bf93 100644 --- a/src/agents/types.test.ts +++ b/src/agents/types.test.ts @@ -3,68 +3,44 @@ import { isGptModel, isGeminiModel, isGlmModel, - isGpt5_4Model, - isGpt5_5Model, isGptNativeSisyphusModel, isMiniMaxModel, } from "./types"; -describe("isGpt5_4Model", () => { - test("detects gpt-5.4 models", () => { - expect(isGpt5_4Model("openai/gpt-5.4")).toBe(true); - expect(isGpt5_4Model("openai/gpt-5-4")).toBe(true); - expect(isGpt5_4Model("openai/gpt-5.4-codex")).toBe(true); - expect(isGpt5_4Model("github-copilot/gpt-5.4")).toBe(true); - expect(isGpt5_4Model("venice/gpt-5-4")).toBe(true); - }); - - test("does not match other GPT models", () => { - expect(isGpt5_4Model("openai/gpt-5.3-codex")).toBe(false); - expect(isGpt5_4Model("openai/gpt-5.1")).toBe(false); - expect(isGpt5_4Model("openai/gpt-4o")).toBe(false); - expect(isGpt5_4Model("github-copilot/gpt-4o")).toBe(false); - }); - - test("does not match non-GPT models", () => { - expect(isGpt5_4Model("anthropic/claude-opus-4-7")).toBe(false); - expect(isGpt5_4Model("google/gemini-3.1-pro")).toBe(false); - expect(isGpt5_4Model("openai/o1")).toBe(false); - }); -}); - -describe("isGpt5_5Model", () => { - test("detects gpt-5.5 models", () => { - expect(isGpt5_5Model("gpt-5.5")).toBe(true); - expect(isGpt5_5Model("gpt-5-5")).toBe(true); - expect(isGpt5_5Model("openai/gpt-5.5")).toBe(true); - expect(isGpt5_5Model("openai/gpt-5-5")).toBe(true); - expect(isGpt5_5Model("github-copilot/gpt-5.5")).toBe(true); - }); - - test("does not match other GPT models", () => { - expect(isGpt5_5Model("openai/gpt-5.4")).toBe(false); - expect(isGpt5_5Model("openai/gpt-5.3-codex")).toBe(false); - expect(isGpt5_5Model("openai/gpt-4o")).toBe(false); - }); - - test("does not match non-GPT models", () => { - expect(isGpt5_5Model("anthropic/claude-opus-4-7")).toBe(false); - expect(isGpt5_5Model("google/gemini-3.1-pro")).toBe(false); - }); -}); - describe("isGptNativeSisyphusModel", () => { - test("allows GPT-5.4 and GPT-5.5 variants", () => { + test("allows GPT-5.x where x >= 4", () => { expect(isGptNativeSisyphusModel("openai/gpt-5.4")).toBe(true); expect(isGptNativeSisyphusModel("openai/gpt-5-4")).toBe(true); expect(isGptNativeSisyphusModel("openai/gpt-5.5")).toBe(true); expect(isGptNativeSisyphusModel("openai/gpt-5-5")).toBe(true); + expect(isGptNativeSisyphusModel("openai/gpt-5.9")).toBe(true); + expect(isGptNativeSisyphusModel("openai/gpt-5-9")).toBe(true); + expect(isGptNativeSisyphusModel("openai/gpt-5.10")).toBe(true); + expect(isGptNativeSisyphusModel("openai/gpt-5-10")).toBe(true); }); - test("rejects non-native Sisyphus GPT models and non-GPT models", () => { + test("allows with various providers and suffixes", () => { + expect(isGptNativeSisyphusModel("github-copilot/gpt-5.4")).toBe(true); + expect(isGptNativeSisyphusModel("venice/gpt-5-4")).toBe(true); + expect(isGptNativeSisyphusModel("openai/gpt-5.4-codex")).toBe(true); + expect(isGptNativeSisyphusModel("openai/gpt-5.5-mini")).toBe(true); + }); + + test("rejects GPT-5.x where x < 4", () => { expect(isGptNativeSisyphusModel("openai/gpt-5.3-codex")).toBe(false); + expect(isGptNativeSisyphusModel("openai/gpt-5.1")).toBe(false); + expect(isGptNativeSisyphusModel("openai/gpt-5-0")).toBe(false); + }); + + test("rejects other GPT models", () => { expect(isGptNativeSisyphusModel("openai/gpt-4o")).toBe(false); + expect(isGptNativeSisyphusModel("github-copilot/gpt-4o")).toBe(false); + }); + + test("rejects non-GPT models", () => { expect(isGptNativeSisyphusModel("anthropic/claude-opus-4-7")).toBe(false); + expect(isGptNativeSisyphusModel("google/gemini-3.1-pro")).toBe(false); + expect(isGptNativeSisyphusModel("openai/o1")).toBe(false); }); }); diff --git a/src/agents/types.ts b/src/agents/types.ts index abab2cbb2..1224e096b 100644 --- a/src/agents/types.ts +++ b/src/agents/types.ts @@ -79,18 +79,11 @@ export function isGptModel(model: string): boolean { return modelName.includes("gpt"); } -export function isGpt5_4Model(model: string): boolean { - const modelName = extractModelName(model).toLowerCase(); - return modelName.includes("gpt-5.4") || modelName.includes("gpt-5-4"); -} - -export function isGpt5_5Model(model: string): boolean { - const modelName = extractModelName(model).toLowerCase(); - return modelName.includes("gpt-5.5") || modelName.includes("gpt-5-5"); -} +const GPT_NATIVE_SISYPHUS_RE = /gpt-5[.-](?:[4-9]|\d{2,})/i; export function isGptNativeSisyphusModel(model: string): boolean { - return isGpt5_4Model(model) || isGpt5_5Model(model); + const modelName = extractModelName(model).toLowerCase(); + return GPT_NATIVE_SISYPHUS_RE.test(modelName); } export function isGpt5_3CodexModel(model: string): boolean {