codex-chatgpt-control 0.5.1-alpha.2 → 0.5.1-alpha.4
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.
- package/CHANGELOG.md +42 -0
- package/README.md +43 -0
- package/contracts/v1/fixtures/backend-capabilities.json +40 -1
- package/contracts/v1/fixtures/backend-compatibility.json +21 -0
- package/contracts/v1/fixtures/backend-version.json +6 -1
- package/contracts/v1/fixtures/download-blocked-by-browser.json +22 -0
- package/contracts/v1/fixtures/download-receipt-failed.json +22 -0
- package/contracts/v1/fixtures/download-receipt-timeout.json +22 -0
- package/contracts/v1/fixtures/journal-rpc-indeterminate.json +32 -0
- package/contracts/v1/fixtures/journal-rpc-unsupported-platform.json +32 -0
- package/contracts/v1/fixtures/journal-runtime-unavailable.json +32 -0
- package/contracts/v1/fixtures/operation-action-prepared-event.json +42 -0
- package/contracts/v1/fixtures/operation-action.json +13 -0
- package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
- package/contracts/v1/fixtures/operation-blocker.json +10 -0
- package/contracts/v1/fixtures/operation-collect-request.json +17 -0
- package/contracts/v1/fixtures/operation-collect-result.json +42 -0
- package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
- package/contracts/v1/fixtures/operation-control-request.json +18 -0
- package/contracts/v1/fixtures/operation-control-result.json +31 -0
- package/contracts/v1/fixtures/operation-event.json +18 -0
- package/contracts/v1/fixtures/operation-handle.json +10 -0
- package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
- package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
- package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
- package/contracts/v1/fixtures/operation-receipt.json +32 -0
- package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
- package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
- package/contracts/v1/fixtures/operation-request.json +33 -0
- package/contracts/v1/fixtures/operation-state.json +144 -0
- package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
- package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
- package/contracts/v1/fixtures/operation-submit-result.json +16 -0
- package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
- package/contracts/v1/manifest.json +185 -1
- package/contracts/v1/parity-suite.json +106 -8
- package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
- package/contracts/v1/schemas/backend-request.schema.json +8 -2
- package/contracts/v1/schemas/capabilities.schema.json +81 -1
- package/contracts/v1/schemas/manifest.schema.json +57 -0
- package/contracts/v1/schemas/operation-action.schema.json +155 -0
- package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
- package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
- package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
- package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
- package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
- package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
- package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
- package/contracts/v1/schemas/operation-event.schema.json +756 -0
- package/contracts/v1/schemas/operation-handle.schema.json +55 -0
- package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
- package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
- package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
- package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
- package/contracts/v1/schemas/operation-request.schema.json +158 -0
- package/contracts/v1/schemas/operation-state.schema.json +691 -0
- package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
- package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
- package/contracts/v1/surface-drift-policy.json +50 -0
- package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
- package/dist/codex-chatgpt-control-backend.mjs +45882 -9361
- package/dist/codex-chatgpt-control-journal.mjs +5547 -0
- package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +51677 -0
- package/dist/codex-chatgpt-control-release-canary.bundle.mjs +52104 -0
- package/dist/codex-chatgpt-control.bundle.mjs +48392 -10260
- package/dist/src/backend/client.d.ts +103 -2
- package/dist/src/backend/client.js +1436 -97
- package/dist/src/backend/compatibility.d.ts +12 -0
- package/dist/src/backend/compatibility.js +208 -0
- package/dist/src/backend/protocol.d.ts +84 -1
- package/dist/src/backend/protocol.js +31 -5
- package/dist/src/backend/runtime-identity.d.ts +10 -0
- package/dist/src/backend/runtime-identity.js +141 -0
- package/dist/src/backend/session.d.ts +10 -2
- package/dist/src/backend/session.js +478 -7
- package/dist/src/backend/stdio-server.d.ts +4 -1
- package/dist/src/backend/stdio-server.js +240 -28
- package/dist/src/browser/active-composer-file-input.d.ts +9 -0
- package/dist/src/browser/active-composer-file-input.js +33 -0
- package/dist/src/browser/attach.d.ts +4 -1
- package/dist/src/browser/attach.js +136 -28
- package/dist/src/browser/chatgpt-url.d.ts +2 -0
- package/dist/src/browser/chatgpt-url.js +9 -0
- package/dist/src/browser/downloads.d.ts +17 -1
- package/dist/src/browser/downloads.js +150 -28
- package/dist/src/browser/page-state.js +6 -0
- package/dist/src/client.d.ts +43 -0
- package/dist/src/client.js +1279 -59
- package/dist/src/commands/artifacts.js +6 -4
- package/dist/src/commands/chat-popover.d.ts +37 -0
- package/dist/src/commands/chat-popover.js +537 -0
- package/dist/src/commands/configuration.d.ts +5 -0
- package/dist/src/commands/configuration.js +134 -21
- package/dist/src/commands/context.js +10 -3
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +27 -4
- package/dist/src/commands/experience.d.ts +5 -0
- package/dist/src/commands/experience.js +104 -21
- package/dist/src/commands/files.js +14 -33
- package/dist/src/commands/modes.js +85 -21
- package/dist/src/commands/power-discovery.d.ts +130 -0
- package/dist/src/commands/power-discovery.js +669 -0
- package/dist/src/commands/project-sources.js +325 -31
- package/dist/src/commands/sequence.js +59 -32
- package/dist/src/commands/session.js +19 -6
- package/dist/src/commands/work.js +31 -0
- package/dist/src/dom/composer-text.d.ts +6 -0
- package/dist/src/dom/composer-text.js +85 -0
- package/dist/src/errors.d.ts +9 -0
- package/dist/src/errors.js +22 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +9 -0
- package/dist/src/operations/artifact-output.d.ts +69 -0
- package/dist/src/operations/artifact-output.js +1748 -0
- package/dist/src/operations/artifact-stream.d.ts +19 -0
- package/dist/src/operations/artifact-stream.js +35 -0
- package/dist/src/operations/artifact-transfer.d.ts +149 -0
- package/dist/src/operations/artifact-transfer.js +1312 -0
- package/dist/src/operations/browser-adapter.d.ts +167 -0
- package/dist/src/operations/browser-adapter.js +2103 -0
- package/dist/src/operations/browser-observation.d.ts +110 -0
- package/dist/src/operations/browser-observation.js +1256 -0
- package/dist/src/operations/browser-target.d.ts +105 -0
- package/dist/src/operations/browser-target.js +531 -0
- package/dist/src/operations/canonical.d.ts +4 -0
- package/dist/src/operations/canonical.js +412 -0
- package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
- package/dist/src/operations/chatgpt-runtime.js +1232 -0
- package/dist/src/operations/client.d.ts +138 -0
- package/dist/src/operations/client.js +1145 -0
- package/dist/src/operations/collector.d.ts +195 -0
- package/dist/src/operations/collector.js +1039 -0
- package/dist/src/operations/configuration-routing.d.ts +4 -0
- package/dist/src/operations/configuration-routing.js +14 -0
- package/dist/src/operations/control.d.ts +372 -0
- package/dist/src/operations/control.js +1498 -0
- package/dist/src/operations/file-identity.d.ts +33 -0
- package/dist/src/operations/file-identity.js +153 -0
- package/dist/src/operations/handle.d.ts +19 -0
- package/dist/src/operations/handle.js +727 -0
- package/dist/src/operations/index.d.ts +25 -0
- package/dist/src/operations/index.js +25 -0
- package/dist/src/operations/journal-authority.d.ts +12 -0
- package/dist/src/operations/journal-authority.js +1 -0
- package/dist/src/operations/journal-rpc-client.d.ts +12 -0
- package/dist/src/operations/journal-rpc-client.js +225 -0
- package/dist/src/operations/journal-rpc-protocol.d.ts +32 -0
- package/dist/src/operations/journal-rpc-protocol.js +214 -0
- package/dist/src/operations/journal-rpc-server.d.ts +15 -0
- package/dist/src/operations/journal-rpc-server.js +272 -0
- package/dist/src/operations/journal.d.ts +143 -0
- package/dist/src/operations/journal.js +1957 -0
- package/dist/src/operations/production-attachments.d.ts +118 -0
- package/dist/src/operations/production-attachments.js +1035 -0
- package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
- package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
- package/dist/src/operations/production-chatgpt-attachments.d.ts +80 -0
- package/dist/src/operations/production-chatgpt-attachments.js +1639 -0
- package/dist/src/operations/production-configuration.d.ts +42 -0
- package/dist/src/operations/production-configuration.js +1544 -0
- package/dist/src/operations/production-primitives.d.ts +53 -0
- package/dist/src/operations/production-primitives.js +856 -0
- package/dist/src/operations/production-work-steer.d.ts +203 -0
- package/dist/src/operations/production-work-steer.js +1218 -0
- package/dist/src/operations/recovery.d.ts +80 -0
- package/dist/src/operations/recovery.js +174 -0
- package/dist/src/operations/runtime-adapter.d.ts +126 -0
- package/dist/src/operations/runtime-adapter.js +802 -0
- package/dist/src/operations/send-once.d.ts +224 -0
- package/dist/src/operations/send-once.js +1081 -0
- package/dist/src/operations/service.d.ts +286 -0
- package/dist/src/operations/service.js +2831 -0
- package/dist/src/operations/staging.d.ts +136 -0
- package/dist/src/operations/staging.js +630 -0
- package/dist/src/operations/state-machine.d.ts +29 -0
- package/dist/src/operations/state-machine.js +2047 -0
- package/dist/src/operations/submission.d.ts +423 -0
- package/dist/src/operations/submission.js +1676 -0
- package/dist/src/operations/transactional-chat-power.d.ts +17 -0
- package/dist/src/operations/transactional-chat-power.js +212 -0
- package/dist/src/operations/turn-ownership.d.ts +202 -0
- package/dist/src/operations/turn-ownership.js +700 -0
- package/dist/src/operations/types.d.ts +454 -0
- package/dist/src/operations/types.js +20 -0
- package/dist/src/operations/wire-requests.d.ts +21 -0
- package/dist/src/operations/wire-requests.js +396 -0
- package/dist/src/operations/wire-results.d.ts +97 -0
- package/dist/src/operations/wire-results.js +818 -0
- package/dist/src/runner/responses.d.ts +3 -1
- package/dist/src/runner/responses.js +19 -1
- package/dist/src/runner/result.js +227 -55
- package/dist/src/runner/types.d.ts +12 -0
- package/dist/src/runtime/command-routing.d.ts +149 -0
- package/dist/src/runtime/command-routing.js +431 -0
- package/dist/src/runtime/coordinated-browser.d.ts +24 -0
- package/dist/src/runtime/coordinated-browser.js +315 -0
- package/dist/src/runtime/coordinated-page.d.ts +41 -0
- package/dist/src/runtime/coordinated-page.js +651 -0
- package/dist/src/runtime/operation-context.d.ts +142 -0
- package/dist/src/runtime/operation-context.js +410 -0
- package/dist/src/runtime/runtime-session.d.ts +95 -0
- package/dist/src/runtime/runtime-session.js +314 -0
- package/dist/src/runtime/tab-coordinator.d.ts +200 -0
- package/dist/src/runtime/tab-coordinator.js +1200 -0
- package/dist/src/runtime/value-boundaries.d.ts +18 -0
- package/dist/src/runtime/value-boundaries.js +49 -0
- package/dist/src/safety/blockers.js +8 -1
- package/dist/src/safety/untrusted-output.js +2 -1
- package/dist/src/scripts/backend-server.js +4 -1
- package/dist/src/scripts/capture-surface-profile.js +7 -2
- package/dist/src/scripts/journal-server.d.ts +2 -0
- package/dist/src/scripts/journal-server.js +37 -0
- package/dist/src/scripts/live-smoke/harness.js +79 -7
- package/dist/src/scripts/live-smoke/scenarios.d.ts +42 -1
- package/dist/src/scripts/live-smoke/scenarios.js +147 -30
- package/dist/src/scripts/live-smoke/transactional.d.ts +17 -0
- package/dist/src/scripts/live-smoke/transactional.js +254 -0
- package/dist/src/scripts/live-smoke/types.d.ts +3 -0
- package/dist/src/scripts/release-canary-module.js +17 -4
- package/dist/src/types.d.ts +38 -1
- package/package.json +8 -3
- package/references/2026-08-16-transactional-operations.md +459 -0
- package/references/2026-09-06-journal-service.md +140 -0
- package/references/agents-runner.md +34 -0
- package/references/backend-protocol.md +176 -0
- package/references/python-parity.md +137 -0
- package/references/responses-adapter.md +19 -0
- package/references/streaming.md +6 -0
|
@@ -108,6 +108,43 @@ The final event contains a normal runner result:
|
|
|
108
108
|
|
|
109
109
|
Streaming is milestone streaming only. It does not promise token deltas or OpenAI API stream-event parity. Partial assistant text is emitted as `message_in_progress`; only completion-confirmed output is emitted as `message_completed`.
|
|
110
110
|
|
|
111
|
+
Persistent clients perform one single-flight `backend.hello` negotiation before
|
|
112
|
+
admitting multiplexed work. When the backend advertises request-ID-scoped unary
|
|
113
|
+
and stream multiplexing, one lifecycle-owned reader routes every response and
|
|
114
|
+
event to its exact `requestId`; compatible older backends remain single-flight.
|
|
115
|
+
Cancellation and timeout retain a bounded late-output tombstone. A record for a
|
|
116
|
+
known tombstone is drained, while an unknown request ID quarantines and recycles
|
|
117
|
+
the connection rather than being guessed into an active route.
|
|
118
|
+
|
|
119
|
+
The transport retains a bounded, redacted `backend_compatibility.v1` snapshot for
|
|
120
|
+
the current backend generation. Protocol or capability incompatibility rejects
|
|
121
|
+
the hello before any browser command is admitted. Compatible package, runtime,
|
|
122
|
+
and build differences are warnings rather than an exact package-version gate;
|
|
123
|
+
the report includes a `build_digest_mismatch` warning even when package versions
|
|
124
|
+
match. Missing provenance is reported as `unknown`, never inferred, and the
|
|
125
|
+
snapshot contains no command list, prompts, paths, secrets, or provider output.
|
|
126
|
+
|
|
127
|
+
Backpressure is bounded by both event count and encoded UTF-8 bytes. Overflow
|
|
128
|
+
fails only the affected stream route and leaves unrelated correlated routes
|
|
129
|
+
usable. The Node and Python clients bound aggregate queued stdin frames by
|
|
130
|
+
count and bytes, and both clients bound aggregate caller/control route
|
|
131
|
+
admissions with `maxInFlight`/`max_in_flight` (default `256`, minimum `2`) across
|
|
132
|
+
handshake probes, waiting legacy slots, pending unary routes, async
|
|
133
|
+
pre-reservations, and streams. During negotiation gaps where the handshake is
|
|
134
|
+
unknown/in progress and no control route is currently charged, caller
|
|
135
|
+
reservations use at most `maxInFlight - 1` slots so the transport can always
|
|
136
|
+
admit the next hello/legacy control probe. Once a control route is charged, it
|
|
137
|
+
counts as one ordinary live route and callers can use the full configured
|
|
138
|
+
bound; the virtual headroom returns between sequential legacy probes. Saturation
|
|
139
|
+
is rejected before request-ID
|
|
140
|
+
reservation and every terminal, cancellation, timeout, queued-never-started
|
|
141
|
+
release, and recycle path releases its live slot. The client rechecks route
|
|
142
|
+
ownership immediately before writing, so a request canceled while queued is never written later. If a started stdin write
|
|
143
|
+
does not settle, the child is recycled; at most one unresolved generation may
|
|
144
|
+
be detached, and a second unresolved generation fails closed until teardown
|
|
145
|
+
settles. These are transport liveness guards, not proof that a browser mutation
|
|
146
|
+
did or did not occur.
|
|
147
|
+
|
|
111
148
|
## Required Backend Commands
|
|
112
149
|
|
|
113
150
|
The backend must support:
|
|
@@ -129,6 +166,68 @@ timeout Work result is recovered through status/wait/read on the same task, not
|
|
|
129
166
|
by resubmitting the original prompt.
|
|
130
167
|
|
|
131
168
|
`doctor` returns a normal `CommandResult` whose `data.checks` map is extensible. Scenario checks such as `existing_tab`, `artifacts`, `file_preflight`, `localization`, and `reports` may add optional `code`, `blockerKind`, `nextCommand`, and JSON `details` fields to individual check entries while preserving the existing `status`, `message`, and `remediation` fields.
|
|
169
|
+
The additive `compatibility` check is browser-free and exposes the retained
|
|
170
|
+
report in `details`; warning and unknown provenance map to an `unknown` check,
|
|
171
|
+
while a rejected negotiation maps to `blocked` and makes the report not ready.
|
|
172
|
+
|
|
173
|
+
## Transactional operations (v1)
|
|
174
|
+
|
|
175
|
+
The additive operation surface uses four strict backend commands:
|
|
176
|
+
`operations.submit`, `operations.collect`, `operations.inspect`, and
|
|
177
|
+
`operations.control`. Their request and result schemas, caller-owned
|
|
178
|
+
`operationId` rules, fresh-handle recovery, and privacy boundary are defined in
|
|
179
|
+
[the transactional operations reference](2026-08-16-transactional-operations.md).
|
|
180
|
+
|
|
181
|
+
These commands are not aliases for `messages.submit`, `messages.wait`, or the
|
|
182
|
+
legacy workflow runner. `operations.submit` creates/reconciles one journal
|
|
183
|
+
record and returns an accepted/completed/blocked/uncertain envelope;
|
|
184
|
+
`operations.collect` observes only that operation's owned turn;
|
|
185
|
+
`operations.inspect` is browser-free durable inspection; and `operations.control`
|
|
186
|
+
binds one Stop or Work steer to a generating parent handle. `operations.run`
|
|
187
|
+
is an SDK composition, not a fifth wire command.
|
|
188
|
+
|
|
189
|
+
`operations.inspect` is browser-free and may include the same additive
|
|
190
|
+
`compatibility` report projected from the lifecycle-owned transport. It does not
|
|
191
|
+
reopen a tab or perform a browser read.
|
|
192
|
+
|
|
193
|
+
Transactional wire validation rejects unsupported fields before browser use.
|
|
194
|
+
The backend redacts adapter/journal failures at the protocol boundary so raw
|
|
195
|
+
prompts, local paths, URLs, and provider-private diagnostics do not cross the
|
|
196
|
+
NDJSON response. With no custom adapter seam, the default client constructs a
|
|
197
|
+
lazy request-local ChatGPT adapter after journal admission and fails closed if
|
|
198
|
+
the bridge, authenticated target evidence, or required provider primitive is
|
|
199
|
+
unavailable. A custom adapter configuration must supply the complete adapter
|
|
200
|
+
factory set; neither path falls back to a legacy sequence.
|
|
201
|
+
|
|
202
|
+
The default local journal requires real process identity, platform-appropriate
|
|
203
|
+
file ownership, and process-liveness authority. It validates those host
|
|
204
|
+
capabilities before creating journal directories or touching the browser. When
|
|
205
|
+
they are unavailable and no explicit journal service is configured, an
|
|
206
|
+
operation-aware high-level `ask` returns the normal command
|
|
207
|
+
result shape with `status: "blocked"`, `blocker.kind: "unknown"`,
|
|
208
|
+
`blocker.code: "journal_runtime_unavailable"`, `blocker.resumable: false`, and
|
|
209
|
+
`error.recoverable: false`. The bounded remediation uses the established
|
|
210
|
+
`label`, `instruction`, and `userActionRequired` fields. This is an unavailable
|
|
211
|
+
runtime result, not evidence of composer drift or a successful submission.
|
|
212
|
+
The shared `journal-runtime-unavailable.json` fixture is generated through the
|
|
213
|
+
public facade and preserves that result across Python decoding.
|
|
214
|
+
|
|
215
|
+
As verified on 2026-09-06, the restricted Codex JavaScript host used for issue
|
|
216
|
+
41 exposes its browser bridge but does not expose the required process APIs.
|
|
217
|
+
It can run compatibility workflows, but its default local journal is
|
|
218
|
+
unavailable. An explicitly started normal Node journal service supplies durable
|
|
219
|
+
storage and signing through the authenticated private-file connection while
|
|
220
|
+
browser actions remain in the active bridge host. Configure
|
|
221
|
+
`operations.journalService.descriptorPath` as described in the
|
|
222
|
+
[journal service runbook](2026-09-06-journal-service.md). A plain Node subprocess
|
|
223
|
+
still cannot inherit the browser bridge. Do not substitute PID or owner values,
|
|
224
|
+
install a fake `process`, disable ownership checks, or infer that an unknown
|
|
225
|
+
lock owner is dead. An automatic retry or a new operation ID cannot repair a
|
|
226
|
+
missing host capability.
|
|
227
|
+
|
|
228
|
+
`operations.collect` optionally accepts `pollIntervalMs`, an integer from `0`
|
|
229
|
+
through `60000`. It controls only the interval between bounded observation
|
|
230
|
+
attempts. Poll sleeps occur outside browser/tab transactions.
|
|
132
231
|
|
|
133
232
|
## Host-Local Attachment Paths
|
|
134
233
|
|
|
@@ -185,6 +284,29 @@ reported as structured blockers such as
|
|
|
185
284
|
`artifact_unavailable`, `artifact_selector_drift`, or
|
|
186
285
|
`artifact_download_unavailable`, not protocol errors.
|
|
187
286
|
|
|
287
|
+
After a visible download activation, the runtime requires the browser bridge's
|
|
288
|
+
native completion receipt within the operation deadline. An unverified
|
|
289
|
+
completion returns `download_receipt_timeout` with kind `download_unavailable`,
|
|
290
|
+
status `blocked`, and nonresumable/nonrecoverable flags. It does not retry the
|
|
291
|
+
activation or switch download strategies, and preserves existing browser
|
|
292
|
+
downloads. A bridge that cannot expose a native receipt remains unsupported
|
|
293
|
+
for verified download completion.
|
|
294
|
+
|
|
295
|
+
A structurally identified Chrome error page with the exact
|
|
296
|
+
`ERR_BLOCKED_BY_CLIENT` code returns `download_blocked_by_browser` with the same
|
|
297
|
+
`download_unavailable` kind, blocked status, and nonresumable/nonrecoverable
|
|
298
|
+
flags. Text mentioning that code in a normal conversation is not browser-error
|
|
299
|
+
evidence. The runtime does not retry the activation or bypass browser
|
|
300
|
+
restrictions; the caller receives no successful download receipt and completion
|
|
301
|
+
remains unverified. This browser-error observation is distinct from a native
|
|
302
|
+
receipt timeout.
|
|
303
|
+
|
|
304
|
+
Other native event or activation failures return `download_receipt_failed`
|
|
305
|
+
with the same blocked and nonretryable semantics. A fixed message replaces
|
|
306
|
+
native error details, which may include sensitive download URLs. The runtime
|
|
307
|
+
supplies no successful receipt and does not switch to another strategy after
|
|
308
|
+
an uncertain activation.
|
|
309
|
+
|
|
188
310
|
`session.bootstrap` accepts `existingTab` for explicit reuse of a user-open Chrome tab before any read or prompt step. The wire shape is shared by TypeScript and Python:
|
|
189
311
|
|
|
190
312
|
```json
|
|
@@ -261,6 +383,56 @@ python scripts/live_smoke.py --mode ordinary-shell
|
|
|
261
383
|
|
|
262
384
|
In an ordinary shell without Codex browser bridge access, browser-required commands must return a structured `browser_bridge_unavailable` blocker. This is a successful smoke result when the backend process stays alive and protocol calls such as `backend.health` and `commands` succeed.
|
|
263
385
|
|
|
386
|
+
## Transactional Live Qualification
|
|
387
|
+
|
|
388
|
+
Compatibility live smokes and release canaries do not qualify submit-once
|
|
389
|
+
behavior. The additive Node live scenario `transactional-submit-once` is
|
|
390
|
+
explicitly enabled with `CHATGPT_E2E_TRANSACTIONAL=1`; select that scenario
|
|
391
|
+
alone when using `CHATGPT_E2E_SCENARIOS` or the live-smoke module's scenario
|
|
392
|
+
filter. In a supported host with an already initialized browser bridge:
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
const selected = smoke.filterScenarios(smoke.optionalScenarios, "transactional-submit-once");
|
|
396
|
+
const run = await smoke.runLiveSmoke({
|
|
397
|
+
agent,
|
|
398
|
+
browser,
|
|
399
|
+
reportDir: "/absolute/path/to/local/reports/live-smoke",
|
|
400
|
+
env: {
|
|
401
|
+
CHATGPT_E2E_TRANSACTIONAL: "1",
|
|
402
|
+
// Optional when the browser host requires the separate journal service.
|
|
403
|
+
CHATGPT_E2E_JOURNAL_DESCRIPTOR: "/absolute/private/session/connection.json"
|
|
404
|
+
}
|
|
405
|
+
}, selected);
|
|
406
|
+
const qualified = run.results.length === 1 && run.results[0].status === "pass";
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Here `smoke` is the imported `codex-chatgpt-control-live-smoke.bundle.mjs`.
|
|
410
|
+
The scenario creates one synthetic Chat conversation using the public `ask`
|
|
411
|
+
facade and the default production runtime, with a fresh UUID, zero files, and a
|
|
412
|
+
multiline prompt. It performs submit-only, bounded collect, owned-receipt
|
|
413
|
+
verification, and a same-ID replay only after a completed receipt. It verifies
|
|
414
|
+
one satisfied Send action, the same operation/request/target handle, and exactly
|
|
415
|
+
one user/assistant exchange in the same established conversation before and
|
|
416
|
+
after replay. For `ambiguous_submit` only, it may make one observation-only
|
|
417
|
+
same-ID recovery after inspection proves the matching target and a durable
|
|
418
|
+
`observe_only_after_intent` Send action at the `send_may_have_occurred` boundary.
|
|
419
|
+
It then verifies the same action and intent survived recovery. Other blockers
|
|
420
|
+
stop qualification; there is no blind resubmission or replacement operation ID.
|
|
421
|
+
Reports contain only structural evidence, response length/hash, and fixed
|
|
422
|
+
status codes.
|
|
423
|
+
|
|
424
|
+
This scenario is optional, so inspect its own `status`; an empty
|
|
425
|
+
`requiredFailures` list does not establish a pass. A missing host capability,
|
|
426
|
+
pending collect, absent receipt, or changed turn count fails qualification.
|
|
427
|
+
Without the explicit service, the restricted Codex host described above fails
|
|
428
|
+
with `journal_runtime_unavailable`. Configuring the service makes that host
|
|
429
|
+
eligible for this qualification; the scenario must still pass submit, collect,
|
|
430
|
+
receipt and replay checks. A successful journal connection alone does not
|
|
431
|
+
qualify browser behavior. Python fixture and facade checks validate result
|
|
432
|
+
preservation; Python operation-aware relay qualification remains a separate
|
|
433
|
+
gate requiring a live bridge-hosted Node backend and a permitted transport to
|
|
434
|
+
that backend.
|
|
435
|
+
|
|
264
436
|
## Browser-Bridge Smoke
|
|
265
437
|
|
|
266
438
|
Run only when intentionally operating a backend with live browser access:
|
|
@@ -355,3 +527,7 @@ npm run test:backend-conformance
|
|
|
355
527
|
```
|
|
356
528
|
|
|
357
529
|
Python must also load and round-trip the same fixtures through Pydantic models. Any future backend implementation should pass these fixtures before claiming compatibility.
|
|
530
|
+
|
|
531
|
+
## Restricted-host journal authority
|
|
532
|
+
|
|
533
|
+
The Node backend can use an explicit asynchronous journal service while keeping browser control in its active host. See [the journal service runbook](2026-09-06-journal-service.md) for startup, recovery, transport boundaries, and the intentional TypeScript host API asymmetry. Operation wire shapes and Python facades are unchanged. The private-file transport rejects Windows with `journal_rpc_unsupported_platform` before filesystem access; the existing local Node journal path is unchanged.
|
|
@@ -30,6 +30,98 @@ Wire fields stay TypeScript-compatible. Python exposes idiomatic aliases:
|
|
|
30
30
|
| `newTask` | `new_task` |
|
|
31
31
|
| `includeArtifacts` | `include_artifacts` |
|
|
32
32
|
|
|
33
|
+
Negotiated compatibility is also shared contract behavior. The Node and Python
|
|
34
|
+
transports retain a bounded `BackendCompatibilityReport` for the current
|
|
35
|
+
backend generation and expose it through `compatibility_report()` (or the
|
|
36
|
+
TypeScript equivalent). Protocol/capability rejection blocks before browser
|
|
37
|
+
commands; package, runtime, and build differences are precise warnings, not an
|
|
38
|
+
exact package-version requirement. A matching package version with a different
|
|
39
|
+
build digest remains a `build_digest_mismatch` warning. Unknown provenance stays
|
|
40
|
+
unknown. The report is redacted and contains no command list, prompt, path,
|
|
41
|
+
secret, or provider output.
|
|
42
|
+
|
|
43
|
+
## Transactional operations parity
|
|
44
|
+
|
|
45
|
+
The direct v1 operation surface is shared by TypeScript and Python through the
|
|
46
|
+
same strict wire schemas and backend commands:
|
|
47
|
+
|
|
48
|
+
- `operations.submit`
|
|
49
|
+
- `operations.collect`
|
|
50
|
+
- `operations.inspect`
|
|
51
|
+
- `operations.control`
|
|
52
|
+
|
|
53
|
+
Python exposes sync `OperationsClient` and async `AsyncOperationsClient` on the
|
|
54
|
+
`ChatGPT`/`AsyncChatGPT` facades. Their keyword aliases are idiomatic
|
|
55
|
+
snake_case (`operation_id`, `response_content`, `timeout_ms`,
|
|
56
|
+
`control_action_id`), but `to_wire()` always emits the TypeScript-compatible
|
|
57
|
+
camelCase fields. Every envelope validates operation ID, request digest, fresh
|
|
58
|
+
handle, target binding, receipt/blocker identity, and mutation-boundary
|
|
59
|
+
monotonicity before returning to the caller. `run()` is local composition of
|
|
60
|
+
one submit and at most one collect; it is not a fifth backend command.
|
|
61
|
+
`operations.inspect` projects the transport compatibility snapshot into its
|
|
62
|
+
additive `compatibility` field without browser access. `doctor` exposes the same
|
|
63
|
+
report in its browser-free `compatibility` check; a warning or unknown
|
|
64
|
+
provenance is diagnostic and does not block readiness, while rejected
|
|
65
|
+
negotiation is blocked.
|
|
66
|
+
|
|
67
|
+
The immutable submit capture contract is exposed as
|
|
68
|
+
`OperationDurableCapturePolicy` (with the `OperationCapturePolicyState` alias)
|
|
69
|
+
and is serialized as the path-free `capturePolicy` object on created/state
|
|
70
|
+
records. It contains only `responseContent`, `responseFormat` (defaulting to
|
|
71
|
+
`markdown`), and `artifacts`; request-local `outputDirectory` is never accepted
|
|
72
|
+
on a durable model. A recovered `transfer` policy remains a transfer
|
|
73
|
+
obligation until a new request-local destination is explicitly authorized.
|
|
74
|
+
|
|
75
|
+
This direct parity does not make Python a second browser runtime. The current
|
|
76
|
+
backend remains Node-backed and, with no custom seam, creates the same lazy
|
|
77
|
+
request-local ChatGPT adapter as the TypeScript client. Browser-touching calls
|
|
78
|
+
still require a bridge-enabled runtime, authenticated target evidence, and the
|
|
79
|
+
required provider primitives. `inspect` is browser-free; an ordinary
|
|
80
|
+
Python-spawned Node process cannot inherit Codex's in-process bridge, so
|
|
81
|
+
ordinary-shell checks can exercise request/result validation and structured
|
|
82
|
+
blockers without claiming live ChatGPT control. Raw
|
|
83
|
+
`liveResponse` content is explicitly ephemeral and is never accepted into a
|
|
84
|
+
durable receipt or operation state.
|
|
85
|
+
|
|
86
|
+
Operation-aware Python `ask` preserves the Node host blocker
|
|
87
|
+
`journal_runtime_unavailable` as a `CommandResult` with `status == "blocked"`,
|
|
88
|
+
`blocker["kind"] == "unknown"`, `blocker["resumable"] == False`, and
|
|
89
|
+
`error["recoverable"] == False`, including the existing remediation fields.
|
|
90
|
+
Sync and async facades return it after one backend request; they do not replace
|
|
91
|
+
it with transport uncertainty, retry, or open another operation. The shared
|
|
92
|
+
`journal-runtime-unavailable.json` fixture covers exact wire round-tripping.
|
|
93
|
+
No Python model or browser implementation change is needed because the
|
|
94
|
+
TypeScript journal remains authoritative.
|
|
95
|
+
|
|
96
|
+
The default local journal requires real process identity, platform-appropriate
|
|
97
|
+
ownership, and process-liveness APIs before filesystem or browser mutation.
|
|
98
|
+
The restricted Codex JavaScript host observed on 2026-09-06 lacks those APIs
|
|
99
|
+
even though its browser bridge works. Configure the explicit journal service
|
|
100
|
+
on its bridge-hosted Node `BackendSession` to provide storage and signing from
|
|
101
|
+
a normal Node process. The Python facade and operation protocol stay unchanged.
|
|
102
|
+
A Python-to-Node relay alone cannot supply journal authority, and a plain Node
|
|
103
|
+
subprocess cannot inherit the browser bridge. Do not spoof process identity,
|
|
104
|
+
weaken ownership/lock checks, or retry with a new UUID.
|
|
105
|
+
|
|
106
|
+
The TypeScript and Python high-level Runner and Responses adapters now have an
|
|
107
|
+
explicit caller-owned operation-ID opt-in. Python accepts the idiomatic
|
|
108
|
+
`operation_id` keyword (or the `operation_id`/`operationId` member of the
|
|
109
|
+
runner input), validates it and all supported combinations before backend
|
|
110
|
+
traffic, then routes exactly one submit followed by at most one collect through
|
|
111
|
+
the shared operation facade. Legacy calls with no operation ID retain their
|
|
112
|
+
existing `runner.run`/`responses.create` transport path. Returned run/response
|
|
113
|
+
data carries the validated operation ID and fresh handle; pending, blocked, and
|
|
114
|
+
uncertain operation envelopes remain partial/blocked results with their
|
|
115
|
+
contract blocker, while identity mismatches fail closed. The full request,
|
|
116
|
+
recovery, coordinator, privacy, and compatibility boundary is documented in
|
|
117
|
+
[Transactional browser operations](2026-08-16-transactional-operations.md).
|
|
118
|
+
|
|
119
|
+
Direct Python `collect`/`run` expose `poll_interval_ms`; transactional Runner
|
|
120
|
+
wait objects additionally accept `pollMs`, `poll_ms`, `pollIntervalMs`, or
|
|
121
|
+
`poll_interval_ms` when aliases agree. The wire field is `pollIntervalMs`, its
|
|
122
|
+
range is the inclusive integer interval `0..60000`, and sleeping never holds a
|
|
123
|
+
browser/tab coordinator transaction.
|
|
124
|
+
|
|
33
125
|
Incomplete response capture is also shared contract behavior. Python must preserve `status == "partial"`, `output_text`, warnings, and any nested `data.captureLimit` dictionaries exactly as the TypeScript backend returns them. `partial` is not a protocol error: callers should inspect `data.complete` and run another wait/read on the same thread when they need final output.
|
|
34
126
|
|
|
35
127
|
For long-answer polling, Python forwards `response_content="metadata"` to the shared wire field `responseContent: "metadata"` on `messages.wait`. The TypeScript backend then omits assistant text from wait results and returns compact metadata such as `data.responseChars` and `data.responseSha256`; Python must preserve those fields without trying to reconstruct omitted content.
|
|
@@ -43,6 +135,23 @@ the same backend commands through `chatgpt.artifacts.list_latest(...)`,
|
|
|
43
135
|
`chatgpt.artifacts.wait(...)`, and `chatgpt.artifacts.download_latest(...)`.
|
|
44
136
|
Those methods forward to `artifacts.listLatest`, `artifacts.wait`, and
|
|
45
137
|
`artifacts.downloadLatest`; they do not duplicate DOM or selector logic.
|
|
138
|
+
|
|
139
|
+
Python preserves the backend's `download_receipt_timeout` blocker when native
|
|
140
|
+
browser download completion cannot be verified within the deadline. The result
|
|
141
|
+
is blocked, nonresumable and nonrecoverable; the facade does not retry the
|
|
142
|
+
activation or select an alternate download path. Existing browser downloads
|
|
143
|
+
remain in place. Python also preserves `download_blocked_by_browser` when the
|
|
144
|
+
TypeScript runtime identifies Chrome's `ERR_BLOCKED_BY_CLIENT` error page. It
|
|
145
|
+
is a blocked, nonresumable, nonrecoverable command result with no download
|
|
146
|
+
receipt; Python does not retry or duplicate the browser-error detection. The
|
|
147
|
+
shared `download-blocked-by-browser.json` fixture and Python snapshot test lock
|
|
148
|
+
this behavior without adding wire fields or Python-specific browser logic.
|
|
149
|
+
The `download-receipt-failed.json` fixture also preserves the sanitized
|
|
150
|
+
`download_receipt_failed` result from native event or activation failures:
|
|
151
|
+
blocked status, no receipt, and false resumable/recoverable flags. Python keeps
|
|
152
|
+
the fixed backend message and never reconstructs native error details or
|
|
153
|
+
retries an uncertain activation.
|
|
154
|
+
|
|
46
155
|
If the TypeScript runtime recovers a generated image by reopening a stalled
|
|
47
156
|
claimed conversation in a temporary bridge-owned tab and exporting through
|
|
48
157
|
`pageAssets`, Python observes the same command result through the backend
|
|
@@ -183,6 +292,30 @@ Python is a native SDK facade over the local backend protocol. The initial brows
|
|
|
183
292
|
- Ordinary-shell smoke passes when browser-required calls return structured `browser_bridge_unavailable`.
|
|
184
293
|
- Browser-bridge runtime smoke remains explicitly gated because it can operate a real ChatGPT session.
|
|
185
294
|
|
|
295
|
+
## Transactional Qualification Is Separate
|
|
296
|
+
|
|
297
|
+
The opt-in Node scenario `transactional-submit-once` uses the default public
|
|
298
|
+
runtime with `CHATGPT_E2E_TRANSACTIONAL=1`. It verifies a fresh-ID multiline,
|
|
299
|
+
zero-file ask, owned collection, a completed receipt, and same-ID replay with
|
|
300
|
+
one Send and one user/assistant exchange. One `ambiguous_submit` recovery is
|
|
301
|
+
permitted only after proving the existing observation-only Send intent and
|
|
302
|
+
matching target; other blockers stop qualification. See [Transactional Live Qualification](backend-protocol.md#transactional-live-qualification)
|
|
303
|
+
for selection and report checks. A host blocker is a failed qualification,
|
|
304
|
+
even when ordinary-shell blocker handling or compatibility browser smokes
|
|
305
|
+
pass.
|
|
306
|
+
|
|
307
|
+
Python's existing `scripts/live_smoke.py --mode browser-bridge` matrix omits
|
|
308
|
+
operation IDs and therefore covers compatibility workflows. Its success does
|
|
309
|
+
not establish transactional parity. This patch adds shared-fixture and
|
|
310
|
+
sync/async `ask` preservation coverage; full Python operation-aware relay
|
|
311
|
+
qualification remains a separate gate. It requires a bridge-hosted Node backend
|
|
312
|
+
with either a supported local journal or the configured journal service, plus
|
|
313
|
+
a permitted Python-to-backend transport. The existing HTTP test relay is
|
|
314
|
+
unavailable where that browser host forbids local sockets; filesystem journal
|
|
315
|
+
transport does not itself provide a Python backend relay. Keep browser
|
|
316
|
+
interaction and ownership verification in TypeScript rather than adding Python
|
|
317
|
+
DOM selectors.
|
|
318
|
+
|
|
186
319
|
## Browser-Bridge Smoke
|
|
187
320
|
|
|
188
321
|
Run this only when you intentionally want Python to drive a live backend with browser access:
|
|
@@ -246,3 +379,7 @@ Smoke output is a redacted JSON summary. It reports output matches and lengths,
|
|
|
246
379
|
| `0` | All browser-bridge scenarios passed. |
|
|
247
380
|
| `1` | At least one scenario failed unexpectedly. |
|
|
248
381
|
| `2` | Scenarios recorded documented blockers such as `browser_bridge_unavailable`, `login_required`, or `selector_drift`. |
|
|
382
|
+
|
|
383
|
+
## Restricted-host journal authority
|
|
384
|
+
|
|
385
|
+
The Node backend can use an explicit asynchronous journal service while keeping browser control in its active host. See [the journal service runbook](2026-09-06-journal-service.md) for startup, recovery, transport boundaries, and the intentional TypeScript host API asymmetry. Operation wire shapes and Python facades are unchanged. Python preserves `journal_rpc_unsupported_platform` when the Node backend rejects the private-file transport on Windows; it does not bypass the platform guard. Existing local Node journal behavior on Windows is unchanged.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
Accepted fields:
|
|
6
6
|
|
|
7
7
|
- `input`
|
|
8
|
+
- `operationId` (TypeScript transactional opt-in; caller-owned canonical UUID)
|
|
8
9
|
- `thread`
|
|
9
10
|
- `existingTab`
|
|
10
11
|
- `preferExistingTab`
|
|
@@ -22,6 +23,7 @@ Rejected API-only fields return `status: "unsupported"` before any prompt is sub
|
|
|
22
23
|
|
|
23
24
|
```ts
|
|
24
25
|
const response = await chatgpt.responses.create({
|
|
26
|
+
operationId: "123e4567-e89b-42d3-a456-426614174000",
|
|
25
27
|
input: "Summarize the latest plan.",
|
|
26
28
|
thread: { type: "conversationId", conversationId: "abc-123" },
|
|
27
29
|
experience: "chat",
|
|
@@ -31,6 +33,23 @@ const response = await chatgpt.responses.create({
|
|
|
31
33
|
});
|
|
32
34
|
```
|
|
33
35
|
|
|
36
|
+
In the TypeScript adapter, supplying `operationId` selects the additive
|
|
37
|
+
transactional runner path and returns the operation ID and fresh handle in
|
|
38
|
+
`response.browser_control` when the mapper reaches the operation boundary.
|
|
39
|
+
Omitting it retains the legacy Responses/runner path. The transactional path
|
|
40
|
+
still accepts only visible-prefix instructions, rejects API-only fields before
|
|
41
|
+
browser use, and does not provide token-delta streaming. With no custom seam,
|
|
42
|
+
the client creates a lazy request-local ChatGPT adapter; it fails closed when
|
|
43
|
+
the bridge, target evidence, or required provider primitive is unavailable.
|
|
44
|
+
Use
|
|
45
|
+
[Transactional browser operations](2026-08-16-transactional-operations.md) for
|
|
46
|
+
submit/collect/inspect/control recovery and capability rules.
|
|
47
|
+
|
|
48
|
+
The Python `ResponsesClient` accepts the idiomatic `operation_id` alias and
|
|
49
|
+
returns the same operation ID and fresh handle in `browser_control`. It validates
|
|
50
|
+
transactional combinations before transport and never resubmits an accepted
|
|
51
|
+
operation.
|
|
52
|
+
|
|
34
53
|
`experience` and `configuration` represent visible product controls, not API
|
|
35
54
|
model selection. Configuration is strict through the runner plan and must
|
|
36
55
|
verify the visible postcondition. Existing callers may continue to pass
|
package/references/streaming.md
CHANGED
|
@@ -13,3 +13,9 @@ const result = await stream.completed;
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
This is not token streaming. Events are emitted for browser-control milestones such as `message_submitted`, `message_completed`, `file_attached`, and `run_blocked`. Do not expect token deltas or OpenAI API stream event parity.
|
|
16
|
+
|
|
17
|
+
Supplying a caller-owned `operationId` opts the runner into the transactional
|
|
18
|
+
submit/collect mapper, but does not change this stream contract. Polling and
|
|
19
|
+
long waits belong to operation collection outside short page transactions; use
|
|
20
|
+
the returned handle with `operations.inspect`/`operations.collect` for exact
|
|
21
|
+
turn recovery. See [Transactional browser operations](2026-08-16-transactional-operations.md).
|