oh-my-opencode overwrote OpenCode's default_agent with sisyphus whenever Sisyphus orchestration was enabled. This made explicit defaults like Hephaestus ineffective and forced manual agent switching in new sessions. Only assign sisyphus as default when default_agent is missing or blank, and preserve existing configured values. Add tests for both preservation and fallback behavior to prevent regressions.
218 lines
7.7 KiB
TypeScript
218 lines
7.7 KiB
TypeScript
import { createBuiltinAgents } from "../agents";
|
|
import { createSisyphusJuniorAgentWithOverrides } from "../agents/sisyphus-junior";
|
|
import type { OhMyOpenCodeConfig } from "../config";
|
|
import { log, migrateAgentConfig } from "../shared";
|
|
import { AGENT_NAME_MAP } from "../shared/migration";
|
|
import { getAgentDisplayName } from "../shared/agent-display-names";
|
|
import {
|
|
discoverConfigSourceSkills,
|
|
discoverOpencodeGlobalSkills,
|
|
discoverOpencodeProjectSkills,
|
|
discoverProjectClaudeSkills,
|
|
discoverUserClaudeSkills,
|
|
} from "../features/opencode-skill-loader";
|
|
import { loadProjectAgents, loadUserAgents } from "../features/claude-code-agent-loader";
|
|
import type { PluginComponents } from "./plugin-components-loader";
|
|
import { reorderAgentsByPriority } from "./agent-priority-order";
|
|
import { remapAgentKeysToDisplayNames } from "./agent-key-remapper";
|
|
import { buildPrometheusAgentConfig } from "./prometheus-agent-config-builder";
|
|
import { buildPlanDemoteConfig } from "./plan-model-inheritance";
|
|
|
|
type AgentConfigRecord = Record<string, Record<string, unknown> | undefined> & {
|
|
build?: Record<string, unknown>;
|
|
plan?: Record<string, unknown>;
|
|
};
|
|
|
|
function hasConfiguredDefaultAgent(config: Record<string, unknown>): boolean {
|
|
const defaultAgent = config.default_agent;
|
|
return typeof defaultAgent === "string" && defaultAgent.trim().length > 0;
|
|
}
|
|
|
|
export async function applyAgentConfig(params: {
|
|
config: Record<string, unknown>;
|
|
pluginConfig: OhMyOpenCodeConfig;
|
|
ctx: { directory: string; client?: any };
|
|
pluginComponents: PluginComponents;
|
|
}): Promise<Record<string, unknown>> {
|
|
const migratedDisabledAgents = (params.pluginConfig.disabled_agents ?? []).map(
|
|
(agent) => {
|
|
return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
|
|
},
|
|
) as typeof params.pluginConfig.disabled_agents;
|
|
|
|
const includeClaudeSkillsForAwareness = params.pluginConfig.claude_code?.skills ?? true;
|
|
const [
|
|
discoveredConfigSourceSkills,
|
|
discoveredUserSkills,
|
|
discoveredProjectSkills,
|
|
discoveredOpencodeGlobalSkills,
|
|
discoveredOpencodeProjectSkills,
|
|
] = await Promise.all([
|
|
discoverConfigSourceSkills({
|
|
config: params.pluginConfig.skills,
|
|
configDir: params.ctx.directory,
|
|
}),
|
|
includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]),
|
|
includeClaudeSkillsForAwareness
|
|
? discoverProjectClaudeSkills(params.ctx.directory)
|
|
: Promise.resolve([]),
|
|
discoverOpencodeGlobalSkills(),
|
|
discoverOpencodeProjectSkills(params.ctx.directory),
|
|
]);
|
|
|
|
const allDiscoveredSkills = [
|
|
...discoveredConfigSourceSkills,
|
|
...discoveredOpencodeProjectSkills,
|
|
...discoveredProjectSkills,
|
|
...discoveredOpencodeGlobalSkills,
|
|
...discoveredUserSkills,
|
|
];
|
|
|
|
const browserProvider =
|
|
params.pluginConfig.browser_automation_engine?.provider ?? "playwright";
|
|
const currentModel = params.config.model as string | undefined;
|
|
const disabledSkills = new Set<string>(params.pluginConfig.disabled_skills ?? []);
|
|
const useTaskSystem = params.pluginConfig.experimental?.task_system ?? false;
|
|
|
|
const builtinAgents = await createBuiltinAgents(
|
|
migratedDisabledAgents,
|
|
params.pluginConfig.agents,
|
|
params.ctx.directory,
|
|
undefined,
|
|
params.pluginConfig.categories,
|
|
params.pluginConfig.git_master,
|
|
allDiscoveredSkills,
|
|
params.ctx.client,
|
|
browserProvider,
|
|
currentModel,
|
|
disabledSkills,
|
|
useTaskSystem,
|
|
);
|
|
|
|
const includeClaudeAgents = params.pluginConfig.claude_code?.agents ?? true;
|
|
const userAgents = includeClaudeAgents ? loadUserAgents() : {};
|
|
const projectAgents = includeClaudeAgents ? loadProjectAgents(params.ctx.directory) : {};
|
|
|
|
const rawPluginAgents = params.pluginComponents.agents;
|
|
const pluginAgents = Object.fromEntries(
|
|
Object.entries(rawPluginAgents).map(([key, value]) => [
|
|
key,
|
|
value ? migrateAgentConfig(value as Record<string, unknown>) : value,
|
|
]),
|
|
);
|
|
|
|
const isSisyphusEnabled = params.pluginConfig.sisyphus_agent?.disabled !== true;
|
|
const builderEnabled =
|
|
params.pluginConfig.sisyphus_agent?.default_builder_enabled ?? false;
|
|
const plannerEnabled = params.pluginConfig.sisyphus_agent?.planner_enabled ?? true;
|
|
const replacePlan = params.pluginConfig.sisyphus_agent?.replace_plan ?? true;
|
|
const shouldDemotePlan = plannerEnabled && replacePlan;
|
|
|
|
const configAgent = params.config.agent as AgentConfigRecord | undefined;
|
|
|
|
if (isSisyphusEnabled && builtinAgents.sisyphus) {
|
|
if (!hasConfiguredDefaultAgent(params.config)) {
|
|
(params.config as { default_agent?: string }).default_agent =
|
|
getAgentDisplayName("sisyphus");
|
|
}
|
|
|
|
const agentConfig: Record<string, unknown> = {
|
|
sisyphus: builtinAgents.sisyphus,
|
|
};
|
|
|
|
agentConfig["sisyphus-junior"] = createSisyphusJuniorAgentWithOverrides(
|
|
params.pluginConfig.agents?.["sisyphus-junior"],
|
|
undefined,
|
|
useTaskSystem,
|
|
);
|
|
|
|
if (builderEnabled) {
|
|
const { name: _buildName, ...buildConfigWithoutName } =
|
|
configAgent?.build ?? {};
|
|
const migratedBuildConfig = migrateAgentConfig(
|
|
buildConfigWithoutName as Record<string, unknown>,
|
|
);
|
|
const override = params.pluginConfig.agents?.["OpenCode-Builder"];
|
|
const base = {
|
|
...migratedBuildConfig,
|
|
description: `${(configAgent?.build?.description as string) ?? "Build agent"} (OpenCode default)`,
|
|
};
|
|
agentConfig["OpenCode-Builder"] = override ? { ...base, ...override } : base;
|
|
}
|
|
|
|
if (plannerEnabled) {
|
|
const prometheusOverride = params.pluginConfig.agents?.["prometheus"] as
|
|
| (Record<string, unknown> & { prompt_append?: string })
|
|
| undefined;
|
|
|
|
agentConfig["prometheus"] = await buildPrometheusAgentConfig({
|
|
configAgentPlan: configAgent?.plan,
|
|
pluginPrometheusOverride: prometheusOverride,
|
|
userCategories: params.pluginConfig.categories,
|
|
currentModel,
|
|
});
|
|
}
|
|
|
|
const filteredConfigAgents = configAgent
|
|
? Object.fromEntries(
|
|
Object.entries(configAgent)
|
|
.filter(([key]) => {
|
|
if (key === "build") return false;
|
|
if (key === "plan" && shouldDemotePlan) return false;
|
|
if (key in builtinAgents) return false;
|
|
return true;
|
|
})
|
|
.map(([key, value]) => [
|
|
key,
|
|
value ? migrateAgentConfig(value as Record<string, unknown>) : value,
|
|
]),
|
|
)
|
|
: {};
|
|
|
|
const migratedBuild = configAgent?.build
|
|
? migrateAgentConfig(configAgent.build as Record<string, unknown>)
|
|
: {};
|
|
|
|
const planDemoteConfig = shouldDemotePlan
|
|
? buildPlanDemoteConfig(
|
|
agentConfig["prometheus"] as Record<string, unknown> | undefined,
|
|
params.pluginConfig.agents?.plan as Record<string, unknown> | undefined,
|
|
)
|
|
: undefined;
|
|
|
|
params.config.agent = {
|
|
...agentConfig,
|
|
...Object.fromEntries(
|
|
Object.entries(builtinAgents).filter(([key]) => key !== "sisyphus"),
|
|
),
|
|
...userAgents,
|
|
...projectAgents,
|
|
...pluginAgents,
|
|
...filteredConfigAgents,
|
|
build: { ...migratedBuild, mode: "subagent", hidden: true },
|
|
...(planDemoteConfig ? { plan: planDemoteConfig } : {}),
|
|
};
|
|
} else {
|
|
params.config.agent = {
|
|
...builtinAgents,
|
|
...userAgents,
|
|
...projectAgents,
|
|
...pluginAgents,
|
|
...configAgent,
|
|
};
|
|
}
|
|
|
|
if (params.config.agent) {
|
|
params.config.agent = remapAgentKeysToDisplayNames(
|
|
params.config.agent as Record<string, unknown>,
|
|
);
|
|
params.config.agent = reorderAgentsByPriority(
|
|
params.config.agent as Record<string, unknown>,
|
|
);
|
|
}
|
|
|
|
const agentResult = params.config.agent as Record<string, unknown>;
|
|
log("[config-handler] agents loaded", { agentKeys: Object.keys(agentResult) });
|
|
return agentResult;
|
|
}
|