From 0e7ecaa9391bf2c72a62599c685330ddaec422cf Mon Sep 17 00:00:00 2001 From: jayy-77 <1427jay@gmail.com> Date: Sat, 7 Feb 2026 03:17:45 +0530 Subject: [PATCH] plugin_framework fix --- src/google/adk/plugins/base_plugin.py | 21 +++++++++++++++++++++ src/google/adk/plugins/plugin_manager.py | 22 ++++++++++++++++++++++ src/google/adk/runners.py | 12 ++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/google/adk/plugins/base_plugin.py b/src/google/adk/plugins/base_plugin.py index 3639f61aa2..ac30fb1218 100644 --- a/src/google/adk/plugins/base_plugin.py +++ b/src/google/adk/plugins/base_plugin.py @@ -370,3 +370,24 @@ async def on_tool_error_callback( allows the original error to be raised. """ pass + + async def on_state_change_callback( + self, + *, + invocation_context: InvocationContext, + state_delta: dict[str, Any], + ) -> None: + """Callback executed when session state changes via event.actions.state_delta. + + This callback is invoked whenever an event with a non-empty state_delta + is yielded from the runner, allowing plugins to observe and log state + changes. The callback is observational only - the return value is ignored. + + Args: + invocation_context: The context for the entire invocation. + state_delta: A copy of the state changes. Plugins should not mutate this. + + Returns: + None + """ + pass diff --git a/src/google/adk/plugins/plugin_manager.py b/src/google/adk/plugins/plugin_manager.py index c781e8fa4e..d5fbfc6002 100644 --- a/src/google/adk/plugins/plugin_manager.py +++ b/src/google/adk/plugins/plugin_manager.py @@ -52,6 +52,7 @@ "after_model_callback", "on_tool_error_callback", "on_model_error_callback", + "on_state_change_callback", ] logger = logging.getLogger("google_adk." + __name__) @@ -257,6 +258,27 @@ async def run_on_tool_error_callback( error=error, ) + async def run_on_state_change_callback( + self, + *, + invocation_context: InvocationContext, + state_delta: dict[str, Any], + ) -> None: + """Runs the `on_state_change_callback` for all plugins. + + Args: + invocation_context: The invocation context. + state_delta: A copy of the state changes. + + Returns: + None. This callback is observational only. + """ + await self._run_callbacks( + "on_state_change_callback", + invocation_context=invocation_context, + state_delta=state_delta, + ) + async def _run_callbacks( self, callback_name: PluginCallbackName, **kwargs: Any ) -> Optional[Any]: diff --git a/src/google/adk/runners.py b/src/google/adk/runners.py index 545a0e83e6..14cec07a70 100644 --- a/src/google/adk/runners.py +++ b/src/google/adk/runners.py @@ -840,8 +840,20 @@ async def _exec_with_plugin( modified_event, invocation_context.run_config ) yield modified_event + # 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(), + ) # Step 4: Run the after_run callbacks to perform global cleanup tasks or # finalizing logs and metrics data.