fix(agents): log warning when a builtin agent is silently skipped due to model availability (fixes #4150)
When AGENT_MODEL_REQUIREMENTS gates an agent (sisyphus / hephaestus / atlas / general agents) and resolution returns no model -- or the requiresModel / requiresAnyModel / requiresProvider constraint is not satisfied by any connected provider -- the agent was being dropped from the registered set with no log, no warning, no doctor signal. Users upgrading from v3 to v4 saw their configured agents disappear from 'opencode agent list' with zero indication of why, and the only debugging path was reading the source.\n\nAdd a log() call at every silent-drop point in the four wrapper files so the user-facing 'oh-my-opencode.log' shows exactly which agent was skipped and which model / provider requirement failed. Follows the existing precedent in src/tools/delegate-task/categories.ts:44 ([resolveCategoryConfig] Category X requires Y but not available) and the in-file precedent in general-agents.ts:86 ([agent-registration] User-configured model not resolved). Zero behavior change -- agents that were skipped before are still skipped now, the only difference is they are no longer silent.\n\nVerification: bun test src/agents/builtin-agents/ -> 27/27 pass. bun test src/agents/ -> 405/405 pass. bun run typecheck -> exit 0. LSP diagnostics clean on all four touched files.
This commit is contained in:
@@ -3,6 +3,7 @@ import type { AgentOverrides } from "../types"
|
||||
import type { CategoriesConfig, CategoryConfig } from "../../config/schema"
|
||||
import type { AvailableAgent, AvailableSkill } from "../dynamic-agent-prompt-builder"
|
||||
import { AGENT_MODEL_REQUIREMENTS } from "../../shared"
|
||||
import { log } from "../../shared/logger"
|
||||
import { applyOverrides } from "./agent-overrides"
|
||||
import { applyModelResolution } from "./model-resolution"
|
||||
import { createAtlasAgent } from "../atlas"
|
||||
@@ -46,7 +47,13 @@ export function maybeCreateAtlasConfig(input: {
|
||||
systemDefaultModel,
|
||||
})
|
||||
|
||||
if (!atlasResolution) return undefined
|
||||
if (!atlasResolution) {
|
||||
log("[agent-registration] Agent skipped: model resolution returned no result", {
|
||||
agent: "atlas",
|
||||
configuredModel: orchestratorOverride?.model,
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
const { model: atlasModel, variant: atlasResolvedVariant } = atlasResolution
|
||||
|
||||
let orchestratorConfig = createAtlasAgent({
|
||||
|
||||
@@ -66,6 +66,10 @@ export function collectPendingBuiltinAgents(input: {
|
||||
// Check if agent requires a specific model
|
||||
if (requirement?.requiresModel && availableModels) {
|
||||
if (!isModelAvailable(requirement.requiresModel, availableModels)) {
|
||||
log("[agent-registration] Agent skipped: required model not available", {
|
||||
agent: agentName,
|
||||
requiredModel: requirement.requiresModel,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -92,7 +96,13 @@ export function collectPendingBuiltinAgents(input: {
|
||||
resolution = getFirstFallbackModel(requirement)
|
||||
}
|
||||
}
|
||||
if (!resolution) continue
|
||||
if (!resolution) {
|
||||
log("[agent-registration] Agent skipped: model resolution returned no result", {
|
||||
agent: agentName,
|
||||
configuredModel: override?.model,
|
||||
})
|
||||
continue
|
||||
}
|
||||
const { model, variant: resolvedVariant } = resolution
|
||||
|
||||
let config = buildAgent(source, model, mergedCategories)
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { AgentOverrides } from "../types"
|
||||
import type { CategoryConfig } from "../../config/schema"
|
||||
import type { AvailableAgent, AvailableCategory, AvailableSkill } from "../dynamic-agent-prompt-builder"
|
||||
import { AGENT_MODEL_REQUIREMENTS, isAnyProviderConnected } from "../../shared"
|
||||
import { log } from "../../shared/logger"
|
||||
import { createHephaestusAgent } from "../hephaestus"
|
||||
import { applyEnvironmentContext } from "./environment-context"
|
||||
import { applyCategoryOverride, mergeAgentConfig } from "./agent-overrides"
|
||||
@@ -51,7 +52,13 @@ export function maybeCreateHephaestusConfig(input: {
|
||||
isFirstRunNoCache ||
|
||||
isAnyProviderConnected(hephaestusRequirement.requiresProvider, availableModels)
|
||||
|
||||
if (!hasRequiredProvider) return undefined
|
||||
if (!hasRequiredProvider) {
|
||||
log("[agent-registration] Agent skipped: required provider not connected", {
|
||||
agent: "hephaestus",
|
||||
requiredProvider: hephaestusRequirement?.requiresProvider,
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
|
||||
let hephaestusResolution = applyModelResolution({
|
||||
userModel: hephaestusOverride?.model,
|
||||
@@ -64,7 +71,13 @@ export function maybeCreateHephaestusConfig(input: {
|
||||
hephaestusResolution = getFirstFallbackModel(hephaestusRequirement)
|
||||
}
|
||||
|
||||
if (!hephaestusResolution) return undefined
|
||||
if (!hephaestusResolution) {
|
||||
log("[agent-registration] Agent skipped: model resolution returned no result", {
|
||||
agent: "hephaestus",
|
||||
configuredModel: hephaestusOverride?.model,
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
const { model: hephaestusModel, variant: hephaestusResolvedVariant } = hephaestusResolution
|
||||
|
||||
let hephaestusConfig = createHephaestusAgent(
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { AgentOverrides } from "../types"
|
||||
import type { CategoriesConfig, CategoryConfig } from "../../config/schema"
|
||||
import type { AvailableAgent, AvailableCategory, AvailableSkill } from "../dynamic-agent-prompt-builder"
|
||||
import { AGENT_MODEL_REQUIREMENTS, isAnyFallbackModelAvailable } from "../../shared"
|
||||
import { log } from "../../shared/logger"
|
||||
import { applyEnvironmentContext } from "./environment-context"
|
||||
import { applyOverrides } from "./agent-overrides"
|
||||
import { applyModelResolution, getFirstFallbackModel } from "./model-resolution"
|
||||
@@ -51,6 +52,11 @@ export function maybeCreateSisyphusConfig(input: {
|
||||
isFirstRunNoCache ||
|
||||
isAnyFallbackModelAvailable(sisyphusRequirement.fallbackChain, availableModels)
|
||||
|
||||
if (!disabledAgents.includes("sisyphus") && !meetsSisyphusAnyModelRequirement) {
|
||||
log("[agent-registration] Agent skipped: no model in fallback chain is available", {
|
||||
agent: "sisyphus",
|
||||
})
|
||||
}
|
||||
if (disabledAgents.includes("sisyphus") || !meetsSisyphusAnyModelRequirement) return undefined
|
||||
|
||||
let sisyphusResolution = applyModelResolution({
|
||||
@@ -65,7 +71,13 @@ export function maybeCreateSisyphusConfig(input: {
|
||||
sisyphusResolution = getFirstFallbackModel(sisyphusRequirement)
|
||||
}
|
||||
|
||||
if (!sisyphusResolution) return undefined
|
||||
if (!sisyphusResolution) {
|
||||
log("[agent-registration] Agent skipped: model resolution returned no result", {
|
||||
agent: "sisyphus",
|
||||
configuredModel: sisyphusOverride?.model,
|
||||
})
|
||||
return undefined
|
||||
}
|
||||
const { model: sisyphusModel, variant: sisyphusResolvedVariant } = sisyphusResolution
|
||||
|
||||
let sisyphusConfig = createSisyphusAgent(
|
||||
|
||||
Reference in New Issue
Block a user