import { describe, expect, test } from "bun:test" import { createAutoRetryHelpers } from "./auto-retry" import { createFallbackState } from "./fallback-state" import type { HookDeps, RuntimeFallbackPluginInput } from "./types" function createContext(promptCalls: { count: number }): RuntimeFallbackPluginInput { const session = { abort: async () => ({}), messages: async () => ({ data: [ { info: { role: "user" }, parts: [{ type: "text", text: "retry this" }], }, ], }), promptAsync: async () => { promptCalls.count += 1 return {} }, status: async () => ({ data: { "session-auto-retry": { type: "busy" } } }), } return { client: { session, tui: { showToast: async () => ({}), }, }, directory: "/test/dir", } } function createDeps(promptCalls: { count: number }): HookDeps { return { ctx: createContext(promptCalls), config: { enabled: true, retry_on_errors: [429, 503, 529], max_fallback_attempts: 3, cooldown_seconds: 60, timeout_seconds: 0, notify_on_fallback: false, }, options: undefined, pluginConfig: undefined, sessionStates: new Map(), sessionLastAccess: new Map(), sessionRetryInFlight: new Set(), sessionAwaitingFallbackResult: new Set(), sessionFallbackTimeouts: new Map(), sessionStatusRetryKeys: new Map(), internallyAbortedSessions: new Set(), } } describe("createAutoRetryHelpers", () => { test("#given an existing fallback result is pending #when a new fallback retry is skipped by the prompt gate #then the previous pending state is preserved", async () => { // given const promptCalls = { count: 0 } const deps = createDeps(promptCalls) const helpers = createAutoRetryHelpers(deps) const sessionID = "session-auto-retry" const state = createFallbackState("anthropic/claude-opus-4-7") state.pendingFallbackModel = "openai/gpt-5.4" deps.sessionStates.set(sessionID, state) deps.sessionAwaitingFallbackResult.add(sessionID) // when await helpers.autoRetryWithFallback(sessionID, "google/gemini-2.5-pro", undefined, "session.status") // then expect(promptCalls.count).toBe(0) expect(deps.sessionAwaitingFallbackResult.has(sessionID)).toBe(true) expect(state.pendingFallbackModel).toBe("openai/gpt-5.4") }) })