diff --git a/src/agents/types.test.ts b/src/agents/types.test.ts index 7330904b7..614991867 100644 --- a/src/agents/types.test.ts +++ b/src/agents/types.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from "bun:test"; -import { isGptModel } from "./types"; +import { isGptModel, isGeminiModel } from "./types"; describe("isGptModel", () => { test("standard openai provider models", () => { @@ -47,3 +47,47 @@ describe("isGptModel", () => { expect(isGptModel("opencode/claude-opus-4-6")).toBe(false); }); }); + +describe("isGeminiModel", () => { + test("#given google provider models #then returns true", () => { + expect(isGeminiModel("google/gemini-3-pro")).toBe(true); + expect(isGeminiModel("google/gemini-3-flash")).toBe(true); + expect(isGeminiModel("google/gemini-2.5-pro")).toBe(true); + }); + + test("#given google-vertex provider models #then returns true", () => { + expect(isGeminiModel("google-vertex/gemini-3-pro")).toBe(true); + expect(isGeminiModel("google-vertex/gemini-3-flash")).toBe(true); + }); + + test("#given github copilot gemini models #then returns true", () => { + expect(isGeminiModel("github-copilot/gemini-3-pro")).toBe(true); + expect(isGeminiModel("github-copilot/gemini-3-flash")).toBe(true); + }); + + test("#given litellm proxied gemini models #then returns true", () => { + expect(isGeminiModel("litellm/gemini-3-pro")).toBe(true); + expect(isGeminiModel("litellm/gemini-3-flash")).toBe(true); + expect(isGeminiModel("litellm/gemini-2.5-pro")).toBe(true); + }); + + test("#given other proxied gemini models #then returns true", () => { + expect(isGeminiModel("custom-provider/gemini-3-pro")).toBe(true); + expect(isGeminiModel("ollama/gemini-3-flash")).toBe(true); + }); + + test("#given gpt models #then returns false", () => { + expect(isGeminiModel("openai/gpt-5.2")).toBe(false); + expect(isGeminiModel("openai/o3-mini")).toBe(false); + expect(isGeminiModel("litellm/gpt-4o")).toBe(false); + }); + + test("#given claude models #then returns false", () => { + expect(isGeminiModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGeminiModel("anthropic/claude-sonnet-4-6")).toBe(false); + }); + + test("#given opencode provider #then returns false", () => { + expect(isGeminiModel("opencode/claude-opus-4-6")).toBe(false); + }); +}); diff --git a/src/agents/types.ts b/src/agents/types.ts index 4ee1b3a6f..2d4f6c0cb 100644 --- a/src/agents/types.ts +++ b/src/agents/types.ts @@ -80,6 +80,19 @@ export function isGptModel(model: string): boolean { return GPT_MODEL_PREFIXES.some((prefix) => modelName.startsWith(prefix)) } +const GEMINI_PROVIDERS = ["google/", "google-vertex/"] + +export function isGeminiModel(model: string): boolean { + if (GEMINI_PROVIDERS.some((prefix) => model.startsWith(prefix))) + return true + + if (model.startsWith("github-copilot/") && extractModelName(model).toLowerCase().startsWith("gemini")) + return true + + const modelName = extractModelName(model).toLowerCase() + return modelName.startsWith("gemini-") +} + export type BuiltinAgentName = | "sisyphus" | "hephaestus"