pi-openai-codex-compat 0.0.1 → 0.0.3

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 CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.0.3 - 2026-08-04
6
+
7
+ ### Added
8
+
9
+ - Expose Pi AI-compatible Codex WebSocket debug statistics, reset helpers, and force-close control for connection reuse, continuation deltas, failures, and SSE fallback.
10
+
11
+ ### Changed
12
+
13
+ - Rely on Pi's compaction indicator instead of adding a temporary third footer status line during percentage-triggered compaction.
14
+ - Adapt the `image_gen.imagegen` descriptions and prompt metadata to Pi while retaining the server-reserved schema.
15
+ - Normalize local image paths before reading them and enforce image-count bounds and edit-selector exclusivity in the executor.
16
+ - Add a concise `web.run` prompt snippet and four high-signal system-prompt guidelines derived from its official description.
17
+ - Clarify the `apply_patch` prompt snippet, format its system-prompt guidance consistently, and omit the redundant Python file-I/O reminder.
18
+ - Disable standalone `web.run` and hosted web search by default; both remain available through settings or environment overrides.
19
+
20
+ ### Fixed
21
+
22
+ - Report WebSocket close codes and reasons instead of `[object CloseEvent]`, and preserve an underlying WebSocket error when a close event follows it.
23
+ - Scope sticky Codex WebSockets to the authenticated account so changing accounts cannot reuse a connection authorized for another account.
24
+ - Recover once from expired WebSocket continuations and connection-limit responses while preserving structured Codex API and protocol errors.
25
+ - Finish SSE requests as soon as a terminal response arrives, even if the response body remains open, and reject pre-aborted cached-WebSocket requests before sending.
26
+ - Apply `cacheRetention: "none"` consistently to ordinary and compaction payloads and clamp cache-affinity headers to the backend's 64-character limit.
27
+ - Keep SSE fallback sticky after midstream WebSocket failures and use the fallback for later requests regardless of the preferred WebSocket mode.
28
+ - Validate transport timeouts, allow zero to disable the WebSocket connect timeout, report SSE header timeouts clearly, and honor bounded `Retry-After` guidance.
29
+ - Surface concise structured Codex HTTP errors, fail closed on malformed WebSocket events, and retain WebSocket-to-SSE recovery diagnostics on assistant messages.
30
+ - Distinguish output-token truncation from other incomplete Codex responses and preserve the provider's incomplete reason.
31
+ - Match Pi AI's Codex stream lifecycle by delaying `start` until transport readiness, cleaning parser scratch state on failure, and normalizing structured or non-Error failures.
32
+ - Honor every non-undefined payload replacement and reject missing `streamSimple` authentication synchronously, matching Pi AI.
33
+ - Match Pi AI's configured SSE retry behavior for callback, body-read, and otherwise non-terminal response-acquisition failures.
34
+ - Use Pi AI's time-ordered UUIDv7 identifiers for WebSocket requests without session affinity.
35
+ - Stop at terminal WebSocket events and honor aborts while requests wait for session transport ownership or finish streaming.
36
+ - Ignore type-less Codex events before transport start and retain WebSocket continuation IDs supplied by `response.created`.
37
+ - Validate Codex authentication before request hooks, template capture, or native compaction work.
38
+ - Apply service-tier pricing to unsuccessful terminal responses and match Pi AI when total-token usage is absent.
39
+ - Match Pi AI's final-answer phase state, reasoning-part separators, and suppression of empty final tool-call deltas.
40
+ - Retry generic Codex usage-limit responses according to Pi AI's configured SSE retry policy.
41
+ - Require Pi AI's order-sensitive request and history equality before sending cached WebSocket deltas.
42
+ - Cache the exact canonical or native assistant representation replayed by the next turn so harmless response key ordering cannot disable WebSocket continuation.
43
+ - Send full WebSocket context when a payload hook supplies string-valued Responses input instead of incorrectly continuing with an empty delta.
44
+ - Treat an empty Codex session identifier as absent and generate a stable UUIDv7 WebSocket request identifier.
45
+ - Preserve Pi AI's exact Codex HTTP error bodies and fallback wording without local trimming or truncation.
46
+ - Keep native Codex history keyed by the complete Pi session identifier even when cache retention is disabled or the backend cache key is shortened.
47
+ - Represent overlong Codex cache identifiers with collision-resistant 64-character SHA-256 hex values instead of truncating them.
48
+ - Prevent SSE reader cleanup failures from masking the original Codex stream error.
49
+ - Reject malformed Codex credentials whose account identifier is empty.
50
+ - Snapshot cached WebSocket continuation requests through their JSON wire representation so payload-hook values omitted by JSON serialization cannot break completed responses.
51
+ - Match Pi AI's metadata for non-Error WebSocket failures and its fallback wording for unavailable transports and terminal responses without provider details.
52
+ - Discard WebSockets and continuation state when downstream response parsing or terminal validation fails, report parser diagnostics, and retry a fresh WebSocket on later requests without activating sticky SSE fallback.
53
+ - Reuse one JSON serialization for SSE requests, align outbound WebSocket close reasons, and match Pi AI's closed grammar-input error wording.
54
+
55
+ ## 0.0.2 - 2026-08-03
56
+
57
+ ### Added
58
+
59
+ - Add transient `PI_OPENAI_CODEX_COMPAT_*` environment overrides for every compatibility setting, including common boolean aliases, explicit `off`/`default` percentage-compaction values, and an unambiguous `WEB_SEARCH_MODE` name.
60
+
61
+ ### Changed
62
+
63
+ - Make `Enter` save and close `/codex-settings`, make `Escape` discard unsaved changes and close, and retain `Ctrl+S` as save without closing.
64
+
5
65
  ## 0.0.1 - 2026-08-03
