Skip to content

chore(sdk): refactor dependency management#2082

Open
jezekra1 wants to merge 1 commit intomainfrom
sdk-streaming-refactor
Open

chore(sdk): refactor dependency management#2082
jezekra1 wants to merge 1 commit intomainfrom
sdk-streaming-refactor

Conversation

@jezekra1
Copy link
Collaborator

Summary

Linked Issues

Documentation

  • No Docs Needed:

If this PR adds new feature or changes existing. Make sure documentation is adjusted accordingly. If the docs is not needed, please explain why.

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Feb 11, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jezekra1, 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 introduces a significant refactoring of the SDK's dependency management and agent initialization processes. The core aim is to streamline how extensions are accessed and configured, moving towards a more context-aware and less explicit dependency passing model. This change enhances the clarity and maintainability of the agent's lifecycle, making it easier to manage implicit functionalities and security configurations. The update also includes a bump in the ruff linter version, ensuring adherence to the latest code quality standards.

Highlights

  • Refactored Dependency Injection: The dependency injection mechanism for extensions has been significantly refactored to utilize ContextVar, allowing extensions to access their instances via ExtensionServer.current() rather than being explicitly passed through method arguments. This simplifies the dependency signature and improves modularity.
  • Enhanced Agent Initialization and Structure: The Agent class has been transformed from a NamedTuple into a full class, introducing a dedicated initialize method. This centralizes the setup of agent capabilities, URL, security, and implicit extensions, providing a more robust and configurable agent lifecycle.
  • Centralized Implicit Extension Management: Implicit extensions (like streaming, error handling, and platform API) are now managed through a DEFAULT_IMPLICIT_EXTENSIONS dictionary and integrated during agent initialization. This ensures consistent application of core functionalities across agents.
  • Improved AgentCard Security Scheme Handling: The way security schemes are applied to the AgentCard has been updated. The SdkAuthenticationBackend now provides security schemes directly via get_card_security_schemes, which are then incorporated during the agent's initialization process.
  • Ruff Linter Update: The ruff linter dependency has been updated across the SDK, moving from version 0.12.3 to 0.15.0, which may introduce new linting rules or performance improvements.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • apps/agentstack-cli/uv.lock
    • Updated ruff dependency to version 0.15.0.
  • apps/agentstack-sdk-py/examples/mcp_client.py
    • Added noqa: ASYNC250 comment to input() call to suppress linter warning.
  • apps/agentstack-sdk-py/examples/tool_call_approval_client.py
    • Added noqa: ASYNC250 comment to input() call to suppress linter warning.
  • apps/agentstack-sdk-py/pyproject.toml
    • Updated ruff dependency to version 0.15.0.
  • apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py
    • Imported ContextVar and Self for context-aware dependency management.
    • Removed Dependency import from TYPE_CHECKING block.
    • Modified BaseExtensionSpec.init to include a 'required' parameter.
    • Refactored BaseExtensionSpec.from_agent_card to handle extension lookup more robustly and extract 'required' status.
    • Updated BaseExtensionSpec.to_agent_card_extensions to use the instance's 'required' status if not explicitly provided.
    • Adjusted NoParamsBaseExtensionSpec to align with the new 'required' parameter handling.
    • Introduced _context_var (ContextVar) and a current() class method in BaseExtensionServer for context-based instance retrieval.
    • Removed _dependencies attribute and its usage in BaseExtensionServer.call, replacing it with context variable assignment.
  • apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py
    • Removed _get_oauth_server and _get_platform_server helper methods.
    • Updated _create_auth to retrieve PlatformApiExtensionServer and OAuthExtensionServer instances using their new current() class methods.
  • apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py
    • Removed direct import of PlatformAuthenticatedUser.
    • Moved PlatformAuthenticatedUser import to be local within _get_header_token function.
    • Modified lifespan to check for auth_token existence before attempting to use the client.
    • Removed the explicit ExtensionError raise if auth_token is missing in handle_incoming_message.
    • Added _PlatformSelfRegistrationExtensionServer class for self-registration functionality.
  • apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py
    • Reordered TaskStatusUpdateEvent and TaskArtifactUpdateEvent in RunYield type alias.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py
    • Converted Agent from a NamedTuple to a class with comprehensive initialization logic.
    • Introduced ActiveDependenciesContainer to encapsulate and manage active dependencies.
    • Modified the agent decorator to return an Agent instance directly, simplifying its usage.
    • Refactored implicit extension handling and their inclusion in the agent card.
    • Updated Executor to integrate with the new Agent class structure and its dependency_container.
    • Removed the _dependencies_lifespan method from Executor.
    • Updated Executor.resume to use the new _dependency_container for message handling.
    • Modified Executor.start to pass the context store instance to RunContext during initialization.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py
    • Modified create_app to accept url, implicit_extensions, required_extensions, and auth_backend as parameters.
    • Updated create_app to call agent.initialize() with the new configuration parameters.
    • Removed direct manipulation of agent.card properties, delegating this to agent.initialize.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py
    • Removed _IMPLICIT_DEPENDENCY_PREFIX constant.
    • Defined DEFAULT_IMPLICIT_EXTENSIONS dictionary to centralize implicit extension instances.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py
    • Modified RunContext to require a ContextStoreInstance (_store) during initialization.
    • Added an explicit init method to RunContext to handle _store assignment.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/dependencies.py
    • Simplified Dependency TypeAlias by removing the explicit dictionary parameter.
    • Updated Depends.call to no longer accept the 'dependencies' dictionary parameter.
    • Adjusted extract_dependencies to reflect the simplified dependency signature.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py
    • Removed AgentCard import.
    • Replaced update_card_security_schemes with get_card_security_schemes, which now returns an A2ASecurity TypedDict.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py
    • Removed AnyUrl import.
    • Removed AgentFactory import and the _agent_factory attribute.
    • Updated Server.agent decorator to directly assign the Agent instance.
    • Refactored Server.serve to utilize the new agent.initialize method and handle implicit extensions and self-registration more cleanly.
    • Removed the call to auth_backend.update_card_security_schemes, as this is now handled during agent initialization.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/store/context_store.py
    • Removed TYPE_CHECKING block for Dependency and Depends.
    • Removed initialized_dependencies parameter from ContextStore.create.
    • Added required_extensions property to ContextStore.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py
    • Removed initialized_dependencies parameter from MemoryContextStore.create.
  • apps/agentstack-sdk-py/src/agentstack_sdk/server/store/platform_context_store.py
    • Removed _IMPLICIT_DEPENDENCY_PREFIX and Depends imports.
    • Updated PlatformContextStore to use the required_extensions property instead of modify_dependencies.
    • Simplified the create method, removing the initialized_dependencies parameter.
    • Refactored PlatformContextStoreInstance to access PlatformApiExtensionServer via its current() class method, aligning with the new context variable approach.
  • apps/agentstack-sdk-py/src/agentstack_sdk/types.py
    • Added A2ASecurity TypedDict for clearer security scheme definitions.
    • Updated SdkAuthenticationBackend abstract method from update_card_security_schemes to get_card_security_schemes, returning A2ASecurity.
  • apps/agentstack-sdk-py/uv.lock
    • Updated ruff dependency to version 0.15.0.
  • apps/agentstack-server/uv.lock
    • Updated ruff dependency to version 0.15.0.
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.

