fix: detect GPT models behind proxy providers (litellm, ollama) in isGptModel
isGptModel only matched openai/ and github-copilot/gpt- prefixes, causing models like litellm/gpt-5.2 to fall into the Claude code path. This injected Claude-specific thinking config, which the opencode runtime translated into a reasoningSummary API parameter — rejected by OpenAI. Extract model name after provider prefix and match against GPT model name patterns (gpt-*, o1, o3, o4). Closes #1788 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
49
src/agents/types.test.ts
Normal file
49
src/agents/types.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { describe, test, expect } from "bun:test";
|
||||
import { isGptModel } from "./types";
|
||||
|
||||
describe("isGptModel", () => {
|
||||
test("standard openai provider models", () => {
|
||||
expect(isGptModel("openai/gpt-5.2")).toBe(true);
|
||||
expect(isGptModel("openai/gpt-4o")).toBe(true);
|
||||
expect(isGptModel("openai/o1")).toBe(true);
|
||||
expect(isGptModel("openai/o3-mini")).toBe(true);
|
||||
});
|
||||
|
||||
test("github copilot gpt models", () => {
|
||||
expect(isGptModel("github-copilot/gpt-5.2")).toBe(true);
|
||||
expect(isGptModel("github-copilot/gpt-4o")).toBe(true);
|
||||
});
|
||||
|
||||
test("litellm proxied gpt models", () => {
|
||||
expect(isGptModel("litellm/gpt-5.2")).toBe(true);
|
||||
expect(isGptModel("litellm/gpt-4o")).toBe(true);
|
||||
expect(isGptModel("litellm/o1")).toBe(true);
|
||||
expect(isGptModel("litellm/o3-mini")).toBe(true);
|
||||
expect(isGptModel("litellm/o4-mini")).toBe(true);
|
||||
});
|
||||
|
||||
test("other proxied gpt models", () => {
|
||||
expect(isGptModel("ollama/gpt-4o")).toBe(true);
|
||||
expect(isGptModel("custom-provider/gpt-5.2")).toBe(true);
|
||||
});
|
||||
|
||||
test("gpt4 prefix without hyphen (legacy naming)", () => {
|
||||
expect(isGptModel("litellm/gpt4o")).toBe(true);
|
||||
expect(isGptModel("ollama/gpt4")).toBe(true);
|
||||
});
|
||||
|
||||
test("claude models are not gpt", () => {
|
||||
expect(isGptModel("anthropic/claude-opus-4-6")).toBe(false);
|
||||
expect(isGptModel("anthropic/claude-sonnet-4-5")).toBe(false);
|
||||
expect(isGptModel("litellm/anthropic.claude-opus-4-5")).toBe(false);
|
||||
});
|
||||
|
||||
test("gemini models are not gpt", () => {
|
||||
expect(isGptModel("google/gemini-3-pro")).toBe(false);
|
||||
expect(isGptModel("litellm/gemini-3-pro")).toBe(false);
|
||||
});
|
||||
|
||||
test("opencode provider is not gpt", () => {
|
||||
expect(isGptModel("opencode/claude-opus-4-6")).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -66,8 +66,18 @@ export interface AgentPromptMetadata {
|
||||
keyTrigger?: string
|
||||
}
|
||||
|
||||
function extractModelName(model: string): string {
|
||||
return model.includes("/") ? model.split("/").pop() ?? model : model
|
||||
}
|
||||
|
||||
const GPT_MODEL_PREFIXES = ["gpt-", "gpt4", "o1", "o3", "o4"]
|
||||
|
||||
export function isGptModel(model: string): boolean {
|
||||
return model.startsWith("openai/") || model.startsWith("github-copilot/gpt-")
|
||||
if (model.startsWith("openai/") || model.startsWith("github-copilot/gpt-"))
|
||||
return true
|
||||
|
||||
const modelName = extractModelName(model).toLowerCase()
|
||||
return GPT_MODEL_PREFIXES.some((prefix) => modelName.startsWith(prefix))
|
||||
}
|
||||
|
||||
export type BuiltinAgentName =
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* 3. Everything else (Claude, etc.) → default.ts
|
||||
*/
|
||||
|
||||
import { isGptModel } from "../../../agents/types"
|
||||
|
||||
/**
|
||||
* Checks if agent is a planner-type agent.
|
||||
* Planners don't need ultrawork injection (they ARE the planner).
|
||||
@@ -20,15 +22,7 @@ export function isPlannerAgent(agentName?: string): boolean {
|
||||
return /\bplan\b/.test(normalized)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if model is GPT 5.2 series.
|
||||
* GPT models benefit from specific prompting patterns.
|
||||
*/
|
||||
export function isGptModel(modelID?: string): boolean {
|
||||
if (!modelID) return false
|
||||
const lowerModel = modelID.toLowerCase()
|
||||
return lowerModel.includes("gpt")
|
||||
}
|
||||
export { isGptModel }
|
||||
|
||||
/** Ultrawork message source type */
|
||||
export type UltraworkSource = "planner" | "gpt" | "default"
|
||||
@@ -45,8 +39,8 @@ export function getUltraworkSource(
|
||||
return "planner"
|
||||
}
|
||||
|
||||
// Priority 2: GPT 5.2 models
|
||||
if (isGptModel(modelID)) {
|
||||
// Priority 2: GPT models
|
||||
if (modelID && isGptModel(modelID)) {
|
||||
return "gpt"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user