Skip to content

feat(skill): add model configuration and SubAgent context sharing support#841

Open
xun404 wants to merge 5 commits intoagentscope-ai:mainfrom
xun404:skill-support-model
Open

feat(skill): add model configuration and SubAgent context sharing support#841
xun404 wants to merge 5 commits intoagentscope-ai:mainfrom
xun404:skill-support-model

Conversation

@xun404
Copy link

@xun404 xun404 commented Feb 27, 2026

AgentScope-Java Version

1.0.10-SNAPSHOT

Description

Background

The Skill system needs to support custom model configuration, and SubAgent requires better context sharing management.

Key Changes

1. Skill Model Configuration Support

  • Added SkillModelProvider interface for model lookup by name or alias
  • Added MapBasedSkillModelProvider implementation with Map-based model mapping
  • SkillBox and SkillToolFactory support model configuration via modelProvider
  • AgentSkill parses model field from SKILL.md

2. SubAgent Context Sharing Mechanism

  • Added ContextSharingMode enum: SHARED, FORK, NEW
  • Added SubAgentContext class to carry parent agent info and pre-computed memory
  • Refactored SubAgentProvider interface for context-aware agent creation
  • SubAgentTool supports memory sharing/isolation based on mode:
    • SHARED/FORK: Fork parent agent's memory (pending tool calls removed)
    • NEW: Independent memory with custom system prompt

3. Other Improvements

  • Added fork() method to Memory interface, all implementations support creating independent copies
  • SubAgentTool inherits session_id from parent context (SHARED/FORK mode)
  • SubAgentTool forwards images from user messages (SHARED/FORK mode)
  • Fixed session_id JSON Schema validation (allow null type)

How to Test

mvn test -pl agentscope-core -Dtest="SkillTest,SubAgentToolTest"

Checklist

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated
  • Code is ready for review

@xun404 xun404 requested a review from a team February 27, 2026 11:12
@cla-assistant
Copy link

cla-assistant bot commented Feb 27, 2026

CLA assistant check
All committers have signed the CLA.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the AgentScope-Java framework by introducing advanced capabilities for skill management and sub-agent interaction. It provides granular control over which AI models execute specific skills and offers flexible options for how sub-agents share or isolate their conversational memory with parent agents. These changes aim to improve the modularity, reusability, and contextual awareness of agents within the system.

Highlights

  • Skill Model Configuration: Introduced the ability for skills to specify a preferred AI model for their execution, allowing for more targeted and efficient agent behavior. This includes a new SkillModelProvider interface and a MapBasedSkillModelProvider implementation for flexible model lookup and alias management.
  • Dynamic Sub-Agent Tool Creation: The system now automatically creates a SubAgentTool for any skill that has a model configured, simplifying the process of integrating specialized AI capabilities into agent workflows.
  • Sub-Agent Context Sharing Mechanism: Implemented a robust mechanism for sub-agents to manage their conversational context with parent agents. This includes a new ContextSharingMode enum (SHARED, FORK, NEW) and a SubAgentContext class to pass relevant parent information during sub-agent creation.
  • Memory Forking and Isolation: The Memory interface now includes a fork() method, enabling sub-agents to receive an independent copy of their parent's memory. This supports both shared and isolated memory scenarios, preventing unintended side effects on the parent's conversation history.
  • Enhanced Sub-Agent Tool Functionality: The SubAgentTool has been updated to inherit session IDs from parent agents in shared/forked modes and to automatically forward images from parent user messages, improving continuity and multimodal capabilities in sub-agent interactions.
