google / google/adk-python

Add a turn/response group identifier to streaming events

Đang mở
#4,793 2 bình luận 0 reaction 2 người được giao Được @wuliang229 nhận Xem trên GitHub
core needs review
Ngôn ngữ chính
Python
Star
21.5k
Fork
4k
Merge trung bình
1 ngày 14 giờ
Pull request đã merge (30 ngày)
37

Mô tả

# 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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.