6
66
 
7
67
  ### Added
package/README.md CHANGED
@@ -12,7 +12,7 @@ OpenAI Codex compatibility for [Pi](https://github.com/earendil-works/pi-mono),
12
12
  - **Dedicated Codex tool UI**: renders `apply_patch`, `image_gen.imagegen`, and `web.run` on a shared configurable surface with compact summaries and `Ctrl+O` expansion.
13
13
  - **Hosted web-search fallback**: injects native `web_search` only when `web.run` is inactive, with cached, indexed, or live modes.
14
14
  - **Native request controls**: configures Responses API text verbosity, reasoning summaries, and GPT-5.6 standard/pro reasoning mode.
15
- - **Session-local settings pane**: `/codex-settings` changes every compatibility setting for the current session; `Ctrl+S` explicitly persists the current values.
15
+ - **Session-local settings pane**: `/codex-settings` changes every compatibility setting for the current session; `Enter` persists and closes, `Escape` discards unsaved changes and closes, and `Ctrl+S` persists without closing.
16
16
  - **Compact footer indicators**: non-default Codex request modes are appended to the model side of Pi's normal second footer line.
17
17
 
18
18
  Pi provides the Codex OAuth flow and model catalog. At session start, this package overrides the built-in `openai-codex` runtime under the same provider id so ordinary responses and remote compaction share one transport, parser, native-history store, and sticky WebSocket session.
@@ -35,17 +35,17 @@ The compatibility baseline is official Codex CLI `0.146.0`, released July 29, 20
35
35
 
36
36
  ### Configurable defaults that differ from Codex
37
37
 
38
- | Area | This package by default | Official Codex | Configuration |
39
- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
40
- | Generated-image detail sent back to the model | Sends image tool-result content with `input_image.detail: "auto"`. On GPT-5.6, `auto` uses original-size image accounting. | Uses `high`. | `imageDetail`: `auto`, `low`, `high`, or `original`. |
41
- | Image-generation tool | Enabled whenever an `openai-codex` model is selected. Backend capability and account failures surface when the tool executes. | Stable and enabled by default, but additionally gated by plan, model, provider, authentication, image-generation, and namespace capabilities. | `imageGeneration`: boolean. |
42
- | Standalone `web.run` | Enabled and preferred over hosted `web_search`, using the complete reserved command schema and tool description. | The standalone feature is under development and disabled by default outside environments such as Responses Lite. | `webRun`: boolean. |
43
- | Hosted web search | Omitted while `web.run` is active; otherwise injected in cached mode. | Normally uses hosted cached search because standalone `web.run` is disabled by default. | `webRun` and `webSearch`: `disabled`, `cached`, `indexed`, or `live`. |
44
- | Coding mutation tools | Enables `apply_patch` and suppresses Pi's active `edit` and `write` tools. | Chooses its tool surface from model metadata and runtime capabilities; there are no Pi `edit` or `write` tools to suppress. | `applyPatch`: boolean. |
45
- | Codex tool background | Uses a subtle theme-derived surface for extension-owned Codex tools. | Uses Codex's own TUI activity cells rather than Pi tool rows. | `toolBackground`: `subtle`, `status`, or `none`. |
46
- | Auto-compaction trigger | Relies on Pi's reserve-token threshold unless a percentage is configured. | Tracks Codex's model/token-budget state before and between sampling steps. | `autoCompactAtPercent`: percentage or unset. Pi's own compaction settings remain separate. |
47
- | Fast mode | Uses the normal tier. | Uses the configured Codex service tier. | `fastMode`: boolean; `true` requests the priority tier. |
48
- | Text and reasoning request controls | Explicitly sends low text verbosity, automatic reasoning summaries, and standard GPT-5.6 reasoning mode. | Resolves these controls through Codex configuration, model metadata, and turn state. | `textVerbosity`, `reasoningSummary`, and `reasoningMode`. |
38
+ | Area | This package by default | Official Codex | Configuration |
39
+ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
40
+ | Generated-image detail sent back to the model | Sends image tool-result content with `input_image.detail: "auto"`. On GPT-5.6, `auto` uses original-size image accounting. | Uses `high`. | `imageDetail`: `auto`, `low`, `high`, or `original`. |
41
+ | Image-generation tool | Enabled whenever an `openai-codex` model is selected. Backend capability and account failures surface when the tool executes. | Stable and enabled by default, but additionally gated by plan, model, provider, authentication, image-generation, and namespace capabilities. | `imageGeneration`: boolean. |
42
+ | Standalone `web.run` | Disabled by default; when enabled, preferred over hosted `web_search` and sent with the complete reserved schema and description. | Enabled by default for `gpt-5.6-sol` through Responses Lite; otherwise subject to standalone-search feature and runtime gates. | `webRun`: boolean. |
43
+ | Hosted web search | Disabled by default; when enabled, injected only while `web.run` is inactive. | Omitted for `gpt-5.6-sol` while standalone `web.run` is available; otherwise defaults to cached mode when hosted search is supported. | `webRun` and `webSearch`: `disabled`, `cached`, `indexed`, or `live`. |
44
+ | Coding mutation tools | Enables `apply_patch` and suppresses Pi's active `edit` and `write` tools. | Chooses its tool surface from model metadata and runtime capabilities; there are no Pi `edit` or `write` tools to suppress. | `applyPatch`: boolean. |
45
+ | Codex tool background | Uses a subtle theme-derived surface for extension-owned Codex tools. | Uses Codex's own TUI activity cells rather than Pi tool rows. | `toolBackground`: `subtle`, `status`, or `none`. |
46
+ | Auto-compaction trigger | Relies on Pi's reserve-token threshold unless a percentage is configured. | Tracks Codex's model/token-budget state before and between sampling steps. | `autoCompactAtPercent`: percentage or unset. Pi's own compaction settings remain separate. |
47
+ | Fast mode | Uses the normal tier. | Uses the configured Codex service tier. | `fastMode`: boolean; `true` requests the priority tier. |
48
+ | Text and reasoning request controls | Explicitly sends low text verbosity, automatic reasoning summaries, and standard GPT-5.6 reasoning mode. | Resolves these controls through Codex configuration, model metadata, and turn state. | `textVerbosity`, `reasoningSummary`, and `reasoningMode`. |
49
49
 
50
50
  `web.run` is a reserved GPT-5.6 tool name. Its declaration therefore reproduces the complete current Codex post-normalization `SearchCommands` schema and official tool description instead of using Pi's normal compact tool schema. This intentionally omits generated annotations such as `format` and `minimum` that Codex removes before sending the declaration to Responses.
51
51
 
@@ -66,6 +66,7 @@ The compatibility baseline is official Codex CLI `0.146.0`, released July 29, 20
66
66
  | Tool namespaces | Pi registers dotted names such as `web.run` as exact flat identifiers. The provider converts only the fixed extension-owned allowlist into real Responses namespace/member identities and rejects unknown or ambiguously flat namespaced calls. |
67
67
  | Capability gating | Tool activation is based on the selected `openai-codex` provider plus package settings. It does not reproduce every official model-metadata, plan, feature-stage, executor, mode, or account gate. |
68
68
  | Sandbox and approvals | Pi extensions run with full process permissions. `apply_patch`, local image reads, generated-image writes, and sibling Codex endpoints do not use Codex's sandbox, permission-profile, or approval lifecycle. |
69
+ | Image tool instructions | The package retains the server-reserved image-generation schema while replacing Rust-specific path annotations and Codex Code Mode instructions with model-facing descriptions, a prompt snippet, and system-prompt guidelines. Image-count bounds and selector exclusivity are enforced before execution. |
69
70
  | Image artifact hint | When image saving succeeds, this package always returns the path hint, says “the generated image,” and has no 1,024-byte cutoff. Official Codex says “a generated image” and omits the hint when it exceeds 1,024 UTF-8 bytes. |
70
71
  | Image artifacts | Generated files use Pi's agent directory and the Pi session/tool-call IDs. Official Codex uses its own artifact/output-directory lifecycle. |
71
72
  | Web references | `web.run` structured results are retained branch-locally in Pi tool-result details rather than Codex extension events, and hosted native items are preserved for provider replay. Reference IDs are resolved remotely by `alpha/search`, as in Codex. Hosted citation annotations remain a separate unimplemented path. |
@@ -143,7 +144,7 @@ A trusted project can override it at:
143
144
  <project>/.pi/openai-codex-compat.json
144
145
  ```
145
146
 
146
- Each session inherits the effective file-backed settings. Open `/codex-settings` to make immediate session-local changes. Press `Ctrl+S` in the pane to persist the current values; the global file is the normal save target, while an existing trusted project override remains the target for that project.
147
+ Each session inherits the effective file-backed settings. Open `/codex-settings` to make immediate session-local changes. Press `Enter` to persist and close, `Escape` to discard unsaved changes and close, or `Ctrl+S` to persist without closing. The global file is the normal save target, while an existing trusted project override remains the target for that project. After `Ctrl+S`, later unsaved changes can still be discarded back to the values from that save.
147
148
 
148
149
  The effective settings are printed once when a TUI session starts. The footer shows `fast` and `pro` only when enabled, and shows text verbosity or reasoning summary only when they differ from their defaults.
149
150
 
@@ -156,9 +157,9 @@ Example:
156
157
  "applyPatch": true,
157
158
  "imageGeneration": true,
158
159
  "imageDetail": "auto",
159
- "webRun": true,
160
+ "webRun": false,
160
161
  "autoCompactAtPercent": 90,
161
- "webSearch": "cached",
162
+ "webSearch": "disabled",
162
163
  "textVerbosity": "low",
163
164
  "reasoningSummary": "auto",
164
165
  "reasoningMode": "standard"
@@ -174,14 +175,43 @@ Defaults:
174
175
  | `applyPatch` | boolean | `true` | On selected `openai-codex` models, uses the extension's `apply_patch` tool instead of Pi's active `edit` and `write` tools. Other providers always use their normal Pi tool set. |
175
176
  | `imageGeneration` | boolean | `true` | Enables the extension-owned `image_gen.imagegen` tool on selected `openai-codex` models. |
176
177
  | `imageDetail` | `auto`, `low`, `high`, `original` | `auto` | Sets `input_image.detail` when an image tool result is sent back to the model. It does not change `gpt-image-2` generation quality. |
177
- | `webRun` | boolean | `true` | Enables the extension-owned `web.run` tool on selected `openai-codex` models. When active, it replaces hosted `web_search` in the Responses tool list. |
178
+ | `webRun` | boolean | `false` | Enables the extension-owned `web.run` tool on selected `openai-codex` models. When active, it replaces hosted `web_search` in the Responses tool list. |
178
179
  | `autoCompactAtPercent` | number greater than `0` and at most `100`, or `null` | unset | Adds provider-boundary compaction independently of Pi's normal reserve-token threshold. A project value of `null` disables a global percentage threshold. |
179
- | `webSearch` | `disabled`, `cached`, `indexed`, `live` | `cached` | Controls hosted search and standalone-search external access. `disabled` removes hosted search but leaves an independently enabled `web.run` in cached-only mode; `indexed` prefers indexed content; `live` permits live external access. |
180
+ | `webSearch` | `disabled`, `cached`, `indexed`, `live` | `disabled` | Controls hosted search and standalone-search external access. `disabled` removes hosted search but leaves an independently enabled `web.run` in cached-only mode; `indexed` prefers indexed content; `live` permits live external access. |
180
181
  | `textVerbosity` | `low`, `medium`, `high` | `low` | Sets Responses API `text.verbosity`. |
181
182
  | `reasoningSummary` | `auto`, `concise`, `detailed`, `off` | `auto` | Sets `reasoning.summary` when reasoning is enabled; `off` omits the summary parameter. |
182
183
  | `reasoningMode` | `standard`, `pro` | `standard` | Sets `reasoning.mode` on GPT-5.6 models independently of Pi's reasoning-effort control. |
183
184
 
184
- Invalid values are ignored and invalid JSON does not prevent Pi from starting. The settings pane never writes on ordinary changes, refuses to overwrite invalid JSON when `Ctrl+S` is pressed, and retains unknown keys when saving. Project configuration is read only when the project is trusted.
185
+ Invalid JSON setting values are ignored and invalid JSON does not prevent Pi from starting. The settings pane never writes on ordinary changes, refuses to overwrite invalid JSON when `Enter` or `Ctrl+S` attempts to save, and retains unknown keys when saving. Project configuration is read only when the project is trusted.
186
+
187
+ Every setting can also be overridden for one Pi process with an environment variable:
188
+
189
+ | Setting | Environment variable |
190
+ | ---------------------- | ------------------------------------------------ |
191
+ | `fastMode` | `PI_OPENAI_CODEX_COMPAT_FAST_MODE` |
192
+ | `toolBackground` | `PI_OPENAI_CODEX_COMPAT_TOOL_BACKGROUND` |
193
+ | `applyPatch` | `PI_OPENAI_CODEX_COMPAT_APPLY_PATCH` |
194
+ | `imageGeneration` | `PI_OPENAI_CODEX_COMPAT_IMAGE_GENERATION` |
195
+ | `imageDetail` | `PI_OPENAI_CODEX_COMPAT_IMAGE_DETAIL` |
196
+ | `webRun` | `PI_OPENAI_CODEX_COMPAT_WEB_RUN` |
197
+ | `autoCompactAtPercent` | `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT` |
198
+ | `webSearch` | `PI_OPENAI_CODEX_COMPAT_WEB_SEARCH_MODE` |
199
+ | `textVerbosity` | `PI_OPENAI_CODEX_COMPAT_TEXT_VERBOSITY` |
200
+ | `reasoningSummary` | `PI_OPENAI_CODEX_COMPAT_REASONING_SUMMARY` |
201
+ | `reasoningMode` | `PI_OPENAI_CODEX_COMPAT_REASONING_MODE` |
202
+
203
+ Environment variables have the highest precedence: defaults < global JSON < trusted-project JSON < environment. Boolean values accept `true`/`false`, `1`/`0`, `on`/`off`, or `enabled`/`disabled`. Other settings use the values in the defaults table; `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT=off` and `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT=default` explicitly select Pi's default compaction lifecycle.
204
+
205
+ Environment-controlled rows are marked `(env)` and locked in `/codex-settings`. Saving the pane does not copy their effective values into JSON, so CLI overrides remain transient. Invalid environment values fail fast with the variable name and accepted values.
206
+
207
+ For example:
208
+
209
+ ```bash
210
+ PI_OPENAI_CODEX_COMPAT_WEB_RUN=off \
211
+ PI_OPENAI_CODEX_COMPAT_IMAGE_DETAIL=high \
212
+ PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT=90 \
213
+ pi
214
+ ```
185
215
 
186
216
  ## Native compaction
187
217
 
@@ -262,7 +292,9 @@ The tool generates new images with `gpt-image-2` or edits up to five local/recen
262
292
  ~/.pi/agent/generated_images/<session-id>/<call-id>.png
263
293
  ```
264
294
 
265
- The active Pi agent directory replaces `~/.pi/agent` when configured differently. Turning `imageGeneration` off removes the tool immediately for the current session; `Ctrl+S` in `/codex-settings` persists the value.
295
+ The active Pi agent directory replaces `~/.pi/agent` when configured differently. Turning `imageGeneration` off removes the tool immediately for the current session; `Enter` or `Ctrl+S` in `/codex-settings` persists the value.
296
+
297
+ The tool registers the server-reserved schema directly with a model-facing absolute-path annotation that names the supported image formats. OpenAI rejects additional schema keywords for image-count bounds and selector exclusivity, so the executor enforces those constraints before filesystem or network access. Local paths are lexically normalized before reading. A one-line system-prompt snippet and four high-signal guidelines cover normal model use. Local images are inspected with Pi's `read` tool, and generated image content is displayed and saved automatically without Codex Code Mode wrappers.
266
298
 
267
299
  Pi also persists the returned image content in tool-result history so later image edits and provider replay remain self-contained. Generated-image turns therefore increase the session file by approximately the base64 image size in addition to the saved PNG artifact.
268
300
 
@@ -316,11 +348,22 @@ npm run check
316
348
  npm test
317
349
  ```
318
350
 
351
+ Run the credentialed Codex transport tests separately. They use the real
352
+ WebSocket service and ask the model to report all prior history markers after
353
+ each canonical and native continuation:
354
+
355
+ ```bash
356
+ mise run test:live:codex
357
+ ```
358
+
359
+ The task obtains the local Codex bearer token and runs the tests with
360
+ `gpt-5.6-luna` at medium reasoning effort.
361
+
319
362
  The focused Pi AI serializer copy lives under `extensions/openai-codex-compat/vendor/pi-ai/`. The custom Codex provider transport and stream parser are focused adaptations of Pi AI's corresponding implementation. Equivalence and protocol tests cover canonical serialization, native namespace round-trips, raw native replay, sibling Codex JSON endpoints, SSE request behavior, WebSocket reuse, grammar tools, image results, standalone search, and compaction continuation.
320
363
 
321
364
  ## Release staging
322
365
 
323
- The GitHub Actions workflow stages npm releases when a `v*` tag is pushed. The tag must match `package.json` version and point at a commit whose subject is `release: v<version>`.
366
+ The GitHub Actions workflow stages npm releases when a `v*` tag is pushed. The tag must match the `package.json` version, point at a commit whose subject is `release: v<version>`, and be a lightweight tag. Create it with `git tag v<version>`; do not use `git tag -a`, `git tag -s`, `git tag -m`, or `cog bump --annotated`.
324
367
 
325
368
  ## Acknowledgements
326
369
 
@@ -73,12 +73,11 @@ export default function registerApplyPatch(
73
73
  label: APPLY_PATCH_TOOL_NAME,
74
74
  description:
75
75
  "The `apply_patch` tool can be used to edit files. This is a FREEFORM tool, so do not wrap the patch in JSON.",
76
- promptSnippet: "Apply Codex-format patches to add, edit, move, or delete files",
76
+ promptSnippet: "Apply freeform patches to add, update, move, or delete files",
77
77
  promptGuidelines: [
78
- "Use apply_patch for local file edits.",
79
- "Do not create or edit files with cat or other shell write tricks.",
80
- "Formatting commands and bulk mechanical rewrites do not need apply_patch.",
81
- "Do not use Python to read or write files when a simple shell command or apply_patch is enough.",
78
+ "Use `apply_patch` for local file edits.",
79
+ "Do not create or edit files with `cat` or other shell write tricks.",
80
+ "Formatting commands and bulk mechanical rewrites do not need `apply_patch`.",
82
81
  ],
83
82
  parameters: Type.Object({
84
83
  patch: Type.String({ description: "Raw patch text beginning with *** Begin Patch" }),
@@ -0,0 +1,9 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
4
+
5
+ export function codexCacheKey(sessionId: string | undefined): string | undefined {
6
+ if (sessionId === undefined) return undefined;
7
+ if (Array.from(sessionId).length <= OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH) return sessionId;
8
+ return createHash("sha256").update(sessionId, "utf8").digest("hex");
9
+ }
@@ -269,7 +269,7 @@ export function remoteCompactionPayload(options: {
269
269
  modelId: string;
270
270
  history: readonly ResponsesItem[];
271
271
  instructions: string;
272
- sessionId: string;
272
+ sessionId?: string | undefined;
273
273
  fallbackTools?: unknown[] | undefined;
274
274
  priority: boolean;
275
275
  }): JsonRecord {
@@ -290,7 +290,8 @@ export function remoteCompactionPayload(options: {
290
290
  typeof payload.parallel_tool_calls === "boolean" ? payload.parallel_tool_calls : true;
291
291
  payload.tool_choice ??= "auto";
292
292
  payload.include = [...new Set([...include, "reasoning.encrypted_content"])];
293
- payload.prompt_cache_key = options.sessionId;
293
+ if (options.sessionId) payload.prompt_cache_key = options.sessionId;
294
+ else delete payload.prompt_cache_key;
294
295
  payload.text =
295
296
  isObject(payload.text) && typeof payload.text.verbosity === "string"
296
297
  ? { verbosity: payload.text.verbosity }