Add a turn/response group identifier to streaming events
- 主要言語
- Python
- スター
- 21.5k
- フォーク
- 4k
- 平均マージ
- 1日 14時間
- マージ済み PR(30日)
- 37
説明
# Add a turn/response group identifier to streaming events
## Problem
When using `runner.run_async()` with `StreamingMode.SSE`, there is no way to distinguish which partial streaming chunks belong to which LLM response turn within a single invocation.
In a typical flow where the LLM responds with text, calls a tool, and then responds with more text, the events look like this:
```
Event(partial=True, text="Looking up...") # LLM call 1
Event(partial=True, text="Looking up info...") # LLM call 1
Event(partial=False, function_call=...) # LLM call 1 (final)
Event(function_response=...) # Tool result
Event(partial=True, text="Here are the...") # LLM call 2
Event(partial=True, text="Here are the results...") # LLM call 2
Event(partial=False, text="Here are the results...") # LLM call 2 (final)
```
All of these events share the same `invocation_id`, and the `id` field changes on every yield (not per turn). There is no field to programmatically determine that the first two partial chunks belong to LLM call 1 and the last two belong to LLM call 2.
## Current workaround
The only way to detect turn boundaries is by observing transition patterns: a `partial=False` event followed by function call/response events implicitly signals the end of one text group. This is fragile and requires the consumer to maintain state tracking.
## Proposed solution
Add a `turn_id` (or `llm_call_id` / `response_group_id`) field to `Event` that:
- Is generated once per LLM call within `_run_one_step_async`
- Remains the same across all partial chunks and the final aggregated event of that LLM call
- Changes when a new LLM call starts (e.g., after tool execution)
This would allow consumers to trivially group streaming chunks by turn:
```python
async for event in runner.run_async(...):
if event.partial:
# event.turn_id groups this chunk with others from the same LLM call
buffer[event.turn_id] += extract_text(event)
```
## Use case
We build a chat UI that streams partial text to the user via WebSocket. When the agent produces text, calls a tool, and then produces more text, we need to render them as separate message bubbles. Without a turn identifier, we cannot cleanly separate the two text blocks on the client side without implementing brittle heuristics based on event type transitions.
## Environment
- ADK version: latest (pip)
- Streaming mode: SSE
- Python 3.12
コントリビューションガイド
評価
この issue はまだ評価されていません。