Changelog
  • agentscope-core/src/main/java/io/agentscope/core/memory/InMemoryMemory.java
    • Implemented the fork() method to create a deep copy of the memory.
  • agentscope-core/src/main/java/io/agentscope/core/memory/Memory.java
    • Added the fork() method to the Memory interface for creating independent memory copies.
  • agentscope-core/src/main/java/io/agentscope/core/skill/AgentSkill.java
    • Added model and context fields to AgentSkill.
    • Updated constructors and builder methods to support model and context fields.
    • Introduced getters for model and context properties.
  • agentscope-core/src/main/java/io/agentscope/core/skill/MapBasedSkillModelProvider.java
    • Added a new class providing a map-based implementation for SkillModelProvider to resolve model references.
  • agentscope-core/src/main/java/io/agentscope/core/skill/SkillBox.java
    • Updated imports to include Model, Memory, ReActAgent, ContextSharingMode, and SubAgentContext.
    • Added a modelProvider field and updated constructors to accept it.
    • Introduced getModelProvider() and setModelProvider() methods.
    • Integrated logic to automatically create SubAgentTool instances for skills with configured models during registration.
    • Added a parseContextSharingMode() helper method.
  • agentscope-core/src/main/java/io/agentscope/core/skill/SkillModelProvider.java
    • Added a new interface for resolving model references to Model instances.
  • agentscope-core/src/main/java/io/agentscope/core/skill/SkillSubagentPromptBuilder.java
    • Added a new class to construct detailed system prompts for skill-based sub-agents.
  • agentscope-core/src/main/java/io/agentscope/core/skill/SkillToolFactory.java
    • Updated constructor to accept SkillBox.
    • Modified buildSkillMarkdownResponse to include model information and hints about the automatically created sub-agent tool.
    • Added createSubAgentIfHasModel() to dynamically create sub-agent tools when skills are loaded.
    • Introduced parseContextSharingMode() for context parsing.
  • agentscope-core/src/main/java/io/agentscope/core/skill/util/SkillUtil.java
    • Modified createFrom method to parse model and context fields from SKILL.md markdown.
  • agentscope-core/src/main/java/io/agentscope/core/tool/subagent/ContextSharingMode.java
    • Added a new enum defining modes for memory sharing between parent and sub-agents (SHARED, FORK, NEW).
  • agentscope-core/src/main/java/io/agentscope/core/tool/subagent/SubAgentConfig.java
    • Updated Javadoc to clarify session_id usage and introduce context sharing modes.
    • Added contextSharingMode field and builder method, defaulting to SHARED.
  • agentscope-core/src/main/java/io/agentscope/core/tool/subagent/SubAgentContext.java
    • Added a new class to encapsulate context information for sub-agent creation, including parent agent and pre-computed memory.
  • agentscope-core/src/main/java/io/agentscope/core/tool/subagent/SubAgentProvider.java
    • Modified the interface to support context-aware agent provisioning via provideWithContext(SubAgentContext context).
  • agentscope-core/src/main/java/io/agentscope/core/tool/subagent/SubAgentTool.java
    • Enhanced to support context sharing modes, inheriting session IDs from parent agents, and forwarding images from parent messages.
    • Updated its JSON schema for session_id to explicitly allow null values.
    • Added private helper methods: computeMemoryToUse(), removePendingToolCalls(), hasOnlyToolCalls(), getParentSessionId(), and buildUserMessage().
  • agentscope-core/src/test/java/io/agentscope/core/skill/AgentSkillTest.java
    • Added tests for AgentSkill model and context fields.
  • agentscope-core/src/test/java/io/agentscope/core/skill/MapBasedSkillModelProviderTest.java
    • Added new tests for MapBasedSkillModelProvider functionality, including direct name lookup, alias resolution, and default model fallback.
  • agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxRegistrationTest.java
    • Added new tests for SkillBox registration with model configuration and runtime overrides, verifying sub-agent tool creation.
  • agentscope-core/src/test/java/io/agentscope/core/skill/SkillBoxTest.java
    • Added tests for SkillBox model provider management, including setting and retrieving providers.
  • agentscope-core/src/test/java/io/agentscope/core/skill/SkillModelProviderTest.java
    • Added new tests for the SkillModelProvider interface, verifying model retrieval and availability checks.
  • agentscope-core/src/test/java/io/agentscope/core/skill/SkillSubagentPromptBuilderTest.java
    • Added new tests for SkillSubagentPromptBuilder, covering prompt construction with various skill details and null handling.
  • agentscope-core/src/test/java/io/agentscope/core/skill/SkillToolFactoryTest.java
    • Added tests to verify model information and sub-agent tool hints are correctly included in skill markdown responses.
  • agentscope-core/src/test/java/io/agentscope/core/skill/util/SkillUtilTest.java
    • Added tests for parsing model information from SKILL.md.
  • agentscope-core/src/test/java/io/agentscope/core/tool/ToolkitTest.java
    • Updated subAgent registration calls to use the new context-aware provider signature.
  • agentscope-core/src/test/java/io/agentscope/core/tool/subagent/SubAgentToolTest.java
    • Added extensive tests for context sharing modes (SHARED, FORK, NEW), session ID inheritance, image forwarding, and Memory.fork() behavior.
  • agentscope-dependencies-bom/pom.xml
    • Updated project version to 1.0.10-SNAPSHOT.
  • agentscope-distribution/agentscope-bom/pom.xml
    • Updated project version to 1.0.10-SNAPSHOT.
  • agentscope-extensions/agentscope-extensions-autocontext-memory/src/main/java/io/agentscope/core/memory/autocontext/AutoContextMemory.java
    • Implemented the fork() method for AutoContextMemory to create a deep copy of its state.
  • docs/en/task/agent-skill.md
    • Updated documentation to reflect the new model field in SKILL.md and the functionality of SkillModelProvider and runtime model overrides.
  • docs/zh/task/agent-skill.md
    • Updated Chinese documentation to reflect the new model field in SKILL.md and the functionality of SkillModelProvider and runtime model overrides.
  • pom.xml
    • Updated project version to 1.0.10-SNAPSHOT.
