codex-chatgpt-control 0.2.0-alpha.1 → 0.5.0-alpha.1
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 +15 -0
- package/README.md +42 -2
- package/contracts/v1/fixtures/backend-capabilities.json +11 -0
- package/contracts/v1/fixtures/command-descriptors.json +289 -7
- package/contracts/v1/fixtures/describe-runner-run.json +5 -2
- package/contracts/v1/fixtures/doctor-scenario-preflight.json +45 -2
- package/contracts/v1/fixtures/help-root.json +1 -1
- package/contracts/v1/fixtures/output-json-parse-success.json +9 -0
- package/contracts/v1/fixtures/reports-create-redacted.json +1 -1
- package/contracts/v1/fixtures/run-timeout-partial.json +15 -4
- package/contracts/v1/fixtures/stream-in-progress.ndjson +3 -0
- package/contracts/v1/fixtures/stream-submitted-completed.ndjson +1 -1
- package/contracts/v1/fixtures/surface-chat-legacy.json +35 -0
- package/contracts/v1/fixtures/surface-chat-simplified.json +37 -0
- package/contracts/v1/fixtures/surface-sidebar-false-positive.json +29 -0
- package/contracts/v1/fixtures/surface-work-advanced.json +45 -0
- package/contracts/v1/fixtures/surface-work-basic.json +38 -0
- package/contracts/v1/fixtures/workflow-ask-success.json +8 -0
- package/contracts/v1/manifest.json +32 -1
- package/contracts/v1/parity-suite.json +121 -1
- package/contracts/v1/schemas/backend-request.schema.json +15 -0
- package/contracts/v1/schemas/manifest.schema.json +6 -3
- package/contracts/v1/schemas/surface-profile.schema.json +166 -0
- package/dist/codex-chatgpt-control-backend.mjs +3198 -340
- package/dist/codex-chatgpt-control.bundle.mjs +4454 -1555
- package/dist/src/backend/client.d.ts +26 -1
- package/dist/src/backend/client.js +23 -1
- package/dist/src/backend/protocol.d.ts +1 -1
- package/dist/src/backend/protocol.js +11 -0
- package/dist/src/backend/session.js +22 -0
- package/dist/src/browser/attach.d.ts +1 -0
- package/dist/src/browser/attach.js +3 -3
- package/dist/src/browser/clipboard.d.ts +11 -0
- package/dist/src/browser/clipboard.js +34 -7
- package/dist/src/browser/page-state.js +17 -4
- package/dist/src/client.d.ts +32 -1
- package/dist/src/client.js +72 -16
- package/dist/src/commands/artifacts.js +1 -7
- package/dist/src/commands/configuration.d.ts +15 -0
- package/dist/src/commands/configuration.js +674 -0
- package/dist/src/commands/context.js +3 -1
- package/dist/src/commands/conversation.d.ts +15 -0
- package/dist/src/commands/conversation.js +44 -0
- package/dist/src/commands/deadline.d.ts +8 -0
- package/dist/src/commands/deadline.js +14 -0
- package/dist/src/commands/doctor.js +47 -3
- package/dist/src/commands/experience.d.ts +12 -0
- package/dist/src/commands/experience.js +288 -0
- package/dist/src/commands/files.js +61 -13
- package/dist/src/commands/messages.d.ts +2 -1
- package/dist/src/commands/messages.js +349 -87
- package/dist/src/commands/modes.d.ts +4 -1
- package/dist/src/commands/modes.js +243 -44
- package/dist/src/commands/probes.d.ts +15 -0
- package/dist/src/commands/probes.js +64 -0
- package/dist/src/commands/registry.js +102 -8
- package/dist/src/commands/reports.js +1 -1
- package/dist/src/commands/response-actions.js +1 -7
- package/dist/src/commands/sequence.js +24 -1
- package/dist/src/commands/session.d.ts +2 -0
- package/dist/src/commands/session.js +50 -1
- package/dist/src/commands/threads.js +3 -31
- package/dist/src/commands/work.d.ts +6 -0
- package/dist/src/commands/work.js +338 -0
- package/dist/src/dom/generation-state.d.ts +7 -0
- package/dist/src/dom/generation-state.js +7 -1
- package/dist/src/dom/label-match.d.ts +3 -0
- package/dist/src/dom/label-match.js +25 -0
- package/dist/src/dom/locale/am.d.ts +8 -1
- package/dist/src/dom/locale/am.js +8 -1
- package/dist/src/dom/locale/ar.d.ts +9 -1
- package/dist/src/dom/locale/ar.js +9 -1
- package/dist/src/dom/locale/bg.d.ts +9 -1
- package/dist/src/dom/locale/bg.js +9 -1
- package/dist/src/dom/locale/bn.d.ts +9 -1
- package/dist/src/dom/locale/bn.js +9 -1
- package/dist/src/dom/locale/bs.d.ts +8 -1
- package/dist/src/dom/locale/bs.js +8 -1
- package/dist/src/dom/locale/ca.d.ts +8 -1
- package/dist/src/dom/locale/ca.js +8 -1
- package/dist/src/dom/locale/cs.d.ts +8 -1
- package/dist/src/dom/locale/cs.js +8 -1
- package/dist/src/dom/locale/da.d.ts +7 -1
- package/dist/src/dom/locale/da.js +7 -1
- package/dist/src/dom/locale/de.d.ts +10 -3
- package/dist/src/dom/locale/de.js +10 -3
- package/dist/src/dom/locale/el.d.ts +8 -1
- package/dist/src/dom/locale/el.js +8 -1
- package/dist/src/dom/locale/en.d.ts +40 -1
- package/dist/src/dom/locale/en.js +42 -1
- package/dist/src/dom/locale/es-419.d.ts +8 -1
- package/dist/src/dom/locale/es-419.js +8 -1
- package/dist/src/dom/locale/es-ES.d.ts +8 -1
- package/dist/src/dom/locale/es-ES.js +8 -1
- package/dist/src/dom/locale/et.d.ts +8 -1
- package/dist/src/dom/locale/et.js +8 -1
- package/dist/src/dom/locale/fa.d.ts +9 -1
- package/dist/src/dom/locale/fa.js +9 -1
- package/dist/src/dom/locale/fi.d.ts +8 -1
- package/dist/src/dom/locale/fi.js +8 -1
- package/dist/src/dom/locale/fr-CA.d.ts +8 -1
- package/dist/src/dom/locale/fr-CA.js +8 -1
- package/dist/src/dom/locale/fr-FR.d.ts +8 -3
- package/dist/src/dom/locale/fr-FR.js +8 -3
- package/dist/src/dom/locale/gu.d.ts +8 -1
- package/dist/src/dom/locale/gu.js +8 -1
- package/dist/src/dom/locale/hi.d.ts +8 -1
- package/dist/src/dom/locale/hi.js +8 -1
- package/dist/src/dom/locale/hr.d.ts +7 -1
- package/dist/src/dom/locale/hr.js +7 -1
- package/dist/src/dom/locale/hu.d.ts +8 -1
- package/dist/src/dom/locale/hu.js +8 -1
- package/dist/src/dom/locale/hy.d.ts +9 -1
- package/dist/src/dom/locale/hy.js +9 -1
- package/dist/src/dom/locale/id.d.ts +8 -1
- package/dist/src/dom/locale/id.js +8 -1
- package/dist/src/dom/locale/index.d.ts +20 -1
- package/dist/src/dom/locale/index.js +102 -0
- package/dist/src/dom/locale/is.d.ts +8 -1
- package/dist/src/dom/locale/is.js +8 -1
- package/dist/src/dom/locale/it.d.ts +8 -1
- package/dist/src/dom/locale/it.js +8 -1
- package/dist/src/dom/locale/ja.d.ts +8 -1
- package/dist/src/dom/locale/ja.js +8 -1
- package/dist/src/dom/locale/ka.d.ts +8 -1
- package/dist/src/dom/locale/ka.js +8 -1
- package/dist/src/dom/locale/kk.d.ts +8 -1
- package/dist/src/dom/locale/kk.js +8 -1
- package/dist/src/dom/locale/kn.d.ts +9 -1
- package/dist/src/dom/locale/kn.js +9 -1
- package/dist/src/dom/locale/ko.d.ts +8 -1
- package/dist/src/dom/locale/ko.js +8 -1
- package/dist/src/dom/locale/lt.d.ts +9 -1
- package/dist/src/dom/locale/lt.js +9 -1
- package/dist/src/dom/locale/lv.d.ts +8 -1
- package/dist/src/dom/locale/lv.js +8 -1
- package/dist/src/dom/locale/mk.d.ts +7 -1
- package/dist/src/dom/locale/mk.js +7 -1
- package/dist/src/dom/locale/ml.d.ts +9 -1
- package/dist/src/dom/locale/ml.js +9 -1
- package/dist/src/dom/locale/mn.d.ts +9 -1
- package/dist/src/dom/locale/mn.js +9 -1
- package/dist/src/dom/locale/mr.d.ts +9 -1
- package/dist/src/dom/locale/mr.js +9 -1
- package/dist/src/dom/locale/ms.d.ts +8 -1
- package/dist/src/dom/locale/ms.js +8 -1
- package/dist/src/dom/locale/my.d.ts +8 -1
- package/dist/src/dom/locale/my.js +8 -1
- package/dist/src/dom/locale/nb.d.ts +8 -1
- package/dist/src/dom/locale/nb.js +8 -1
- package/dist/src/dom/locale/nl.d.ts +8 -1
- package/dist/src/dom/locale/nl.js +8 -1
- package/dist/src/dom/locale/pa.d.ts +9 -1
- package/dist/src/dom/locale/pa.js +9 -1
- package/dist/src/dom/locale/pl.d.ts +8 -1
- package/dist/src/dom/locale/pl.js +8 -1
- package/dist/src/dom/locale/pt-BR.d.ts +8 -1
- package/dist/src/dom/locale/pt-BR.js +8 -1
- package/dist/src/dom/locale/pt-PT.d.ts +8 -1
- package/dist/src/dom/locale/pt-PT.js +8 -1
- package/dist/src/dom/locale/ro.d.ts +7 -1
- package/dist/src/dom/locale/ro.js +7 -1
- package/dist/src/dom/locale/ru.d.ts +5 -1
- package/dist/src/dom/locale/ru.js +5 -1
- package/dist/src/dom/locale/sk.d.ts +8 -1
- package/dist/src/dom/locale/sk.js +8 -1
- package/dist/src/dom/locale/sl.d.ts +8 -1
- package/dist/src/dom/locale/sl.js +8 -1
- package/dist/src/dom/locale/so.d.ts +8 -1
- package/dist/src/dom/locale/so.js +8 -1
- package/dist/src/dom/locale/sq.d.ts +8 -1
- package/dist/src/dom/locale/sq.js +8 -1
- package/dist/src/dom/locale/sr.d.ts +5 -1
- package/dist/src/dom/locale/sr.js +5 -1
- package/dist/src/dom/locale/sv.d.ts +8 -1
- package/dist/src/dom/locale/sv.js +8 -1
- package/dist/src/dom/locale/sw.d.ts +8 -1
- package/dist/src/dom/locale/sw.js +8 -1
- package/dist/src/dom/locale/ta.d.ts +9 -1
- package/dist/src/dom/locale/ta.js +9 -1
- package/dist/src/dom/locale/te.d.ts +9 -1
- package/dist/src/dom/locale/te.js +9 -1
- package/dist/src/dom/locale/th.d.ts +8 -1
- package/dist/src/dom/locale/th.js +8 -1
- package/dist/src/dom/locale/tl.d.ts +4 -5
- package/dist/src/dom/locale/tl.js +4 -5
- package/dist/src/dom/locale/tr.d.ts +8 -1
- package/dist/src/dom/locale/tr.js +8 -1
- package/dist/src/dom/locale/types.d.ts +25 -1
- package/dist/src/dom/locale/uk.d.ts +8 -1
- package/dist/src/dom/locale/uk.js +8 -1
- package/dist/src/dom/locale/ur.d.ts +8 -1
- package/dist/src/dom/locale/ur.js +8 -1
- package/dist/src/dom/locale/vi.d.ts +8 -1
- package/dist/src/dom/locale/vi.js +8 -1
- package/dist/src/dom/locale/zh-HK.d.ts +9 -1
- package/dist/src/dom/locale/zh-HK.js +10 -2
- package/dist/src/dom/locale/zh-Hans.d.ts +9 -1
- package/dist/src/dom/locale/zh-Hans.js +9 -1
- package/dist/src/dom/locale/zh-TW.d.ts +9 -1
- package/dist/src/dom/locale/zh-TW.js +9 -1
- package/dist/src/dom/menus.js +13 -2
- package/dist/src/dom/selectors.js +6 -1
- package/dist/src/dom/wait-snapshot.d.ts +43 -0
- package/dist/src/dom/wait-snapshot.js +127 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/runner/responses.d.ts +3 -1
- package/dist/src/runner/responses.js +16 -1
- package/dist/src/runner/result.js +129 -4
- package/dist/src/runner/stream.d.ts +1 -1
- package/dist/src/runner/stream.js +6 -0
- package/dist/src/runner/types.d.ts +35 -1
- package/dist/src/safety/risk.d.ts +11 -0
- package/dist/src/safety/risk.js +11 -0
- package/dist/src/scripts/apply-intelligence-locale-captures.d.ts +6 -0
- package/dist/src/scripts/apply-intelligence-locale-captures.js +147 -15
- package/dist/src/scripts/capture-intelligence-locales.d.ts +3 -0
- package/dist/src/scripts/capture-intelligence-locales.js +372 -3
- package/dist/src/scripts/capture-surface-profile.d.ts +23 -0
- package/dist/src/scripts/capture-surface-profile.js +304 -0
- package/dist/src/scripts/live-smoke/scenarios.js +34 -1
- package/dist/src/scripts/live-smoke.js +1 -0
- package/dist/src/types.d.ts +273 -2
- package/package.json +4 -3
- package/references/2026-07-16-chat-work-surfaces.md +87 -0
- package/references/agents-runner.md +13 -2
- package/references/backend-protocol.md +19 -7
- package/references/language-coverage.md +40 -3
- package/references/localization.md +48 -10
- package/references/python-parity.md +16 -4
- package/references/responses-adapter.md +12 -1
- package/references/troubleshooting.md +49 -6
|
@@ -52,9 +52,9 @@ workflow selector.
|
|
|
52
52
|
|
|
53
53
|
Two rules that never change regardless of language:
|
|
54
54
|
|
|
55
|
-
- **API keys stay English.** Callers pass `
|
|
56
|
-
`
|
|
57
|
-
`tool: "web_search"`. Only the *matched DOM text* is localized. You add the
|
|
55
|
+
- **API keys stay English.** Callers pass `experience: "work"`,
|
|
56
|
+
`model: "GPT-5.6 Sol"`, `intelligence: "Pro"`, `effort: "High"`,
|
|
57
|
+
`speed: "Standard"`, or `tool: "web_search"`. Only the *matched DOM text* is localized. You add the
|
|
58
58
|
German label to the registry array; the caller-facing key is untouched.
|
|
59
59
|
- **Structural anchors are language-agnostic and are not in this file.** Element ids
|
|
60
60
|
(`#composer-plus-btn`, `#upload-files`), `data-message-author-role`,
|
|
@@ -68,6 +68,11 @@ Localized — lives in `src/dom/locale/en.ts` (English) and per-locale files, sa
|
|
|
68
68
|
| Registry key | Surface | Capture from |
|
|
69
69
|
|---|---|---|
|
|
70
70
|
| `composerTextbox` | composer textbox | `aria-label` |
|
|
71
|
+
| `workComposerTextbox` | Work composer textbox | `aria-label` / placeholder |
|
|
72
|
+
| `newWork` | start-another-Work-task control | visible button or link text |
|
|
73
|
+
| `experienceOptions.chat` / `.work` | Chat/Work switch controls | visible button, tab, link, or menu text |
|
|
74
|
+
| `configurationAxes.*` | model/intelligence/effort/speed/advanced rows | visible row text |
|
|
75
|
+
| `configurationOptions.*` | Chat and Work configuration values | visible menu text |
|
|
71
76
|
| `sendButton` | send button | `aria-label` |
|
|
72
77
|
| `searchChatsButton` | search-chats button | `aria-label` |
|
|
73
78
|
| `searchChatsPlaceholder` | search input | `placeholder` (mind the ellipsis — see caveats) |
|
|
@@ -77,7 +82,8 @@ Localized — lives in `src/dom/locale/en.ts` (English) and per-locale files, sa
|
|
|
77
82
|
| `projectSourcesTab` / `projectSourcesAddSource` / `projectSourcesUploadFiles` | Project Sources tab and append-add flow | visible tab/button/menu text |
|
|
78
83
|
| `copyResponse` | copy-response button | `aria-label` |
|
|
79
84
|
| `download` / `downloadImage` / `imageContainerHint` | download affordances | `aria-label` / container hint |
|
|
80
|
-
| `modeLabels` / `modeOpenerExtra` | model/effort switcher | visible button + menu text |
|
|
85
|
+
| `modeLabels` / `modeOpenerExtra` | model/effort switcher recognition and openers | visible button + menu text |
|
|
86
|
+
| `modeOptions.<semantic-id>` | selectable model/intelligence mode options | visible picker rows, keyed by stable ids such as `high`, `extraHigh`, and `pro` |
|
|
81
87
|
| `tools.web_search` / `tools.deep_research` / `tools.create_image` | tool menu items | visible menu text |
|
|
82
88
|
| `signedInMarkers` | signed-in detection | sidebar/shell words |
|
|
83
89
|
| `transientAssistant` | streaming placeholder filter | assistant streaming text ("Thinking", etc.) |
|
|
@@ -100,6 +106,27 @@ Localized — lives in `src/dom/locale/en.ts` (English) and per-locale files, sa
|
|
|
100
106
|
The type definitions for `LocaleStrings` (complete) and `LocaleContribution` (partial, for
|
|
101
107
|
non-English files) live in [`src/dom/locale/types.ts`](../src/dom/locale/types.ts).
|
|
102
108
|
|
|
109
|
+
The first Chat/Work profile fixtures are English evidence. The nested locale
|
|
110
|
+
combiner lets existing locale files omit the new groups without breaking
|
|
111
|
+
compilation, but that is not proof that Work configuration is localized in
|
|
112
|
+
those languages. Add observed labels and a sanitized surface-profile fixture
|
|
113
|
+
before claiming support for a new locale/profile combination.
|
|
114
|
+
|
|
115
|
+
Create a read-only draft from an already-open authorized ChatGPT tab:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run capture:surface-profile -- \
|
|
119
|
+
--id work-basic-de \
|
|
120
|
+
--locale de-DE
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The command defaults region, plan, account, and workspace metadata to
|
|
124
|
+
`not-recorded`, defaults support state to `unverified`, strips conversation
|
|
125
|
+
identifiers, and excludes prompt/response/sidebar text. Review the draft under
|
|
126
|
+
`outputs/surface-profiles/`, add only verified localized labels to the registry,
|
|
127
|
+
then move a sanitized fixture into `contracts/v1/fixtures/` and update the
|
|
128
|
+
manifest/parity matrix.
|
|
129
|
+
|
|
103
130
|
## Adding a new language
|
|
104
131
|
|
|
105
132
|
### Step 1 — put a real ChatGPT session into the target language
|
|
@@ -141,7 +168,13 @@ import type { LocaleContribution } from "./types.js";
|
|
|
141
168
|
|
|
142
169
|
export const de = {
|
|
143
170
|
sendButton: ["Nachricht senden"],
|
|
144
|
-
modeLabels: ["
|
|
171
|
+
modeLabels: ["Sofort", "Mittel", "Hoch", "Extra hoch"],
|
|
172
|
+
modeOptions: {
|
|
173
|
+
instant: ["Sofort"],
|
|
174
|
+
medium: ["Mittel"],
|
|
175
|
+
high: ["Hoch"],
|
|
176
|
+
extraHigh: ["Extra hoch"],
|
|
177
|
+
},
|
|
145
178
|
tools: {
|
|
146
179
|
web_search: ["Websuche"],
|
|
147
180
|
},
|
|
@@ -150,11 +183,14 @@ export const de = {
|
|
|
150
183
|
```
|
|
151
184
|
|
|
152
185
|
Leave the canonical English first (it comes from `en.ts`), and leave the API keys
|
|
153
|
-
(`web_search`,
|
|
186
|
+
(`web_search`, `modeOptions.pro`, `modeOptions.high`, and the other semantic ids)
|
|
187
|
+
unchanged.
|
|
154
188
|
|
|
155
189
|
Newer ChatGPT rollouts may expose `Medium`, `High`, `Extra High`, and `Pro`
|
|
156
190
|
under an `Intelligence` picker. Add localized equivalents only after observing
|
|
157
|
-
those exact labels in the target locale.
|
|
191
|
+
those exact labels in the target locale. Put broad picker/opening labels in
|
|
192
|
+
`modeLabels`, but put selectable labels under `modeOptions.<semantic-id>` so
|
|
193
|
+
short labels such as `Pro` cannot match unrelated rows like `Move to project`.
|
|
158
194
|
|
|
159
195
|
Then open [`src/dom/locale/index.ts`](../src/dom/locale/index.ts) and register the new
|
|
160
196
|
locale:
|
|
@@ -239,9 +275,11 @@ Notes:
|
|
|
239
275
|
- All consumer import paths (`from "../dom/locale-labels.js"`) are unchanged — the barrel
|
|
240
276
|
`locale-labels.ts` re-exports everything from `locale/index.ts`.
|
|
241
277
|
- `doctor({ check: ["localization"] })` verifies that the registry is populated and
|
|
242
|
-
canonical English values are present. It
|
|
243
|
-
|
|
244
|
-
|
|
278
|
+
canonical English values are present. It also reports running-state localization coverage
|
|
279
|
+
separately from the flattened selector list, because `stopControl` and
|
|
280
|
+
`stoppedAssistant` require a live mid-generation capture. It does not yet prove full
|
|
281
|
+
localized selector coverage; treat localized workflow failures as selector-wiring work
|
|
282
|
+
unless the registry is missing the observed labels.
|
|
245
283
|
- The public-export plugin bundles under `plugins/codex-chatgpt-control/runtime/node/` are
|
|
246
284
|
produced by a separate pipeline (`tools/public-export/export-public.mjs`) and are not
|
|
247
285
|
updated by the sync above.
|
|
@@ -26,9 +26,14 @@ Wire fields stay TypeScript-compatible. Python exposes idiomatic aliases:
|
|
|
26
26
|
| `totalBytes` | `total_bytes` |
|
|
27
27
|
| `projectUrl` | `project_url` |
|
|
28
28
|
| `displayPath` | `display_path` |
|
|
29
|
+
| `selectorProfile` | `selector_profile` |
|
|
30
|
+
| `newTask` | `new_task` |
|
|
31
|
+
| `includeArtifacts` | `include_artifacts` |
|
|
29
32
|
|
|
30
33
|
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.
|
|
31
34
|
|
|
35
|
+
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.
|
|
36
|
+
|
|
32
37
|
Generated-image behavior stays owned by the TypeScript runtime. Python exposes
|
|
33
38
|
the same backend commands through `chatgpt.artifacts.list_latest(...)`,
|
|
34
39
|
`chatgpt.artifacts.wait(...)`, and `chatgpt.artifacts.download_latest(...)`.
|
|
@@ -39,6 +44,13 @@ claimed conversation in a temporary bridge-owned tab and exporting through
|
|
|
39
44
|
`pageAssets`, Python observes the same command result through the backend
|
|
40
45
|
protocol without any Python-side browser logic.
|
|
41
46
|
|
|
47
|
+
Chat/Work behavior follows the same authority boundary. Python exposes matching
|
|
48
|
+
sync and async `experience`, `configuration`, and `work` groups, but surface
|
|
49
|
+
detection, selector profiles, configuration state machines, submit-once Work
|
|
50
|
+
semantics, and artifact extraction remain owned by TypeScript. Nested Python
|
|
51
|
+
dictionaries and model instances are recursively converted from snake_case to
|
|
52
|
+
the camelCase wire contract.
|
|
53
|
+
|
|
42
54
|
Blocker explainability follows the same rule. TypeScript owns blocker creation,
|
|
43
55
|
runner interruption decisions, and existing-tab diagnostics. Python exposes
|
|
44
56
|
`explain_blocker(...)` over the backend blocker dictionary and is checked against
|
|
@@ -49,7 +61,7 @@ the shared `blocker-explanation-profiles.json` and
|
|
|
49
61
|
|
|
50
62
|
Python does not reinterpret attachment paths. It sends the path string to the Node backend, and the backend validates the path against its own host operating system. Attachment paths must be absolute on the backend host. On macOS/Linux/WSL backends, use POSIX paths such as `/example/user/file.pdf` or `/mnt/c/example/user/file.pdf`. On Windows backends, use fully qualified paths such as `C:\Users\you\file.pdf` or UNC paths such as `\\server\share\file.pdf`. Drive-relative paths, root-relative paths, and Windows-looking paths sent to a POSIX backend are rejected before filesystem access.
|
|
51
63
|
|
|
52
|
-
Python exposes the backend-visible `files.preflight` command as `chatgpt.files.preflight(...)`. It returns the same `CommandResult` as TypeScript and can be decoded with `FilePreflightData` when callers want typed metadata. The command validates paths, readability, file-vs-directory status, size limits, duplicate basenames, duplicate resolved paths, zero-byte files, and extension-based MIME/category guesses without opening ChatGPT or reading file contents for MIME detection.
|
|
64
|
+
Python exposes the backend-visible `files.preflight` command as `chatgpt.files.preflight(...)`. It returns the same `CommandResult` as TypeScript and can be decoded with `FilePreflightData` when callers want typed metadata. The command validates paths, readability, file-vs-directory status, size limits, duplicate basenames, duplicate resolved paths, zero-byte files, and extension-based MIME/category guesses without opening ChatGPT or reading file contents for MIME detection. Zero-byte files are blocked before browser interaction. Optional `include_hashes=True` / wire `includeHashes: true` adds SHA-256 metadata to `FilePreflightFile.sha256` for local diagnostics; file contents are never returned.
|
|
53
65
|
|
|
54
66
|
## Project Sources
|
|
55
67
|
|
|
@@ -121,7 +133,7 @@ Report results may include `metaPath` plus `integrity` metadata. Python exposes
|
|
|
121
133
|
|
|
122
134
|
## Streaming
|
|
123
135
|
|
|
124
|
-
`stream-*.ndjson` fixtures are milestone streams. They are not token streams. The final `completed` event contains a normal `ChatGPTRunResult` wire object, including blockers when the run cannot proceed.
|
|
136
|
+
`stream-*.ndjson` fixtures are milestone streams. They are not token streams. The final `completed` event contains a normal `ChatGPTRunResult` wire object, including blockers when the run cannot proceed. Running partial assistant text uses `message.in_progress` / `message_in_progress`; completion-confirmed assistant output uses `message.completed` / `message_completed`.
|
|
125
137
|
|
|
126
138
|
```python
|
|
127
139
|
from codex_chatgpt_control import ChatGPTStreamEvent
|
|
@@ -161,7 +173,7 @@ Python is a native SDK facade over the local backend protocol. The initial brows
|
|
|
161
173
|
|
|
162
174
|
- `dist/codex-chatgpt-control-backend.mjs` is the stdio backend bundle.
|
|
163
175
|
- `BackendClient` and `StdioBackendTransport` keep Python backend calls long-lived.
|
|
164
|
-
- `NodeSidecarTransport.run(...)` remains as a compatibility wrapper over backend `runner.run`.
|
|
176
|
+
- `NodeSidecarTransport.run(...)` remains as a compatibility wrapper over backend `runner.run`. By default each call spawns and tears down its own backend subprocess; use it as a context manager (or call `open()`/`close()`) to reuse one persistent backend process across calls in multi-command workflows. Transport-level failures close the persistent session; protocol-level errors keep it open.
|
|
165
177
|
- Ordinary-shell smoke passes when browser-required calls return structured `browser_bridge_unavailable`.
|
|
166
178
|
- Browser-bridge runtime smoke remains explicitly gated because it can operate a real ChatGPT session.
|
|
167
179
|
|
|
@@ -199,7 +211,7 @@ python scripts/live_smoke.py --mode browser-bridge
|
|
|
199
211
|
When the live backend is hosted inside the Codex Chrome plugin runtime, do not test bridge availability from a normal shell or an unbootstrapped Node REPL. First initialize the Chrome runtime:
|
|
200
212
|
|
|
201
213
|
```js
|
|
202
|
-
const { setupBrowserRuntime } = await import("/example/user/.codex/plugins/cache/openai-bundled/chrome/
|
|
214
|
+
const { setupBrowserRuntime } = await import("/example/user/.codex/plugins/cache/openai-bundled/chrome/latest/scripts/browser-client.mjs");
|
|
203
215
|
await setupBrowserRuntime({ globals: globalThis });
|
|
204
216
|
globalThis.browser = await agent.browsers.get("extension");
|
|
205
217
|
```
|
|
@@ -6,8 +6,12 @@ Accepted fields:
|
|
|
6
6
|
|
|
7
7
|
- `input`
|
|
8
8
|
- `thread`
|
|
9
|
+
- `existingTab`
|
|
10
|
+
- `preferExistingTab`
|
|
11
|
+
- `experience`
|
|
12
|
+
- `configuration`
|
|
9
13
|
- `attachments`
|
|
10
|
-
- `mode`
|
|
14
|
+
- `mode` (legacy compatibility)
|
|
11
15
|
- `tools`
|
|
12
16
|
- `text.format`
|
|
13
17
|
- `stream: false`
|
|
@@ -20,9 +24,16 @@ Rejected API-only fields return `status: "unsupported"` before any prompt is sub
|
|
|
20
24
|
const response = await chatgpt.responses.create({
|
|
21
25
|
input: "Summarize the latest plan.",
|
|
22
26
|
thread: { type: "conversationId", conversationId: "abc-123" },
|
|
27
|
+
experience: "chat",
|
|
28
|
+
configuration: { intelligence: "High" },
|
|
23
29
|
text: { format: "markdown" },
|
|
24
30
|
stream: false
|
|
25
31
|
});
|
|
26
32
|
```
|
|
27
33
|
|
|
34
|
+
`experience` and `configuration` represent visible product controls, not API
|
|
35
|
+
model selection. Configuration is strict through the runner plan and must
|
|
36
|
+
verify the visible postcondition. Existing callers may continue to pass
|
|
37
|
+
`mode`; new callers should prefer the surface-aware fields.
|
|
38
|
+
|
|
28
39
|
Use `chatgpt.runner.run()` for lower-level browser-control workflows, multi-step command planning, attachments, downloads, reports, and explicit interruption handling.
|
|
@@ -33,7 +33,7 @@ Use `chatgpt.explainBlocker(result)` or Python `explain_blocker(result)` when re
|
|
|
33
33
|
Do not conclude that Chrome or the extension is broken from a plain shell result, or from checking `globalThis.agent` before the Chrome plugin runtime is initialized. For a true Codex Chrome-plugin live run, bootstrap the runtime first:
|
|
34
34
|
|
|
35
35
|
```js
|
|
36
|
-
const { setupBrowserRuntime } = await import("/example/user/.codex/plugins/cache/openai-bundled/chrome/
|
|
36
|
+
const { setupBrowserRuntime } = await import("/example/user/.codex/plugins/cache/openai-bundled/chrome/latest/scripts/browser-client.mjs");
|
|
37
37
|
await setupBrowserRuntime({ globals: globalThis });
|
|
38
38
|
globalThis.browser = await agent.browsers.get("extension");
|
|
39
39
|
```
|
|
@@ -69,6 +69,17 @@ The ChatGPT UI changed or the page loaded an unexpected surface. Return visible
|
|
|
69
69
|
|
|
70
70
|
Runner results surface this as `interruptions[0].type === "selector_drift"` with `blocker.candidates` when visible candidates were available. Do not retry automatically; ask the user or update selectors.
|
|
71
71
|
|
|
72
|
+
For Chat/Work drift, capture only scoped capability evidence: composer label,
|
|
73
|
+
main controls, configuration rows/options, locale, URL shape, selector profile,
|
|
74
|
+
and observation date. Do not retain sidebar thread titles or conversation
|
|
75
|
+
content. An unknown profile, missing axis, or unverified postcondition is a
|
|
76
|
+
normal blocker during staged account/region/workspace rollouts.
|
|
77
|
+
|
|
78
|
+
If `work.start` returns `work_new_task_control_not_found`, a task is already
|
|
79
|
+
loaded and the SDK refused to append. Pass `newTask: false` only when the user
|
|
80
|
+
intends to continue that exact task. If a Work submission returns partial or
|
|
81
|
+
timeout, use `work.status`, `work.wait`, or `work.readLatest`; do not resubmit.
|
|
82
|
+
|
|
72
83
|
## Existing Tab Not Found Or Ambiguous
|
|
73
84
|
|
|
74
85
|
When `existingTab` targeting cannot select one already-open tab, inspect `blocker.diagnostics.existingTab` or the rendered blocker explanation. Diagnostics are metadata-only: requested target, whether user-open tabs were available, candidate tab IDs, URLs, titles, conversation IDs, omitted candidate count, and mismatch reason. They must not include page text or chat content.
|
|
@@ -90,9 +101,24 @@ Agent-facing remediation text should name both settings:
|
|
|
90
101
|
|
|
91
102
|
Attachment paths are validated against the backend host's operating system. If a Windows-looking path is rejected on macOS/Linux, do not retry with the same string. Convert it to the backend host's real path, for example `/mnt/c/example/user/file.pdf` for a WSL/Linux backend. Drive-relative paths like `C:Users\you\file.pdf`, root-relative paths like `\tmp\file.pdf`, and empty or relative paths are always rejected.
|
|
92
103
|
|
|
104
|
+
## Empty Or Stripped Attachments
|
|
105
|
+
|
|
106
|
+
Zero-byte files are blocked by `files.preflight` before browser upload because
|
|
107
|
+
ChatGPT rejects empty attachments with a generic help-center error. If a user
|
|
108
|
+
reports that manual upload works but automated upload fails, compare local and
|
|
109
|
+
browser-side metadata instead of guessing:
|
|
110
|
+
|
|
111
|
+
1. Run `files.preflight({ paths, includeHashes: true })` and inspect `bytes`
|
|
112
|
+
plus `sha256` for the backend-visible file.
|
|
113
|
+
2. Run `files.attach({ paths, includeDiagnostics: true, includeHashes: true })`
|
|
114
|
+
and inspect `data.diagnostics.browserInput.files[].size` when available.
|
|
115
|
+
3. If preflight `bytes` is zero, investigate the source path, generation race,
|
|
116
|
+
cloud placeholder, or host/container path mapping. If preflight bytes are
|
|
117
|
+
nonzero but browser-side size is zero, investigate the Chrome handoff.
|
|
118
|
+
|
|
93
119
|
## Clipboard Unavailable
|
|
94
120
|
|
|
95
|
-
`response.copy` falls back to DOM text extraction when the
|
|
121
|
+
`response.copy` falls back to DOM text extraction when the system clipboard does not change. Clipboard reads use `pbpaste` on macOS, PowerShell `Get-Clipboard` on Windows, and `xclip`/`xsel`/`wl-paste` on Linux; hosts without any of these tools always use the DOM fallback.
|
|
96
122
|
|
|
97
123
|
## Flattened Or Unreadable Response Capture
|
|
98
124
|
|
|
@@ -100,16 +126,33 @@ Use `readLatest({ format: "markdown" })`, `copyLatest()`, or the default SDK `re
|
|
|
100
126
|
|
|
101
127
|
## Long Responses Return `partial`
|
|
102
128
|
|
|
103
|
-
Long Pro, Thinking, Deep Research, or file-backed answers can take longer than the default wait window. Treat `status: "partial"` and `data.complete: false` as an incomplete capture even when `output_text` is non-empty. Re-run `messages.wait(...)` on the same thread with a larger timeout, then call `readLatest(...)` or `copyLatest(...)`
|
|
129
|
+
Long Pro, Thinking, Deep Research, or file-backed answers can take longer than the default wait window. Treat `status: "partial"` and `data.complete: false` as an incomplete capture even when `output_text` is non-empty. Check `data.completionState` and `data.generationActive`; `completionState: "generating"` or `generationActive: true` means ChatGPT is still running and the prompt must not be resubmitted. For repeated polling, prefer `messages.status({ maxPreviewChars })` for a cheap snapshot, or `messages.wait({ responseContent: "metadata", ... })` so Codex receives compact status metadata instead of the same growing partial answer body. Re-run `messages.wait(...)` on the same thread (with a larger timeout if needed) until completion is confirmed, then call `readLatest(...)` or `copyLatest(...)` once.
|
|
104
130
|
|
|
105
131
|
Recommended long-answer wait:
|
|
106
132
|
|
|
107
133
|
```ts
|
|
108
|
-
wait
|
|
134
|
+
await chatgpt.messages.wait({
|
|
135
|
+
timeoutMs: 45_000,
|
|
136
|
+
stableMs: 2_000,
|
|
137
|
+
pollMs: 1_000,
|
|
138
|
+
mode: "deep_research",
|
|
139
|
+
responseContent: "metadata"
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const final = await chatgpt.messages.readLatest({ format: "markdown" });
|
|
109
143
|
```
|
|
110
144
|
|
|
111
145
|
Active generation may appear as a visible or accessible-name control such as `Stop answering`, `Stop generating`, or `Stop streaming`. Stopped generation may appear as `Stopped thinking`. Treat all of those as incomplete states.
|
|
112
146
|
|
|
147
|
+
When the outer host tool-call ceiling is short, poll in bounded chunks instead of issuing a single very long wait:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const status = await chatgpt.messages.status({ maxPreviewChars: 400 });
|
|
151
|
+
if (status.data?.completionState === "generating" || status.data?.generationActive) {
|
|
152
|
+
await chatgpt.messages.wait({ timeoutMs: 30000, stableMs: 8000, pollMs: 1000 });
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
113
156
|
`maxChars` limits captured text returned by the SDK. It does not control ChatGPT generation. When set and clipping occurs, inspect result warnings and `data.captureLimit`, then rerun without `maxChars` for full capture.
|
|
114
157
|
|
|
115
158
|
## Response Branch Ambiguity
|
|
@@ -144,6 +187,6 @@ Doctor also supports opt-in scenario checks:
|
|
|
144
187
|
|
|
145
188
|
- `existing_tab`: claims only the requested already-open tab target by default and reports `existing_tab_not_found` / `existing_tab_ambiguous` diagnostics without opening a replacement tab unless `existingTab.ifMissing` explicitly allows that.
|
|
146
189
|
- `artifacts`: verifies current-page artifact selector/download/asset support without requesting generation.
|
|
147
|
-
- `file_preflight`: validates supplied local file paths without opening ChatGPT or attempting upload. It reports path count, total bytes, duplicate
|
|
148
|
-
- `localization`: checks locale-label registry readiness and English canonical labels without changing the ChatGPT account language
|
|
190
|
+
- `file_preflight`: validates supplied local file paths without opening ChatGPT or attempting upload. It reports path count, total bytes, duplicate warnings, zero-byte blockers, and extension-based MIME/category metadata; fatal local file problems map to the same structured blockers as `files.preflight`.
|
|
191
|
+
- `localization`: checks locale-label registry readiness and English canonical labels without changing the ChatGPT account language. It reports running-state label coverage (`stopControl` and `stoppedAssistant`) separately so English-only, partial, and complete live-capture coverage are visible. It is not yet proof of full localized selector coverage.
|
|
149
192
|
- `reports`: checks redacted-report policy and existing destination writability when possible without writing a report.
|