Skip to content

fix(core): ignore agent names without active teams#5115

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
he-yufeng:fix/agent-name-without-team
Jun 14, 2026
Merged

fix(core): ignore agent names without active teams#5115
wenshao merged 1 commit into
QwenLM:mainfrom
he-yufeng:fix/agent-name-without-team

Conversation

@he-yufeng

Copy link
Copy Markdown
Contributor

What this PR does

When agent teams are disabled, the Agent tool no longer advertises the teammate-only name parameter in its schema. If an older prompt or bundled workflow still sends name without an active team, the tool now ignores that name and runs the requested agent as a normal one-shot subagent instead of failing immediately.

Why it's needed

Fixes #5100. The current schema always exposes name, while the guidance that explains team usage is only shown when teams are enabled. That gives the model a parameter it can fill even though there is no active team. The resulting hard error is especially painful for /review, where named review agents can turn into repeated failed spawns. Hiding the parameter when teams are off removes the bad steering, and the fallback keeps existing prompts from aborting the task if name leaks through anyway.

Reviewer Test Plan

How to verify

With teams disabled, inspect the Agent tool schema and confirm name is absent. Then call the Agent tool with name anyway; it should proceed through the normal one-shot subagent path instead of returning a "no active team" error. With teams enabled, name should still be present in the schema for teammate spawning.

Evidence (Before & After)

Before: the unit test asserted that name without an active team returned a hard "no active team" error and did not load the requested subagent. After: the updated test asserts that name is hidden when teams are disabled, visible when teams are enabled, and a leaked name falls back to the one-shot subagent path.

Tested on

OS Status
🍏 macOS ⚠️ not tested
🪟 Windows ✅ tested
🐧 Linux ⚠️ not tested

Environment (optional)

Windows 11, Node.js v24.15.0, npm 11.12.1.

Validated locally:

npx prettier --check packages/core/src/tools/agent/agent.ts packages/core/src/tools/agent/agent.test.ts
npx eslint packages/core/src/tools/agent/agent.ts packages/core/src/tools/agent/agent.test.ts --max-warnings 0
cd packages/core && npx vitest run src/tools/agent/agent.test.ts
npm run typecheck --workspace=@qwen-code/qwen-code-core -- --pretty false
npm run build --workspace=@qwen-code/qwen-code-core
git diff --check

Risk & Scope

  • Main risk or tradeoff: if a caller expected name to fail loudly without a team, it now behaves like a normal one-shot agent. That is intentional because name is only meaningful for active teams.
  • Not validated / out of scope: I did not change the bundled /review skill or add a separate repeated-call circuit breaker.
  • Breaking changes / migration notes: none expected.

Linked Issues

Fixes #5100

中文说明

这个 PR 做了什么

当 agent team 功能关闭时,Agent tool 不再在 schema 中暴露只属于 teammate 场景的 name 参数。如果旧 prompt 或内置流程仍然在没有 active team 的情况下传入 name,现在会忽略这个名字,并按普通 one-shot subagent 执行,而不是立刻失败。

为什么需要

修复 #5100。当前 schema 始终暴露 name,但解释 team 用法的 guidance 只有在 team 功能启用时才出现。这会让模型看到一个可填的参数,却不知道它需要 active team。对 /review 这种会命名多个 review agent 的流程来说,这个 hard error 很容易变成重复失败调用。关闭 team 时隐藏参数可以避免错误引导;fallback 则保证历史 prompt 即便传入 name 也不会直接中止任务。

Reviewer Test Plan

如何验证

在 team 功能关闭时,检查 Agent tool schema,确认没有 name。然后即使手动传入 name,也应该进入普通 one-shot subagent 路径,而不是返回 “no active team” 错误。team 功能开启时,name 仍然应该出现在 schema 中,用于 teammate spawn。

前后证据

修改前:单测断言没有 active team 时传入 name 会返回 hard error,并且不会加载目标 subagent。修改后:单测断言 team 关闭时 name 被隐藏,team 开启时 name 可见,并且泄漏进来的 name 会降级到 one-shot subagent 路径。

本地验证环境

Windows 11,Node.js v24.15.0,npm 11.12.1。已本地运行上方列出的格式、lint、单测、typecheck、build 和 diff check。

风险与范围

  • 主要风险或取舍:如果某个调用方依赖 “无 team + name 必须报错”,现在会变成普通 one-shot agent。这是有意行为,因为 name 只有在 active team 下才有 teammate 语义。
  • 未覆盖范围:没有修改内置 /review skill,也没有单独增加重复调用熔断器。
  • 破坏性变更 / 迁移说明:预计没有。

@wenshao

wenshao commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

✅ Local Linux verification — author's commands, a real-execution harness, and a live agent-spawn session