Activity
  • The pull request author xun404 has implemented features for skill model configuration and sub-agent context sharing.
  • The author has provided a detailed description of the background and key changes in the PR body.
  • Testing instructions for *Skill*Test,SubAgentToolTest are included.
  • A checklist for code formatting, passing tests, Javadoc, and documentation has been provided and presumably completed by the author.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant enhancements to the skill system, adding support for custom model configurations and sub-agent context sharing. The changes are extensive, including new interfaces for model providers, context-aware sub-agent creation, and memory forking capabilities. The implementation is well-tested and documented. My review focuses on a few key areas: I've identified some code duplication that could be refactored for better maintainability, a discrepancy between the documented and implemented behavior of the SHARED context sharing mode, a potential issue with shallow copying in the fork() method of AutoContextMemory, and a minor error in the documentation examples. Addressing these points will improve the robustness and clarity of this new feature.

Comment on lines +285 to +286
// Create sub-agent tool if skill has model configured
createSubAgentForSkill(skill, skillId);

Choose a reason for hiding this comment

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

high

This call to createSubAgentForSkill is redundant and can lead to incorrect behavior. The SkillRegistration.apply() method, which is the primary way to register skills, already calls createSubAgentIfHasModel() to handle sub-agent creation. This duplication means the sub-agent tool might be created twice. If runtimeModel is used, the first creation by this method is incorrect and immediately overwritten. To avoid this, this call and the createSubAgentForSkill method should be removed, centralizing the logic within the SkillRegistration flow.

Comment on lines +293 to +306
case SHARED:
// Fork parent's memory and remove pending tool calls
// Note: We cannot directly share parent's memory because it contains
// the pending tool call to this sub-agent, which would cause
// validation errors when the sub-agent tries to add new messages.
// We use a forked copy with pending tool calls removed.
Memory sharedMemory = parentMemory.fork();
removePendingToolCalls(sharedMemory);
logger.debug(
"Sub-agent will use SHARED (forked with pending calls removed) memory from"
+ " parent ({} messages)",
sharedMemory.getMessages().size());
return sharedMemory;

Choose a reason for hiding this comment

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

high

The implementation for SHARED mode is identical to FORK mode, as both fork the parent's memory. This contradicts the documentation in ContextSharingMode, which states that SHARED mode uses the same memory instance. With the current implementation, any changes the sub-agent makes to its memory will not be reflected in the parent's memory, which is not what "shared" implies.

