fix(a2a): parse multi-line SSE events - #1155
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughThe SSE relay now buffers complete events, joins multiple ChangesSSE frame reassembly
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant UpstreamAgent
participant A2aBridge
participant GatewayClient
UpstreamAgent->>A2aBridge: Send SSE event with multiple data fields
A2aBridge->>A2aBridge: Join data fields and parse JSON payload
A2aBridge->>GatewayClient: Emit reframed event
Suggested reviewers: Merge Risk: ⚪ Minimal · up to No concrete issue remains that should block merging after the normal checks. 🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
7f73bb6 to
a79362b
Compare
a79362b to
7625bec
Compare
|
Hi @jarvis9443, a gentle follow-up on this fix when you have a chance. I've rebased the branch onto the latest Validation on the rebased revision (Rust 1.93.1, Linux/WSL):
The regression coverage includes multiline SSE data, chunk boundaries, split CRLF, malformed trailing data, and the event-size limit. These are local checks, not a claim that the full project CI has passed. The new CI run and the other fork workflows are still awaiting approval. Could a maintainer approve them and help review this when convenient? If there's anything you'd like changed in the approach or additional coverage you'd find useful, I'm happy to follow up. Thanks for your time! |
The event-stream grammar lets a bare `\r` end a line and lets the stream open with a UTF-8 BOM. The frame reader ended lines only on `\n`, so a CR-framed agent's events never ended, and a leading BOM made the first field name unrecognisable, silently dropping the first envelope. A `\r` now ends a line and a directly following `\n` is swallowed, tracked across chunk boundaries; a BOM is stripped at stream start only. Adds a DP e2e case where the agent writes each envelope across several CRLF `data:` lines, asserting every event reaches the client as a single-line frame.
|
Thanks @mat973252-coder, this is a clean fix and the regression coverage made it easy to land. We added a few small follow-ups on top before merging: bare-CR line endings, stripping a leading BOM, and an e2e case that covers the gateway's re-framing of multi-line events. Merged now, thanks again! |
Fixes #1143.
An A2A agent can split a JSON-RPC envelope across several
data:fields in one SSE event. The relay previously parsed each line separately and terminated the stream on the first incomplete JSON fragment.Buffer until the event's blank line, join its data fields with newlines, and parse the envelope once, following the SSE event-stream rules. This handles LF/CRLF framing and network chunk boundaries while ignoring comments and metadata. The existing 16 MiB limit now bounds the accumulated event. Existing compatibility for an unterminated final event is retained.
Malformed JSON is now reported when the complete event arrives, or at EOF, rather than after its first data line. Existing configurations need no changes.
Regression coverage includes multiline payloads, interspersed metadata, split CRLF/JSON writes, malformed JSON, and an oversized event made of individually small lines. The HTTP round-trip regression fails against the original reader with
malformed JSON-RPC eventand passes with this change.Maintainer follow-ups on top: a bare
\rnow also ends a line (with a directly following\nswallowed, including across chunk boundaries), and a UTF-8 BOM at the very start of the stream is stripped, both per the same spec section. Before, a CR-framed agent's events never ended, and a leading BOM silently dropped the first envelope. A DP e2e case now has the stub agent write each envelope across several CRLFdata:lines and asserts every event reaches the client as a single-line frame, which covers the gateway's re-serialisation layer.Validation
Validated on Rust 1.93.1 in a Linux checkout, at commit
7f73bb63b569288a3284559dcbb28d741c911567:cargo fmt --all --checkpassed.cargo check --locked --workspacepassed.cargo clippy --locked --workspace -- -D warningspassed.cargo test --locked --workspace --no-fail-fasthas one failing test:aisix-mcp::bridge::tests::connect_timeout_bounds_an_unreachable_upstream.The same full-workspace test command, in the same environment, on unmodified upstream
main(c8e96aa) fails only that same MCP test. It exceeds the test's eight-second bound while reaching the unreachable test address. No tests were skipped or weakened to hide this failure. Local proxy/network behavior affects this test, so this draft does not claim a green full-workspace test run; upstream CI still needs to validate it.The separate repository E2E suite has not been run locally. This change is limited to the A2A reader and its tests.
Summary by CodeRabbit