fix(realtime): preserve base URL queries in WebSocket upgrades - #3971
Conversation
Castiron custom code✅ No new custom-code files detected. 47 mixed files remain; 1 existing customization changed. Compared
46 existing customizations unchanged
6 more in the full report. A changed generated baseline means this report cannot reliably identify which handwritten lines changed. Inspect the custom-code diffDownload the exact patch produced by this run (requires repository access): gh run download 36339913572 --repo openai/openai-python \
--name castiron-custom-code-36339913572-1 --dir /tmp/castiron-custom-code-36339913572-1
git apply --stat /tmp/castiron-custom-code-36339913572-1/custom-code.patch
cat /tmp/castiron-custom-code-36339913572-1/custom-code.patchOr reproduce it from an SDK checkout containing the vendored reporter: git fetch --no-tags origin 43443d14c5ab8b9bc9d7aaf31263351f071afca2 a5a6f80b56b834bf524acfda149bdfd95c68fe53
python3 scripts/castiron/custom_code_report.py report \
--base 43443d14c5ab8b9bc9d7aaf31263351f071afca2 \
--head a5a6f80b56b834bf524acfda149bdfd95c68fe53 --fetch --require-head-hash --public \
--out /tmp/castiron-custom-code-a5a6f80b56b8
cat /tmp/castiron-custom-code-a5a6f80b56b8/custom-code.patchThis is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR. |
jbeckwith-oai
left a comment
There was a problem hiding this comment.
Reviewed a5a6f80. No blocking findings.
Splitting the raw path from its query before adding the trailing slash and Realtime endpoint fixes the malformed upgrade URL without changing header precedence or recoverable-error behavior. The sync/async loopback tests cover a custom path with and without base query parameters, one Authorization header, option/header preservation, typed error recovery, unknown fields, and same-socket reuse. I also checked the shared normalization callers and server failure/cleanup handling.
Validation: 64 controlled cases using the exact extracted Realtime URL methods and 16 shared-normalization cases passed with installed HTTPX 0.28.1, including escaped path characters, query values ending in '/', empty values, fragments, HTTP/HTTPS, and explicit WebSocket bases. All three changed Python files compile in memory. These are isolated URL-method probes, not a local full-SDK run; exact-head hosted Python 3.10/3.14, HTTPX2, lint/build and Castiron checks passed. No live API calls.
…nai#3972) Stacked on openai#3971, which fixes base URL normalization. Once that is merged, this PR can be retargeted to main. Live WebSocket primary, fork and sideband managers appended their endpoint after the base URL query. For example, /v1/customer?tenant=sample dialed /v1/customer instead of the Live endpoint. Append the path before the query in all six sync/async managers. Tests cover the actual WebSocket upgrade, preserved query parameters and escaped session IDs, caller-initiated primary and fork starts, immediate sideband events without waiting for session.started, follow-up updates and clean close. Validation: all six query cases failed and six plain cases passed before the fix. After it, all 363 affected tests and 12 base URL tests passed on both Pydantic v1 and v2. Full Ruff, mypy and Pyright passed. No hosted-service or stored-fork-eligibility claims.
Automated Release PR --- ## [3.20.0](openai/openai-python@v3.19.2...v3.20.0) (2026-09-28) ### Features * **api:** add Agents credential and session options ([openai#3967](openai#3967)) ([bb68198](openai@bb68198)) * **api:** add Cyber access programs to Responses ([openai#3956](openai#3956)) ([09c5b6f](openai@09c5b6f)) * **responses:** opt in to incremental WebSocket text and tool snapshots ([openai#3973](openai#3973)) ([d0207b4](openai@d0207b4)) * **responses:** preserve detailed WebSocket accumulator snapshots ([openai#3981](openai#3981)) ([a380cf2](openai@a380cf2)) ### Bug Fixes * **client:** retry unmapped TLS transport errors ([openai#3982](openai#3982)) ([0d35a26](openai@0d35a26)) * **live:** avoid hangs at fractional transcript grouping deadlines ([openai#3970](openai#3970)) ([4ef4129](openai@4ef4129)) * **live:** keep query parameters out of WebSocket endpoint paths ([openai#3972](openai#3972)) ([f9c458b](openai@f9c458b)) * **live:** preserve caller queues and prevent uncertain WebSocket replay ([openai#3980](openai#3980)) ([80e9686](openai@80e9686)) * **realtime:** preserve base URL queries in WebSocket upgrades ([openai#3971](openai#3971)) ([f7bd4a7](openai@f7bd4a7)) * **realtime:** retain configured queues without replaying attempted sends ([openai#3978](openai#3978)) ([a52805c](openai@a52805c)) ### Chores * **api:** clarify documented API error responses ([openai#3965](openai#3965)) ([384fee3](openai@384fee3)) * **api:** document batch error responses ([openai#3961](openai#3961)) ([6e4a79c](openai@6e4a79c)) * **api:** document files and uploads error responses ([openai#3960](openai#3960)) ([a9d727f](openai@a9d727f)) * **api:** document fine-tuning and model errors ([openai#3964](openai#3964)) ([5d4003c](openai@5d4003c)) * **api:** document Responses not-found errors ([openai#3959](openai#3959)) ([63099e7](openai@63099e7)) * **api:** document stored chat completion errors ([openai#3963](openai#3963)) ([a73fe0c](openai@a73fe0c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: openai-sdks[bot] <284451331+openai-sdks[bot]@users.noreply.github.com>
A custom base URL such as https://example.test/v1/customer?tenant=sample failed to open Realtime WebSockets. Both the base URL normalization and sync/async Realtime path preparation appended to HTTPX's raw_path, which includes the query. As a result, the server received /v1/customer instead of /v1/customer/realtime.
Append the slash and endpoint before the existing query, preserving the original query and connection options. Four real WebSocket tests verify the path, authentication and header overrides, configured compression, outbound messages, same-connection recovery after an API error, unknown fields and clean close.
Validation:
No new API or schema changes. Shared base URL normalization also applies to HTTP clients; broader HTTP relative-query behavior is outside this change.