Verified this PR three ways on Linux (the PR table marks 🐧 Linux as ⚠ not tested): reproduced the author's commands, drove the compiled AgentTool directly to confirm the schema gating + one-shot fallback, and ran a real Agent-tool spawn under tmux. Posting as a merge reference.

Setup

  • Branch fix/agent-name-without-team @ f326408 (fresh git worktree + npm install + npm run build), CLI v0.18.0
  • Platform 🐧 Linux / Node v22.22.2

1) Author's Reviewer Test Plan reproduced — all green

Check Result
vitest run src/tools/agent/agent.test.ts (full file) 103 passed
the 3 PR tests (-t "name when teams … disabled|… enabled|falls back to one-shot") 3 passed
prettier --check (agent.ts + agent.test.ts) ✅ clean
eslint … --max-warnings 0 ✅ clean
tsc --noEmit (core) ✅ no errors
npm run build (core) ✅ exit 0
git diff --check ✅ clean

The three new/updated tests pass: does not expose teammate name when teams are disabled, exposes teammate name when teams are enabled, falls back to one-shot when name is supplied without a team.

2) Real-execution harness against the compiled AgentTool — 5/5

Imported the built AgentTool from dist and drove it with a known-good config stub (no reuse of the test's assertions), toggling isAgentTeamEnabled():

1.  teams OFF: schema.properties.name is absent                                   PASS  (name=undefined)
2a. teams ON:  schema.properties.name is present                                  PASS
2b. teams ON:  name description mentions "active team"                            PASS
3a. leaked name + no team: result does NOT contain "no active team"              PASS  (llmContent="Subagent \"file-search\" not found")
3b. leaked name + no team: fell through to one-shot (loadSubagent('file-search')) PASS

This independently confirms the fix against the compiled bundle:

3) Live tmux session (teams OFF, --yolo --debug) — Agent tool works end-to-end

Asked the model to delegate a one-shot task via the Agent tool with subagent_type: general-purpose:

✓  Agent  Reply PONG-5115
   ✔ general-purpose: Reply PONG-5115 · 0 tools · 6.5s · 24k tokens
✦ The subagent returned: PONG-5115
  • ✅ With teams off the model is offered subagent_type but not name; the one-shot subagent spawned, returned, and the parent relayed the result — no no active team error and no schema error. Confirms the changed execute() team-routing block is non-regressive on Linux.

Observations (none are blockers)

  • The fix gates name in two places — the base schema builder and the dynamic schema refresh (which also rewrites subagent_type.enum). Both check isAgentTeamEnabled(), so the schema can't go stale with a name after a subagent-list refresh. Good belt-and-suspenders consistency.
  • Behavior change is intentional and matches the schema contract: name is meaningful only with an active team, so a leaked name becoming a one-shot agent (rather than a hard failure) is the safe direction.

Verdict

LGTM — recommend merge. Small, well-scoped fix that removes the bad steering (hiding name when teams are off) and makes a leaked name degrade gracefully to a one-shot subagent. Verified against real shipped code (tests), the compiled bundle (harness), and a live session on Linux; tests/lint/typecheck/build are all clean.

中文版(点击展开)

✅ 本地 Linux 验证 —— 复现作者命令、真实执行 harness、以及一次实时 agent 派生会话

在 Linux 上用三种方式验证(PR 表格里 Linux 标注为 ⚠ 未测):复现作者命令、直接驱动编译后AgentTool 确认 schema 门控 + one-shot 降级、并在 tmux 里跑了一次真实的 Agent 工具派生。作为合并参考。

环境

  • 分支 fix/agent-name-without-team @ f326408(全新 worktree + npm install + npm run build),CLI v0.18.0
  • 平台 🐧 Linux / Node v22.22.2

1) 复现作者 Reviewer Test Plan —— 全绿

  • agent.test.ts 完整文件 103 passed;三个 PR 新增/修改测试 3 passed(team 关闭时不暴露 name / team 开启时暴露 name / 泄漏 name 时降级 one-shot);
  • prettier --check ✅、eslint --max-warnings 0 ✅、core tsc --noEmit ✅、npm run build ✅、git diff --check ✅。

2) 针对编译产物 AgentTool 的真实执行 harness —— 5/5

dist 导入编译后的 AgentTool,用一份已验证的 config stub 驱动(不复用测试断言),切换 isAgentTeamEnabled()

==== 5 passed, 0 failed ====

3) tmux 实时会话(team 关闭,--yolo --debug)—— Agent 工具端到端可用

让模型用 Agent 工具(subagent_type: general-purpose)派生一个 one-shot 任务:

✔ general-purpose: Reply PONG-5115 · 6.5s
✦ The subagent returned: PONG-5115
  • ✅ team 关闭时模型只拿到 subagent_type没有 name;one-shot subagent 成功派生、返回并由父 agent 转述 —— 无 no active team 错误、无 schema 错误。证明改动后的 execute() team-routing 分支在 Linux 上无回归。

