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

[adk-middleware] Adopt interrupt-aware run lifecycle — emit RunFinished.outcome: interrupt and consume RunAgentInput.resume[]

Đang mở
#2,031 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
enhancement
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

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.