7070from typing_extensions import override
7171import yaml
7272
73+ from ..agents ._caller_principal import CallerPrincipal
7374from ..agents ._streaming_mode import StreamingMode
7475from ..agents .base_agent import BaseAgent
7576from ..agents .llm_agent import LlmAgent
@@ -447,23 +448,68 @@ def _accepts_kwargs(func: Callable[..., Any], kwargs: dict[str, Any]) -> bool:
447448 return True
448449
449450
451+ def _run_async_accepts (runner : Runner , name : str ) -> bool :
452+ """Whether runner.run_async takes the keyword ``name`` (or ``**kwargs``)."""
453+ try :
454+ params = inspect .signature (runner .run_async ).parameters
455+ except (ValueError , TypeError ):
456+ return True
457+ return name in params or any (
458+ p .kind == inspect .Parameter .VAR_KEYWORD for p in params .values ()
459+ )
460+
461+
450462def _with_abort_signal_kwarg (
451463 runner : Runner ,
452464 kwargs : dict [str , Any ],
453465 abort_signal : asyncio .Event ,
454466) -> dict [str , Any ]:
455467 """Adds abort_signal to kwargs when runner.run_async accepts it."""
456- try :
457- params = inspect .signature (runner .run_async ).parameters
458- if "abort_signal" in params or any (
459- p .kind == inspect .Parameter .VAR_KEYWORD for p in params .values ()
460- ):
461- kwargs ["abort_signal" ] = abort_signal
462- except (ValueError , TypeError ):
468+ if _run_async_accepts (runner , "abort_signal" ):
463469 kwargs ["abort_signal" ] = abort_signal
464470 return kwargs
465471
466472
473+ def _with_caller_principal_kwarg (
474+ runner : Runner ,
475+ kwargs : dict [str , Any ],
476+ caller_principal : CallerPrincipal ,
477+ ) -> dict [str , Any ]:
478+ """Adds caller_principal to kwargs when runner.run_async accepts it."""
479+ if _run_async_accepts (runner , "caller_principal" ):
480+ kwargs ["caller_principal" ] = caller_principal
481+ return kwargs
482+
483+
484+ _API_SERVER_PRINCIPAL_SOURCE = "api_server"
485+
486+
487+ def _caller_principal_for_request (
488+ request : Optional [Request ],
489+ ) -> CallerPrincipal :
490+ """Returns the caller identity to run a /run or /run_sse request as.
491+
492+ The API server does not authenticate callers itself. A deployment that does,
493+ in middleware or a dependency in front of these routes, states the result on
494+ ``request.state.caller_principal`` and that value is used as is. Without
495+ one, the request is recorded as unauthenticated from the ``api_server``
496+ edge, so a tool confirmation it carries is warned about (default) or refused
497+ (strict mode), the same decision made for an unauthenticated A2A caller.
498+ The ``user_id`` in the request body is a claim the caller made rather than
499+ one the server checked, so it is not consulted here.
500+ """
501+ principal = (
502+ getattr (request .state , "caller_principal" , None )
503+ if request is not None
504+ else None
505+ )
506+ if isinstance (principal , CallerPrincipal ):
507+ return principal
508+ return CallerPrincipal (
509+ authenticated = False , source = _API_SERVER_PRINCIPAL_SOURCE
510+ )
511+
512+
467513_current_session_options : contextvars .ContextVar [Optional [dict [str , Any ]]] = (
468514 contextvars .ContextVar ("current_session_options" , default = None )
469515)
@@ -2123,6 +2169,7 @@ async def run_agent(req: RunAgentRequest, request: Request) -> Response:
21232169 )
21242170
21252171 abort_signal = asyncio .Event ()
2172+ caller_principal = _caller_principal_for_request (request )
21262173
21272174 async def worker () -> list [Event ]:
21282175 run_async_kwargs = _with_abort_signal_kwarg (
@@ -2137,6 +2184,9 @@ async def worker() -> list[Event]:
21372184 },
21382185 abort_signal ,
21392186 )
2187+ run_async_kwargs = _with_caller_principal_kwarg (
2188+ runner , run_async_kwargs , caller_principal
2189+ )
21402190 try :
21412191 async with Aclosing (runner .run_async (** run_async_kwargs )) as agen :
21422192 return [public_event (event ) async for event in agen ]
@@ -2186,7 +2236,9 @@ async def monitor() -> None:
21862236 monitor_task .cancel ()
21872237
21882238 @app .post ("/run_sse" )
2189- async def run_agent_sse (req : RunAgentRequest ) -> StreamingResponse :
2239+ async def run_agent_sse (
2240+ req : RunAgentRequest , request : Request = None
2241+ ) -> StreamingResponse :
21902242 app_name = req .app_name or self .default_app_name
21912243 if not app_name :
21922244 raise HTTPException (
@@ -2235,6 +2287,8 @@ async def run_agent_sse(req: RunAgentRequest) -> StreamingResponse:
22352287 detail = f"Session not found: { req .session_id } " ,
22362288 )
22372289
2290+ caller_principal = _caller_principal_for_request (request )
2291+
22382292 # Convert the events to properly formatted SSE
22392293 async def event_generator () -> AsyncIterator [str ]:
22402294 is_closing = False
@@ -2257,6 +2311,9 @@ async def _produce_events() -> None:
22572311 },
22582312 abort_signal ,
22592313 )
2314+ run_async_kwargs = _with_caller_principal_kwarg (
2315+ runner , run_async_kwargs , caller_principal
2316+ )
22602317 try :
22612318 async with Aclosing (runner .run_async (** run_async_kwargs )) as agen :
22622319 try :
0 commit comments