fix: register custom user agents in delegate-task resolver (#2689)

agent-config-handler.ts now registers custom agents from
~/.config/opencode/agents/ into the task subagent registry.

5005 tests pass, tsc clean.

Closes #2689
This commit is contained in:
YeonGyu-Kim
2026-04-07 15:24:21 +09:00
parent be562905d6
commit fc009caaa1
2 changed files with 99 additions and 9 deletions
@@ -293,6 +293,81 @@ describe("applyAgentConfig builtin override protection", () => {
expect(createSisyphusJuniorAgentSpy).toHaveBeenCalledWith(undefined, "openai/gpt-5.4", false)
})
test("defaults mode to subagent for configAgent entries missing mode", async () => {
// given
const config = createBaseConfig()
;(config as Record<string, unknown>).agent = {
"custom-reviewer": {
name: "custom-reviewer",
prompt: "Review code for security issues",
description: "Custom code reviewer",
},
}
// when
const result = await applyAgentConfig({
config,
pluginConfig: createPluginConfig(),
ctx: { directory: "/tmp" },
pluginComponents: createPluginComponents(),
})
// then
const customAgent = result["custom-reviewer"] as Record<string, unknown>
expect(customAgent).toBeDefined()
expect(customAgent.mode).toBe("subagent")
})
test("preserves explicit mode on configAgent entries", async () => {
// given
const config = createBaseConfig()
;(config as Record<string, unknown>).agent = {
"custom-primary": {
name: "custom-primary",
prompt: "Primary agent",
mode: "primary",
},
}
// when
const result = await applyAgentConfig({
config,
pluginConfig: createPluginConfig(),
ctx: { directory: "/tmp" },
pluginComponents: createPluginComponents(),
})
// then
const customAgent = result["custom-primary"] as Record<string, unknown>
expect(customAgent).toBeDefined()
expect(customAgent.mode).toBe("primary")
})
test("defaults mode to subagent for plugin agents missing mode", async () => {
// given
const pluginComponents = createPluginComponents()
pluginComponents.agents = {
"plugin-worker": {
name: "plugin-worker",
prompt: "Do work",
description: "Plugin worker agent",
} as Record<string, unknown>,
}
// when
const result = await applyAgentConfig({
config: createBaseConfig(),
pluginConfig: createPluginConfig(),
ctx: { directory: "/tmp" },
pluginComponents,
})
// then
const pluginAgent = result["plugin-worker"] as Record<string, unknown>
expect(pluginAgent).toBeDefined()
expect(pluginAgent.mode).toBe("subagent")
})
test("includes project and global .agents skills in builtin agent awareness", async () => {
// given
const projectAgentsSkill = {
+24 -9
View File
@@ -99,10 +99,12 @@ export async function applyAgentConfig(params: {
const rawPluginAgents = params.pluginComponents.agents;
const pluginAgents = Object.fromEntries(
Object.entries(rawPluginAgents).map(([key, value]) => [
key,
value ? migrateAgentConfig(value as Record<string, unknown>) : value,
]),
Object.entries(rawPluginAgents).map(([key, value]) => {
if (!value) return [key, value];
const migrated = migrateAgentConfig(value as Record<string, unknown>);
if (!migrated.mode) migrated.mode = "subagent";
return [key, migrated];
}),
);
const configAgent = params.config.agent as AgentConfigRecord | undefined;
@@ -219,10 +221,12 @@ export async function applyAgentConfig(params: {
if (key in builtinAgents) return false;
return true;
})
.map(([key, value]) => [
key,
value ? migrateAgentConfig(value as Record<string, unknown>) : value,
]),
.map(([key, value]) => {
if (!value) return [key, value];
const migrated = migrateAgentConfig(value as Record<string, unknown>);
if (!migrated.mode) migrated.mode = "subagent";
return [key, migrated];
}),
)
: {};
@@ -285,12 +289,23 @@ export async function applyAgentConfig(params: {
protectedBuiltinAgentNames,
);
const defaultedConfigAgents = configAgent
? Object.fromEntries(
Object.entries(configAgent).map(([key, value]) => {
if (!value) return [key, value];
const migrated = migrateAgentConfig(value as Record<string, unknown>);
if (!migrated.mode) migrated.mode = "subagent";
return [key, migrated];
}),
)
: {};
params.config.agent = {
...builtinAgents,
...filterDisabledAgents(filteredUserAgents),
...filterDisabledAgents(filteredProjectAgents),
...filterDisabledAgents(filteredPluginAgents),
...configAgent,
...defaultedConfigAgents,
};
}