fix(delegate-task): restrict task-callable agent modes
This commit is contained in:
@@ -85,6 +85,41 @@ describe("resolveSubagentExecution", () => {
|
||||
})
|
||||
})
|
||||
|
||||
test("hides primary agents from task delegation lookups", async () => {
|
||||
//#given
|
||||
const args = createBaseArgs({ subagent_type: "sisyphus" })
|
||||
const executorCtx = createExecutorContext(async () => ([
|
||||
{ name: "sisyphus", mode: "primary" },
|
||||
{ name: "oracle", mode: "subagent" },
|
||||
{ name: "metis", mode: "all" },
|
||||
]))
|
||||
|
||||
//#when
|
||||
const result = await resolveSubagentExecution(args, executorCtx, "sisyphus", "deep")
|
||||
|
||||
//#then
|
||||
expect(result.agentToUse).toBe("")
|
||||
expect(result.categoryModel).toBeUndefined()
|
||||
expect(result.error).toBe('Unknown agent: "sisyphus". Available agents: metis, oracle')
|
||||
})
|
||||
|
||||
test("requires explicit all or subagent mode for task-callable agents", async () => {
|
||||
//#given
|
||||
const args = createBaseArgs({ subagent_type: "custom-worker" })
|
||||
const executorCtx = createExecutorContext(async () => ([
|
||||
{ name: "custom-worker" },
|
||||
{ name: "oracle", mode: "subagent" },
|
||||
]))
|
||||
|
||||
//#when
|
||||
const result = await resolveSubagentExecution(args, executorCtx, "sisyphus", "deep")
|
||||
|
||||
//#then
|
||||
expect(result.agentToUse).toBe("")
|
||||
expect(result.categoryModel).toBeUndefined()
|
||||
expect(result.error).toBe('Unknown agent: "custom-worker". Available agents: oracle')
|
||||
})
|
||||
|
||||
test("normalizes matched agent model string before returning categoryModel", async () => {
|
||||
//#given
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readProviderModelsCache").mockReturnValue({
|
||||
|
||||
@@ -16,6 +16,8 @@ import { resolveModelForDelegateTask } from "./model-selection"
|
||||
import { fuzzyMatchModel } from "../../shared/model-availability"
|
||||
import type { CategoryConfig } from "../../config/schema"
|
||||
|
||||
type AgentMode = "subagent" | "primary" | "all" | undefined
|
||||
|
||||
function applyCategoryParams(
|
||||
base: DelegatedModelConfig,
|
||||
config: CategoryConfig | undefined,
|
||||
@@ -85,7 +87,7 @@ Create the work plan directly - that's your job as the planning agent.`,
|
||||
preferResponseOnMissingData: true,
|
||||
})
|
||||
|
||||
const callableAgents = agents.filter((a) => a.mode !== "primary")
|
||||
const callableAgents = agents.filter((agent) => isTaskCallableAgentMode(agent.mode))
|
||||
|
||||
const resolvedDisplayName = getAgentDisplayName(agentToUse)
|
||||
const matchedAgent = callableAgents.find(
|
||||
@@ -93,19 +95,6 @@ Create the work plan directly - that's your job as the planning agent.`,
|
||||
|| agent.name.toLowerCase() === resolvedDisplayName.toLowerCase()
|
||||
)
|
||||
if (!matchedAgent) {
|
||||
const isPrimaryAgent = agents
|
||||
.filter((a) => a.mode === "primary")
|
||||
.find((agent) => agent.name.toLowerCase() === agentToUse.toLowerCase()
|
||||
|| agent.name.toLowerCase() === resolvedDisplayName.toLowerCase())
|
||||
|
||||
if (isPrimaryAgent) {
|
||||
return {
|
||||
agentToUse: "",
|
||||
categoryModel: undefined,
|
||||
error: `Cannot call primary agent "${isPrimaryAgent.name}" via task. Primary agents are top-level orchestrators.`,
|
||||
}
|
||||
}
|
||||
|
||||
const availableAgents = callableAgents
|
||||
.map((a) => a.name)
|
||||
.sort()
|
||||
@@ -239,3 +228,7 @@ Create the work plan directly - that's your job as the planning agent.`,
|
||||
|
||||
return { agentToUse, categoryModel, fallbackChain }
|
||||
}
|
||||
|
||||
function isTaskCallableAgentMode(mode: AgentMode): boolean {
|
||||
return mode === "all" || mode === "subagent"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user