ag-ui-protocol / ag-ui-protocol/ag-ui
feat(ag-ui-adk): surface HITL pauses as AG-UI interrupts on RUN_FINISHED.outcome
- 主要语言
- Python
- 星标
- 15.9k
- 派生
- 1.4k
- 平均合并
- 1 天 17 小时
- 30 天内合并 PR
- 163
描述
## Summary
AG-UI defines an **interrupt protocol**: a run can finish with `RunFinishedEvent.outcome = RunFinishedInterruptOutcome(interrupts=[Interrupt(...)])`, the client surfaces them as `pendingInterrupts`, and resumes by addressing each in the `resume: ResumeEntry[]` array of the next `RunAgentInput`.
`ag-ui-adk` implements Human-in-the-Loop through its own mechanism (a frontend / long-running tool call pauses the run: `TOOL_CALL_START/ARGS/END` with no `TOOL_CALL_RESULT`, then `RUN_FINISHED`; the client resumes by sending a tool-result message). That works for CopilotKit, but the pause is **not represented as a spec `Interrupt`** — `RUN_FINISHED` is emitted with no `outcome`, so spec-compliant AG-UI clients never see `pendingInterrupts` and can't use the standard interrupt/resume UI.
## Proposal (emit side)
Add an **opt-in** `emit_interrupts: bool = False` to `ADKAgent`. When enabled, a run that pauses on unresolved HITL/long-running tool calls finishes with a `RunFinishedInterruptOutcome` carrying one `Interrupt` per pending tool call (`id` and `tool_call_id` = the tool call id, `reason="tool_call"`). Off by default → existing CopilotKit-style resume flows are unaffected; `outcome` stays absent unless enabled.
Detection is transport-level and self-contained: in the run's event consumer, track `TOOL_CALL_END` ids and drop those that get a `TOOL_CALL_RESULT`; whatever remains at `RUN_FINISHED` is what the run paused on.
```python
agui_agent = ADKAgent(adk_agent=root_agent, emit_interrupts=True)
# a HITL pause now finishes as:
# RUN_FINISHED { outcome: { type: "interrupt", interrupts: [{ id, reason:"tool_call", toolCallId }] } }
```
## Scope
- **This issue/PR covers the emit side** — surfacing ADK HITL pauses as spec interrupts so clients get `pendingInterrupts`.
- **Follow-up (not in this PR):** consuming the standard `resume: ResumeEntry[]` array on the way back. Today ag-ui-adk resumes via a tool-result message; mapping `ResumeEntry` (resolved/cancelled + payload) onto that resume path is a larger, separate change. Tracking it here so the two halves are explicit.
## Non-goals
- No change to the existing HITL/tool-result resume mechanism.
- Additive and orthogonal to SSE/WebSocket/httpBinary and the default translation.
Happy to send the emit-side PR (flag on `ADKAgent` + outcome on `RUN_FINISHED`, with tests).
贡献指南
评估
这个 Issue 还没有评估数据。