ag-ui-protocol / ag-ui-protocol/ag-ui
[adk-middleware] Adopt interrupt-aware run lifecycle — emit RunFinished.outcome: interrupt and consume RunAgentInput.resume[]
- Ngôn ngữ chính
- Python
- Star
- 15.9k
- Fork
- 1.4k
- Merge trung bình
- 1 ngày 17 giờ
- Pull request đã merge (30 ngày)
- 163
Mô tả
## Summary
The core SDKs landed the interrupt-aware run lifecycle in #1569 (spec: [`docs/concepts/interrupts.mdx`](https://github.com/ag-ui-protocol/ag-ui/blob/main/docs/concepts/interrupts.mdx)). That PR explicitly scoped framework integrations out: *"Framework integrations are explicitly out of scope — they will adopt against the now-finalized spec in a follow-up."* LangGraph and Strands have interrupt-protocol follow-ups (#1409, #1318, #2014); **ADK does not.** This issue tracks that gap.
Originally raised as the protocol-level ask in #170; that issue's protocol concern is now resolved by #1569, and this is the remaining ADK implementation work.
## Current behavior
`adk-middleware` does not participate in the interrupt lifecycle:
- `RunFinishedEvent` is emitted with **no `outcome` field** — the legacy "omitted → success" shape ([`adk_agent.py:1592`](https://github.com/ag-ui-protocol/ag-ui/blob/main/integrations/adk-middleware/python/src/ag_ui_adk/adk_agent.py#L1592), [`adk_agent.py:1875`](https://github.com/ag-ui-protocol/ag-ui/blob/main/integrations/adk-middleware/python/src/ag_ui_adk/adk_agent.py#L1875)).
- It never emits `outcome: { type: "interrupt", interrupts: [...] }`.
- It does not read `RunAgentInput.resume[]`; long-running/HITL results are round-tripped via the legacy tool-message path (`HITL_RESUME`, [`adk_agent.py:1793`](https://github.com/ag-ui-protocol/ag-ui/blob/main/integrations/adk-middleware/python/src/ag_ui_adk/adk_agent.py#L1793)).
Functionally LRO/HITL works (client tools wrapped in `LongRunningFunctionTool`, results returned as tool messages), but it does so via the pre-interrupt convention rather than the formal protocol contract.
## Proposed work
1. **Emit interrupt outcomes:** when an ADK run pauses on a long-running/HITL tool call, end the run with `RunFinished { outcome: { type: "interrupt", interrupts: [{ id, reason: "tool_call", toolCallId, responseSchema?, … }] } }` instead of a bare `RunFinished`. Emit required `StateSnapshot` / `MessagesSnapshot` before it per the spec's state-at-boundary rule.
2. **Consume `resume[]`:** read `RunAgentInput.resume[]`, correlate `interruptId` → `toolCallId`, and emit `ToolCallResult` against the original `toolCallId` **without** re-emitting `ToolCallStart/Args/End`.
3. **Support `approveWithEdits`:** honor `editedArgs` in the resume payload (full replacement, not merge) where applicable.
4. **Declare capabilities:** advertise `humanInTheLoop.interrupts` (and `approveWithEdits` if supported).
5. **Enforce contract rules:** pending interrupts block non-conforming input (rule 4 → `RunError`); `expiresAt` and `responseSchema` validation; idempotent replay of resumes.
6. **Back-compat:** keep the legacy tool-message HITL path working for clients on `maxVersion <= 0.0.52` (mirrors the `BackwardCompatibility_0_0_52` normalization in core).
7. **Tests:** interrupt-outcome emission, resume round-trip, parallel interrupts, approve-with-edits, expiry/validation `RunError` paths.
## References
- Spec: [`docs/concepts/interrupts.mdx`](https://github.com/ag-ui-protocol/ag-ui/blob/main/docs/concepts/interrupts.mdx)
- Capabilities: `humanInTheLoop.interrupts` / `approveWithEdits`
- Core lifecycle PR: #1569
- Original protocol ask: #170 · discussion #200
- Peer integration adoption: #1409, #1318, #2014
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.