fix(runtime-fallback): skip equivalent claude aliases
Prevent runtime fallback from cycling through provider aliases that resolve to the same underlying Claude family model. This keeps retry handling moving toward a genuinely distinct fallback model instead of appearing to fallback while staying on the same effective model. Constraint: Live retry/fallback bug is in /Users/ravi/Code/personal/oh-my-opencode, while oh-my-openagent contribution work remains isolated to /Users/ravi/Code/forks/oh-my-openagent Rejected: Change fallback chain precedence (category vs agent) first | lower-confidence root cause than equivalent-model retry Confidence: high Scope-risk: narrow Directive: Keep alias-equivalence logic limited to model families that are intentionally interchangeable for runtime failover, and expand with targeted tests before broadening provider-family collapsing Tested: bun run typecheck Tested: bun test src/hooks/runtime-fallback/index.test.ts src/hooks/runtime-fallback/error-classifier.test.ts src/plugin/event.model-fallback.test.ts Not-tested: Full live end-to-end session repro against external provider outages
This commit is contained in:
committed by
YeonGyu-Kim
parent
f54888b2fe
commit
f501c47c49
@@ -1305,7 +1305,10 @@ describe("runtime-fallback", () => {
|
||||
|
||||
expect(retriedModels.length).toBeGreaterThanOrEqual(2)
|
||||
expect(retriedModels[0]).toBe("github-copilot/claude-opus-4.7")
|
||||
expect(retriedModels[1]).toBe("anthropic/claude-opus-4-7")
|
||||
expect(retriedModels[1]).toBe("openai/gpt-5.4")
|
||||
|
||||
const equivalentSkipLog = logCalls.find((c) => c.msg.includes("Skipping equivalent fallback model"))
|
||||
expect(equivalentSkipLog).toBeDefined()
|
||||
|
||||
void sessionErrorPromise
|
||||
})
|
||||
@@ -1374,7 +1377,7 @@ describe("runtime-fallback", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||
|
||||
expect(retriedModels).toContain("github-copilot/claude-opus-4.7")
|
||||
expect(retriedModels).toContain("anthropic/claude-opus-4-7")
|
||||
expect(retriedModels).toContain("openai/gpt-5.4")
|
||||
expect(abortCalls.some((call) => call.path?.id === sessionID)).toBe(true)
|
||||
|
||||
const timeoutLog = logCalls.find((c) => c.msg.includes("Session fallback timeout reached"))
|
||||
@@ -1452,7 +1455,7 @@ describe("runtime-fallback", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||
|
||||
expect(retriedModels).toContain("github-copilot/claude-opus-4.7")
|
||||
expect(retriedModels).toContain("anthropic/claude-opus-4-7")
|
||||
expect(retriedModels).toContain("openai/gpt-5.4")
|
||||
})
|
||||
|
||||
test("should abort in-flight fallback request before advancing on timeout", async () => {
|
||||
@@ -1526,7 +1529,7 @@ describe("runtime-fallback", () => {
|
||||
|
||||
expect(abortCalls.some((call) => call.path?.id === sessionID)).toBe(true)
|
||||
expect(retriedModels).toContain("github-copilot/claude-opus-4.7")
|
||||
expect(retriedModels).toContain("anthropic/claude-opus-4-7")
|
||||
expect(retriedModels).toContain("openai/gpt-5.4")
|
||||
|
||||
void sessionErrorPromise
|
||||
})
|
||||
@@ -2451,7 +2454,10 @@ describe("runtime-fallback", () => {
|
||||
}),
|
||||
{
|
||||
config: createMockConfig({ notify_on_fallback: false }),
|
||||
pluginConfig: createMockPluginConfigWithAgentFallback("prometheus", ["github-copilot/claude-opus-4.7"]),
|
||||
pluginConfig: createMockPluginConfigWithAgentFallback("prometheus", [
|
||||
"github-copilot/claude-opus-4.7",
|
||||
"openai/gpt-5.4",
|
||||
]),
|
||||
},
|
||||
)
|
||||
const sessionID = "test-preserve-agent-on-retry"
|
||||
@@ -2471,7 +2477,7 @@ describe("runtime-fallback", () => {
|
||||
expect(promptCalls.length).toBe(1)
|
||||
const callBody = promptCalls[0]?.body as Record<string, unknown>
|
||||
expect(callBody?.agent).toBe("prometheus")
|
||||
expect(callBody?.model).toEqual({ providerID: "github-copilot", modelID: "claude-opus-4.7" })
|
||||
expect(callBody?.model).toEqual({ providerID: "openai", modelID: "gpt-5.4" })
|
||||
})
|
||||
|
||||
test("should not dispatch a second fallback prompt while the accepted retry session is still active", async () => {
|
||||
|
||||
Reference in New Issue
Block a user