Skip to content

fix(gateway): send CORS headers on session chat/stream and run-events SSE - #90673

Open
gaomind wants to merge 1 commit into
NousResearch:mainfrom
gaomind:fix/sse-cors-headers
Open

fix(gateway): send CORS headers on session chat/stream and run-events SSE#90673
gaomind wants to merge 1 commit into
NousResearch:mainfrom
gaomind:fix/sse-cors-headers

Conversation

@gaomind

@gaomind gaomind commented Aug 20, 2026

Copy link
Copy Markdown

Problem

Two SSE endpoints return 200 text/event-stream without any Access-Control-* headers, so a cross-origin browser client is forbidden from reading the response body:

  • POST /api/sessions/{session_id}/chat/stream
  • GET /v1/runs/{run_id}/events

The failure mode is nasty: the request succeeds server-side — the agent runs and consumes model tokens — but the browser surfaces only a generic Failed to fetch. Both surfaces are advertised to browser clients via /v1/capabilities (session_chat_streaming, run_events_sse), so as shipped the capability announcement is not honoured for cross-origin callers.

Root cause

The CORS middleware cannot inject headers into a web.StreamResponse after prepare() flushes them. _write_sse_chat_completion and _write_sse_responses already resolve CORS up front for exactly this reason (the comment is in the file), but these two exits were missed.

Fix

Apply the same idiom at both sites: resolve self._cors_headers_for_origin(origin) before constructing the StreamResponse. Same configured-allowlist policy as every other endpoint — nothing is opened up that the non-streaming endpoints don't already allow, and callers without an Origin header keep exactly the old header surface.

Tests

Three tests added to tests/gateway/test_session_api.py:

  • chat/stream carries Access-Control-Allow-Origin for an allowed origin
  • chat/stream without Origin adds no CORS headers (negative — non-browser callers unchanged)
  • run-events SSE carries Access-Control-Allow-Origin

All three fail without the fix; full tests/gateway/test_session_api.py suite passes with it.

Found while integrating a cross-origin SPA that talks directly to the gateway.

🤖 Generated with Claude Code

… SSE

The CORS middleware cannot amend a StreamResponse after prepare() flushes
its headers, so SSE handlers must resolve CORS up front.
_write_sse_chat_completion and _write_sse_responses already do this (with a
comment explaining why), but two SSE exits were missed:

  * POST /api/sessions/{session_id}/chat/stream
  * GET  /v1/runs/{run_id}/events

A cross-origin browser client therefore received a 200 it was forbidden to
read: the request succeeded, the agent ran (and billed tokens), but the
caller saw only a generic fetch error. Both surfaces are advertised to
browser clients via /v1/capabilities (session_chat_streaming,
run_events_sse), so they should actually be browser-readable.

Same _cors_headers_for_origin policy as every other endpoint — configured
allowlist only, and callers without an Origin header keep exactly the old
header surface (pinned by a negative test).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery labels Aug 20, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #72945 (session-chat stream) and #6367 (run-events SSE). This PR covers both distinct handlers with the same established pre-prepare CORS pattern, so it is an omnibus competing fix rather than a duplicate of either single-endpoint PR.

@gaomind

gaomind commented Aug 20, 2026

Copy link
Copy Markdown
Author

Thanks for the triage link-up — to make the relationship explicit for reviewers:

Credit to @Tranquil-Flow and @kawanoii for identifying the per-endpoint gaps first. If maintainers prefer landing either of those, I'm happy to rebase this down to the remaining endpoint — otherwise this can land as the single omnibus fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants