codex-backend-sdk 0.5.8__tar.gz → 0.5.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/CHANGELOG.md +11 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/PKG-INFO +1 -1
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/__init__.py +1 -1
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/realtime.py +43 -6
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/docs/api-reference.md +29 -5
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/docs/backend-api.md +20 -4
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/docs/openai-compatibility.md +2 -1
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/pyproject.toml +1 -1
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_realtime_resource.py +34 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/uv.lock +1 -1
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/.gitignore +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/LICENSE +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/README.md +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/_client.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/_codex_version.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/_models.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/_streaming.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/_transport.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/_utils.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/codex_client.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/oauth.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/pkce.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/__init__.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/_responses_payloads.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/_responses_routing.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_apps.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_connectors.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_plugin_bundles.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_plugin_shares.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_plugins.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_writing_blocks.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/codex.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/codex_web_search.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/files.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/images.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/models.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/openai_oauth.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/remote_control.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/responses.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/responses_websocket.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/worktree_snapshots.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/storage.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/docs/codex-source-audit.md +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/docs/desktop-endpoint-inventory.md +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/docs/endpoint-coverage.md +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/examples/agent.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/conftest.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/general/test_codex_source_contracts.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_account_info.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_basic.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_apps.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_connectors.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_plugin_bundles.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_plugin_shares.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_plugins.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_projects_gizmos.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_resources.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_search_files.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_chatgpt_writing_blocks.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_client_retry.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_codex_resources.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_codex_version.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_codex_web_search.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_conversation.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_files_resource.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_hosted_mcp.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_images.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_oauth.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_openai_compatibility.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_openai_oauth_resources.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_prompt_cache_usage.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_reasoning.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_remote_control_resource.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_responses_resource.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_responses_routing.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_responses_websocket.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_structured_output.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_tools.py +0 -0
- {codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/test_worktree_snapshots.py +0 -0
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.5.9] - 2026-10-24
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- OAuth transcription-only primary Realtime WebSocket with JSON events,
|
|
9
|
+
context-managed cleanup, bounded socket timeout, and no automatic audio replay.
|
|
10
|
+
Verified with synthetic PCM16LE mono 24 kHz speech, no developer API key.
|
|
11
|
+
|
|
12
|
+
### Documentation
|
|
13
|
+
- Distinguish verified Realtime transcription from the legacy batch route's
|
|
14
|
+
current HTTP 403 responses; OAuth success does not establish quota coverage.
|
|
15
|
+
|
|
5
16
|
## [0.5.8] - 2026-10-22
|
|
6
17
|
|
|
7
18
|
### Added
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
from contextlib import contextmanager
|
|
6
7
|
import threading
|
|
7
8
|
import urllib.parse
|
|
8
9
|
import uuid
|
|
@@ -33,6 +34,38 @@ class Realtime:
|
|
|
33
34
|
self.sideband = RealtimeSideband(client)
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
@contextmanager
|
|
38
|
+
def connect(self, *, intent: str, timeout: Optional[float] = None):
|
|
39
|
+
"""Open a transcription-only primary WebSocket with ChatGPT OAuth.
|
|
40
|
+
|
|
41
|
+
Events are JSON dictionaries sent/received with ``send``/``recv``.
|
|
42
|
+
There is no automatic retry or audio replay. Availability and usage
|
|
43
|
+
attribution depend on the backend; subscription coverage is not implied.
|
|
44
|
+
"""
|
|
45
|
+
if intent != "transcription":
|
|
46
|
+
raise CodexBackendUnsupportedParameterError(
|
|
47
|
+
"Only intent='transcription' is supported by the OAuth primary socket."
|
|
48
|
+
)
|
|
49
|
+
store = self._client._store
|
|
50
|
+
if store is None or not store.access_token:
|
|
51
|
+
raise RuntimeError("Realtime transcription requires ChatGPT OAuth authentication.")
|
|
52
|
+
headers = {
|
|
53
|
+
"Authorization": f"Bearer {store.access_token}",
|
|
54
|
+
"originator": "codex_cli_rs",
|
|
55
|
+
"x-session-id": str(uuid.uuid4()),
|
|
56
|
+
}
|
|
57
|
+
if store.account_id:
|
|
58
|
+
headers["ChatGPT-Account-ID"] = store.account_id
|
|
59
|
+
socket = websocket.create_connection(
|
|
60
|
+
"wss://api.openai.com/v1/realtime?intent=transcription",
|
|
61
|
+
header=headers,
|
|
62
|
+
timeout=self._client._timeout if timeout is None else timeout,
|
|
63
|
+
redirect_limit=0,
|
|
64
|
+
)
|
|
65
|
+
with RealtimeConnection(socket) as connection:
|
|
66
|
+
yield connection
|
|
67
|
+
|
|
68
|
+
|
|
36
69
|
class Live:
|
|
37
70
|
"""OpenAI-compatible Live resource backed by ChatGPT OAuth.
|
|
38
71
|
|
|
@@ -114,8 +147,8 @@ class Live:
|
|
|
114
147
|
)
|
|
115
148
|
|
|
116
149
|
|
|
117
|
-
class
|
|
118
|
-
"""JSON transport
|
|
150
|
+
class RealtimeConnection:
|
|
151
|
+
"""Synchronous JSON event transport with deterministic socket cleanup."""
|
|
119
152
|
|
|
120
153
|
def __init__(self, socket: Any, *, graceful_close: bool = False) -> None:
|
|
121
154
|
self._socket = socket
|
|
@@ -125,20 +158,20 @@ class RealtimeSidebandConnection:
|
|
|
125
158
|
|
|
126
159
|
def send(self, event: Any) -> None:
|
|
127
160
|
if self.closed:
|
|
128
|
-
raise RuntimeError("Realtime
|
|
161
|
+
raise RuntimeError("Realtime connection is closed.")
|
|
129
162
|
payload = json.dumps(_jsonable(event), ensure_ascii=False)
|
|
130
163
|
with self._send_lock:
|
|
131
164
|
self._socket.send(payload)
|
|
132
165
|
|
|
133
166
|
def recv(self) -> dict[str, Any]:
|
|
134
167
|
if self.closed:
|
|
135
|
-
raise RuntimeError("Realtime
|
|
168
|
+
raise RuntimeError("Realtime connection is closed.")
|
|
136
169
|
payload = self._socket.recv()
|
|
137
170
|
if isinstance(payload, bytes):
|
|
138
171
|
payload = payload.decode("utf-8")
|
|
139
172
|
event = json.loads(payload)
|
|
140
173
|
if not isinstance(event, dict):
|
|
141
|
-
raise TypeError("Expected a Realtime
|
|
174
|
+
raise TypeError("Expected a Realtime event to be a JSON object.")
|
|
142
175
|
return event
|
|
143
176
|
|
|
144
177
|
def close(self) -> None:
|
|
@@ -159,13 +192,17 @@ class RealtimeSidebandConnection:
|
|
|
159
192
|
except (IndexError, StopIteration):
|
|
160
193
|
return
|
|
161
194
|
|
|
162
|
-
def __enter__(self) -> "
|
|
195
|
+
def __enter__(self) -> "RealtimeConnection":
|
|
163
196
|
return self
|
|
164
197
|
|
|
165
198
|
def __exit__(self, *_: Any) -> None:
|
|
166
199
|
self.close()
|
|
167
200
|
|
|
168
201
|
|
|
202
|
+
class RealtimeSidebandConnection(RealtimeConnection):
|
|
203
|
+
"""JSON transport joined to an existing Realtime v3 WebRTC call."""
|
|
204
|
+
|
|
205
|
+
|
|
169
206
|
class LiveSidebandConnection(RealtimeSidebandConnection):
|
|
170
207
|
"""Live-shaped event stream over the Codex OAuth sideband dialect."""
|
|
171
208
|
|
|
@@ -250,7 +250,8 @@ content and a MIME type.
|
|
|
250
250
|
Required: `file`, `model`. Supported optional backend parameters are `language`,
|
|
251
251
|
`prompt`, `response_format` (`json` or `text`), `temperature`, `extra_headers`,
|
|
252
252
|
`extra_query`, `extra_body`, and `timeout`. Returns typed `Transcription` for
|
|
253
|
-
JSON or `str` for text.
|
|
253
|
+
JSON or `str` for text. The legacy batch route returned HTTP 403 in live tests
|
|
254
|
+
on October 24, 2026; prefer the verified transcription WebSocket below.
|
|
254
255
|
|
|
255
256
|
The OpenAI-compatible signature rejects unsupported `chunking_strategy`,
|
|
256
257
|
`include`, `known_speaker_names`, `known_speaker_references`, `stream`, and
|
|
@@ -271,6 +272,7 @@ Platform quota rather than the ChatGPT subscription.
|
|
|
271
272
|
|
|
272
273
|
| Method | Parameters | Returns |
|
|
273
274
|
| --- | --- | --- |
|
|
275
|
+
| `client.realtime.connect(...)` | `intent="transcription"`, optional `timeout` | context manager yielding a JSON `RealtimeConnection` |
|
|
274
276
|
| `client.live.create(...)` | official `session`, `transport`; standard request extensions | `LiveCreateResponse` with `session.id` and `transport.sdp` |
|
|
275
277
|
| `client.live.sideband.connect(...)` | official sideband keywords including `session_id`, `graceful_close`, request/socket/retry options | lazy `LiveSidebandConnectionManager` context manager |
|
|
276
278
|
| `client.realtime.calls.create_v3(...)` | `sdp`, `session`, optional `session_id`, `thread_id`, transport extensions | typed `RealtimeCallResponse` |
|
|
@@ -284,11 +286,11 @@ apply `response.transport.sdp`, then attach with
|
|
|
284
286
|
adapter presents the backend call ID as the Live session ID. The connection is
|
|
285
287
|
iterable and yields forward-compatible `LiveEvent` objects with attribute
|
|
286
288
|
access. The public primary `client.live.connect()` transport raises an explicit
|
|
287
|
-
unsupported error
|
|
288
|
-
|
|
289
|
+
unsupported error. This is distinct from the transcription-only primary
|
|
290
|
+
`client.realtime.connect(intent="transcription")` socket, verified with OAuth
|
|
291
|
+
on October 24, 2026. Its quota/billing attribution is not established.
|
|
289
292
|
|
|
290
|
-
`create_v3()`
|
|
291
|
-
`gpt-live-1-boulder-alpha`, removes any caller-supplied session ID, generates
|
|
293
|
+
`create_v3()` forwards the requested model and explicit correlation IDs, generates
|
|
292
294
|
required backend correlation IDs when omitted, and applies the current Codex v3
|
|
293
295
|
intent/architecture. The result exposes `answer_sdp`, `call_id`, raw `session`,
|
|
294
296
|
and original response text. The sideband connection joins that call over
|
|
@@ -768,3 +770,25 @@ validation errors according to the boundary.
|
|
|
768
770
|
mutations.
|
|
769
771
|
- Commercial/admin, attestation, reporting, telemetry, analytics, beacon, and
|
|
770
772
|
personal-access-token surfaces are outside the public SDK API.
|
|
773
|
+
|
|
774
|
+
### Transcription-only OAuth WebSocket
|
|
775
|
+
|
|
776
|
+
```python
|
|
777
|
+
client.authenticate(interactive=False)
|
|
778
|
+
with client.realtime.connect(intent="transcription", timeout=10) as connection:
|
|
779
|
+
connection.send({"type": "session.update", "session": {
|
|
780
|
+
"type": "transcription", "audio": {"input": {
|
|
781
|
+
"format": {"type": "audio/pcm", "rate": 24000},
|
|
782
|
+
"transcription": {"model": "gpt-4o-mini-transcribe", "language": "fr"},
|
|
783
|
+
"turn_detection": None,
|
|
784
|
+
}},
|
|
785
|
+
}})
|
|
786
|
+
# Wait for session.updated (handle error events), then send base64 PCM16LE
|
|
787
|
+
# mono chunks as input_audio_buffer.append and input_audio_buffer.commit.
|
|
788
|
+
# Receive conversation.item.input_audio_transcription.completed.
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
This synchronous raw-event surface has no automatic retry/replay, generated
|
|
792
|
+
assistant response, tools, or output audio. Set a bounded socket timeout and an
|
|
793
|
+
application-level total deadline. Context exit closes the socket even on failure.
|
|
794
|
+
Only `intent="transcription"` is supported; model/session events remain caller-owned.
|
|
@@ -402,7 +402,8 @@ low-level `client.realtime.sideband.connect(...)`) joins its
|
|
|
402
402
|
JSON control/delegation channel at `/v1/live/{call_id}` with the current ChatGPT
|
|
403
403
|
OAuth account. This transport is used for client-managed delegation events and
|
|
404
404
|
context appends. The SDK intentionally does not expose the unrelated API-key
|
|
405
|
-
Voice v2 WebSocket surface.
|
|
405
|
+
Voice v2 conversation WebSocket surface. It separately exposes the verified
|
|
406
|
+
transcription-only primary socket described below.
|
|
406
407
|
|
|
407
408
|
---
|
|
408
409
|
|
|
@@ -410,8 +411,10 @@ Voice v2 WebSocket surface.
|
|
|
410
411
|
|
|
411
412
|
These OpenAI-shaped resources deliberately use different upstreams. Embeddings
|
|
412
413
|
remain an OpenAI Platform call and consume the associated developer-account
|
|
413
|
-
quota.
|
|
414
|
-
|
|
414
|
+
quota. Legacy batch transcription uses the authenticated ChatGPT backend but
|
|
415
|
+
returned HTTP 403 in current live tests. The transcription-only Realtime socket
|
|
416
|
+
accepts ChatGPT OAuth without a developer API key; its quota/billing attribution
|
|
417
|
+
is not established.
|
|
415
418
|
|
|
416
419
|
### `POST /v1/embeddings`
|
|
417
420
|
|
|
@@ -437,13 +440,26 @@ subscription.
|
|
|
437
440
|
|
|
438
441
|
**SDK method**: `client.audio.transcriptions.create(...)`
|
|
439
442
|
|
|
440
|
-
**Status**:
|
|
443
|
+
**Status**: Legacy adapter present, but live tests with WebM and WAV returned
|
|
444
|
+
HTTP 403 HTML on October 24, 2026. This is not proof of permanent removal. The SDK
|
|
441
445
|
uploads multipart audio with the OAuth bearer and `ChatGPT-Account-ID`, and
|
|
442
446
|
supports the `model`, `language`, `prompt`, `temperature`, and `json`/`text`
|
|
443
447
|
response options used by Codex Agent. Streaming, timestamps, speaker references,
|
|
444
448
|
chunking, SRT, and VTT are rejected locally rather than falling back to a
|
|
445
449
|
billable Platform endpoint.
|
|
446
450
|
|
|
451
|
+
### `WSS /v1/realtime?intent=transcription` (api.openai.com)
|
|
452
|
+
|
|
453
|
+
**SDK method**: `client.realtime.connect(intent="transcription", timeout=...)`
|
|
454
|
+
|
|
455
|
+
**Status**: Verified October 24, 2026 with a ChatGPT OAuth bearer, no API key.
|
|
456
|
+
`session.update` with type `transcription`, PCM16LE mono 24 kHz,
|
|
457
|
+
`gpt-4o-mini-transcribe`, and `turn_detection: null` accepted synthetic speech and
|
|
458
|
+
returned the correct `conversation.item.input_audio_transcription.completed` text.
|
|
459
|
+
The ChatGPT backend URL `/backend-api/codex/realtime?intent=transcription` instead
|
|
460
|
+
returned HTTP 403. Subscription coverage and quota/billing attribution remain
|
|
461
|
+
unverified; successful OAuth authentication alone does not establish either.
|
|
462
|
+
|
|
447
463
|
### `POST /backend-api/codex/images/generations`
|
|
448
464
|
|
|
449
465
|
**SDK method**: `client.images.generate(...)`
|
|
@@ -20,7 +20,8 @@ parameter cannot disappear silently from the backend client surface.
|
|
|
20
20
|
| `responses.compact` | Official parameters preserved; Codex tool/reasoning controls are additive | Supported request options and `extra_body` are forwarded | Stored-response continuation and explicit Platform prompt-cache controls are unavailable |
|
|
21
21
|
| `models.list` / `retrieve` | Official parameters preserved; `force_refresh` is additive | Returns iterable OpenAI-shaped model pages | Catalog retrieval is a Codex endpoint and `retrieve` resolves from that catalog |
|
|
22
22
|
| `embeddings.create` | Official signature preserved | Uses the OpenAI endpoint with the Codex OAuth bearer | Availability depends on OAuth scopes and account rollout |
|
|
23
|
-
| `
|
|
23
|
+
| `realtime.connect` | Transcription-only OAuth subset | Context manager, raw JSON send/recv, deterministic close | Only `intent="transcription"`; no automatic replay; quota attribution unverified |
|
|
24
|
+
| `audio.transcriptions.create` | Official signature preserved | Legacy batch adapter retains file inputs and options; live route returned HTTP 403 on October 24, 2026 | Streaming, diarization, timestamps, `keywords`, and multi-language hints raise explicitly |
|
|
24
25
|
| `images.generate` | Official signature preserved | GPT Image generation returns OpenAI-shaped base64 results | Codex always returns non-streamed PNG/base64 output; format/compression and Platform user attribution are unavailable |
|
|
25
26
|
| `images.edit` | Official signature preserved | Single/multiple file inputs, URLs, data URLs, reference objects, and masks are normalized to Codex JSON | A mask targets the first image; `file_id` is contract-derived but not live-verified; Codex returns non-streamed PNG/base64 output |
|
|
26
27
|
| `files.create` | Official signature is present | Not callable with Codex OAuth | Live probe returned missing `api.files.write`; the method raises a scope-specific unsupported error |
|
|
@@ -279,3 +279,37 @@ def test_realtime_call_response_requires_valid_location():
|
|
|
279
279
|
assert "does not contain a valid call id" in str(exc)
|
|
280
280
|
else:
|
|
281
281
|
raise AssertionError("Expected invalid Location to fail")
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def test_primary_transcription_socket_uses_oauth_and_closes_on_failure(monkeypatch):
|
|
285
|
+
client = FakeRealtimeClient()
|
|
286
|
+
socket = FakeWebSocket([json.dumps({"type": "session.created"})])
|
|
287
|
+
captured = {}
|
|
288
|
+
def connect(url, **kwargs):
|
|
289
|
+
captured.update(url=url, **kwargs)
|
|
290
|
+
return socket
|
|
291
|
+
monkeypatch.setattr("codex_backend_sdk.resources.realtime.websocket.create_connection", connect)
|
|
292
|
+
with pytest.raises(ValueError, match="consumer"):
|
|
293
|
+
with client.realtime.connect(intent="transcription", timeout=12) as connection:
|
|
294
|
+
assert connection.recv() == {"type": "session.created"}
|
|
295
|
+
connection.send({"type": "input_audio_buffer.commit"})
|
|
296
|
+
raise ValueError("consumer")
|
|
297
|
+
assert captured["url"] == "wss://api.openai.com/v1/realtime?intent=transcription"
|
|
298
|
+
assert captured["header"]["Authorization"] == "Bearer chatgpt-token"
|
|
299
|
+
assert captured["header"]["ChatGPT-Account-ID"] == "account-id"
|
|
300
|
+
assert captured["header"]["x-session-id"]
|
|
301
|
+
assert captured["timeout"] == 12
|
|
302
|
+
assert captured["redirect_limit"] == 0
|
|
303
|
+
assert json.loads(socket.sent[0]) == {"type": "input_audio_buffer.commit"}
|
|
304
|
+
assert socket.closed
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def test_primary_socket_rejects_other_intents_and_missing_oauth():
|
|
308
|
+
client = FakeRealtimeClient()
|
|
309
|
+
with pytest.raises(NotImplementedError):
|
|
310
|
+
with client.realtime.connect(intent="realtime"):
|
|
311
|
+
pass
|
|
312
|
+
client._store = None
|
|
313
|
+
with pytest.raises(RuntimeError, match="ChatGPT OAuth"):
|
|
314
|
+
with client.realtime.connect(intent="transcription"):
|
|
315
|
+
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_apps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/chatgpt_plugins.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/codex_web_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/openai_oauth.py
RENAMED
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/remote_control.py
RENAMED
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/codex_backend_sdk/resources/responses.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.8 → codex_backend_sdk-0.5.9}/tests/general/test_codex_source_contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|