Skip to content

fix(openai): bound realtime voice websocket payload at 16 MiB#99450

Merged
steipete merged 2 commits into
openclaw:mainfrom
sunlit-deng:sunlit/fix/openai-voice-ws-payload
Jul 5, 2026
Merged

fix(openai): bound realtime voice websocket payload at 16 MiB#99450
steipete merged 2 commits into
openclaw:mainfrom
sunlit-deng:sunlit/fix/openai-voice-ws-payload

Conversation

@sunlit-deng

@sunlit-deng sunlit-deng commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where the OpenAI realtime voice backend WebSocket could accept inbound frames up to the ws dependency default of 100 MiB when the provider path did not set an explicit payload cap.

Why This Change Was Made

The OpenAI realtime voice bridge now passes maxPayload: 16 * 1024 * 1024 to its backend WebSocket constructor. This is an intentional hardening cap for the provider relay path; frames above 16 MiB fail closed with WebSocket close status 1009.

User Impact

Gateway voice sessions have a bounded inbound WebSocket frame size instead of inheriting the larger dependency default.

Evidence

  • node --import tsx outputs/pr-99450/verify-openai-voice-ws-max-payload.mjs: loopback proof through buildOpenAIRealtimeVoiceProvider().createBridge() and the realtime voice WebSocket constructor.
[proof] provider=openai capability=realtime-voice maxPayload=16777216
[server] connection path=/v1/realtime?model=gpt-realtime-2
[server] observed client session frame bytes=447
[server] sent oversized frame bytes=16778240 limit=16777216
[client] connect rejected name=RangeError message="Max payload size exceeded" code=WS_ERR_UNSUPPORTED_MESSAGE_LENGTH status=1009
[server] close code=1009 reason=""
[proof] serverObservedClose1009=true

AI-assisted: built with Codex

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 5, 2026, 6:59 PM ET / 22:59 UTC.

Summary
The PR adds a 16 MiB maxPayload cap to the OpenAI realtime voice backend WebSocket and covers that option in the provider test.

PR surface: Source +2, Tests +3. Total +5 across 2 files.

Reproducibility: yes. source-level: current main constructs the OpenAI realtime voice backend WebSocket without maxPayload, and ws 8.21.0 defaults that client option to 100 MiB. The PR body provides after-fix loopback output showing the configured 16 MiB cap rejects an oversized frame with status 1009.

Review metrics: 1 noteworthy metric.

  • Runtime Payload Ceiling: 1 added: ws default 100 MiB to 16 MiB cap. The new ceiling is the maintainer-visible compatibility tradeoff for existing voice sessions.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

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

Rank-up moves:

  • [P2] Get maintainer acceptance or tuning of the 16 MiB realtime voice hard cap before merge.

Risk before merge

  • [P1] Merging intentionally changes existing behavior: OpenAI or Azure realtime voice backend frames between 16 MiB and the prior ws 100 MiB default will now close the backend voice session with status 1009.
  • [P1] The submitted proof verifies the ws enforcement path, but it does not prove that legitimate OpenAI or Azure realtime voice output frames never exceed 16 MiB.

Maintainer options:

  1. Accept Or Tune The Cap Before Merge (recommended)
    Have the OpenAI realtime voice owner confirm 16 MiB or adjust the constant to the intended bounded value before landing.
  2. Pause For Vendor Frame Evidence
    Hold the PR if maintainers want representative OpenAI or Azure realtime frame sizes before selecting a permanent ceiling.

Next step before merge

  • [P1] The remaining action is maintainer acceptance or tuning of the fail-closed payload threshold; there is no narrow code defect for automation to repair.

Maintainer decision needed

  • Question: Should OpenAI realtime voice backend WebSocket frames fail closed at 16 MiB, or should maintainers choose a different supported ceiling before merge?
  • Rationale: The implementation is small and correct, but the exact ceiling changes existing runtime behavior for any backend frame between 16 MiB and the previous ws 100 MiB default; automation cannot know the intended vendor-frame tolerance.
  • Likely owner: steipete — steipete is the current assignee and the strongest OpenAI realtime voice feature-history owner in the inspected commit history.
  • Options:
    • Accept 16 MiB Cap (recommended): Land the hardening as written and own that larger realtime voice backend frames close with status 1009.
    • Tune The Ceiling: Change the constant to a larger bounded value if representative OpenAI or Azure realtime frames need more headroom.
    • Pause For Vendor Evidence: Keep the PR open until maintainers collect live-session telemetry or vendor guidance for a permanent ceiling.