@jezekra1 jezekra1 force-pushed the sdk-streaming-refactor branch from a7532f6 to 35660eb Compare February 11, 2026 15:27
Copy link
Contributor

@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 significantly refactors the SDK's dependency management and agent initialization, moving to contextvars for request-scoped dependency injection and centralizing configuration logic in Agent.initialize. While these changes enhance maintainability, they also introduce or expose critical security vulnerabilities, specifically Server-Side Request Forgery (SSRF) and authentication token leakage. The PlatformApiExtensionServer and MCPServiceExtensionServer allow untrusted clients to control target URLs and potentially leak platform authentication tokens. Additionally, a critical issue was identified in the logic for combining required extensions. To address the security concerns, all client-provided URLs must be strictly validated against an allow-list or rely solely on trusted server-side configuration.

Comment on lines +166 to 177
platform = PlatformApiExtensionServer.current()
if (
platform
and platform.data
and platform.data.base_url
and transport.url.startswith(str(platform.data.base_url))
):
return await platform.create_httpx_auth()
oauth = self._get_oauth_server()
oauth = OAuthExtensionServer.current()
if oauth:
return await oauth.create_httpx_auth(resource_url=pydantic.AnyUrl(transport.url))
return None
Copy link
Contributor

Choose a reason for hiding this comment

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

security-critical critical

The _create_auth method contains a critical security flaw where it attaches the platform authentication token to requests if the target URL starts with the platform's base_url. Since both the target URL (transport.url) and the platform base_url can be controlled by a malicious client via message metadata, an attacker can trick the agent into sending its authentication token to an attacker-controlled server. This is a form of Server-Side Request Forgery (SSRF) leading to credential leakage.

preferred_transport=preferred_transport,
additional_interfaces=additional_interfaces,
implicit_extensions=implicit_extensions,
required_extensions=(required_extensions or set()) & context_store.required_extensions,
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The logic for combining required_extensions from the app configuration and the context store appears to be incorrect. Using a set intersection (&) means an extension will only be marked as required if it's specified in both the user-provided set and the context store's required set. This is likely not the intended behavior. For instance, if PlatformContextStore is used, it requires the PlatformApiExtension, but this extension will not be marked as required unless the user also explicitly lists it. This should probably be a set union (|) to ensure that extensions required by either the user or the context store are correctly flagged as required.

Suggested change
required_extensions=(required_extensions or set()) & context_store.required_extensions,
required_extensions=(required_extensions or set()) | context_store.required_extensions,

Comment on lines +62 to 64
if self.data and self.data.auth_token and self.spec.params.auto_use:
async with self.use_client():
yield
Copy link
Contributor

Choose a reason for hiding this comment

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

security-high high

The lifespan method triggers a network request via use_client() if an authentication token is present. The target of this request is self.data.base_url, which can be specified by the client in the message metadata. Because this URL is not validated against an allow-list, an attacker can use this to perform Server-Side Request Forgery (SSRF) against internal services or exfiltrate data. The risk is elevated because this extension is now enabled by default for all agents.

Comment on lines +11 to 15
ErrorExtensionSpec.URI: ErrorExtensionServer(ErrorExtensionSpec(ErrorExtensionParams())),
PlatformApiExtensionSpec.URI: PlatformApiExtensionServer(PlatformApiExtensionSpec()),
}


Copy link
Contributor

Choose a reason for hiding this comment

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

security-high high

Adding PlatformApiExtensionServer to DEFAULT_IMPLICIT_EXTENSIONS enables this extension by default for all agents. As noted in other comments, this extension is vulnerable to SSRF because it allows clients to specify a base_url in message metadata without validation. Enabling it by default significantly increases the attack surface of the SDK.

Signed-off-by: Radek Ježek <radek.jezek@ibm.com>
@jezekra1 jezekra1 force-pushed the sdk-streaming-refactor branch from 35660eb to 5a85c7c Compare February 11, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant