diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index 7627edd38..3784f9570 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -64,7 +64,7 @@ These agents have Claude-optimized prompts — long, detailed, mechanics-driven. | Agent | Role | Fallback Chain | Notes | | ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- | -| **Sisyphus** | Main orchestrator | Claude Opus → GLM 5 → Big Pickle | Claude-family first. GPT-5.4 has dedicated support, but Claude/Kimi/GLM remain the preferred fit. | +| **Sisyphus** | Main orchestrator | Claude Opus → K2P5 → Kimi K2.5 → GPT-5.4 → GLM 5 → Big Pickle | Claude-family first. GPT-5.4 has dedicated prompt support. Kimi/GLM as intermediate fallbacks. | | **Metis** | Plan gap analyzer | Claude Opus → GPT-5.4 → Gemini 3.1 Pro | Claude preferred, GPT acceptable fallback. | ### Dual-Prompt Agents → Claude preferred, GPT supported diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index b13835188..a4dcf175a 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -10,7 +10,7 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each | Agent | Model | Temp | Mode | Fallback Chain | Purpose | |-------|-------|------|------|----------------|---------| -| **Sisyphus** | claude-opus-4-6 max | 0.1 | all | glm-5 → big-pickle | Main orchestrator, plans + delegates | +| **Sisyphus** | claude-opus-4-6 max | 0.1 | all | k2p5 → kimi-k2.5 → gpt-5.4 medium → glm-5 → big-pickle | Main orchestrator, plans + delegates | | **Hephaestus** | gpt-5.3-codex medium | 0.1 | all | gpt-5.4 medium (copilot) | Autonomous deep worker | | **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high → claude-opus-4-6 max | Read-only consultation | | **Librarian** | gemini-3-flash | 0.1 | subagent | minimax-m2.5-free → big-pickle | External docs/code search | diff --git a/src/agents/utils.test.ts b/src/agents/utils.test.ts index 0d8b35be3..f49c5230b 100644 --- a/src/agents/utils.test.ts +++ b/src/agents/utils.test.ts @@ -891,9 +891,9 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { }) test("sisyphus is not created when no fallback model is available and provider not connected", async () => { - // #given - only openai/gpt-5.4 available, not in sisyphus fallback chain + // #given - only venice/deepseek-v3.2 available, not in sisyphus fallback chain const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["openai/gpt-5.4"]) + new Set(["venice/deepseek-v3.2"]) ) const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue([]) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index e03eea8c8..07b1c2b76 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -224,6 +224,10 @@ exports[`generateModelConfig single native provider uses OpenAI models when only "model": "openai/gpt-5.4", "variant": "high", }, + "sisyphus": { + "model": "openai/gpt-5.4", + "variant": "medium", + }, }, "categories": { "deep": { @@ -293,6 +297,10 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa "model": "openai/gpt-5.4", "variant": "high", }, + "sisyphus": { + "model": "openai/gpt-5.4", + "variant": "medium", + }, }, "categories": { "deep": { diff --git a/src/cli/config-manager.test.ts b/src/cli/config-manager.test.ts index f5ea0f787..33f40ad71 100644 --- a/src/cli/config-manager.test.ts +++ b/src/cli/config-manager.test.ts @@ -249,8 +249,9 @@ describe("generateOmoConfig - model fallback system", () => { // #when generating config const result = generateOmoConfig(config) - // #then Sisyphus is omitted (requires all fallback providers) - expect((result.agents as Record).sisyphus).toBeUndefined() + // #then Sisyphus resolves to gpt-5.4 medium (openai is now in sisyphus chain) + expect((result.agents as Record).sisyphus.model).toBe("openai/gpt-5.4") + expect((result.agents as Record).sisyphus.variant).toBe("medium") // #then Oracle should use native OpenAI (first fallback entry) expect((result.agents as Record).oracle.model).toBe("openai/gpt-5.4") // #then multimodal-looker should use native OpenAI (first fallback entry is gpt-5.3-codex) diff --git a/src/cli/model-fallback-requirements.ts b/src/cli/model-fallback-requirements.ts index 33d8076ce..f3298fa08 100644 --- a/src/cli/model-fallback-requirements.ts +++ b/src/cli/model-fallback-requirements.ts @@ -13,6 +13,7 @@ export const CLI_AGENT_MODEL_REQUIREMENTS: Record = { variant: "max", }, { providers: ["kimi-for-coding"], model: "k2p5" }, + { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "medium" }, { providers: ["zai-coding-plan", "opencode"], model: "glm-5" }, ], requiresAnyModel: true, diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index 5b36fc953..dcc83e023 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -396,7 +396,7 @@ describe("generateModelConfig", () => { expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") }) - test("Sisyphus is omitted when no fallback provider is available (OpenAI not in chain)", () => { + test("Sisyphus resolves to gpt-5.4 medium when only OpenAI is available", () => { // #given const config = createConfig({ hasOpenAI: true }) @@ -404,7 +404,8 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus).toBeUndefined() + expect(result.agents?.sisyphus?.model).toBe("openai/gpt-5.4") + expect(result.agents?.sisyphus?.variant).toBe("medium") }) }) diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 24684caec..aa1f70fd1 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -134,8 +134,8 @@ describe("model fallback hook", () => { //#then - chain should progress to entry[1], not repeat entry[0] expect(secondOutput.message["model"]).toEqual({ - providerID: "zai-coding-plan", - modelID: "glm-5", + providerID: "kimi-for-coding", + modelID: "k2p5", }) expect(secondOutput.message["variant"]).toBeUndefined() }) diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 1cdf2712c..66b933c85 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -334,8 +334,8 @@ describe("createEventHandler - model fallback", () => { //#then - second fallback entry applied (chain advanced) expect(second.message["model"]).toEqual({ - providerID: "zai-coding-plan", - modelID: "glm-5", + providerID: "kimi-for-coding", + modelID: "k2p5", }) expect(second.message["variant"]).toBeUndefined() expect(abortCalls).toEqual([sessionID, sessionID]) diff --git a/src/shared/agent-variant.test.ts b/src/shared/agent-variant.test.ts index c579c69ee..53e32baa3 100644 --- a/src/shared/agent-variant.test.ts +++ b/src/shared/agent-variant.test.ts @@ -124,8 +124,8 @@ describe("resolveVariantForModel", () => { expect(variant).toBe("medium") }) - test("returns undefined for provider not in sisyphus chain", () => { - // #given openai is not in sisyphus fallback chain anymore + test("returns medium for openai/gpt-5.4 in sisyphus chain", () => { + // #given openai/gpt-5.4 is now in sisyphus fallback chain with variant medium const config = {} as OhMyOpenCodeConfig const model = { providerID: "openai", modelID: "gpt-5.4" } @@ -133,7 +133,7 @@ describe("resolveVariantForModel", () => { const variant = resolveVariantForModel(config, "sisyphus", model) // then - expect(variant).toBeUndefined() + expect(variant).toBe("medium") }) test("returns undefined for provider not in chain", () => { diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index 29c477057..d2a106e15 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -23,15 +23,15 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(primary.variant).toBe("high") }) - test("sisyphus has claude-opus-4-6 as primary and requiresAnyModel", () => { + test("sisyphus has claude-opus-4-6 as primary with k2p5, kimi-k2.5, gpt-5.4 medium fallbacks", () => { // #given - sisyphus agent requirement const sisyphus = AGENT_MODEL_REQUIREMENTS["sisyphus"] // #when - accessing Sisyphus requirement - // #then - fallbackChain has claude-opus-4-6 first, big-pickle last + // #then - fallbackChain has 6 entries with correct ordering expect(sisyphus).toBeDefined() expect(sisyphus.fallbackChain).toBeArray() - expect(sisyphus.fallbackChain).toHaveLength(3) + expect(sisyphus.fallbackChain).toHaveLength(6) expect(sisyphus.requiresAnyModel).toBe(true) const primary = sisyphus.fallbackChain[0] @@ -39,7 +39,19 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(primary.model).toBe("claude-opus-4-6") expect(primary.variant).toBe("max") - const last = sisyphus.fallbackChain[2] + const second = sisyphus.fallbackChain[1] + expect(second.providers).toEqual(["kimi-for-coding"]) + expect(second.model).toBe("k2p5") + + const third = sisyphus.fallbackChain[2] + expect(third.model).toBe("kimi-k2.5") + + const fourth = sisyphus.fallbackChain[3] + expect(fourth.providers).toContain("openai") + expect(fourth.model).toBe("gpt-5.4") + expect(fourth.variant).toBe("medium") + + const last = sisyphus.fallbackChain[5] expect(last.providers[0]).toBe("opencode") expect(last.model).toBe("big-pickle") }) diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index 84ade0801..7d033f122 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -20,6 +20,19 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "claude-opus-4-6", variant: "max", }, + { providers: ["kimi-for-coding"], model: "k2p5" }, + { + providers: [ + "opencode", + "moonshotai", + "moonshotai-cn", + "firmware", + "ollama-cloud", + "aihubmix", + ], + model: "kimi-k2.5", + }, + { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "medium" }, { providers: ["zai-coding-plan", "opencode"], model: "glm-5" }, { providers: ["opencode"], model: "big-pickle" }, ],