feat(core): wire AgentSession invocations into agent-tool#26948
feat(core): wire AgentSession invocations into agent-tool#26948adamfweidman wants to merge 8 commits into
Conversation
Summary of ChangesHello, 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 enables AgentSession support within the AgentTool framework, allowing for more robust subagent interactions behind a feature flag. It also includes critical improvements to session state management for remote agents and adds validation logic to the AgentRegistry to prevent and surface duplicate agent name conflicts. Highlights
Using Gemini Code AssistThe 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
Customization To customize the 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 Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. 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. Footnotes
|
6833fa1 to
926a4e3
Compare
There was a problem hiding this comment.
Code Review
This pull request implements session-based subagent invocations, gated by a feature flag, and adds a warning mechanism for duplicate agent names in the registry. It also updates remote session state management to use a composite key of name and URL. Review feedback highlights security concerns and potential memory leaks regarding the use of a static map for session state, suggesting a refactor to session-scoped storage or an LRU cache. Additionally, a redundant method definition in the configuration class was identified for removal.
I am having trouble creating individual review comments. Click here to see my feedback.
packages/core/src/agents/remote-session-invocation.ts (62-65)
The sessionKey method generates a key for the static sessionState Map using only the agent name and URL, but it omits the sessionId. Because sessionState is a static member, it is shared across all instances of RemoteSessionInvocation within the same process. In multi-tenant environments (e.g., if this core library is used in a server-side application), this will cause different user sessions to share the same A2A conversation state (contextId and taskId) if they invoke the same remote agent. This leads to session collision or hijacking, where one user could inadvertently continue or access another user's conversation.
To remediate this, the sessionId should be incorporated into the session key to ensure that conversation state is isolated per session. This will require passing the AgentLoopContext to the sessionKey method.
References
- Avoid module-level global variables for state to prevent race conditions in concurrent environments. Instead, use instance-scoped properties, such as within a session class, for state that is primarily used within that scope.
packages/core/src/agents/remote-session-invocation.ts (53-56)
The use of a static Map for sessionState violates the general rule against module-level global variables for state. This implementation poses a memory leak risk in long-running processes as the map grows indefinitely with every unique agent/URL combination. More critically, it introduces a security vulnerability in multi-session or concurrent environments (such as a server) where A2A conversation state (contextId, taskId) could leak between different users or sessions sharing the same process.
Please refactor this to use session-scoped state (e.g., stored within the Config or a session-scoped service) or, at minimum, use a standard LRUCache with a reasonable size limit to mitigate memory issues.
References
- Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state and leverage standard cache implementations like LRUCache.
- For caching, use the existing
LruCachedependency instead of clearing the entire cache or implementing a custom LRU policy.
packages/core/src/config/config.ts (2584-2586)
The method isAgentSessionEnabled is redundantly defined here. It is already present in the class at line 2560. Please remove this duplicate definition to maintain code clarity and avoid confusion.
There was a problem hiding this comment.
Code Review
This pull request introduces session-based agent invocations gated by a feature flag and adds duplicate agent name detection to the registry. It also updates remote session state management to use composite keys for improved isolation. Feedback identifies a critical security risk where the use of static maps for session state could lead to data leakage between concurrent sessions. Furthermore, the reviewer pointed out redundant and duplicate methods in the configuration class that should be consolidated.
I am having trouble creating individual review comments. Click here to see my feedback.
packages/core/src/agents/remote-session-invocation.ts (121-122)
The RemoteSessionInvocation class uses a static Map named sessionState to persist A2A (Agent-to-Agent) conversation state. Because the map is static, it is shared across all instances within the same process, leading to state leakage between sessions in concurrent environments. Move the sessionState map to a session-scoped object, such as the Config instance or the AgentLoopContext.
References
- Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state and leverage standard cache implementations like LRUCache.
packages/core/src/agents/remote-session-invocation.ts (228-231)
This line persists the A2A conversation state into a static sessionState map. Using a static map for session-specific state leads to cross-session data leakage in long-lived processes. The state should be stored in a session-scoped container to ensure isolation.
References
- Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state and leverage standard cache implementations like LRUCache.
packages/core/src/config/config.ts (2584-2587)
This method is a duplicate of the one already defined at line 2560. Please consolidate this logic to avoid duplication and improve maintainability, as per the project's architectural guidelines.
References
- When adding new functionality, such as filtering, consolidate it with existing similar logic to avoid duplication and improve maintainability.
packages/core/src/config/config.ts (3783-3786)
This method is redundant as it performs the exact same logic as isAgentSessionEnabled(). Instead of maintaining redundant logic or backward compatibility for configuration settings, remove the extra getter entirely to avoid confusion.
References
- Instead of maintaining backward compatibility for deprecated or unshipped configuration settings, remove them and their associated logic entirely to avoid confusion.
packages/core/src/agents/remote-session-invocation.ts (53-56)
The use of a static map for storing session state violates the rule against module-level global variables for state. This approach can lead to race conditions and data leakage in concurrent environments. This state should be moved to a session-scoped store, such as a property on the Config instance.
References
- Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state and leverage standard cache implementations like LRUCache.
There was a problem hiding this comment.
Code Review
This pull request introduces session-based subagent invocations and enhances the agent registry to handle duplicate agent names with warnings. Key changes include updating AgentTool to support event threading, implementing composite keys (name and URL) for remote session state isolation, and adding feature flag checks for session-enabled invocations. Review feedback identifies a critical TypeScript compilation error due to a duplicate method definition in the Config class, a security concern regarding session leakage from static state in RemoteSessionInvocation, and a logic improvement to prevent false-positive warnings in the AgentRegistry when an agent is disabled via overrides.
I am having trouble creating individual review comments. Click here to see my feedback.
packages/core/src/config/config.ts (2584-2587)
The method isAgentSessionEnabled is being added here, but it is already defined earlier in the class (around line 2563 in the current branch state). This duplication will cause a TypeScript compilation error ("Duplicate identifier 'isAgentSessionEnabled'").
packages/core/src/agents/remote-session-invocation.ts (53-56)
The sessionState Map is declared as static, which means it is shared across all instances of RemoteSessionInvocation within the same process. This Map stores A2A conversation state (such as contextId and taskId) for remote agents. In environments where the same process handles multiple user sessions or different conversations (e.g., a long-running interactive shell or a server-side deployment of the core library), this can lead to session leakage. One session could potentially retrieve or overwrite the conversation state of another session if they use a remote agent with the same name and URL. Consider moving this state to a session-scoped object like AgentLoopContext or Config.
References
- Avoid module-level global variables for state like caches to prevent race conditions and memory issues in concurrent environments. Instead, use session-scoped or instance-scoped state.
packages/core/src/agents/registry.ts (340-351)
The warning for duplicate agent names is emitted before checking if the new agent definition is actually enabled. If the later definition is disabled (via settings overrides), it will not actually override the existing one in this.agents (as registerLocalAgent/registerRemoteAgent will return early), making this warning a false positive. The check should verify enablement before emitting the feedback.
const existing = this.agents.get(definition.name);
const overrides = this.config.getAgentsSettings().overrides?.[definition.name];
if (existing && existing !== definition && this.isAgentEnabled(definition, overrides)) {
coreEvents.emitFeedback(
'warning',
'Duplicate agent name \'' + definition.name + '\' detected. ' +
'The later definition will override the earlier one. ' +
'Rename one of the agents to avoid this conflict.',
);
debugLogger.warn(
'[AgentRegistry] Overriding agent \'' + definition.name + '\' — duplicate name from a different definition.',
);
}
3e54174 to
c34e81e
Compare
926a4e3 to
0dcda82
Compare
c34e81e to
0fea5cb
Compare
0dcda82 to
755885f
Compare
0fea5cb to
b36d17a
Compare
712c435 to
4ad0926
Compare
c414010 to
ca5d4a2
Compare
Two changes: 1. RemoteSessionInvocation now uses a composite key (name::targetUrl) for the static sessionState map. This ensures agents with the same name but different endpoints maintain independent A2A state. Falls back to name-only when no URL can be derived. 2. AgentRegistry.registerAgent now emits a visible warning when a different definition tries to register under an existing name. Override still proceeds to preserve existing precedence order (user → project → extension). The warning surfaces potential naming conflicts to users.
…ure flag Add agentSessionSubagentEnabled setting under experimental.adk that routes subagent invocations through LocalSessionInvocation and RemoteSessionInvocation instead of legacy executors. When disabled (default), all behavior is unchanged. - Add agentSessionSubagentEnabled to ADKSettings, Config, and settings schema - Thread onAgentEvent callback through AgentTool → DelegateInvocation - Route local/remote agents to session invocations when flag is enabled - Browser agent always uses BrowserAgentInvocation regardless of flag - Copy local protocol files needed for the session invocation path
be3b6f6 to
c0981bd
Compare
Summary
Wires
AgentSessioninvocations intoAgentToolbehind theadk.agentSessionSubagentEnabledfeature flag.Details
packages/core/src/agents/agent-tool.tsto checkcontext.config.isAgentSessionEnabled().RemoteSessionInvocationandLocalSessionInvocationfor subagent calls.experimental-flag.Related Issues
Relates to #22700
How to Validate
Verified that the codebase builds successfully. Unit tests for
agent-toolshould be run to confirm behavior.Pre-Merge Checklist