import type { HookDeps } from "./types" import type { AutoRetryHelpers } from "./auto-retry" import { HOOK_NAME } from "./constants" import { log } from "../../shared/logger" import { extractAutoRetrySignal } from "./error-classifier" import { createFallbackState } from "./fallback-state" import { getFallbackModelsForSession } from "./fallback-models" import { normalizeRetryStatusMessage, extractRetryAttempt } from "../../shared/retry-status-utils" import { resolveFallbackBootstrapModel } from "./fallback-bootstrap-model" import { dispatchFallbackRetry } from "./fallback-retry-dispatcher" export function createSessionStatusHandler( deps: HookDeps, helpers: AutoRetryHelpers, sessionStatusRetryKeys: Map, ) { const { pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, } = deps return async (props: Record | undefined) => { const sessionID = props?.sessionID as string | undefined const status = props?.status as { type?: string; message?: string; attempt?: number } | undefined const agent = props?.agent as string | undefined const model = props?.model as string | undefined if (!sessionID || status?.type !== "retry") return const retryMessage = typeof status.message === "string" ? status.message : "" const retrySignal = extractAutoRetrySignal({ status: retryMessage, message: retryMessage }) if (!retrySignal) return const retryKey = `${extractRetryAttempt(status.attempt, retryMessage)}:${normalizeRetryStatusMessage(retryMessage)}` if (sessionStatusRetryKeys.get(sessionID) === retryKey) { return } sessionStatusRetryKeys.set(sessionID, retryKey) if (sessionRetryInFlight.has(sessionID)) { log(`[${HOOK_NAME}] session.status retry skipped — retry already in flight`, { sessionID }) return } const resolvedAgent = await helpers.resolveAgentForSessionFromContext(sessionID, agent) const fallbackModels = getFallbackModelsForSession(sessionID, resolvedAgent, pluginConfig) if (fallbackModels.length === 0) return let state = sessionStates.get(sessionID) if (!state) { const initialModel = resolveFallbackBootstrapModel({ sessionID, source: "session.status", eventModel: model, resolvedAgent, pluginConfig, }) if (!initialModel) { log(`[${HOOK_NAME}] session.status retry missing model info, cannot fallback`, { sessionID }) return } state = createFallbackState(initialModel) sessionStates.set(sessionID, state) } sessionLastAccess.set(sessionID, Date.now()) if (state.pendingFallbackModel) { log(`[${HOOK_NAME}] session.status retry skipped (pending fallback in progress)`, { sessionID, pendingFallbackModel: state.pendingFallbackModel, }) return } log(`[${HOOK_NAME}] Detected provider auto-retry signal in session.status`, { sessionID, model: state.currentModel, retryAttempt: status.attempt, }) await helpers.abortSessionRequest(sessionID, "session.status.retry-signal") await dispatchFallbackRetry(deps, helpers, { sessionID, state, fallbackModels, resolvedAgent, source: "session.status", }) } }