import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentMode, BuiltinAgentName, AgentOverrides, AgentPromptMetadata } from "../types" import type { CategoryConfig, GitMasterConfig } from "../../config/schema" import type { BrowserAutomationProvider } from "../../config/schema" import type { AvailableAgent } from "../dynamic-agent-prompt-builder" import { AGENT_MODEL_REQUIREMENTS, isModelAvailable } from "../../shared" import { buildAgent, isFactory } from "../agent-builder" import { applyOverrides } from "./agent-overrides" import { applyEnvironmentContext } from "./environment-context" import { applyModelResolution, getFirstFallbackModel } from "./model-resolution" import { log } from "../../shared/logger" export function collectPendingBuiltinAgents(input: { agentSources: Partial> agentMetadata: Partial> disabledAgents: string[] agentOverrides: AgentOverrides directory?: string systemDefaultModel?: string mergedCategories: Record gitMasterConfig?: GitMasterConfig browserProvider?: BrowserAutomationProvider uiSelectedModel?: string availableModels: Set isFirstRunNoCache: boolean disabledSkills?: Set useTaskSystem?: boolean disableOmoEnv?: boolean }): { pendingAgentConfigs: Map; availableAgents: AvailableAgent[] } { const { agentSources, agentMetadata, disabledAgents, agentOverrides, directory, systemDefaultModel, mergedCategories, gitMasterConfig, browserProvider, uiSelectedModel, availableModels, isFirstRunNoCache, disabledSkills, disableOmoEnv = false, } = input const availableAgents: AvailableAgent[] = [] const pendingAgentConfigs: Map = new Map() for (const [name, source] of Object.entries(agentSources)) { const agentName = name as BuiltinAgentName if (agentName === "sisyphus") continue if (agentName === "hephaestus") continue if (agentName === "atlas") continue if (agentName === "sisyphus-junior") continue if (disabledAgents.some((name) => name.toLowerCase() === agentName.toLowerCase())) continue const override = agentOverrides[agentName] ?? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentName.toLowerCase())?.[1] const requirement = AGENT_MODEL_REQUIREMENTS[agentName] // Check if agent requires a specific model if (requirement?.requiresModel && availableModels) { if (!isModelAvailable(requirement.requiresModel, availableModels)) { continue } } const isPrimaryAgent = isFactory(source) && (source.mode === "primary" || source.mode === "all") let resolution = applyModelResolution({ uiSelectedModel: (isPrimaryAgent && override?.model === undefined) ? uiSelectedModel : undefined, userModel: override?.model, requirement, availableModels, systemDefaultModel, }) if (!resolution) { if (override?.model) { // User explicitly configured a model but resolution failed (e.g., cold cache). // Honor the user's choice directly instead of falling back to hardcoded chain. log("[agent-registration] User-configured model not resolved, using as-is", { agent: agentName, configuredModel: override.model, }) resolution = { model: override.model, provenance: "override" as const } } else { resolution = getFirstFallbackModel(requirement) } } if (!resolution) continue const { model, variant: resolvedVariant } = resolution let config = buildAgent(source, model, mergedCategories, gitMasterConfig, browserProvider, disabledSkills) // Apply resolved variant from model fallback chain if (resolvedVariant) { config = { ...config, variant: resolvedVariant } } if (agentName === "librarian") { config = applyEnvironmentContext(config, directory, { disableOmoEnv }) } config = applyOverrides(config, override, mergedCategories, directory) // Store for later - will be added after sisyphus and hephaestus pendingAgentConfigs.set(name, config) const metadata = agentMetadata[agentName] if (metadata) { const mode = isFactory(source) ? source.mode : (config.mode as AgentMode | undefined) availableAgents.push({ name: agentName, description: config.description ?? "", metadata, mode, }) } } return { pendingAgentConfigs, availableAgents } }