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:
@@ -2,6 +2,7 @@ import type { BackgroundTask, LaunchInput, ResumeInput } from "./types"
|
||||
import type { OpencodeClient, OnSubagentSessionCreated, QueueItem } from "./constants"
|
||||
import { TMUX_CALLBACK_DELAY_MS } from "./constants"
|
||||
import { log, getAgentToolRestrictions, promptWithModelSuggestionRetry, createInternalAgentTextPart } from "../../shared"
|
||||
import { setSessionPromptParams } from "../../shared/session-prompt-params-state"
|
||||
import { subagentSessions } from "../claude-code-session-state"
|
||||
import { getTaskToastManager } from "../task-toast-manager"
|
||||
import { isInsideTmux } from "../../shared/tmux"
|
||||
@@ -128,10 +129,33 @@ export async function startTask(
|
||||
})
|
||||
|
||||
const launchModel = input.model
|
||||
? { providerID: input.model.providerID, modelID: input.model.modelID }
|
||||
? {
|
||||
providerID: input.model.providerID,
|
||||
modelID: input.model.modelID,
|
||||
}
|
||||
: undefined
|
||||
const launchVariant = input.model?.variant
|
||||
|
||||
if (input.model) {
|
||||
const promptOptions: Record<string, unknown> = {
|
||||
...(input.model.reasoningEffort ? { reasoningEffort: input.model.reasoningEffort } : {}),
|
||||
...(input.model.thinking ? { thinking: input.model.thinking } : {}),
|
||||
...(input.model.maxTokens !== undefined ? { maxTokens: input.model.maxTokens } : {}),
|
||||
}
|
||||
|
||||
if (
|
||||
input.model.temperature !== undefined ||
|
||||
input.model.top_p !== undefined ||
|
||||
Object.keys(promptOptions).length > 0
|
||||
) {
|
||||
setSessionPromptParams(sessionID, {
|
||||
...(input.model.temperature !== undefined ? { temperature: input.model.temperature } : {}),
|
||||
...(input.model.top_p !== undefined ? { topP: input.model.top_p } : {}),
|
||||
...(Object.keys(promptOptions).length > 0 ? { options: promptOptions } : {}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
promptWithModelSuggestionRetry(client, {
|
||||
path: { id: sessionID },
|
||||
body: {
|
||||
@@ -213,10 +237,33 @@ export async function resumeTask(
|
||||
})
|
||||
|
||||
const resumeModel = task.model
|
||||
? { providerID: task.model.providerID, modelID: task.model.modelID }
|
||||
? {
|
||||
providerID: task.model.providerID,
|
||||
modelID: task.model.modelID,
|
||||
}
|
||||
: undefined
|
||||
const resumeVariant = task.model?.variant
|
||||
|
||||
if (task.model) {
|
||||
const promptOptions: Record<string, unknown> = {
|
||||
...(task.model.reasoningEffort ? { reasoningEffort: task.model.reasoningEffort } : {}),
|
||||
...(task.model.thinking ? { thinking: task.model.thinking } : {}),
|
||||
...(task.model.maxTokens !== undefined ? { maxTokens: task.model.maxTokens } : {}),
|
||||
}
|
||||
|
||||
if (
|
||||
task.model.temperature !== undefined ||
|
||||
task.model.top_p !== undefined ||
|
||||
Object.keys(promptOptions).length > 0
|
||||
) {
|
||||
setSessionPromptParams(task.sessionID, {
|
||||
...(task.model.temperature !== undefined ? { temperature: task.model.temperature } : {}),
|
||||
...(task.model.top_p !== undefined ? { topP: task.model.top_p } : {}),
|
||||
...(Object.keys(promptOptions).length > 0 ? { options: promptOptions } : {}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
client.session.promptAsync({
|
||||
path: { id: task.sessionID },
|
||||
body: {
|
||||
|
||||
Reference in New Issue
Block a user