(req: RunAgentRequest)
| 1524 | |
| 1525 | @app.post("/run_sse") |
| 1526 | async def run_agent_sse(req: RunAgentRequest) -> StreamingResponse: |
| 1527 | app_name = req.app_name or self.default_app_name |
| 1528 | if not app_name: |
| 1529 | raise HTTPException( |
| 1530 | status_code=400, |
| 1531 | detail="app_name is required when ADK_DEFAULT_APP_NAME is not set", |
| 1532 | ) |
| 1533 | req.app_name = app_name |
| 1534 | self.current_app_name_ref.value = req.app_name |
| 1535 | stream_mode = StreamingMode.SSE if req.streaming else StreamingMode.NONE |
| 1536 | runner = await self.get_runner_async(req.app_name) |
| 1537 | _set_telemetry_context_if_needed(runner) |
| 1538 | |
| 1539 | # Validate session existence before starting the stream. |
| 1540 | # We check directly here instead of eagerly advancing the |
| 1541 | # runner's async generator with anext(), because splitting |
| 1542 | # generator consumption across two asyncio Tasks (request |
| 1543 | # handler vs StreamingResponse) breaks OpenTelemetry context |
| 1544 | # detachment. |
| 1545 | if not runner.auto_create_session: |
| 1546 | session = await self.session_service.get_session( |
| 1547 | app_name=req.app_name, |
| 1548 | user_id=req.user_id, |
| 1549 | session_id=req.session_id, |
| 1550 | ) |
| 1551 | if not session: |
| 1552 | raise HTTPException( |
| 1553 | status_code=404, |
| 1554 | detail=f"Session not found: {req.session_id}", |
| 1555 | ) |
| 1556 | |
| 1557 | # Convert the events to properly formatted SSE |
| 1558 | async def event_generator(): |
| 1559 | async with Aclosing( |
| 1560 | runner.run_async( |
| 1561 | user_id=req.user_id, |
| 1562 | session_id=req.session_id, |
| 1563 | new_message=req.new_message, |
| 1564 | state_delta=req.state_delta, |
| 1565 | run_config=RunConfig( |
| 1566 | streaming_mode=stream_mode, |
| 1567 | custom_metadata=req.custom_metadata, |
| 1568 | ), |
| 1569 | invocation_id=req.invocation_id, |
| 1570 | ) |
| 1571 | ) as agen: |
| 1572 | try: |
| 1573 | async for event in agen: |
| 1574 | # ADK Web renders artifacts from `actions.artifactDelta` |
| 1575 | # during part processing *and* during action processing |
| 1576 | # 1) the original event with `artifactDelta` cleared (content) |
| 1577 | # 2) a content-less "action-only" event carrying `artifactDelta` |
| 1578 | events_to_stream = [event] |
| 1579 | if ( |
| 1580 | not req.function_call_event_id |
| 1581 | and event.actions.artifact_delta |
| 1582 | and event.content |
| 1583 | and event.content.parts |
nothing calls this directly
no test coverage detected