Skip to content

fix(skill): bind ALL agent tools when multiple are registered on one skill - #2372

Open
gxgeek-n wants to merge 2 commits into
agentscope-ai:mainfrom
gxgeek-n:fix/skill-registration-multi-tool
Open

fix(skill): bind ALL agent tools when multiple are registered on one skill#2372
gxgeek-n wants to merge 2 commits into
agentscope-ai:mainfrom
gxgeek-n:fix/skill-registration-multi-tool

Conversation

@gxgeek-n

Copy link
Copy Markdown
Contributor

Summary

SkillBox.SkillRegistration.agentTool() was a single-slot field. Calling it twice on one registration (e.g. a skill that declares two tools) overwrote the first tool, so only the last AgentTool was bound into the skill's gated tool group ({skillId}_skill_tools).

Impact on users: any skill declaring multiple tools silently loses all but the last one — those tools are neither gated (invisible before the skill is loaded) nor unlockable via load_skill_through_path. We hit this in production with skills whose tools list has more than one entry.

Root cause

  • SkillRegistration.agentTool was private AgentTool agentTool; — each call overwrote the previous value.
  • apply() bound only that one surviving field into the group.
  • Toolkit.ToolRegistration enforces exactly-one-tool-per-registration, so chaining multiple tools on one registration can't work anyway — each tool needs its own registration.

Fix

  • agentTools is now a List<AgentTool>; the singular agentTool() method appends (backward compatible).
  • apply() binds each accumulated tool with its own Toolkit.registration() into the skill group.
  • The other tool kinds (toolObject / mcpClient / subAgent) also get their own registrations instead of sharing one chain (which violated the exactly-one rule whenever more than one kind was set).

Tests

New regression test SkillBoxTest#testMultipleAgentToolsAllBoundToSkillGroup:

  • Fails on the v2.0.0 tag with first tool must also be bound into the skill group (regression: was overwritten) ==> expected: <true> but was: <false>
  • Passes with this fix; full SkillBoxTest suite green (16/16)

Also verified: group still starts inactive (gating semantics unchanged), single-tool registration unchanged.

…skill

SkillRegistration.agentTool() was a single-slot field — calling it twice on
one registration overwrote the first tool, so only the last AgentTool was
bound into the skill's gated tool group ({skillId}_skill_tools). Any skill
declaring multiple tools silently lost all but the last one: those tools
were neither gated (visible without loading the skill) nor unlockable.

Since Toolkit.ToolRegistration enforces exactly-one-tool-per-registration,
SkillRegistration now accumulates agentTools into a list and apply() binds
each one with its own Toolkit registration. Other tool kinds (toolObject /
mcpClient / subAgent) also get their own registrations instead of sharing
one chain that violated the exactly-one rule when combined.

Regression test (SkillBoxTest#testMultipleAgentToolsAllBoundToSkillGroup):
- fails on the v2.0.0 tag with "first tool must also be bound into the
  skill group (regression: was overwritten)"
- passes with this fix; full SkillBoxTest suite green (16/16)
Copilot AI review requested due to automatic review settings July 23, 2026 19:05
@CLAassistant

CLAassistant commented Jul 23, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes a regression in SkillBox.SkillRegistration where registering multiple AgentTools on a single skill would overwrite earlier tools, causing only the last tool to be bound into the skill’s gated tool group.

Changes:

  • Change SkillRegistration.agentTool from a single field to a list and register each agent tool into the gated group.
  • Split apply() into multiple Toolkit.registration() calls (one per tool/type) to satisfy Toolkit’s exactly-one-tool-per-registration constraint.
  • Add a regression test ensuring multiple agent tools are all present in the skill’s gated tool group and that the group remains inactive by default.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
agentscope-core/src/main/java/io/agentscope/core/skill/SkillBox.java Accumulates multiple AgentTools and registers them individually into the skill tool group.
agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxTest.java Adds regression coverage for binding multiple agent tools to a single skill group.

Comment on lines 434 to 436
public SkillRegistration agentTool(AgentTool agentTool) {
this.agentTool = agentTool;
this.agentTools.add(agentTool);
return this;
Comment on lines 597 to 601
if (toolObject != null
|| agentTool != null
|| !agentTools.isEmpty()
|| mcpClientWrapper != null
|| subAgentProvider != null) {
if (toolkit == null && (toolkit = skillBox.toolkit) == null) {
Comment on lines +609 to +610
// Toolkit.ToolRegistration 每次只能注册一个工具(exactly-one 校验),
// 多 tool 的 skill 必须逐个独立注册,否则只有最后一个生效
new AgentSkill(
"Multi Tool Skill", "Skill with two agent tools", "# Multi", null);

// 连续两次 agentTool():此前第二次会覆盖第一次,导致只有 second 被绑进门控组
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.23077% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...c/main/java/io/agentscope/core/skill/SkillBox.java 69.23% 9 Missing and 7 partials ⚠️

📢 Thoughts on this report? Let us know!

@oss-maintainer

This comment was marked as abuse.

@oss-maintainer oss-maintainer left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM. Looks good.


Automated review by "github-manager-bot"

@gxgeek-n

Copy link
Copy Markdown
Contributor Author

Friendly ping — this one looks ready to merge from my side:

  • All 6 status checks are green (build ubuntu + windows, Check License, Check Module Sync, codecov/patch, license/cla).
  • oss-maintainer has already left an APPROVED review.
  • Note on the CLA comment above: the "CLA Not Signed" message from oss-maintainer is stale. The actual commit status is license/cla: success — Contributor License Agreement is signed. — so the CLA is no longer blocking.

I also checked the 15 commits merged into main since this PR was opened — none of them touch SkillBox or any skill-related file, so there is no overlap or conflict with this fix.

The branch is currently 14 commits behind main. Happy to rebase onto latest main if that helps you merge — just let me know.

For context on why this matters: with multiple AgentTools registered on one skill, only the last one ends up bound into the skill's gated tool group, so the earlier tools silently become unreachable at runtime.

…ments

Three review items on this PR:

1. agentTool(null) appended null to the list, so apply() handed null to
   Toolkit.registration().agentTool(null) and failed the whole skill
   registration. Now ignored, mirroring Toolkit.ToolRegistration.

2. Registering each agent tool via its own Toolkit.ToolRegistration bypassed
   that class's exactly-one check, so mixing kinds (agentTool + tool +
   mcpClient + subAgent) silently started to succeed and behaved differently
   depending on call order. That was an unintended side effect of this PR — the
   goal was only "several agent tools on one skill", not relaxing kind
   exclusivity. The invariant is now enforced in SkillRegistration.apply() with
   an error naming the combined kinds.

3. Translated the two non-English comments to English per repo convention.

Adds two tests: null agent tool is ignored, and mixing two kinds is rejected.
SkillBoxTest: 18 tests, 0 failures.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants