From baefd16b3f30767dc0e4604e11f09cc770e6cd7c Mon Sep 17 00:00:00 2001 From: justsisyphus Date: Fri, 30 Jan 2026 15:11:19 +0900 Subject: [PATCH] feat(shared): add requiresModel field and isModelAvailable helper --- src/shared/model-availability.ts | 14 ++++++++++++++ src/shared/model-requirements.ts | 31 +++++++++++++++++-------------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/shared/model-availability.ts b/src/shared/model-availability.ts index 3795aecb1..019f36551 100644 --- a/src/shared/model-availability.ts +++ b/src/shared/model-availability.ts @@ -87,6 +87,20 @@ export function fuzzyMatchModel( return result } +/** + * Check if a target model is available (fuzzy match by model name, no provider filtering) + * + * @param targetModel - Model name to check (e.g., "gpt-5.2-codex") + * @param availableModels - Set of available models in "provider/model" format + * @returns true if model is available, false otherwise + */ +export function isModelAvailable( + targetModel: string, + availableModels: Set, +): boolean { + return fuzzyMatchModel(targetModel, availableModels) !== null +} + export async function getConnectedProviders(client: any): Promise { if (!client?.provider?.list) { log("[getConnectedProviders] client.provider.list not available") diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index 8051e58a8..5d6d3a888 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -7,6 +7,7 @@ export type FallbackEntry = { export type ModelRequirement = { fallbackChain: FallbackEntry[] variant?: string // Default variant (used when entry doesn't specify one) + requiresModel?: string // If set, only activates when this model is available (fuzzy match) } export const AGENT_MODEL_REQUIREMENTS: Record = { @@ -98,20 +99,22 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }, ], }, - deep: { - fallbackChain: [ - { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" }, - { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }, - { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }, - ], - }, - artistry: { - fallbackChain: [ - { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }, - { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }, - { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }, - ], - }, + deep: { + fallbackChain: [ + { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" }, + { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }, + { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }, + ], + requiresModel: "gpt-5.2-codex", + }, + artistry: { + fallbackChain: [ + { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }, + { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" }, + { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }, + ], + requiresModel: "gemini-3-pro", + }, quick: { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },