fix: isolate static subagent registries by runtime context#2371
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a concurrency bug in agentscope-harness where static subagent Markdown declarations (and the DefaultAgentManager derived from them) could be overwritten across concurrent calls, causing one user’s invocation to see another user’s subagent registry. It does this by making subagent declaration loading namespace-aware via RuntimeContext, caching an immutable per-call snapshot on the RuntimeContext, and teaching agent_spawn / agent_send to resolve the same call-scoped manager.
Changes:
- Add
RuntimeContext-aware overloads toAgentSpecLoader.loadFromFilesystem(...)and use them fromSubagentsMiddleware. - Store a per-call subagent snapshot (entries +
DefaultAgentManager) inRuntimeContext, and pass the selected manager to tools viaAgentSpawnTool.CTX_AGENT_MANAGER. - Update
AgentSpawnToolto consistently resolve the manager fromRuntimeContext(with fallback to the tool’s default manager) and add regression tests.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| agentscope-harness/src/test/java/io/agentscope/harness/agent/HarnessAgentTest.java | Adds tests for namespaced Markdown declarations and call-scoped isolation; introduces a recording Model helper. |
| agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/AgentSpawnTool.java | Resolves DefaultAgentManager per invocation from RuntimeContext to keep agent_spawn/agent_send consistent with call-scoped subagent snapshots. |
| agentscope-harness/src/main/java/io/agentscope/harness/agent/subagent/DefaultAgentManager.java | Updates refreshEntries documentation to reflect its simpler role after the snapshot approach. |
| agentscope-harness/src/main/java/io/agentscope/harness/agent/subagent/AgentSpecLoader.java | Adds a RuntimeContext-aware filesystem loader overload and updates Javadoc to clarify when to use it. |
| agentscope-harness/src/main/java/io/agentscope/harness/agent/middleware/SubagentsMiddleware.java | Removes shared mutable entry refresh; loads a per-call snapshot and installs it into RuntimeContext for concurrency safety. |
| aliceCall.block(); | ||
| bobCall.block(); |
|
|
||
| private static final class RecordingModel implements Model { | ||
|
|
||
| private final List<List<Msg>> inputs = new java.util.concurrent.CopyOnWriteArrayList<>(); |
| public Flux<ChatResponse> stream( | ||
| List<Msg> messages, | ||
| List<ToolSchema> tools, | ||
| io.agentscope.core.model.GenerateOptions options) { |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
AgentScope-Java Version
2.0.1-SNAPSHOT
Description
Fixes #2328
Fix static subagent declaration isolation for namespace-scoped filesystems.
Previously,
SubagentsMiddlewarerefreshed a shared subagent registry for every call. An interleaved call from another user could overwrite the declarations and manager used by an in-flight call, causing the prompt oragent_spawnto use another user's subagents.This change:
RuntimeContext;RuntimeContext;agent_spawnresolve the same call-scoped manager;Validation performed:
mvn -T1 -pl agentscope-harness -am -Dtest=HarnessAgentTest#staticSubagentsMiddleware_keepsNamespacedDeclarationsCallScoped testChecklist
mvn spotless:applymvn test) — full suite not run; targeted regression test passed