ag-ui-protocol / ag-ui-protocol/ag-ui

Feature Request: ADK middleware - no STEP_STARTED/STEP_FINISHED for workflow / multi-agent runs

Open
#2,075 2 comments 0 reactions 0 assignees View on GitHub
enhancement Integration
Dominant language
Python
Stars
15.9k
Forks
1.4k
Avg merge
1d 17h
Merged PRs (30d)
163

Description

## Summary

The ADK middleware (`integrations/adk-middleware`) never emits `STEP_STARTED` / `STEP_FINISHED` events, even for workflow and multi-agent runs. A `SequentialAgent`, `ParallelAgent`, `LoopAgent`, coordinator/sub-agent tree, or dynamic `transfer_to_agent` flow is flattened into a single event stream, so the frontend cannot tell that the run went through several nodes/sub-agents.

The information is already available — `EventTranslator.translate()` reads `adk_event.author` (the node/sub-agent that produced each event) — it just isn't surfaced as steps.

## Why this matters (spec + parity)

- The AG-UI spec (`docs/concepts/events.mdx`) describes step events as **optional but "highly recommended"** for complex, multi-stage runs, and says explicitly: *"The `stepName` could be the name of a node."* The only hard rule is that a `STEP_FINISHED.stepName` must match its `STEP_STARTED`.
- **ADK 2.0** is itself a **Workflow Graph engine** (agents/tools/functions are nodes) with Graph-based, Dynamic and Collaborative workflows — mapping a node → a step is the natural fit.
- The sibling **LangGraph integration already does this**: it emits a step per graph node (`handle_node_change(node_name)` in `ag_ui_langgraph/agent.py`). ADK users get no equivalent.

## Proposal

Add an **opt-in** `emit_workflow_steps: bool = False` on `ADKAgent`:

- `EventTranslator` emits a `STEP_STARTED`/`STEP_FINISHED` pair per ADK `author` (node/sub-agent) transition; the node name becomes the `stepName`.
- Only activated for workflow/multi-agent topologies (`SequentialAgent`/`ParallelAgent`/`LoopAgent`, the ADK 2.0 `Workflow` graph, or any agent with `sub_agents`), so a plain single `LlmAgent` run is unchanged.
- Default `False` → no behavior change for existing consumers.

Example resulting stream for `SequentialAgent[planner, researcher, writer]`:

```
RUN_STARTED
STEP_STARTED {stepName: "planner"} … STEP_FINISHED {stepName: "planner"}
STEP_STARTED {stepName: "researcher"} … STEP_FINISHED {stepName: "researcher"}
STEP_STARTED {stepName: "writer"} … STEP_FINISHED {stepName: "writer"}
RUN_FINISHED
```

Known limitation: `ParallelAgent` branches interleave in the flat stream, so their steps would be best-effort (closed at the run boundary).

I have a PR implementing this (opt-in flag, translator changes, tests, README) and will link it.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.