fix(team-mode): reject coordinator agents as subagent targets (#4027)

Agents could select coordinator/meta agents (Prometheus, Atlas,
Sisyphus/Ultraworker) as subagent targets via task() / delegation,
producing duplicate orchestration loops and conflicting team state.
This is the inverse of #3987 / #4065 — symmetric guard on the
delegation TARGET side, using the same AGENT_ELIGIBILITY_REGISTRY
classification.

Add a runtime guard at the delegation entry point that rejects
task() calls whose subagent_type resolves to an agent marked as
hard-reject / coordinator-only in the eligibility registry, with
an actionable error naming the agent. Regression test asserts a
prometheus-targeted delegation is rejected before any subagent
session spawns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ZeyuFu
2026-05-16 02:13:28 -04:00
parent fcb96841f8
commit 7af3007e67
4 changed files with 115 additions and 3 deletions
+19
View File
@@ -346,3 +346,22 @@ export function isPlanFamily(category: string | undefined): boolean {
const lowerCategory = getAgentConfigKey(category).toLowerCase().trim()
return PLAN_FAMILY_NAMES.some((name) => lowerCategory === name)
}
/**
* Coordinator/meta agents that own the orchestration loop and must not be used as
* arbitrary subagent targets via task(). Delegating to these creates duplicate
* orchestration and conflicting team state (issue #4027).
*
* Symmetric guard to the caller-eligibility check added by PR #4065 for team_create.
*/
export const COORDINATOR_AGENT_NAMES = ["prometheus", "atlas", "sisyphus"]
/**
* Returns true when the given agent name refers to a coordinator/meta agent that
* should not be reachable as a subagent_type target via task().
*/
export function isCoordinatorAgent(agentName: string | undefined): boolean {
if (!agentName) return false
const normalized = getAgentConfigKey(agentName).toLowerCase().trim()
return COORDINATOR_AGENT_NAMES.some((name) => normalized === name)
}