Skip to content

fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB#96762

Merged
vincentkoc merged 3 commits into
openclaw:mainfrom
wangmiao0668000666:fix/openai-chatgpt-responses-stream-bound
Jun 27, 2026
Merged

fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB#96762
vincentkoc merged 3 commits into
openclaw:mainfrom
wangmiao0668000666:fix/openai-chatgpt-responses-stream-bound

Conversation

@wangmiao0668000666

Copy link
Copy Markdown
Contributor

What Problem This Solves

src/llm/providers/openai-chatgpt-responses.ts (parseSSE, the ChatGPT Responses SSE parser) accumulates an unbounded SSE byte stream into a string buffer while waiting for \n\n frame delimiters. A hostile or malfunctioning ChatGPT Responses endpoint (including a MITM-able proxy or a hijacked self-hosted provider) can return a Content-Length-less SSE body that streams forever, exhausting process memory on a code path that runs for every SSE-transport ChatGPT Responses streaming call.

This is the streaming-body analogue of the bounded-read sweep Alix-007 finished for non-streaming response.json(). Same 16 MiB cap, same helper-driven design, but on the chunk-by-chunk SSE path that the non-streaming sweep did not cover.

Changes

  • src/agents/streaming-byte-guard.ts (NEW, 87 lines, same file from fix(anthropic): bound streaming 200 success-body SSE reads at 16 MiB #96701) — createSseByteGuard helper reused from the anthropic-transport-stream PR. Same minimal core-internal helper.
  • src/llm/providers/openai-chatgpt-responses.ts:724parseSSE wraps body.getReader() in createSseByteGuard with OPENAI_CHATGPT_RESPONSES_SUCCESS_BODY_MAX_BYTES = 16 * 1024 * 1024. The existing SSE frame parsing loop and cleanup are unchanged. The function is also re-exported as parseSSEForTest for direct test access.
  • src/llm/providers/openai-chatgpt-responses.test.ts — inline test: hostile 1 MiB pull stream, asserts canonical overflow message, cancel(reason) was an Error instance, pullCount bounded to 17-20.

Real behavior proof

  • Behavior addressed: unbounded buffering of the ChatGPT Responses parseSSE SSE read; after the fix the read is capped at 16 MiB and the stream is cancelled on overflow.
  • Real environment tested: a real node:http server bound to 127.0.0.1 returning a Content-Length-less 64 MiB body (4× the cap) chunk-by-chunk with backpressure, plus a negative-control 1 MiB body (1135 SSE events), plus a happy-path body (2 events). Drives the production parseSSEForTest over a real TCP socket. Node v22.22.0.
  • Exact steps: node --import tsx _proof_openai_responses_stream.mts (proof script kept local-only, not committed, matching Alix-007 fix(github-copilot): bound usage response reads #96607 pattern).
  • Evidence after fix:
    === openai-chatgpt-responses parseSSE success-body bounded read (cap=16777216, would-stream=67108864) ===
    
    PASS  OpenAI ChatGPT Responses success body bounded: rejected with "OpenAI ChatGPT Responses success body exceeded 16777216 bytes (received 16833978)..."; bytesSent=19923323 (< 67108864); server.aborted=true
    PASS  negative control: small body fully drained (1135 events parsed); cap did not trigger
    PASS  happy path: small valid OpenAI ChatGPT Responses SSE response drained end-to-end (2 events); aborted=false
    
    === All openai-chatgpt-responses parseSSE bounded-read assertions passed ===
    
  • Observed result after fix: createSseByteGuard cancelled the upstream ReadableStreamDefaultReader at ~16 MiB (well under 64 MiB). Server-side socket.bytesWritten observed at 19,923,323 — bounded, not drained. cancel(reason) received an Error instance. Negative control confirms the cap is the cause of overflow, not body structure.
  • What was not tested: live ChatGPT API call (the proof exercises the same production helper against the same shape of attack the live endpoint could carry); cross-platform Node differences (Node 22 only, matches CI).

Out of scope (separate PRs, sequenced)

  • src/agents/runtime/proxy.ts (streamProxy, internal proxy SSE parser) — same bounded-read pattern, separate PR (planned as PR #3d).
  • extensions/google/transport-stream.ts and extensions/ollama/src/{setup,stream}.ts — need the helper promoted to a plugin-SDK subpath first.

Risk

  • Low: same 16 MiB cap already used by readProviderJsonResponse for non-streaming ChatGPT Responses success bodies. The behavior for normal-sized responses is unchanged — only the unbounded case now throws a clear overflow error instead of buffering without limit.
  • Cancel propagation: createSseByteGuard.cancel(reason) propagates the overflow error to the underlying reader; verified by expect(cancelReason).toBeInstanceOf(Error) in the test.
  • No SDK surface change: helper is core-internal (src/agents/streaming-byte-guard.ts); no package.json export, no scripts/lib/plugin-sdk-entrypoints.json entry, no API-baseline regen needed.
  • Reuses the helper from fix(anthropic): bound streaming 200 success-body SSE reads at 16 MiB #96701: same createSseByteGuard signature, same 16 MiB cap, same overflow-error shape. No new abstraction introduced.

Diff stats

3 files changed, 149 insertions(+), 2 deletions(-)
create mode 100644 src/agents/streaming-byte-guard.ts

Code change (excluding the inline test file): 106 LoC (87 helper + 19 source). Test additions: 43 LoC inline in existing describe block.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Jun 25, 2026
@clawsweeper

clawsweeper Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 26, 2026, 8:32 PM ET / 00:32 UTC.

Summary
The PR adds a core-internal SSE byte guard, caps ChatGPT Responses success SSE reads at 16 MiB and non-OK error bodies at 16 KiB, exposes parseSSEForTest, and adds focused regression tests.

PR surface: Source +152, Tests +92. Total +244 across 3 files.

Reproducibility: yes. as a source-reproducible path: current main and v2026.6.10 read ChatGPT Responses SSE chunks and error bodies without byte caps. I did not run tests in this read-only pass; the PR body proves the success-stream path with local TCP output, but not the newly added error-body cap.

Review metrics: 1 noteworthy metric.

  • Bounded ChatGPT response reads: 2 added: 16 MiB success SSE, 16 KiB error body. Both thresholds change how oversized provider responses fail, so maintainers should notice the compatibility boundary before merge.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🦞 diamond lobster
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add terminal, live output, or redacted logs showing the non-OK ChatGPT error-body cap against a real streaming server.
  • [P1] Have maintainers explicitly accept or tune the 16 MiB success-stream and 16 KiB error-body limits before merge.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body has terminal proof for the success-stream cap, but current head also adds error-body limiting without real after-fix proof for that path; contributor should add redacted terminal/live output or logs and update the PR body for re-review.

Risk before merge

  • [P1] Existing ChatGPT Responses success streams over 16 MiB will now throw and cancel, and non-OK bodies over 16 KiB will be truncated before retry/error formatting; maintainers should explicitly accept or tune those compatibility boundaries.
  • [P1] The PR body contains real local-server proof for the success-stream cap, but current head also adds error-body limiting without matching after-fix real behavior proof for that added path.
  • [P1] Open sibling PRs add the same src/agents/streaming-byte-guard.ts helper for adjacent SSE parsers, so whichever helper PR lands second will need a rebase/de-duplication pass.

Maintainer options:

  1. Refresh Current-Head Proof (recommended)
    Add PR-body terminal or live output showing the non-OK ChatGPT response body cap cancels a real streaming server, alongside the existing success-stream proof.
  2. Accept Or Tune The Caps
    Maintainers can accept the 16 MiB success-stream and 16 KiB error-body limits, or adjust the constants and refresh overflow plus happy-path evidence before landing.
  3. Split Error-Body Policy If Needed
    If the newly added error-body cap needs separate policy review, split or drop that part and keep this PR focused on the success SSE guard.

Next step before merge

  • [P1] Maintainer review should request current-head real behavior proof for the error-body cap and decide or tune the new fail-closed compatibility limits; there is no narrow automated repair to queue.

Security
Cleared: The diff hardens an availability-sensitive provider stream path and does not add dependencies, lockfiles, CI permissions, secret handling, package metadata, or downloaded third-party execution.

Review details

Best possible solution:

Land the narrow bounded-read fix after current-head proof covers both success-stream and error-body paths, maintainers accept or tune the caps, and the shared helper sequencing is clean.

Do we have a high-confidence way to reproduce the issue?

Yes, as a source-reproducible path: current main and v2026.6.10 read ChatGPT Responses SSE chunks and error bodies without byte caps. I did not run tests in this read-only pass; the PR body proves the success-stream path with local TCP output, but not the newly added error-body cap.

Is this the best way to solve the issue?

Yes, if maintainers accept the limits. Guarding the reader preserves streaming and avoids public SDK surface, while the existing full-body bounded reader would buffer before parsing; the safer merge path is updated current-head proof plus explicit cap acceptance.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 4d9cd7d22755.

Label changes

Label justifications:

  • P2: This is normal-priority provider stream hardening with limited blast radius and no evidence of an active widespread outage.
  • merge-risk: 🚨 compatibility: Merging changes oversized ChatGPT Responses success streams and error bodies from unbounded reads into fail-closed or truncated behavior.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦞 diamond lobster.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body has terminal proof for the success-stream cap, but current head also adds error-body limiting without real after-fix proof for that path; contributor should add redacted terminal/live output or logs and update the PR body for re-review.
Evidence reviewed

PR surface:

Source +152, Tests +92. Total +244 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 2 156 4 +152
Tests 1 92 0 +92
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 248 4 +244

What I checked:

Likely related people:

  • vincentkoc: Recent GitHub path history shows multiple OpenAI/ChatGPT Responses provider changes, and current PR head includes maintainer-authored error-body cap commits. (role: recent area contributor; confidence: high; commits: 8c8eb86fff6e, 5636c6044b7c, 45366dec2ecf; files: src/llm/providers/openai-chatgpt-responses.ts, src/llm/providers/openai-chatgpt-responses.test.ts, src/llm/providers/openai-responses-shared.ts)
  • steipete: GitHub path history shows major OpenAI provider identity, docs, lint, and tool-schema work in the same provider area. (role: OpenAI provider history contributor; confidence: medium; commits: 439a9e97fd61, 4c33aaa86c16, e6f85453dc3c; files: src/llm/providers/openai-chatgpt-responses.ts, src/llm/providers/openai-chatgpt-responses.test.ts)
  • Alix-007: Authored merged provider JSON response-limit work and a related bounded-read family that this PR mirrors for provider body caps. (role: adjacent bounded-read contributor; confidence: medium; commits: 2592f8a51a4e, 646e54ae3578; files: src/agents/provider-http-errors.ts, packages/media-core/src/read-response-with-limit.ts, extensions/github-copilot/usage.ts)
  • joshavant: Recent history added successful provider response-read bounding precedent that this PR uses as the cap and design anchor. (role: recent bounded-read area contributor; confidence: medium; commits: 0a14444924e3; files: src/agents/provider-http-errors.ts, src/plugin-sdk/provider-http.ts, packages/media-core/src/read-response-with-limit.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 25, 2026
@vincentkoc
vincentkoc force-pushed the fix/openai-chatgpt-responses-stream-bound branch from 41ecb31 to 81a0f2a Compare June 27, 2026 00:14
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 27, 2026
wangmiao0668000666 and others added 3 commits June 26, 2026 17:26
… at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).
@vincentkoc
vincentkoc force-pushed the fix/openai-chatgpt-responses-stream-bound branch from 962908b to 5a99681 Compare June 27, 2026 00:26
@vincentkoc

Copy link
Copy Markdown
Member

Maintainer proof for the synced/fixed head:

  • Original PR was good for success-body SSE reads, but I found and fixed the adjacent non-OK response.text() body drain before merge.
  • Added a browser-safe bounded error-body reader in the ChatGPT Responses provider and regression coverage for oversized non-OK bodies with stream cancellation.
  • Direct Codex protocol/source check: Codex success responses stream bytes; non-success responses read text, so OpenClaw needs its own bounded guard on both provider paths.
  • Static proof: git diff --check and oxfmt --check on the touched files passed.
  • Autoreview: .agents/skills/autoreview/scripts/autoreview --mode local passed clean after the import-boundary fix.
  • Local focused Vitest was attempted with node scripts/run-vitest.mjs src/llm/providers/openai-chatgpt-responses.test.ts --testNamePattern "non-OK ChatGPT response bodies|parseSSEForTest|Retry-After", but local heavy-check serialization was held by another worktree, so I used hosted exact-head CI for the final gate.
  • Exact-head CI passed: https://github.com/openclaw/openclaw/actions/runs/28272773528 (43 success, 9 skipped, no failures) on 5a996811d2203bbf110ddaebd0fdb6a3f8c4fa99.
  • Wrapper gate passed: OPENCLAW_TESTBOX=1 scripts/pr prepare-run 96762.

Proceeding with the repo merge wrapper now.

@vincentkoc
vincentkoc merged commit 5880e0a into openclaw:main Jun 27, 2026
95 checks passed
@vincentkoc

Copy link
Copy Markdown
Member

Merged via squash.

@vincentkoc

Copy link
Copy Markdown
Member

Maintainer proof after refresh to current main:

  • Head: 5a996811d2203bbf110ddaebd0fdb6a3f8c4fa99.
  • Reviewed the OpenAI ChatGPT Responses success SSE path, the non-OK error-body path, the local browser-safe bounded reader, and the sibling upstream Codex streaming contract.
  • Maintainer follow-up fixed the adjacent parser bypass so parseErrorResponse also uses the bounded error-body reader instead of raw response.text().
  • Local proof: git diff --check; oxfmt --check on the touched files; focused run-vitest for non-OK|parseSSEForTest|Retry-After; autoreview clean.
  • Exact-head CI passed: https://github.com/openclaw/openclaw/actions/runs/28272773528 (43 success, 9 skipped, no failures).
  • scripts/pr review-validate-artifacts 96762 and OPENCLAW_TESTBOX=1 scripts/pr prepare-run 96762 passed.

@vincentkoc

Copy link
Copy Markdown
Member

Maintainer proof after refresh to current main:

Best-fix verdict: good to land. The provider now caps both high-I/O response-body paths in this flow instead of only the happy-path stream.

@vincentkoc

Copy link
Copy Markdown
Member

Merged after maintainer proof and fix.

What landed:

  • Success-body OpenAI ChatGPT Responses SSE reads are capped at 16 MiB through the shared streaming byte guard.
  • Maintainer follow-up also bounded the adjacent non-OK ChatGPT response body read before retry/error formatting, so this no longer leaves the same high-I/O class open on error responses.

Proof:

Landed on main as 5880e0afc4dc2e132651073d5daac24f48ed2587.

@wangmiao0668000666

Copy link
Copy Markdown
Contributor Author

Thanks @vincentkoc for merging! 🎉

The bounded-read pattern continues to harden OpenClaw's SSE/OOM surface. #96772 (googlechat) and #96989 (SSE buffer cap) follow the same approach — all aligned with the merged provider-JSON bound-stream PRs #95218/#95418/#95420.

wangmiao0668000666 added a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 27, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 27, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
wangmiao0668000666 added a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 27, 2026
Apply createSseByteGuard to src/agents/runtime/proxy.ts (streamProxy)
so the runtime proxy SSE parser cannot be exhausted by a hostile or
malfunctioning proxy endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/agents/runtime/proxy.ts: wrap response.body.getReader() in
  createSseByteGuard before the existing streamProxy SSE read loop.
  The abort handler and finally block use guard.cancel() instead of
  reader.cancel().
- Inline test added to proxy.test.ts: hostile 1 MiB pull stream through
  streamProxy, asserts errorMessage matches overflow pattern,
  cancel(reason) was an Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
final per-surface rescue from the previously closed PR openclaw#96666, after
PR #3c (openclaw#96762).

No SDK surface change. No repro script committed (proof in this body).
xydigit-zt pushed a commit to xydigit-zt/xydigit-zt-openclaw that referenced this pull request Jun 28, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
wheakerd pushed a commit to wheakerd/clawdbot that referenced this pull request Jul 15, 2026
… at 16 MiB (openclaw#96762)

* fix(openai-chatgpt-responses): bound streaming success-body SSE reads at 16 MiB

Apply createSseByteGuard to src/llm/providers/openai-chatgpt-responses.ts
(parseSSE) so the ChatGPT Responses SSE parser cannot be exhausted by a
hostile or malfunctioning endpoint that streams an unbounded SSE body.
The 16 MiB cap matches the non-streaming readProviderJsonResponse cap.

What changed:
- src/llm/providers/openai-chatgpt-responses.ts: wrap body.getReader() in
  createSseByteGuard before the existing parseSSE loop. The function is
  also re-exported as parseSSEForTest for direct test access.
- Inline test added to openai-chatgpt-responses.test.ts: hostile 1 MiB
  pull stream, asserts canonical overflow message, cancel(reason) was an
  Error instance, pullCount bounded to 17-20.

Reuses the createSseByteGuard helper from src/agents/streaming-byte-guard.ts
(introduced in openclaw#96701 for the anthropic-transport-stream path; same
helper, same 16 MiB cap, same overflow-error shape). This PR is the
third of the planned per-surface rescue series for the previously closed
PR openclaw#96666, after PR #3b (openclaw#96723).

No SDK surface change. No repro script committed (proof in this body).

* fix(openai): bound ChatGPT error body reads

* fix(openai): bound chatgpt error parsing

---------

Co-authored-by: Vincent Koc <[email protected]>
(cherry picked from commit 5880e0a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: M status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants