Merge pull request #4065 from PeterPonyu/fix/3987-team-create-hard-reject-validation
fix(team-mode): reject team_create from hard-reject agents (#3987)
This commit is contained in:
@@ -284,6 +284,34 @@ describe("team lifecycle tools", () => {
|
||||
expect(hasRuntime(created.teamRunId)).toBe(false)
|
||||
})
|
||||
|
||||
test("team_create denies a hard-reject caller even when spec has an explicit lead field", async () => {
|
||||
// given
|
||||
const teamCreateTool = createTeamCreateToolForTest()
|
||||
const prometheusContext = {
|
||||
...createToolContext("lead-session"),
|
||||
agent: "prometheus",
|
||||
}
|
||||
const inlineSpec = {
|
||||
name: "alpha-team",
|
||||
lead: { kind: "subagent_type", subagent_type: "sisyphus" },
|
||||
members: [{ kind: "category", name: "member-a", category: "quick", prompt: "Do the assigned work" }],
|
||||
}
|
||||
|
||||
// when
|
||||
let errorMessage = ""
|
||||
try {
|
||||
await teamCreateTool.execute({ inline_spec: inlineSpec }, prometheusContext)
|
||||
} catch (error) {
|
||||
errorMessage = error instanceof Error ? error.message : String(error)
|
||||
}
|
||||
|
||||
// then
|
||||
expect(errorMessage).toContain("team_create denied")
|
||||
expect(errorMessage).toContain("prometheus")
|
||||
expect(errorMessage).toContain("hard-reject")
|
||||
expect(createTeamRunMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test("team_reject_shutdown records the rejection reason", async () => {
|
||||
// given
|
||||
const createTool = createTeamCreateToolForTest()
|
||||
|
||||
@@ -8,7 +8,9 @@ import { mergeCategories } from "../../../shared/merge-categories"
|
||||
import type { OpencodeClient } from "../../../tools/delegate-task/types"
|
||||
import type { BackgroundManager } from "../../background-agent/manager"
|
||||
import type { TmuxSessionManager } from "../../tmux-subagent/manager"
|
||||
import { getAgentConfigKey } from "../../../shared/agent-display-names"
|
||||
import { resolveCallerTeamLead } from "../resolve-caller-team-lead"
|
||||
import { AGENT_ELIGIBILITY_REGISTRY } from "../types"
|
||||
import { loadTeamSpec, normalizeTeamSpecInput } from "../team-registry/loader"
|
||||
import { validateSpec } from "../team-registry/validator"
|
||||
import { createTeamRun } from "../team-runtime/create"
|
||||
@@ -197,6 +199,13 @@ export function createTeamCreateTool(
|
||||
if (!leadSessionId) throw new Error("team_create requires leadSessionId or tool context sessionID")
|
||||
const projectRoot = typeof runtimeContext.directory === "string" ? runtimeContext.directory : process.cwd()
|
||||
const callerTeamLead = resolveCallerTeamLead(runtimeContext.agent)
|
||||
if (callerTeamLead.displayName !== undefined) {
|
||||
const callerAgentKey = getAgentConfigKey(callerTeamLead.displayName)
|
||||
const callerRegistryEntry = AGENT_ELIGIBILITY_REGISTRY[callerAgentKey]
|
||||
if (callerRegistryEntry?.verdict === "hard-reject") {
|
||||
throw new Error(`team_create denied: caller '${callerAgentKey}' is a hard-reject agent and cannot create teams regardless of an explicit 'lead' in the spec. ${callerRegistryEntry.rejectionMessage ?? `Agent '${callerAgentKey}' is not eligible to lead a team.`}`)
|
||||
}
|
||||
}
|
||||
const defaultCategoryName = resolveDefaultInlineCategory(executorConfig?.userCategories)
|
||||
const spec = args.teamName
|
||||
? await deps.loadTeamSpec(args.teamName, config, projectRoot, { callerTeamLead })
|
||||
|
||||
Reference in New Issue
Block a user