观察(均非阻塞)

  • 该修复在两处门控 name:基础 schema 构建处,以及动态 schema 刷新处(同时重写 subagent_type.enum)。两处都判断 isAgentTeamEnabled(),因此 subagent 列表刷新后 schema 也不会残留 name,一致性良好。
  • 行为变更是有意的、且符合 schema 契约:name 只在 active team 下有意义,泄漏的 name 退化为 one-shot(而非硬失败)是安全方向。

结论

LGTM — 建议合并。 小而聚焦的修复:team 关闭时隐藏 name 消除错误引导,泄漏的 name 优雅降级为 one-shot subagent。已对真实发布代码(测试)、编译产物(harness)、以及 Linux 实时会话三方面验证;tests/lint/typecheck/build 全绿。

@wenshao

wenshao commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR, @he-yufeng!

Template looks good ✓ — all required sections present with bilingual translation.

On direction: this is a clear, well-scoped bug fix for #5100. The Agent Team feature (#4844) unconditionally exposed name in the schema while gating the usage guidance behind isAgentTeamEnabled(), creating a steering trap. The /review skill's named agents then hit a hard error and cascade into a repetitive-call abort. The CHANGELOG confirms Agent Team as a recent experimental feature — fixing this schema/fallback inconsistency is squarely in-scope and directly improves reliability.

On approach: the scope is tight (2 files, +63/-32) and implements exactly the two highest-leverage suggestions from the issue — (1) gate name visibility behind isAgentTeamEnabled() and (2) degrade gracefully when name leaks through without a team. The constant extraction (TEAM_AGENT_NAME_PROPERTY) avoids duplication between the initial schema and the refresh path. Nothing feels extraneous.

Moving on to code review. 🔍

中文说明

感谢贡献,@he-yufeng

模板完整 ✓ — 所有必需章节齐全,含双语翻译。

方向:这是对 #5100 的明确、范围合理的 bug 修复。Agent Team 功能(#4844)在 schema 中无条件暴露 name,但使用指导却被 isAgentTeamEnabled() 门控,形成了引导陷阱。/review skill 的命名 agent 因此触发硬错误并级联为重复调用中止。CHANGELOG 确认 Agent Team 是近期的实验性功能 — 修复此 schema/降级不一致完全在项目范围内,直接提升了可靠性。

方案:范围紧凑(2 个文件,+63/-32),精确实现了 issue 中两个最高杠杆的建议 —(1)将 name 可见性门控在 isAgentTeamEnabled() 之后,(2)当 name 在没有 team 的情况下泄漏时优雅降级。常量提取(TEAM_AGENT_NAME_PROPERTY)避免了初始 schema 和刷新路径之间的重复。没有多余内容。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Before reading the diff, my independent proposal for #5100 was: gate name behind isAgentTeamEnabled() in both the initial schema and the refresh path, extract the property to a constant, and replace the hard error with a debug-log + fallthrough to one-shot. The PR matches this exactly — no simpler path missed.

The implementation is clean and correct across all three change sites:

  • Schema construction — spread-conditional (...(config.isAgentTeamEnabled() ? { name: ... } : {})) is the right idiom; name physically disappears from the schema object when teams are off.
  • Schema refresh (refreshSubagents) — belt-and-suspenders: adds/removes name on every subagent-list change, so the schema can't go stale after a dynamic update.
  • Team routing fallback — the old 12-line hard-error block collapses to a 3-line debug log + fallthrough. The else branch (team manager exists → executeTeammate) is preserved. Clean.

No correctness bugs, security issues, or AGENTS.md violations found. Tests are well-targeted: schema visibility in both modes + fallback path verification (103/103 pass).

Real-Scenario Testing

Ran before/after on Linux (Node v22, teams OFF, --yolo). Same prompt designed to make the model pass name to the Agent tool.

Before (installed qwen v0.18.0)

runner@runnervm1li68:~/work/qwen-code/qwen-code$ qwen -p 'Use the Agent tool to delegate: spawn a general-purpose agent named worker-1 to reply PONG-5115.' --yolo 2>&1 | tee tmp/triage-test-183006/before.log
Warning: running headless with --yolo / approval-mode=yolo and no sandbox.
PONG-5115

Model replied directly — avoided the name parameter (likely recognized the risk on this model). The bug doesn't reproduce here because the model self-corrected, but on weaker models (as described in #5100) the name param gets filled and triggers the hard error loop.

After (this PR via npm run dev)

runner@runnervm1li68:~/work/qwen-code/qwen-code$ npm run dev -- -p 'Use the Agent tool to delegate: spawn a general-purpose agent named worker-1 to reply PONG-5115.' --yolo --debug 2>&1 | tee tmp/triage-test-183006/after.log

