Skip to content

plugin_framework fix#4403

Draft
jayy-77 wants to merge 1 commit intogoogle:mainfrom
jayy-77:plugin_framework
Draft

plugin_framework fix#4403
jayy-77 wants to merge 1 commit intogoogle:mainfrom
jayy-77:plugin_framework

Conversation

@jayy-77
Copy link

@jayy-77 jayy-77 commented Feb 6, 2026

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

#4393

1. Link to an existing issue (if applicable):

  • Closes: #issue_number
  • Related: #issue_number

2. Or, if no issue exists, describe the change:

If applicable, please follow the issue templates to provide as much detail as
possible.

Problem:
A clear and concise description of what the problem is.

Solution:
A clear and concise description of what you want to happen and why you choose
this solution.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required
for all PRs that are not small documentation or typo fixes.

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Please include a summary of passed pytest results.

Manual End-to-End (E2E) Tests:

Please provide instructions on how to manually test your changes, including any
necessary setup or configuration. Please provide logs or screenshots to help
reviewers better understand the fix.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

Add any other context or screenshots about the feature request here.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jayy-77, 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 enhances the plugin framework by introducing a new callback mechanism for plugins to react to changes in the session state. By adding an on_state_change_callback, plugins can now observe and log modifications to the state_delta as events are processed, thereby improving the observability and extensibility of the system.

Highlights

  • New Plugin Callback: Introduced an on_state_change_callback method in base_plugin.py to allow plugins to observe session state changes. This callback is observational only and does not return a value.
  • Plugin Manager Integration: The plugin_manager.py has been updated to register on_state_change_callback and includes a new run_on_state_change_callback method to execute this callback across all active plugins.
  • State Change Detection: Modified runners.py to detect state_delta within events and trigger the on_state_change_callback for plugins after yielding the event, ensuring plugins are notified of state modifications.

🧠 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
  • src/google/adk/plugins/base_plugin.py
    • Added on_state_change_callback method, an asynchronous callback for plugins to observe state changes.
  • src/google/adk/plugins/plugin_manager.py
    • Registered on_state_change_callback in the list of available plugin callbacks.
    • Implemented run_on_state_change_callback to execute the new callback across all plugins.
  • src/google/adk/runners.py
    • Integrated calls to plugin_manager.run_on_state_change_callback within the event processing loop to trigger the callback when an event contains a state_delta.
Activity
  • The pull request description includes a standard template for contributions, indicating the author is following established guidelines.
  • No specific review comments or progress updates are available in the provided context.
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.

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Feb 6, 2026
@adk-bot
Copy link
Collaborator

adk-bot commented Feb 6, 2026

Response from ADK Triaging Agent

Hello @jayy-77, thank you for your contribution!

To help us review this pull request, could you please fill out the Testing Plan section in the PR description? As per our contribution guidelines, this is required for all changes that are not small documentation or typo fixes.

This will help reviewers understand how you've verified the changes. Thanks!

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 introduces a new on_state_change_callback to the plugin framework, allowing plugins to observe state changes. The implementation is sound, but I've identified a couple of areas for improvement. Specifically, the execution logic for the new callback could inadvertently prevent some plugins from being notified, and there's an opportunity to reduce code duplication in the runner. My detailed feedback is in the comments below.

Comment on lines +276 to +280
await self._run_callbacks(
"on_state_change_callback",
invocation_context=invocation_context,
state_delta=state_delta,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Using _run_callbacks here introduces an early-exit behavior if any plugin returns a non-None value. For an observational callback like on_state_change_callback, all registered plugins should be notified regardless of the return values of others. The current implementation could lead to some plugins missing state change notifications if a preceding plugin in the chain returns a value.

To ensure all plugins are reliably called, consider implementing this method by looping through the plugins directly. This would align better with the 'observational only' nature of this callback.

    for plugin in self.plugins:
      callback_method = getattr(plugin, "on_state_change_callback")
      try:
        await callback_method(
            invocation_context=invocation_context,
            state_delta=state_delta,
        )
      except Exception as e:
        error_message = (
            f"Error in plugin '{plugin.name}' during 'on_state_change_callback'"
            f" callback: {e}"
        )
        logger.error(error_message, exc_info=True)
        raise RuntimeError(error_message) from e

Comment on lines +843 to +856
# Detect state_delta changes after yielding the modified event
if modified_event.actions.state_delta:
await plugin_manager.run_on_state_change_callback(
invocation_context=invocation_context,
state_delta=modified_event.actions.state_delta.copy(),
)
else:
yield event
# Detect state_delta changes after yielding the original event
if event.actions.state_delta:
await plugin_manager.run_on_state_change_callback(
invocation_context=invocation_context,
state_delta=event.actions.state_delta.copy(),
)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The logic to detect and handle state_delta is duplicated in both the if modified_event: block and the else block. To improve maintainability and reduce redundancy, this could be refactored. A single block of code after the if/else could determine which event to yield (modified_event or event) and then perform the state_delta check on that final event.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants