fix(agents): stop advertising custom agents to orchestrators

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-31 13:05:38 -07:00
parent 33c8b7f675
commit 68ae9dca4b
3 changed files with 48 additions and 26 deletions
-18
View File
@@ -26,7 +26,6 @@ import { collectPendingBuiltinAgents } from "./builtin-agents/general-agents"
import { maybeCreateSisyphusConfig } from "./builtin-agents/sisyphus-agent"
import { maybeCreateHephaestusConfig } from "./builtin-agents/hephaestus-agent"
import { maybeCreateAtlasConfig } from "./builtin-agents/atlas-agent"
import { buildCustomAgentMetadata, parseRegisteredAgentSummaries } from "./custom-agent-summaries"
type AgentSource = AgentFactory | AgentConfig
@@ -120,23 +119,6 @@ export async function createBuiltinAgents(
disableOmoEnv,
})
const registeredAgents = parseRegisteredAgentSummaries(customAgentSummaries)
const builtinAgentNames = new Set(Object.keys(agentSources).map((name) => name.toLowerCase()))
const disabledAgentNames = new Set(disabledAgents.map((name) => name.toLowerCase()))
for (const agent of registeredAgents) {
const lowerName = agent.name.toLowerCase()
if (builtinAgentNames.has(lowerName)) continue
if (disabledAgentNames.has(lowerName)) continue
if (availableAgents.some((availableAgent) => availableAgent.name.toLowerCase() === lowerName)) continue
availableAgents.push({
name: agent.name,
description: agent.description,
metadata: buildCustomAgentMetadata(agent.name, agent.description),
})
}
const sisyphusConfig = maybeCreateSisyphusConfig({
disabledAgents,
agentOverrides,
@@ -0,0 +1,40 @@
import { describe, expect, spyOn, test } from "bun:test"
import { createBuiltinAgents } from "./builtin-agents"
import * as shared from "../shared"
const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6"
describe("createBuiltinAgents custom agent visibility", () => {
test("#given runtime custom agents #when orchestrator prompts are built #then custom agents are not advertised for automatic delegation", async () => {
//#given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"])
)
try {
//#when
const agents = await createBuiltinAgents(
[],
{},
undefined,
TEST_DEFAULT_MODEL,
undefined,
undefined,
[],
[
{
name: "backend-engineer",
description: "Custom backend specialist",
},
]
)
//#then
expect(agents.sisyphus.prompt).not.toContain("backend-engineer")
expect(agents.hephaestus.prompt).not.toContain("backend-engineer")
expect(agents.atlas.prompt).not.toContain("backend-engineer")
} finally {
fetchSpy.mockRestore()
}
})
})
+8 -8
View File
@@ -278,7 +278,7 @@ describe("createBuiltinAgents with model overrides", () => {
fetchSpy.mockRestore()
})
test("includes custom agents in orchestrator prompts when provided via config", async () => {
test("does not advertise custom agents in orchestrator prompts when provided via config", async () => {
// #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set([
@@ -313,9 +313,9 @@ describe("createBuiltinAgents with model overrides", () => {
)
// #then
expect(agents.sisyphus.prompt).toContain("researcher")
expect(agents.hephaestus.prompt).toContain("researcher")
expect(agents.atlas.prompt).toContain("researcher")
expect(agents.sisyphus.prompt).not.toContain("researcher")
expect(agents.hephaestus.prompt).not.toContain("researcher")
expect(agents.atlas.prompt).not.toContain("researcher")
} finally {
fetchSpy.mockRestore()
}
@@ -429,7 +429,7 @@ describe("createBuiltinAgents with model overrides", () => {
}
})
test("deduplicates custom agents case-insensitively", async () => {
test("does not advertise duplicate custom agents case-insensitively", async () => {
// #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"])
@@ -455,13 +455,13 @@ describe("createBuiltinAgents with model overrides", () => {
// #then
const matches = (agents.sisyphus?.prompt ?? "").match(/Custom agent: researcher/gi) ?? []
expect(matches.length).toBe(1)
expect(matches.length).toBe(0)
} finally {
fetchSpy.mockRestore()
}
})
test("sanitizes custom agent strings for markdown tables", async () => {
test("does not surface custom agent strings in orchestrator prompts", async () => {
// #given
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"])
@@ -488,7 +488,7 @@ describe("createBuiltinAgents with model overrides", () => {
)
// #then
expect(agents.sisyphus.prompt).toContain("Line1 Alpha \\| Beta")
expect(agents.sisyphus.prompt).not.toContain("Line1 Alpha \\| Beta")
} finally {
fetchSpy.mockRestore()
}