> @qwen-code/qwen-code@0.18.0 dev
> node scripts/dev.js -p Use the Agent tool to delegate: spawn a general-purpose agent named worker-1 to reply PONG-5115. --yolo --debug

DEV is set to true, but the React DevTools server is not running.

Debug mode enabled
Logging to: /home/runner/.qwen/debug/41c9b590-eaaf-4539-8d51-5304a3e4a7d9.txt
Warning: running headless with --yolo / approval-mode=yolo and no sandbox.
`worker-1` replied: **PONG-5115**.

Model passed name: "worker-1" → fallback triggered → one-shot subagent spawned successfully → PONG-5115 returned. No "no active team" error. Confirms the fix works end-to-end on Linux: leaked name degrades gracefully to a one-shot agent instead of failing.

Unit Tests

✓ src/tools/agent/agent.test.ts (103 tests) 420ms
  Test Files  1 passed (1)
       Tests  103 passed (103)

All three PR-specific tests pass: does not expose teammate name when teams are disabled, exposes teammate name when teams are enabled, falls back to one-shot when name is supplied without a team.

Verdict

No issues found. The fix is minimal, correct, and well-tested. Moving to final reflection. 🔍

中文说明

代码审查

在看 diff 之前,我对 #5100 的独立方案是:在初始 schema 和刷新路径中都将 name 门控在 isAgentTeamEnabled() 之后,将属性提取为常量,并将硬错误替换为 debug 日志 + 降级到 one-shot。PR 的实现与此完全一致 — 没有遗漏更简单的路径。

三处改动均正确且干净:

  • Schema 构建 — 展开条件(...(config.isAgentTeamEnabled() ? { name: ... } : {}))是正确的写法;team 关闭时 name 物理上从 schema 对象中消失。
  • Schema 刷新refreshSubagents)— 双重保险:每次 subagent 列表变化时添加/移除 name,schema 不会在动态更新后残留 name
  • Team 路由降级 — 旧的 12 行硬错误块简化为 3 行 debug 日志 + 穿透。else 分支(team manager 存在 → executeTeammate)保留。干净。

未发现正确性 bug、安全问题或 AGENTS.md 违规。测试针对性强:两种模式下的 schema 可见性 + 降级路径验证(103/103 通过)。

真实场景测试

在 Linux 上运行 before/after(Node v22,team 关闭,--yolo)。使用专门设计让模型传入 name 的 prompt。

修改前(已安装 qwen v0.18.0)

模型直接回复,避免了 name 参数(该模型自行纠正了)。Bug 在此处未复现,但在较弱模型上(如 #5100 所述),name 会被填充并触发硬错误循环。

修改后(本 PR 通过 npm run dev

模型传入了 name: "worker-1" → 降级触发 → one-shot subagent 成功派生 → PONG-5115 返回。无 "no active team" 错误。确认修复在 Linux 上端到端有效:泄漏的 name 优雅降级为 one-shot agent 而非失败。

单元测试

103 个测试全部通过,包括三个 PR 专属测试。

结论

未发现问题。修复最小化、正确、测试充分。进入最终反思。🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Reflection

This is the kind of PR you want to see from a community contributor: a tight, well-motivated fix for a real bug that hurts users, with no scope creep.

The core insight is correct — the schema/fallback asymmetry (always-visible name + gated guidance + hard error) creates a steering trap, and the fix attacks both sides: hide the parameter when it's meaningless, and degrade gracefully when it leaks through anyway. The /review skill's repeated-failure cascade (described in #5100) is exactly the kind of bug that erodes trust in the tool, so fixing it has real user value.

My independent proposal matched the PR's approach exactly. The implementation is minimal (2 files, +63/-32), the tests are well-targeted (103/103 pass), and the tmux test on Linux confirmed the fallback works end-to-end — a leaked name now spawns a one-shot agent instead of failing.

If I had to maintain this in six months, I'd thank the author for keeping it simple.

Approving.

中文说明

反思

这是你希望从社区贡献者看到的 PR:针对一个真正影响用户的 bug,提供紧凑、动机明确的修复,没有范围蔓延。

核心洞察是正确的 — schema/降级不对称(始终可见的 name + 门控指导 + 硬错误)形成了引导陷阱,修复从两侧攻克:在参数无意义时隐藏它,在泄漏时优雅降级。/review skill 的重复失败级联(#5100 所述)正是那种侵蚀工具信任的 bug,修复它有真实的用户价值。

我的独立方案与 PR 方案完全一致。实现最小化(2 个文件,+63/-32),测试针对性强(103/103 通过),Linux 上的 tmux 测试确认降级端到端有效 — 泄漏的 name 现在派生 one-shot agent 而非失败。

如果六个月后需要维护这段代码,我会感谢作者保持了简洁。

批准。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao wenshao merged commit 4748705 into QwenLM:main Jun 14, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants