google / google/adk-python

LoopAgent: surface the current iteration index in the event stream

Ouverte
#6,266 2 commentaires 0 réactions 2 personnes assignées Réclamée par @i-yliu Voir sur GitHub
core needs review
Langage dominant
Python
Étoiles
21.5k
Forks
4k
Merge moyen
1 j 14 h
PR mergées (30 j)
37

Description

### Context

We maintain the **AG-UI ↔ ADK middleware** (`ag-ui-adk`, part of [ag-ui-protocol/ag-ui](https://github.com/ag-ui-protocol/ag-ui)). AG-UI is a protocol between agents and frontends; one of its event categories is `STEP_STARTED` / `STEP_FINISHED`, which bracket the phases/nodes of a run (the spec recommends `stepName = node name`).

To emit these from ADK workflows (`SequentialAgent` / `ParallelAgent` / `LoopAgent` / the 2.0 `Workflow` graph), the middleware infers node boundaries from the `runner.run_async` event stream using each event's `author` (node name) and `branch` (`ParallelAgent` assigns a distinct `par.` per branch via `_create_branch_ctx_for_sub_agent`). This works cleanly for serial and parallel topologies.

### Problem

There is **one gap: a `ParallelAgent` nested inside a `LoopAgent`.** The concurrent branches keep the **same `author`, `branch`, and `invocation_id`** across iterations, and the flat event stream carries **no iteration-boundary signal** — so a consumer cannot tell iteration 1 from iteration 2. The events are identical except for their unique `id`. (Verified on `google-adk 2.3.0`.)

`LoopAgent(max_iterations=2, sub_agents=[ParallelAgent(sub_agents=[p, q])])` emits:

```
author='p' branch='par.p' invocation_id='e-…' ← iteration 1
author='q' branch='par.q' invocation_id='e-…'
author='p' branch='par.p' invocation_id='e-…' ← iteration 2 (indistinguishable)
author='q' branch='par.q' invocation_id='e-…'
```

As a result, per-iteration steps cannot be reconstructed for this topology.

### ADK already tracks the iteration

`LoopAgent._run_async_impl` already maintains `times_looped`, and on the resumable path it even yields a state event carrying it (`self._create_agent_state_event(ctx)`). It's simply not surfaced on the events produced *within* an iteration.

### Ask (minimal, additive)

Surface the current loop iteration in the event stream, either:

- a **read-only field** on events produced within a `LoopAgent` iteration (e.g. `Event.loop_iteration`, or in event metadata), or
- a lightweight **iteration-boundary marker** event emitted at each iteration start (generalizing the existing resumable-path state event to always fire).

This is purely additive and does not change execution behavior.

### Why not put the iteration into `branch`?

That would be convenient for consumers, but `branch` governs context/event isolation — changing it per iteration could affect how loop iterations **share state** (the whole point of a loop). So we're explicitly asking to expose the iteration **separately from** `branch`.

### Motivation

We need this to faithfully emit **all** AG-UI event types from ADK. `STEP_STARTED`/`STEP_FINISHED` is currently the one category the ADK integration can only approximate (for loop-of-parallel). See the AG-UI PR: ag-ui-protocol/ag-ui#2076.

### Related

A more general alternative — emitting explicit agent/node **lifecycle** events in the stream — is filed as the companion issue #6267, which would subsume this. This issue (#6266) is the minimal, lowest-risk subset scoped to loops.

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.