import type { AgentConfig } from "@opencode-ai/sdk"; import { applyOverrides } from "../agents/builtin-agents/agent-overrides"; import type { AgentOverrideConfig } from "../agents/types"; import type { OhMyOpenCodeConfig } from "../config"; import { getAgentConfigKey } from "../shared/agent-display-names"; import { AGENT_NAME_MAP } from "../shared/migration"; import { mergeCategories } from "../shared/merge-categories"; const RESERVED_AGENT_KEYS = new Set( [ "build", "plan", "sisyphus-junior", "opencode-builder", ...Object.keys(AGENT_NAME_MAP), ...Object.values(AGENT_NAME_MAP), ].map((key) => getAgentConfigKey(key).toLowerCase()), ); export type AgentSummary = { name: string; description: string; hidden?: boolean; disabled?: boolean; enabled?: boolean; }; export function applyCustomAgentOverrides(params: { mergedAgents: Record; userOverrides: OhMyOpenCodeConfig["custom_agents"] | undefined; builtinOverrideKeys: Set; mergedCategories: ReturnType; directory: string; }): void { if (!params.userOverrides) return; for (const [overrideKey, override] of Object.entries(params.userOverrides)) { if (!override) continue; const normalizedOverrideKey = getAgentConfigKey(overrideKey).toLowerCase(); if (params.builtinOverrideKeys.has(normalizedOverrideKey)) continue; const existingKey = Object.keys(params.mergedAgents).find( (key) => key.toLowerCase() === overrideKey.toLowerCase() || key.toLowerCase() === normalizedOverrideKey, ); if (!existingKey) continue; const existingAgent = params.mergedAgents[existingKey]; if (!existingAgent || typeof existingAgent !== "object") continue; params.mergedAgents[existingKey] = applyOverrides( existingAgent as AgentConfig, override as AgentOverrideConfig, params.mergedCategories, params.directory, ); } } export function collectCustomAgentSummariesFromRecord( agents: Record | undefined, ): AgentSummary[] { if (!agents) return []; const summaries: AgentSummary[] = []; for (const [name, value] of Object.entries(agents)) { const normalizedName = getAgentConfigKey(name).toLowerCase(); if (RESERVED_AGENT_KEYS.has(normalizedName)) continue; if (!value || typeof value !== "object") continue; const agentValue = value as Record; const description = typeof agentValue.description === "string" ? agentValue.description : ""; summaries.push({ name, description, hidden: agentValue.hidden === true, disabled: agentValue.disabled === true, enabled: agentValue.enabled === false ? false : true, }); } return summaries; } export function mergeCustomAgentSummaries(...summaryGroups: AgentSummary[][]): AgentSummary[] { const merged = new Map(); for (const group of summaryGroups) { for (const summary of group) { const key = summary.name.toLowerCase(); if (!merged.has(key)) { merged.set(key, summary); continue; } const existing = merged.get(key); if (!existing) continue; const existingDescription = existing.description.trim(); const incomingDescription = summary.description.trim(); if (!existingDescription && incomingDescription) { merged.set(key, summary); } } } return Array.from(merged.values()); } export function collectKnownCustomAgentNames( ...agentGroups: Array | undefined> ): Set { const knownNames = new Set(); for (const group of agentGroups) { if (!group) continue; for (const [name, value] of Object.entries(group)) { const normalizedName = getAgentConfigKey(name).toLowerCase(); if (RESERVED_AGENT_KEYS.has(normalizedName)) continue; if (!value || typeof value !== "object") continue; knownNames.add(normalizedName); } } return knownNames; } export function filterSummariesByKnownNames( summaries: AgentSummary[], knownNames: Set, ): AgentSummary[] { return summaries.filter((summary) => knownNames.has(summary.name.toLowerCase())); }