From a7a847eb9ee8f0e336ca9ef50cc4b2b7881cd787 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 2 Feb 2026 10:49:16 +0900 Subject: [PATCH] feat(cli): implement default agent priority in run command Add resolveRunAgent() to determine agent with priority: 1. CLI --agent flag (highest) 2. OPENCODE_DEFAULT_AGENT environment variable 3. oh-my-opencode.json 'default_run_agent' config 4. 'sisyphus' (fallback) Features: - Case-insensitive agent name matching - Warn and fallback when requested agent is disabled - Pick next available core agent when default is disabled --- src/cli/run/runner.ts | 72 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/src/cli/run/runner.ts b/src/cli/run/runner.ts index 11fe026e..0fe6b819 100644 --- a/src/cli/run/runner.ts +++ b/src/cli/run/runner.ts @@ -3,19 +3,87 @@ import pc from "picocolors" import type { RunOptions, RunContext } from "./types" import { checkCompletionConditions } from "./completion" import { createEventState, processEvents, serializeError } from "./events" +import type { OhMyOpenCodeConfig } from "../../config" +import { loadPluginConfig } from "../../plugin-config" const POLL_INTERVAL_MS = 500 const DEFAULT_TIMEOUT_MS = 0 const SESSION_CREATE_MAX_RETRIES = 3 const SESSION_CREATE_RETRY_DELAY_MS = 1000 +const CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"] as const +const DEFAULT_AGENT = "sisyphus" + +type EnvVars = Record + +const normalizeAgentName = (agent?: string): string | undefined => { + if (!agent) return undefined + const trimmed = agent.trim() + if (!trimmed) return undefined + const lowered = trimmed.toLowerCase() + const coreMatch = CORE_AGENT_ORDER.find((name) => name.toLowerCase() === lowered) + return coreMatch ?? trimmed +} + +const isAgentDisabled = (agent: string, config: OhMyOpenCodeConfig): boolean => { + const lowered = agent.toLowerCase() + if (lowered === "sisyphus" && config.sisyphus_agent?.disabled === true) { + return true + } + return (config.disabled_agents ?? []).some( + (disabled) => disabled.toLowerCase() === lowered + ) +} + +const pickFallbackAgent = (config: OhMyOpenCodeConfig): string => { + for (const agent of CORE_AGENT_ORDER) { + if (!isAgentDisabled(agent, config)) { + return agent + } + } + return DEFAULT_AGENT +} + +export const resolveRunAgent = ( + options: RunOptions, + pluginConfig: OhMyOpenCodeConfig, + env: EnvVars = process.env +): string => { + const cliAgent = normalizeAgentName(options.agent) + const envAgent = normalizeAgentName(env.OPENCODE_DEFAULT_AGENT) + const configAgent = normalizeAgentName(pluginConfig.default_run_agent) + const resolved = cliAgent ?? envAgent ?? configAgent ?? DEFAULT_AGENT + const normalized = normalizeAgentName(resolved) ?? DEFAULT_AGENT + + if (isAgentDisabled(normalized, pluginConfig)) { + const fallback = pickFallbackAgent(pluginConfig) + const fallbackDisabled = isAgentDisabled(fallback, pluginConfig) + if (fallbackDisabled) { + console.log( + pc.yellow( + `Requested agent "${normalized}" is disabled and no enabled core agent was found. Proceeding with "${fallback}".` + ) + ) + return fallback + } + console.log( + pc.yellow( + `Requested agent "${normalized}" is disabled. Falling back to "${fallback}".` + ) + ) + return fallback + } + + return normalized +} export async function run(options: RunOptions): Promise { const { message, - agent, directory = process.cwd(), timeout = DEFAULT_TIMEOUT_MS, } = options + const pluginConfig = loadPluginConfig(directory, { command: "run" }) + const resolvedAgent = resolveRunAgent(options, pluginConfig) console.log(pc.cyan("Starting opencode server...")) @@ -120,7 +188,7 @@ export async function run(options: RunOptions): Promise { await client.session.promptAsync({ path: { id: sessionID }, body: { - agent, + agent: resolvedAgent, parts: [{ type: "text", text: message }], }, query: { directory },