feat(model-requirements): add k2p5, kimi-k2.5, gpt-5.4 medium to Sisyphus fallback chain
Sisyphus can now fall back through Kimi and OpenAI models when Claude is unavailable, enabling OpenAI-only users to use Sisyphus directly instead of being redirected to Hephaestus. Runtime chain: claude-opus-4-6 max → k2p5 → kimi-k2.5 → gpt-5.4 medium → glm-5 → big-pickle CLI chain: claude-opus-4-6 max → k2p5 → gpt-5.4 medium → glm-5
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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([])
|
||||
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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<string, { model: string }>).sisyphus).toBeUndefined()
|
||||
// #then Sisyphus resolves to gpt-5.4 medium (openai is now in sisyphus chain)
|
||||
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.model).toBe("openai/gpt-5.4")
|
||||
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.variant).toBe("medium")
|
||||
// #then Oracle should use native OpenAI (first fallback entry)
|
||||
expect((result.agents as Record<string, { model: string }>).oracle.model).toBe("openai/gpt-5.4")
|
||||
// #then multimodal-looker should use native OpenAI (first fallback entry is gpt-5.3-codex)
|
||||
|
||||
@@ -13,6 +13,7 @@ export const CLI_AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
|
||||
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,
|
||||
|
||||
@@ -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")
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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")
|
||||
})
|
||||
|
||||
@@ -20,6 +20,19 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
|
||||
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" },
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user