Files
oh-my-opencode/src/hooks/runtime-fallback/fallback-models.ts
T
Ravi Tharuma a77a16c494 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
2026-03-25 11:04:49 +01:00

87 lines
3.1 KiB
TypeScript

import type { OhMyOpenCodeConfig } from "../../config"
import type { FallbackModelObject } from "../../config/schema/fallback-models"
import { agentPattern } from "./agent-resolver"
import { HOOK_NAME } from "./constants"
import { log } from "../../shared/logger"
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
import { normalizeFallbackModels, flattenToFallbackModelStrings } from "../../shared/model-resolver"
/**
* Returns fallback model strings for the runtime-fallback system.
* Object entries are flattened to "provider/model(variant)" strings so the
* string-based fallback state machine can work with them unchanged.
*/
export function getFallbackModelsForSession(
sessionID: string,
agent: string | undefined,
pluginConfig: OhMyOpenCodeConfig | undefined
): string[] {
if (!pluginConfig) return []
const raw = getRawFallbackModelsForSession(sessionID, agent, pluginConfig)
return flattenToFallbackModelStrings(raw) ?? []
}
/**
* Returns the raw fallback model entries (strings and objects) for a session.
* Use this when per-model settings (temperature, reasoningEffort, etc.) must be
* preserved — e.g. before passing to buildFallbackChainFromModels.
*/
export function getRawFallbackModels(
sessionID: string,
agent: string | undefined,
pluginConfig: OhMyOpenCodeConfig | undefined,
): (string | FallbackModelObject)[] | undefined {
if (!pluginConfig) return undefined
return getRawFallbackModelsForSession(sessionID, agent, pluginConfig)
}
function getRawFallbackModelsForSession(
sessionID: string,
agent: string | undefined,
pluginConfig: OhMyOpenCodeConfig,
): (string | FallbackModelObject)[] | undefined {
const sessionCategory = SessionCategoryRegistry.get(sessionID)
if (sessionCategory && pluginConfig.categories?.[sessionCategory]) {
const categoryConfig = pluginConfig.categories[sessionCategory]
if (categoryConfig?.fallback_models) {
return normalizeFallbackModels(categoryConfig.fallback_models)
}
}
const tryGetFallbackFromAgent = (agentName: string): (string | FallbackModelObject)[] | undefined => {
const agentConfig = pluginConfig.agents?.[agentName as keyof typeof pluginConfig.agents]
if (!agentConfig) return undefined
if (agentConfig?.fallback_models) {
return normalizeFallbackModels(agentConfig.fallback_models)
}
const agentCategory = agentConfig?.category
if (agentCategory && pluginConfig.categories?.[agentCategory]) {
const categoryConfig = pluginConfig.categories[agentCategory]
if (categoryConfig?.fallback_models) {
return normalizeFallbackModels(categoryConfig.fallback_models)
}
}
return undefined
}
if (agent) {
const result = tryGetFallbackFromAgent(agent)
if (result) return result
}
const sessionAgentMatch = sessionID.match(agentPattern)
if (sessionAgentMatch) {
const detectedAgent = sessionAgentMatch[1].toLowerCase()
const result = tryGetFallbackFromAgent(detectedAgent)
if (result) return result
}
log(`[${HOOK_NAME}] No category/agent fallback models resolved for session`, { sessionID, agent })
return undefined
}