Security
Cleared: The diff tightens an existing WebSocket resource boundary and does not touch dependencies, lockfiles, CI, secrets, permissions, package resolution, or downloaded code.

Review details

Best possible solution:

Merge the provider-owned cap only after the OpenAI realtime voice owner accepts 16 MiB as the intended fail-closed ceiling, or tune that constant from representative vendor-frame evidence.

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

Yes, source-level: current main constructs the OpenAI realtime voice backend WebSocket without maxPayload, and ws 8.21.0 defaults that client option to 100 MiB. The PR body provides after-fix loopback output showing the configured 16 MiB cap rejects an oversized frame with status 1009.

Is this the best way to solve the issue?

Yes for implementation shape if the threshold is accepted: owner-local WebSocket options use the dependency's built-in enforcement and avoid new config surface. The open question remains whether 16 MiB is the intended maintained cap for legitimate realtime voice frames.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is focused OpenAI provider hardening with limited blast radius and no active outage evidence.
  • merge-risk: 🚨 compatibility: The new maxPayload can close realtime voice sessions that previously accepted backend frames above 16 MiB.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes copied after-fix live output from a loopback run through the production provider bridge showing a 16 MiB-plus frame rejected with status 1009.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied after-fix live output from a loopback run through the production provider bridge showing a 16 MiB-plus frame rejected with status 1009.
Evidence reviewed

PR surface:

Source +2, Tests +3. Total +5 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 0 +2
Tests 1 4 1 +3
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 6 1 +5

What I checked:

Likely related people:

  • steipete: Authored the GA realtime bridge/default model change and multiple follow-up OpenAI realtime voice fixes, and is the current PR assignee. (role: feature-history owner and current assignee; confidence: high; commits: 63ec912786b2, 3533297cd9cf, dc2c4aab6d69; files: extensions/openai/realtime-voice-provider.ts, extensions/openai/realtime-voice-provider.test.ts)
  • giodl73-repo: Recent merged OpenAI realtime double-greeting work changed this provider and test file substantially. (role: recent adjacent contributor; confidence: medium; commits: 85ad4cb20028; files: extensions/openai/realtime-voice-provider.ts, extensions/openai/realtime-voice-provider.test.ts)
  • vincentkoc: Recently merged malformed realtime provider tool-name handling through the same OpenAI realtime voice provider and test file. (role: recent area contributor; confidence: medium; commits: 8ec5e06cbf73; files: extensions/openai/realtime-voice-provider.ts, extensions/openai/realtime-voice-provider.test.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-03T15:52:04.400Z sha 0befe00 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 3, 2026
@sunlit-deng
sunlit-deng force-pushed the sunlit/fix/openai-voice-ws-payload branch from 2278347 to a508cc1 Compare July 3, 2026 11:43
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jul 3, 2026
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@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. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 3, 2026
@sunlit-deng
sunlit-deng force-pushed the sunlit/fix/openai-voice-ws-payload branch from a508cc1 to 0befe00 Compare July 3, 2026 15:36
@steipete steipete self-assigned this Jul 5, 2026
@steipete
steipete force-pushed the sunlit/fix/openai-voice-ws-payload branch from 0befe00 to ec15183 Compare July 5, 2026 22:48
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Maintainer pass complete. I kept the contributor's boundary fix, added the missing constructor-level regression assertion, rebased it onto current main, and ran a fresh no-findings autoreview.

Exact-head proof for ec15183cf4e563c5ba382dda39e38d7e39039721:

  • Sanitized public-network AWS Crabbox cbx_48ee84e3e099, run run_97c27f72b833
  • /usr/local/bin/pnpm test extensions/openai/realtime-voice-provider.test.ts
  • Result: 1 file, 60 tests passed
  • Direct dependency check: ws exposes maxPayload at construction and otherwise defaults inbound payloads to 100 MiB

The final shape uses one named 16 MiB limit for both native OpenAI and Azure realtime sockets, with existing proxy/header behavior unchanged. Ready to land.

@steipete
steipete merged commit 2525ea4 into openclaw:main Jul 5, 2026
88 checks passed
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
…aw#99450)

* fix(openai): bound realtime voice websocket payload at 16 MiB

* test(openai): cover realtime voice payload cap

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: openai merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants