feat(config): support object-style fallback_models with per-model settings

Add support for object-style entries in fallback_models arrays, enabling
per-model configuration of variant, reasoningEffort, temperature, top_p,
maxTokens, and thinking settings.

- Zod schema for FallbackModelObject with full validation
- normalizeFallbackModels() and flattenToFallbackModelStrings() utilities
- Provider-agnostic model resolution pipeline with fallback chain
- Session prompt params state management
- Fallback chain construction with prefix-match lookup
- Integration across delegate-task, background-agent, and plugin layers
This commit is contained in:
Ravi Tharuma
2026-03-18 14:21:27 +01:00
parent 7761e48dca
commit a77a16c494
34 changed files with 1686 additions and 126 deletions
+40
View File
@@ -4,6 +4,7 @@ import { createEventHandler } from "./event"
import { createChatMessageHandler } from "./chat-message"
import { _resetForTesting, setMainSession } from "../features/claude-code-session-state"
import { clearPendingModelFallback, createModelFallbackHook } from "../hooks/model-fallback/hook"
import { getSessionPromptParams, setSessionPromptParams } from "../shared/session-prompt-params-state"
type EventInput = { event: { type: string; properties?: unknown } }
@@ -441,6 +442,45 @@ describe("createEventHandler - event forwarding", () => {
expect(disconnectedSessions).toEqual([sessionID])
expect(deletedSessions).toEqual([sessionID])
})
it("clears stored prompt params on session.deleted", async () => {
//#given
const eventHandler = createEventHandler({
ctx: {} as never,
pluginConfig: {} as never,
firstMessageVariantGate: {
markSessionCreated: () => {},
clear: () => {},
},
managers: {
skillMcpManager: {
disconnectSession: async () => {},
},
tmuxSessionManager: {
onSessionCreated: async () => {},
onSessionDeleted: async () => {},
},
} as never,
hooks: {} as never,
})
const sessionID = "ses_prompt_params_deleted"
setSessionPromptParams(sessionID, {
temperature: 0.4,
topP: 0.7,
options: { reasoningEffort: "high" },
})
//#when
await eventHandler({
event: {
type: "session.deleted",
properties: { info: { id: sessionID } },
},
})
//#then
expect(getSessionPromptParams(sessionID)).toBeUndefined()
})
})
describe("createEventHandler - retry dedupe lifecycle", () => {