Please either update the implementation to achieve true memory sharing (which might be complex due to the pending tool call issue you've noted in the comments) or update the documentation for ContextSharingMode.SHARED to clarify that it provides a one-way context copy, similar to FORK. The current discrepancy is misleading.

forked.originalMemoryStorage = new ArrayList<>(this.originalMemoryStorage);

// Copy offload context
forked.offloadContext = new HashMap<>(this.offloadContext);

Choose a reason for hiding this comment

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

high

The copy of offloadContext is a shallow copy. This means both the original and the forked memory will share the same List<Msg> instances as values in the map. If the forked memory modifies one of these lists (e.g., by calling reload() and then modifying the returned list), it will affect the original memory, which defeats the purpose of forking. You should perform a deep copy of the map's values to ensure true isolation.

Suggested change
forked.offloadContext = new HashMap<>(this.offloadContext);
forked.offloadContext = new HashMap<>();
for (Map.Entry<String, List<Msg>> entry : this.offloadContext.entrySet()) {
forked.offloadContext.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}

Comment on lines +749 to +871
/**
* Create a SubAgentTool if the skill has a model configured.
*
* <p>This method automatically creates a sub-agent tool that can execute the skill using the
* configured model. The tool name follows the pattern "call_{skillName}".
*
* <p>If no model is configured, the model provider is missing, or the model is not found,
* this method does nothing (graceful degradation).
*/
private void createSubAgentIfHasModel() {
String effectiveModel = resolveEffectiveModel();
logger.debug(
"createSubAgentIfHasModel called for skill '{}', effectiveModel='{}', "
+ "toolkit={}, modelProvider={}",
skill.getName(),
effectiveModel,
skillBox.toolkit != null ? "present" : "null",
skillBox.modelProvider != null ? "present" : "null");

if (effectiveModel == null || effectiveModel.isBlank()) {
logger.debug(
"Skill '{}' has no model configured, skipping sub-agent creation",
skill.getName());
return; // No model specified
}

if (skillBox.toolkit == null) {
logger.warn(
"No toolkit configured for skill '{}', cannot create sub-agent with model"
+ " '{}'",
skill.getName(),
effectiveModel);
return;
}

if (skillBox.modelProvider == null) {
logger.warn(
"No SkillModelProvider configured for skill '{}', "
+ "cannot create sub-agent with model '{}'",
skill.getName(),
effectiveModel);
return;
}

Model model = skillBox.modelProvider.getModel(effectiveModel);
if (model == null) {
logger.warn(
"Model '{}' not found for skill '{}', skipping sub-agent creation",
effectiveModel,
skill.getName());
return;
}

// Use the same toolkit reference as skillBox
Toolkit effectiveToolkit = toolkit != null ? toolkit : skillBox.toolkit;

// Create SubAgentProvider with structured system prompt
final Model resolvedModel = model;
final Toolkit toolkitCopy = effectiveToolkit.copy();
final String systemPrompt =
SkillSubagentPromptBuilder.builder()
.skill(skill)
.modelName(resolvedModel.getModelName())
.build();

// Parse context sharing mode from skill
final ContextSharingMode contextMode = parseContextSharingMode(skill.getContext());

// Create SubAgentProvider - context-aware for memory sharing
SubAgentProvider<ReActAgent> provider =
new SubAgentProvider<>() {
@Override
public ReActAgent provideWithContext(SubAgentContext context) {
ReActAgent.Builder agentBuilder =
ReActAgent.builder()
.name(skill.getName() + "_agent")
.description(skill.getDescription())
.model(resolvedModel)
.toolkit(toolkitCopy);

// Check if context provides a memory to use (SHARED or FORK mode)
Memory memoryToUse = context.getMemoryToUse();
if (memoryToUse != null) {
// Use the provided memory (shared or forked from parent)
agentBuilder.memory(memoryToUse);
} else {
// No memory provided - use independent memory with our system
// prompt
agentBuilder.sysPrompt(systemPrompt).memory(new InMemoryMemory());
}

return agentBuilder.build();
}
};

// Create tool group if needed
String skillToolGroup = skill.getSkillId() + "_skill_tools";
if (effectiveToolkit.getToolGroup(skillToolGroup) == null) {
effectiveToolkit.createToolGroup(skillToolGroup, skillToolGroup, false);
}

// Register sub-agent tool
effectiveToolkit
.registration()
.group(skillToolGroup)
.subAgent(
provider,
SubAgentConfig.builder()
.toolName("call_" + skill.getName())
.description(
"Execute "
+ skill.getName()
+ " skill task using configured model")
.contextSharingMode(contextMode)
.build())
.apply();

logger.info(
"Created sub-agent tool 'call_{}' for skill '{}' with model '{}'",
skill.getName(),
skill.getName(),
model.getModelName());
}

Choose a reason for hiding this comment

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

medium

This method createSubAgentIfHasModel shares a significant amount of code with SkillToolFactory.createSubAgentIfHasModel. This duplication makes the code harder to maintain. Consider refactoring the common logic into a shared private helper method to reduce redundancy. For instance, a method could be created in SkillBox that takes all necessary parameters (like the effective model, skill, and toolkit) and handles the sub-agent creation, which can then be called from both SkillRegistration and SkillToolFactory.

Comment on lines 888 to 902
private static ContextSharingMode parseContextSharingMode(String context) {
if (context == null || context.isEmpty() || "shared".equalsIgnoreCase(context)) {
return ContextSharingMode.SHARED;
} else if ("fork".equalsIgnoreCase(context)) {
return ContextSharingMode.FORK;
} else if ("new".equalsIgnoreCase(context)) {
return ContextSharingMode.NEW;
} else {
logger.warn(
"Unknown context mode '{}', defaulting to SHARED. "
+ "Supported values: shared, fork, new",
context);
return ContextSharingMode.SHARED;
}
}

Choose a reason for hiding this comment

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

medium

The parseContextSharingMode method is duplicated in SkillToolFactory. To adhere to the DRY (Don't Repeat Yourself) principle, this logic should be centralized. You could make this method package-private (static ContextSharingMode parseContextSharingMode(...)) and call it from SkillToolFactory, or move it to a shared utility class.

Comment on lines +325 to +326
import com.alibaba.agentscope.skill.model.SkillModelProvider;
import com.alibaba.agentscope.skill.model.MapBasedSkillModelProvider;

Choose a reason for hiding this comment

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

medium

The import paths in this example are incorrect. The package name should be io.agentscope.core.skill instead of com.alibaba.agentscope.skill.model.

Suggested change
import com.alibaba.agentscope.skill.model.SkillModelProvider;
import com.alibaba.agentscope.skill.model.MapBasedSkillModelProvider;
import io.agentscope.core.skill.SkillModelProvider;
import io.agentscope.core.skill.MapBasedSkillModelProvider;

Comment on lines +319 to +320
import com.alibaba.agentscope.skill.model.SkillModelProvider;
import com.alibaba.agentscope.skill.model.MapBasedSkillModelProvider;

Choose a reason for hiding this comment

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

medium

The import paths in this example are incorrect. The package name should be io.agentscope.core.skill instead of com.alibaba.agentscope.skill.model.

Suggested change
import com.alibaba.agentscope.skill.model.SkillModelProvider;
import com.alibaba.agentscope.skill.model.MapBasedSkillModelProvider;
import io.agentscope.core.skill.SkillModelProvider;
import io.agentscope.core.skill.MapBasedSkillModelProvider;

@xun404 xun404 force-pushed the skill-support-model branch from eb9e6f9 to 900681a Compare February 27, 2026 11:19
- Remove redundant createSubAgentForSkill call in registerSkill() to prevent
  duplicate sub-agent creation with SkillRegistration.apply()
- Add ContextSharingMode.fromString() factory method and consolidate parsing
  logic from SkillBox and SkillToolFactory (DRY principle)
- Update SHARED mode documentation to accurately reflect fork-based
  implementation due to pending tool call validation constraints
- Fix shallow copy of offloadContext in AutoContextMemory.fork() to use
  deep copy for proper memory isolation
- Refactor duplicate createSubAgentIfHasModel code into shared helper method
  SkillBox.createSubAgentToolForSkill() to reduce ~200 lines of code duplication

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
xun404 and others added 3 commits February 28, 2026 13:13
- Add assertNotSame import to AutoContextMemoryTest

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Clarify why SHARED and FORK have identical implementations
- Explain technical limitation: cannot directly share memory due to pending tool calls
- Document rationale for keeping both modes despite identical behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant