merge: integrate origin/dev into modular-enforcement branch
Resolves all merge conflicts, preserving our split module structure while integrating all dev changes: - Custom agent summaries support (parseRegisteredAgentSummaries) - Background notification queue (enqueueNotificationForParent) - Atlas shared git-worktree module (collectGitDiffStats, formatFileChanges) - Ralph-loop withTimeout + DEFAULT_API_TIMEOUT=5000 - Session recovery assistant_prefill_unsupported error type - Atlas agentOverrides forwarding - Config handler plan model demotion (buildPlanDemoteConfig) - Delegate-task agentOverrides, promptSyncWithModelSuggestionRetry, variant - LSP init timeout + stale init detection - isPlanFamily function + task-continuation-enforcer hook - Handoff command
This commit is contained in:
@@ -251,6 +251,222 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
expect(agents.sisyphus.prompt).toContain("frontend-ui-ux")
|
||||
expect(agents.sisyphus.prompt).toContain("git-master")
|
||||
})
|
||||
|
||||
test("includes custom agents in orchestrator prompts when provided via config", async () => {
|
||||
// #given
|
||||
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
|
||||
new Set([
|
||||
"anthropic/claude-opus-4-6",
|
||||
"kimi-for-coding/k2p5",
|
||||
"opencode/kimi-k2.5-free",
|
||||
"zai-coding-plan/glm-4.7",
|
||||
"opencode/glm-4.7-free",
|
||||
"openai/gpt-5.2",
|
||||
])
|
||||
)
|
||||
|
||||
const customAgentSummaries = [
|
||||
{
|
||||
name: "researcher",
|
||||
description: "Research agent for deep analysis",
|
||||
hidden: false,
|
||||
},
|
||||
]
|
||||
|
||||
try {
|
||||
// #when
|
||||
const agents = await createBuiltinAgents(
|
||||
[],
|
||||
{},
|
||||
undefined,
|
||||
TEST_DEFAULT_MODEL,
|
||||
undefined,
|
||||
undefined,
|
||||
[],
|
||||
customAgentSummaries
|
||||
)
|
||||
|
||||
// #then
|
||||
expect(agents.sisyphus.prompt).toContain("researcher")
|
||||
expect(agents.hephaestus.prompt).toContain("researcher")
|
||||
expect(agents.atlas.prompt).toContain("researcher")
|
||||
} finally {
|
||||
fetchSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
test("excludes hidden custom agents from orchestrator prompts", async () => {
|
||||
// #given
|
||||
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
|
||||
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.2"])
|
||||
)
|
||||
|
||||
const customAgentSummaries = [
|
||||
{
|
||||
name: "hidden-agent",
|
||||
description: "Should never show",
|
||||
hidden: true,
|
||||
},
|
||||
]
|
||||
|
||||
try {
|
||||
// #when
|
||||
const agents = await createBuiltinAgents(
|
||||
[],
|
||||
{},
|
||||
undefined,
|
||||
TEST_DEFAULT_MODEL,
|
||||
undefined,
|
||||
undefined,
|
||||
[],
|
||||
customAgentSummaries
|
||||
)
|
||||
|
||||
// #then
|
||||
expect(agents.sisyphus.prompt).not.toContain("hidden-agent")
|
||||
expect(agents.hephaestus.prompt).not.toContain("hidden-agent")
|
||||
expect(agents.atlas.prompt).not.toContain("hidden-agent")
|
||||
} finally {
|
||||
fetchSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
test("excludes disabled custom agents from orchestrator prompts", async () => {
|
||||
// #given
|
||||
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
|
||||
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.2"])
|
||||
)
|
||||
|
||||
const customAgentSummaries = [
|
||||
{
|
||||
name: "disabled-agent",
|
||||
description: "Should never show",
|
||||
disabled: true,
|
||||
},
|
||||
]
|
||||
|
||||
try {
|
||||
// #when
|
||||
const agents = await createBuiltinAgents(
|
||||
[],
|
||||
{},
|
||||
undefined,
|
||||
TEST_DEFAULT_MODEL,
|
||||
undefined,
|
||||
undefined,
|
||||
[],
|
||||
customAgentSummaries
|
||||
)
|
||||
|
||||
// #then
|
||||
expect(agents.sisyphus.prompt).not.toContain("disabled-agent")
|
||||
expect(agents.hephaestus.prompt).not.toContain("disabled-agent")
|
||||
expect(agents.atlas.prompt).not.toContain("disabled-agent")
|
||||
} finally {
|
||||
fetchSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
test("excludes custom agents when disabledAgents contains their name (case-insensitive)", async () => {
|
||||
// #given
|
||||
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
|
||||
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.2"])
|
||||
)
|
||||
|
||||
const disabledAgents = ["ReSeArChEr"]
|
||||
const customAgentSummaries = [
|
||||
{
|
||||
name: "researcher",
|
||||
description: "Should never show",
|
||||
},
|
||||
]
|
||||
|
||||
try {
|
||||
// #when
|
||||
const agents = await createBuiltinAgents(
|
||||
disabledAgents,
|
||||
{},
|
||||
undefined,
|
||||
TEST_DEFAULT_MODEL,
|
||||
undefined,
|
||||
undefined,
|
||||
[],
|
||||
customAgentSummaries
|
||||
)
|
||||
|
||||
// #then
|
||||
expect(agents.sisyphus.prompt).not.toContain("researcher")
|
||||
expect(agents.hephaestus.prompt).not.toContain("researcher")
|
||||
expect(agents.atlas.prompt).not.toContain("researcher")
|
||||
} finally {
|
||||
fetchSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
test("deduplicates custom agents case-insensitively", async () => {
|
||||
// #given
|
||||
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
|
||||
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.2"])
|
||||
)
|
||||
|
||||
const customAgentSummaries = [
|
||||
{ name: "Researcher", description: "First" },
|
||||
{ name: "researcher", description: "Second" },
|
||||
]
|
||||
|
||||
try {
|
||||
// #when
|
||||
const agents = await createBuiltinAgents(
|
||||
[],
|
||||
{},
|
||||
undefined,
|
||||
TEST_DEFAULT_MODEL,
|
||||
undefined,
|
||||
undefined,
|
||||
[],
|
||||
customAgentSummaries
|
||||
)
|
||||
|
||||
// #then
|
||||
const matches = agents.sisyphus.prompt.match(/Custom agent: researcher/gi) ?? []
|
||||
expect(matches.length).toBe(1)
|
||||
} finally {
|
||||
fetchSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
test("sanitizes custom agent strings for markdown tables", async () => {
|
||||
// #given
|
||||
const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(
|
||||
new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.2"])
|
||||
)
|
||||
|
||||
const customAgentSummaries = [
|
||||
{
|
||||
name: "table-agent",
|
||||
description: "Line1\nAlpha | Beta",
|
||||
},
|
||||
]
|
||||
|
||||
try {
|
||||
// #when
|
||||
const agents = await createBuiltinAgents(
|
||||
[],
|
||||
{},
|
||||
undefined,
|
||||
TEST_DEFAULT_MODEL,
|
||||
undefined,
|
||||
undefined,
|
||||
[],
|
||||
customAgentSummaries
|
||||
)
|
||||
|
||||
// #then
|
||||
expect(agents.sisyphus.prompt).toContain("Line1 Alpha \\| Beta")
|
||||
} finally {
|
||||
fetchSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("createBuiltinAgents without systemDefaultModel", () => {
|
||||
|
||||
Reference in New Issue
Block a user