1616from pathlib import Path
1717import sys
1818import textwrap
19+ from typing import AsyncGenerator
1920from typing import Optional
2021from unittest .mock import AsyncMock
2122
2223from google .adk .agents .base_agent import BaseAgent
2324from google .adk .agents .context_cache_config import ContextCacheConfig
2425from google .adk .agents .invocation_context import InvocationContext
2526from google .adk .agents .llm_agent import LlmAgent
27+ from google .adk .agents .run_config import RunConfig
2628from google .adk .apps .app import App
2729from google .adk .apps .app import ResumabilityConfig
2830from google .adk .artifacts .in_memory_artifact_service import InMemoryArtifactService
@@ -54,7 +56,9 @@ def __init__(
5456 if parent_agent :
5557 self .parent_agent = parent_agent
5658
57- async def _run_async_impl (self , invocation_context ):
59+ async def _run_async_impl (
60+ self , invocation_context : InvocationContext
61+ ) -> AsyncGenerator [Event , None ]:
5862 yield Event (
5963 invocation_id = invocation_context .invocation_id ,
6064 author = self .name ,
@@ -78,7 +82,9 @@ def __init__(
7882 self .disallow_transfer_to_parent = disallow_transfer_to_parent
7983 self .parent_agent = parent_agent
8084
81- async def _run_async_impl (self , invocation_context ):
85+ async def _run_async_impl (
86+ self , invocation_context : InvocationContext
87+ ) -> AsyncGenerator [Event , None ]:
8288 yield Event (
8389 invocation_id = invocation_context .invocation_id ,
8490 author = self .name ,
@@ -88,6 +94,25 @@ async def _run_async_impl(self, invocation_context):
8894 )
8995
9096
97+ class MockAgentWithMetadata (BaseAgent ):
98+ """Mock agent that returns event-level custom metadata."""
99+
100+ def __init__ (self , name : str ):
101+ super ().__init__ (name = name , sub_agents = [])
102+
103+ async def _run_async_impl (
104+ self , invocation_context : InvocationContext
105+ ) -> AsyncGenerator [Event , None ]:
106+ yield Event (
107+ invocation_id = invocation_context .invocation_id ,
108+ author = self .name ,
109+ content = types .Content (
110+ role = "model" , parts = [types .Part (text = "Test response" )]
111+ ),
112+ custom_metadata = {"event_key" : "event_value" },
113+ )
114+
115+
91116class MockPlugin (BasePlugin ):
92117 """Mock plugin for unit testing."""
93118
@@ -495,6 +520,41 @@ def test_is_transferable_across_agent_tree_with_non_llm_agent(self):
495520 assert result is False
496521
497522
523+ @pytest .mark .asyncio
524+ async def test_run_config_custom_metadata_propagates_to_events ():
525+ session_service = InMemorySessionService ()
526+ runner = Runner (
527+ app_name = TEST_APP_ID ,
528+ agent = MockAgentWithMetadata ("metadata_agent" ),
529+ session_service = session_service ,
530+ artifact_service = InMemoryArtifactService (),
531+ )
532+ await session_service .create_session (
533+ app_name = TEST_APP_ID , user_id = TEST_USER_ID , session_id = TEST_SESSION_ID
534+ )
535+
536+ run_config = RunConfig (custom_metadata = {"request_id" : "req-1" })
537+ events = [
538+ event
539+ async for event in runner .run_async (
540+ user_id = TEST_USER_ID ,
541+ session_id = TEST_SESSION_ID ,
542+ new_message = types .Content (role = "user" , parts = [types .Part (text = "hi" )]),
543+ run_config = run_config ,
544+ )
545+ ]
546+
547+ assert events [0 ].custom_metadata is not None
548+ assert events [0 ].custom_metadata ["request_id" ] == "req-1"
549+ assert events [0 ].custom_metadata ["event_key" ] == "event_value"
550+
551+ session = await session_service .get_session (
552+ app_name = TEST_APP_ID , user_id = TEST_USER_ID , session_id = TEST_SESSION_ID
553+ )
554+ user_event = next (event for event in session .events if event .author == "user" )
555+ assert user_event .custom_metadata == {"request_id" : "req-1" }
556+
557+
498558class TestRunnerWithPlugins :
499559 """Tests for Runner with plugins."""
500560
0 commit comments