feat(plan-agent): apply prometheus config to plan agent with fallback chain

- Add prometheus model fallback chain (claude-opus-4-5 → gpt-5.2 → gemini-3-pro)
- Plan agent now inherits prometheus settings (model, prompt, permission, variant)
- Plan agent mode remains 'subagent' while using prometheus config
- Add name field to prometheus config to fix agent.name undefined error
This commit is contained in:
justsisyphus 2026-01-26 18:31:48 +09:00
parent 383f43548b
commit cf6e714946

View File

@ -25,10 +25,12 @@ import { loadMcpConfigs } from "../features/claude-code-mcp-loader";
import { loadAllPluginComponents } from "../features/claude-code-plugin-loader"; import { loadAllPluginComponents } from "../features/claude-code-plugin-loader";
import { createBuiltinMcps } from "../mcp"; import { createBuiltinMcps } from "../mcp";
import type { OhMyOpenCodeConfig } from "../config"; import type { OhMyOpenCodeConfig } from "../config";
import { log } from "../shared"; import { log, fetchAvailableModels, readConnectedProvidersCache } from "../shared";
import { getOpenCodeConfigPaths } from "../shared/opencode-config-dir"; import { getOpenCodeConfigPaths } from "../shared/opencode-config-dir";
import { migrateAgentConfig } from "../shared/permission-compat"; import { migrateAgentConfig } from "../shared/permission-compat";
import { AGENT_NAME_MAP } from "../shared/migration"; import { AGENT_NAME_MAP } from "../shared/migration";
import { resolveModelWithFallback } from "../shared/model-resolver";
import { AGENT_MODEL_REQUIREMENTS } from "../shared/model-requirements";
import { PROMETHEUS_SYSTEM_PROMPT, PROMETHEUS_PERMISSION } from "../agents/prometheus-prompt"; import { PROMETHEUS_SYSTEM_PROMPT, PROMETHEUS_PERMISSION } from "../agents/prometheus-prompt";
import { DEFAULT_CATEGORIES } from "../tools/delegate-task/constants"; import { DEFAULT_CATEGORIES } from "../tools/delegate-task/constants";
import type { ModelCacheState } from "../plugin-state"; import type { ModelCacheState } from "../plugin-state";
@ -221,13 +223,10 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
); );
const prometheusOverride = const prometheusOverride =
pluginConfig.agents?.["prometheus"] as pluginConfig.agents?.["prometheus"] as
| (Record<string, unknown> & { category?: string; model?: string }) | (Record<string, unknown> & { category?: string; model?: string; variant?: string })
| undefined; | undefined;
const defaultModel = config.model as string | undefined; const defaultModel = config.model as string | undefined;
// Resolve full category config (model, temperature, top_p, tools, etc.)
// Apply all category properties when category is specified, but explicit
// overrides (model, temperature, etc.) will take precedence during merge
const categoryConfig = prometheusOverride?.category const categoryConfig = prometheusOverride?.category
? resolveCategoryConfig( ? resolveCategoryConfig(
prometheusOverride.category, prometheusOverride.category,
@ -235,19 +234,31 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
) )
: undefined; : undefined;
// Model resolution: explicit override → category config → OpenCode default const prometheusRequirement = AGENT_MODEL_REQUIREMENTS["prometheus"];
// No hardcoded fallback - OpenCode config.model is the terminal fallback const connectedProviders = readConnectedProvidersCache();
const resolvedModel = prometheusOverride?.model ?? categoryConfig?.model ?? defaultModel; const availableModels = ctx.client
? await fetchAvailableModels(ctx.client, { connectedProviders: connectedProviders ?? undefined })
: new Set<string>();
const modelResolution = resolveModelWithFallback({
userModel: prometheusOverride?.model ?? categoryConfig?.model,
fallbackChain: prometheusRequirement?.fallbackChain,
availableModels,
systemDefaultModel: defaultModel ?? "",
});
const resolvedModel = modelResolution?.model;
const resolvedVariant = modelResolution?.variant;
const variantToUse = prometheusOverride?.variant ?? resolvedVariant;
const prometheusBase = { const prometheusBase = {
// Only include model if one was resolved - let OpenCode apply its own default if none name: "prometheus",
...(resolvedModel ? { model: resolvedModel } : {}), ...(resolvedModel ? { model: resolvedModel } : {}),
...(variantToUse ? { variant: variantToUse } : {}),
mode: "primary" as const, mode: "primary" as const,
prompt: PROMETHEUS_SYSTEM_PROMPT, prompt: PROMETHEUS_SYSTEM_PROMPT,
permission: PROMETHEUS_PERMISSION, permission: PROMETHEUS_PERMISSION,
description: `${configAgent?.plan?.description ?? "Plan agent"} (Prometheus - OhMyOpenCode)`, description: `${configAgent?.plan?.description ?? "Plan agent"} (Prometheus - OhMyOpenCode)`,
color: (configAgent?.plan?.color as string) ?? "#FF6347", color: (configAgent?.plan?.color as string) ?? "#FF6347",
// Apply category properties (temperature, top_p, tools, etc.)
...(categoryConfig?.temperature !== undefined ...(categoryConfig?.temperature !== undefined
? { temperature: categoryConfig.temperature } ? { temperature: categoryConfig.temperature }
: {}), : {}),
@ -295,8 +306,8 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
? migrateAgentConfig(configAgent.build as Record<string, unknown>) ? migrateAgentConfig(configAgent.build as Record<string, unknown>)
: {}; : {};
const planDemoteConfig = replacePlan const planDemoteConfig = replacePlan && agentConfig["prometheus"]
? { mode: "subagent" as const } ? { ...agentConfig["prometheus"], name: "plan", mode: "subagent" as const }
: undefined; : undefined;
config.agent = { config.agent = {