Repository navigation
feat(harness): let custom subagent factories carry a declaration #3442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1cd193f
ac24d94
d12469a
db9393b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,6 @@ | |
| */ | ||
| package io.agentscope.harness.agent; | ||
|
|
||
| import io.agentscope.core.agent.Agent; | ||
| import io.agentscope.core.agent.RuntimeContext; | ||
| import io.agentscope.core.hook.Hook; | ||
| import io.agentscope.core.middleware.MiddlewareBase; | ||
|
|
@@ -129,10 +128,15 @@ static String buildSubagentSysPrompt(String basePrompt) { | |
| } | ||
|
|
||
| /** | ||
| * Custom-supplied subagent factory entry: name + optional description + factory function from | ||
| * name to Agent. | ||
| * Custom-supplied subagent factory entry: name + optional description + factory, plus an | ||
| * optional {@link SubagentDeclaration} whose spawn-time options (e.g. {@code persistSession}) | ||
| * apply to the custom instances. | ||
| */ | ||
| record SubagentFactoryEntry(String name, String description, Function<String, Agent> factory) { | ||
| record SubagentFactoryEntry( | ||
| String name, | ||
| String description, | ||
| SubagentFactory factory, | ||
| SubagentDeclaration declaration) { | ||
|
|
||
| /** Description shown to the orchestrator, falling back to the name when unset. */ | ||
| String displayDescription() { | ||
|
|
@@ -230,12 +234,8 @@ static List<SubagentEntry> buildSubagentEntries( | |
| new SubagentEntry( | ||
| custom.name(), | ||
| custom.displayDescription(), | ||
| // custom factory uses Function<String, Agent> — pre-B-0 signature | ||
| // doesn't accept RuntimeContext. Bridge by ignoring rc here; users | ||
| // that need parent-aware isolation should register a programmatic | ||
| // SubagentEntry directly with a B-0 SubagentFactory lambda. | ||
| (rc) -> custom.factory().apply(custom.name()), | ||
| null)); | ||
| custom.factory(), | ||
| custom.declaration())); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AgentSpawnTool.agentSpawn() derives the key from (parentSessionId, agentId, label) without userId. When a shared parent agent handles (alice, s1) and (bob, s1) with the same agent ID and label, the second spawn retrieves Alice’s cached child, even if the factory created a child configured for Bob. Passing Bob’s RuntimeContext does not replace tools, credentials, or workspace resources already bound to Alice’s instance. |
||
| } | ||
|
|
||
| return entries; | ||
|
|
@@ -273,12 +273,8 @@ static List<SubagentEntry> buildStaticSubagentEntries( | |
| new SubagentEntry( | ||
| custom.name(), | ||
| custom.displayDescription(), | ||
| // custom factory uses Function<String, Agent> — pre-B-0 signature | ||
| // doesn't accept RuntimeContext. Bridge by ignoring rc here; users | ||
| // that need parent-aware isolation should register a programmatic | ||
| // SubagentEntry directly with a B-0 SubagentFactory lambda. | ||
| (rc) -> custom.factory().apply(custom.name()), | ||
| null)); | ||
| custom.factory(), | ||
| custom.declaration())); | ||
| } | ||
|
|
||
| return entries; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this custom factory registered alongside a persistSession=true declaration, it now enters the persistent reuse path in AgentSpawnTool.
manager.createAgentIfPresent() invokes the factory before agentsByKey.get(key). On a cache hit, the newly created child is discarded without being used or closed. A custom factory may allocate resources such as MCP clients or workspace indexes, so repeated persistent spawns can leave those resources unreleased.
Please check for an existing persistent child before creating a new instance. Extend declaredFactory_persistSessionReusesCustomHarnessAgent to assert that the factory is called once for two sequential spawns with the same persistent identity. Its current createdAgents cleanup closes every constructed child in the test, so it does not detect the discarded instance in production.