refactor: simplify task tool subagent filtering
Summary
Small cleanup to align the task tool's filtering approach with how skill.ts handles it, plus simplification of the userInvokedAgents mechanism.
Self-contained filtering:
- Move subagent filtering into
task.tsitself (usingctx?.agentfrom #7042) - Remove the post-hoc regeneration in
prompt.ts
Simplify bypass logic:
- Replace
userInvokedAgentsarray withbypassAgentCheckboolean - Only check the current turn's user message (not all messages in session)
- Prevents bypass from persisting across the entire session
Test cleanup:
- Remove redundant
filterSubagentstests (already covered byPermissionNext.evaluatetests)
Changes
-
task.ts: Filter during description generation + simplify permission check -
prompt.ts: Remove regeneration block + usebypassAgentCheckboolean -
test: Remove redundant tests (~130 lines)
No functional changes to permission behavior - just cleaner code!
The following comment was made by an LLM, it may be inaccurate:
No duplicate PRs found
@rekram1-node Just tidying up, no functionality changes, just moved the filtration logic to task took to be self contained.
Hey! Looked into simplifying userInvokedAgents → bypassAgentCheck.
The tricky part was that the old code looked at ALL user messages in the session, so once you @ invoked any agent, the bypass would persist for the entire session - even for subsequent turns where you didn't @ invoke anything. And with using bypassAgentCheck the primary agent can literally invoke any subagent for the reset of the session once you invoke it once.
Fixed it by only checking the last user message (current turn):
// Before: checks all messages (persists across session)
const userInvokedAgents = msgs
.filter((m) => m.info.role === "user")
.flatMap((m) => m.parts.filter((p) => p.type === "agent"))
.map((p) => p.name)
// After: checks only current turn
const lastUserMsg = msgs.findLast((m) => m.info.role === "user")
const bypassAgentCheck = lastUserMsg?.parts.some((p) => p.type === "agent") ?? false
This way:
- Turn 1:
@plan do X→ bypasses ✅ - Turn 2: "call plan again" (no
@) → prompts as expected ✅
Also cleaned up the redundant filterSubagents tests - the PermissionNext.evaluate tests already cover similar logic.
/review
lgtm