pi-openai-toolkit 0.13.0 → 0.14.0

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/README.md CHANGED
@@ -1,379 +1,246 @@
1
- # pi-openai-toolkit
2
-
3
- <p align="center">
4
- <strong>OpenAI-focused toolkit for <a href="https://github.com/earendil-works/pi">Pi</a>: Codex Remote Context Management, Remote Compaction v2, Hosted Web Search, Native Image Generation &amp; Model-Reviewed Auto Mode</strong>
5
- </p>
6
-
7
- <p align="center">
8
- <a href="./README.md">English</a> | <a href="./README_zh.md">简体中文</a>
9
- </p>
10
-
11
- ---
12
-
13
- `pi-openai-toolkit` is an all-in-one OpenAI enhancement package for **Pi (>= 0.85.1)**. It bundles five extensions designed for OpenAI Responses endpoints:
14
-
15
- 1. **Remote Responses Compaction v2 + Codex Remote Context Management** (`extensions/compaction.ts`): Two long-context strategies. Remote Context management (`compaction.contextManagement: "remote"`) ports Codex's native window system to Pi: a no-summary `new_context` rollover gated on a real notes checkpoint, cross-window `history` / `notes` tools with encrypted argument transport, `get_context_remaining` budgeting, and configurable context reminders — over native Codex OAuth or an allowlisted Codex-compatible gateway. When it is off, the toolkit falls back to server-side opaque `remote_compaction_v2` SSE compaction, which preserves context fidelity without lossy text re-summarization.
16
- 2. **Model-Scoped Web Search** (`extensions/web-search.ts`): Toolkit-owned hosted Web Search for an exact `provider/model-id` allowlist configured with `webSearch.models`, across the supported `openai-responses` and `openai-codex-responses` APIs.
17
- 3. **Native Image Generation** (`extensions/image-generation.ts`): A sequential local tool backed by the hosted Responses `image_generation` tool. It supports text-to-image and explicit local-reference edits while keeping binary image data out of session history.
18
- 4. **Model-Reviewed Auto Mode** (`extensions/auto-mode.ts`): Pi does not prompt before running tools. Auto mode adds a gate on state-changing tool calls and lets a reviewer model you configure approve or deny each one, so the agent keeps working without interrupting you.
19
- 5. **Codex GPT-6 Astra Compatibility** (`extensions/codex-astra.ts`): Sends the Codex backend version-gate header on live requests and keeps prompt caching alive across thinking-level changes on `gpt-6-astra` by carrying later effort changes as `configuration_update` transcript items.
20
-
21
- ## Installation
22
-
23
- Requires **Pi >= 0.85.1** and **Node.js >= 22.19.0**; older Pi versions are not supported. Pi supplies the GPT-6 Astra catalog and OpenAI API Key/Codex subscription login; Toolkit does not implement a separate login flow.
24
-
25
- ### Install the published package globally (recommended)
26
-
27
- ```bash
28
- pi install npm:pi-openai-toolkit
29
- ```
30
-
31
- This adds the package to Pi's global settings. Verify the installation with:
32
-
33
- ```bash
34
- pi list
35
- ```
36
-
37
- To install it only for the current project, use:
38
-
39
- ```bash
40
- pi install npm:pi-openai-toolkit --local
41
- ```
42
-
43
- ### Git installation (alternative / development)
44
-
45
- ```bash
46
- pi install git:github.com/awoaCrim/pi-openai-toolkit
47
- ```
48
-
49
- ### Local Development / Testing
50
-
51
- Load the complete toolkit:
52
-
53
- ```bash
54
- pi --no-extensions -e /absolute/path/to/pi-openai-toolkit
55
- ```
56
-
57
- Or load a single extension independently:
58
-
59
- ```bash
60
- # Compaction only
61
- pi --no-extensions -e /absolute/path/to/pi-openai-toolkit/extensions/compaction.ts
62
-
63
- # Web Search only
64
- pi --no-extensions -e /absolute/path/to/pi-openai-toolkit/extensions/web-search.ts
65
-
66
- # Image generation only
67
- pi --no-extensions -e /absolute/path/to/pi-openai-toolkit/extensions/image-generation.ts
68
-
69
- # Auto mode only
70
- pi --no-extensions -e /absolute/path/to/pi-openai-toolkit/extensions/auto-mode.ts
71
- ```
72
-
73
- ```bash
74
- # Load only the Codex Astra compatibility layer
75
- pi --no-extensions -e /absolute/path/to/pi-openai-toolkit/extensions/codex-astra.ts
76
- ```
77
-
78
- > ⚠️ **Conflict Warning**: Do not run `pi-remote-compact`, `@lll9p/pi-better-compaction`, or standalone `pi-openai-web-search` alongside `pi-openai-toolkit`. Duplicate hooks cause race conditions and duplicated system prompts.
79
-
80
- ---
81
-
82
- ## Configuration
83
-
84
- Configuration file location:
85
-
86
- ```text
87
- ~/.pi/agent/extensions/pi-openai-toolkit/config.json
88
- ```
89
-
90
- On Windows:
91
-
92
- ```text
93
- C:\Users\<user>\.pi\agent\extensions\pi-openai-toolkit\config.json
94
- ```
95
-
96
- ### Example `config.json`
97
-
98
- ```json
99
- {
100
- "compaction": {
101
- "enabled": true,
102
- "contextManagement": "off",
103
- "codexGatewayModels": [],
104
- "allowCompactionContinuityBreak": false,
105
- "remoteCompactModel": "uwoacrimson/gpt-5.6-luna",
106
- "nativeFallback": {
107
- "enabled": true,
108
- "model": null,
109
- "thinkingLevel": "off"
110
- },
111
- "responsesApis": [
112
- "openai-responses",
113
- "openai-codex-responses"
114
- ],
115
- "notifyOnLoad": false,
116
- "debug": false,
117
- "logProviderPayloads": false,
118
- "logCompactResponses": false,
119
- "redactSensitiveData": true,
120
- "artifactRoot": "~/.pi/agent/artifacts/pi-openai-toolkit/compaction"
121
- },
122
- "webSearch": {
123
- "enabled": true,
124
- "models": [
125
- "uwoacrimson/gpt-5.6-luna"
126
- ]
127
- },
128
- "imageGeneration": {
129
- "enabled": false
130
- },
131
- "autoMode": {
132
- "enabled": true,
133
- "models": [
134
- "uwoacrimson/gpt-5.6-luna"
135
- ],
136
- "reviewerModel": "uwoacrimson/gpt-5.6-luna",
137
- "gate": "side-effect",
138
- "extraTools": [
139
- "openai_generate_image"
140
- ],
141
- "timeoutMs": 30000,
142
- "transcript": true,
143
- "evidenceTools": true,
144
- "maxEvidenceRounds": 3,
145
- "classifier": {
146
- "enabled": false,
147
- "model": "uwoacrimson/gpt-5.6-luna",
148
- "timeoutMs": 15000,
149
- "maxLag": 2
150
- },
151
- "circuitBreaker": {
152
- "consecutiveDenials": 3,
153
- "recentDenials": 10,
154
- "windowSize": 50
155
- }
156
- },
157
- "codexAstra": {
158
- "enabled": true,
159
- "models": [
160
- "openai-codex/gpt-6-astra"
161
- ]
162
- }
163
- }
164
- ```
165
-
166
- ### Configuration Options
167
-
168
- #### `compaction`
169
-
170
- - `enabled` (*boolean*, default: `true`): Enable or disable toolkit compaction hooks.
171
- - `contextManagement` (*`"off" | "remote"`*, default: `"off"`): Opt into Codex Remote Context management. `"remote"` is active for the native `openai-codex` / `openai-codex-responses` route, or for an exact entry in `codexGatewayModels` whose model resolves to `uwoacrimson` / `openai-responses`. Native mode reuses Pi's existing Codex OAuth through `ModelRegistry`; gateway mode uses the configured data-plane API key and does not derive or forward a local Codex account ID. Remote windows use Codex history/notes, retain the full Pi JSONL session, and do not generate ordinary summaries. While active, this feature owns context rollover and disables this package's `remote_compaction_v2` request. Set it back to `"off"` or clear the allowlist to roll back to the existing compaction behavior. Remote backend failures are surfaced; they never silently fall back to Local context management.
172
- - `codexGatewayModels` (*string[]*, default: `[]`): Exact `provider/model-id` entries allowed to use the NEWapi/CPA Codex gateway, for example `"uwoacrimson/gpt-5.6-luna"`. Entries are opt-in, trimmed, and matched exactly; the gateway sends the bare model ID in `X-Codex-Model` and keeps the configured `/v1` base URL. An empty list disables gateway Remote Context.
173
- - `allowCompactionContinuityBreak` (*boolean*, default: `false`): When `true`, allows restarting a fresh native opaque compaction chain from Pi's current session text if the latest compaction was made by another strategy (e.g. text summary).
174
- - `remoteCompactModel` (*string | null*, default: `null`): Model formatted as `provider/model-id` used only for the synthetic `remote_compaction_v2` request. Pi's active session model is not switched and resumes normal requests after compaction. The override must resolve to the same effective base URL as the active model; provider, Responses API identifier, and model may differ. `null` preserves the current same-model path.
175
- - `nativeFallback.enabled` (*boolean*, default: `true`): Master switch for toolkit-driven native compaction with an explicit summary model. It never touches the remote chain: `remote_compaction_v2` is still attempted and still wins when it succeeds. When `false`, only the post-failure native step is skipped, so every fallback falls straight through to Pi's own default compaction with the active model.
176
- - `nativeFallback.model` (*string | null*, default: `null`): Summary model formatted as `provider/model-id` (e.g. `"openai/gpt-4o-mini"`) used **only** when the active model cannot use remote v2 at all (non-Responses API, or an API excluded by `responsesApis`). It is never consulted once a remote request was attempted, and `null` means the active model runs Pi's default compaction path.
177
- - `nativeFallback.thinkingLevel` (*string*, default: `"off"`): Reasoning / thinking level passed to Pi's native `compact()` whenever this extension supplies the model (`"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`, `"max"`).
178
- - `responsesApis` (*string[]*): Narrow the supported remote compaction API identifiers (subset of `["openai-responses", "openai-codex-responses"]`). This setting applies only when `contextManagement` is `"off"`.
179
- - `notifyOnLoad` (*boolean*, default: `false`): Show a notification banner on Pi startup.
180
- - `debug` (*boolean*, default: `false`): Output diagnostics and write execution artifacts to disk.
181
- - `logProviderPayloads` / `logCompactResponses` (*boolean*, default: `false`): Write raw provider request payloads and compact SSE event bodies to artifacts.
182
- - `redactSensitiveData` (*boolean*, default: `true`): Apply full sensitive-value redaction to debug artifacts. Authorization credentials, API keys/tokens, Codex account IDs, and opaque `encrypted_content` / `encrypted_output` are always redacted even when this option is `false`.
183
- - `artifactRoot` (*string*): Directory root for diagnostic artifacts. Relative paths resolve against the config directory.
184
- - `contextReminderThresholdPercent` (*integer*, default: `5`, range `0`-`100`): Remote Context only. When tokens remaining in the current window drop below this percentage of the context window, the toolkit injects a checkpoint reminder once per window; at `0` reminders are disabled (the exhausted-window fallback still fires). Set it comfortably above Pi's native reserve band so the model gets a chance to roll the window over before the native threshold is reached.
185
-
186
- ### Recommended Remote Context configuration
187
-
188
- To run Codex Remote Context management on this gateway setup:
189
-
190
- ```json
191
- {
192
- "compaction": {
193
- "enabled": true,
194
- "contextManagement": "remote",
195
- "codexGatewayModels": ["uwoacrimson/gpt-6-astra"],
196
- "contextReminderThresholdPercent": 10
197
- }
198
- }
199
- ```
200
-
201
- Two operational notes:
202
-
203
- - **Disable Pi's native compaction for Remote-managed sessions.** While `contextManagement` is `"remote"` and the model is covered (native Codex, or listed in `codexGatewayModels`), the toolkit already cancels every Pi-native compaction attempt — threshold, manual `/compact`, and overflow — so no lossy summary can slip in behind its back. If you also want belt-and-braces at the host level, set `"compaction": { "enabled": false }` in Pi's `~/.pi/agent/settings.json`; models outside the Remote coverage still compact normally with Pi's own policy either way.
204
- - **`new_context` cannot discard unsaved state silently.** The tool refuses to roll over unless the current window contains a *successful* `notes` `append_to_file` / `write_file` (read-only notes calls and failed writes do not count; the check is rebuilt from the session branch, so it survives restarts and resumes). `force: true` bypasses the gate for explicit user-authorized discards, and the toolkit's own exhausted-context fallback path bypasses it automatically.
205
-
206
- #### Remote Context protocol notes
207
-
208
- When `compaction.contextManagement` is `"remote"`, the toolkit activates `new_context`, `get_context_remaining`, `history`, and `notes` for the native Codex route or an exact allowlisted gateway model. History and notes use the alpha `alpha/history/v2/*` and `alpha/notes/v2/*` endpoints, including encrypted argument policy headers for search and note writes. `new_context` accepts an optional `force` flag; without a successful notes checkpoint in the current window it refuses unless `force` is set (see Recommended Remote Context configuration). Gateway requests carry the same bounded session ID, affinity scope, and bare model hint as live Responses requests; the gateway never receives local OAuth credentials or account cookies. The request carries the current window and turn metadata; timeout, abort, non-2xx, malformed JSON, authentication, and protocol failures are explicit tool errors. For covered models the toolkit also cancels Pi's native compaction while the Remote runtime is inactive, so no lossy summary is produced behind its back; fix the activation reason shown in the notification instead. The protocol is based on `@howaboua/pi-codex-conversion@3.0.29` source commit `7021ae48e8efe36a3becc5830d529696ff798e5e`; these alpha endpoints may change and the endpoint/header fixtures must be updated together.
209
-
210
- #### `webSearch`
211
-
212
- - `enabled` (*boolean*, default: `true`): Enable or disable native OpenAI Web Search injection.
213
- - `models` (*string[]*): Exact `provider/model-id` allowlist. Toolkit Web Search is used only for listed models running on `openai-responses` or `openai-codex-responses`. An empty list disables toolkit Web Search for all models.
214
-
215
- #### `imageGeneration`
216
-
217
- - `enabled` (*boolean*, default: `false`): The single opt-in switch for the `openai_generate_image` local tool. It defaults to off because every successful provider request may incur a charge.
218
-
219
- There is no model allowlist: the hosted `image_generation` tool is a capability of the Responses API, not of one vendor's model. Setting `enabled: true` exposes the tool to every active model whose API is `openai-responses` or `openai-codex-responses`, and hides it everywhere else. Web Search and compaction keep their own independent model allowlists.
220
-
221
- The request uses the current model's resolved Responses endpoint, authentication, and headers, while the hosted image tool itself is fixed to `gpt-image-2`; Pi does not switch the active conversation model. A gateway that does not support the hosted image tool still registers the tool and returns a bounded failure at call time; nothing is retried automatically.
222
-
223
- #### `autoMode`
224
-
225
- - `enabled` (*boolean*, default: `true`): Master switch. With `true` the mode can still never engage until you allowlist a model and set a reviewer.
226
- - `models` (*string[]*, default: `[]`): Exact `provider/model-id` allowlist of **active session models** permitted to run in auto mode. An empty list disables auto mode everywhere.
227
- - `reviewerModel` (*string | null*, default: `null`): The approving model, formatted as `provider/model-id`. It is resolved through Pi's model registry and must exist there; it is used only for one-off review requests and never becomes the active conversation model. Auto mode cannot engage while this is unset.
228
- - `gate` (*`"side-effect" | "all"`*, default: `"side-effect"`): `side-effect` reviews `bash`, `write`, and `edit`; `all` reviews every tool call, including read-only tools.
229
- - `extraTools` (*string[]*, default: `[]`): Additional tool names reviewed on top of the `side-effect` default set, for example `openai_generate_image` or an MCP tool name.
230
- - `timeoutMs` (*integer*, default: `30000`, range `1000`-`120000`): Reviewer deadline across all of its rounds. Expiry never becomes approval.
231
- - `transcript` (*boolean*, default: `true`): Send the reviewer a bounded view of the conversation. Without it the reviewer can only judge the action's intrinsic risk and must treat user authorization as `unknown`.
232
- - `evidenceTools` (*boolean*, default: `true`): Let the reviewer spend read-only tool calls (`read`, `grep`, `find`, `ls`) establishing facts before it decides. These are Pi's own read-only tools executed by this extension; the reviewer is never given `bash`, `write`, `edit`, or network access.
233
- - `maxEvidenceRounds` (*integer*, default: `3`, range `0`-`8`): How many investigation rounds the reviewer may take before it must answer. `0` disables tools and keeps a single completion.
234
- - `classifier.enabled` (*boolean*, default: `false`): Opt in to a non-blocking trajectory pre-scorer that can satisfy an ordinary gated call from a cached low-risk classification instead of waiting for a full review. It is off by default because it adds one model call per gated tool result.
235
- - `classifier.model` (*string | null*): Classifier model as `provider/model-id`; falls back to `reviewerModel`. A classifier only ever defers to the blocking reviewer; it cannot approve on its own beyond a cached low-risk fast path, and it never denies.
236
- - `classifier.timeoutMs` (*integer*, default: `15000`) and `classifier.maxLag` (*integer*, default: `2`, range `0`-`20`): A score older than `maxLag` tool calls, or older than the last user turn, is stale and forces the blocking review.
237
- - `circuitBreaker.consecutiveDenials` (*integer*, default: `3`, `0` disables): Reviewer denials in a row that end the turn instead of letting the agent keep negotiating.
238
- - `circuitBreaker.recentDenials` (*integer*, default: `10`, `0` disables) and `circuitBreaker.windowSize` (*integer*, default: `50`, range `1`-`200`): Denials inside the last N reviewed calls that end the turn. This catches a scattered denial rate that never forms a consecutive run.
239
-
240
- Auto mode is opt-in through the empty-by-default `models` allowlist because it authorizes a model to approve writes and shell commands on your behalf. Enable it for a session with `pi --auto` or `/auto on`, and use `/auto all` to review every tool at once. See [Core Mechanics](#core-mechanics) section 5 for the exact decision and fallback rules.
241
-
242
- #### `codexAstra`
243
-
244
- - `enabled` (*boolean*, default: `false`): Master switch for the GPT-6 Astra compatibility layer: the Codex backend version-gate header on live requests, and the stable-effort `configuration_update` rewrite described in section 6 of Core Mechanics.
245
- - `models` (*string[]*, default: `[]`): Exact `provider/model-id` allowlist of models that accept the `configuration_update` input item. Only Astra-era models answer it correctly (today `["openai-codex/gpt-6-astra"]`, or your gateway's equivalent key such as `"uwoacrimson/gpt-6-astra"`); the rewrite is never applied to any other model, and the version header applies to all `openai-codex-responses` requests regardless of this list.
246
-
247
- ---
248
-
249
- ## Core Mechanics
250
-
251
- ### 0. Codex Remote Context Management
252
-
253
- When `compaction.contextManagement` is `"remote"` and the session's model is covered — native `openai-codex` / `openai-codex-responses`, or an exact `provider/model-id` entry in `codexGatewayModels` resolving to `uwoacrimson` / `openai-responses` — the toolkit replaces summarization-based compaction with Codex's native context-window lifecycle:
254
-
255
- - **Window identity.** `session_start` initializes a context window (first / current / previous window id, window number) and persists each boundary as a `codex-context-window` custom message in the Pi session, replayed on resume and reconstructed after forks. Every live request carries the window and turn identity through `x-codex-window-id` / `x-codex-turn-metadata`.
256
- - **No-summary rollover.** `new_context` installs a fresh window and trims the previous one from the model context; nothing is re-summarized, so no lossy text survives in place of the conversation. The old turns remain retrievable server-side through `history`.
257
- - **Checkpoint gate.** A rollover requires a successful `notes` write inside the current window, verified against the persisted session branch; without it, `new_context` refuses and tells the model to checkpoint first. This is a hard guard against the failure mode where a notes backend is down and a rollover silently discards live working state. `force: true` and the exhausted-context fallback path are the only ways past the gate, and the fallback message instructs a single last notes write before rollover.
258
- - **Cross-window memory.** `history` (`list_windows`, `list_items`, `read_item`, `search_contents`) and `notes` (`list_files_by_prefix`, `read_file`, `search_contents`, `append_to_file`, `write_file`) hit the alpha Codex backend endpoints with encrypted tool arguments and encrypted result handling; note paths resolve under the session agent (`/root/notes/...`). After a rollover, a server-side thread hint points the model at the notes that hold the live task state.
259
- - **Budget.** `get_context_remaining` reports the remaining window budget; `contextReminderThresholdPercent` injects the checkpoint reminder once per window as remaining tokens fall below the configured percentage of the context window.
260
- - **Ownership of compaction.** While configured for a covered model, the toolkit owns all compaction events: Pi-native compaction is cancelled even when the Remote runtime is inactive (the reason is surfaced as a notification, e.g. a tool-name conflict or OAuth resolution failure), and `remote_compaction_v2` is never sent. Set `contextManagement` back to `"off"` or clear the allowlist to restore the previous behavior.
261
-
262
- ### 1. Remote Compaction v2 Protocol
263
-
264
- Instead of legacy JSON endpoints (`POST /responses/compact`), this toolkit implements the **`remote_compaction_v2`** protocol over standard streaming Responses:
265
-
266
- ```http
267
- POST /responses
268
- Content-Type: application/json
269
-
270
- {
271
- "model": "...",
272
- "input": [
273
- ...currentResponsesInput,
274
- { "type": "compaction_trigger" }
275
- ],
276
- "stream": true,
277
- "store": false
278
- }
279
- ```
280
-
281
- - **Validation Criteria**: Must return a valid SSE stream with `response.completed` (status `completed`) containing exactly one output item of `type: "compaction"` with non-empty `encrypted_content`.
282
- - **Remote Model Override**: `compaction.remoteCompactModel` can assign a same-gateway Responses model as the checkpoint producer while the active model remains the consumer. Its registered model metadata, authentication, headers, and effective base URL are used only for the synthetic compact request. Existing and recursive checkpoints remain replayable by the active model.
283
- - **Zero Loss Replay**: The opaque encrypted item is stored in `CompactionEntry.details.compactedWindow`. On subsequent requests, it is transparently prepended after fresh preamble instructions alongside live turns, eliminating lossy text re-summaries.
284
- - **Fail-Closed Replay Guard**: Replay anchors on the Pi-authored compaction summary item by content and replaces it with the opaque compacted window; the post-compaction context is preserved verbatim, so transient messages injected by other extensions no longer block replay. If the summary anchor cannot be found, the toolkit aborts the provider request, shows an error notification, and always writes a content-free `*-replay-failure.json` artifact even when `logProviderPayloads` is disabled. The sentinel-only payload is never sent to the model.
285
- - **Graceful Multi-Tier Fallback**:
286
- 1. Compatible Responses endpoints &rarr; Remote v2 Opaque Compaction.
287
- 2. Remote request attempted but failed on a model that *can* compact remotely &rarr; Pi's native `compact()` with `remoteCompactModel`, or the active model when no override is configured;
288
- 3. Model that cannot use remote v2 at all &rarr; Pi's native `compact()` with `compaction.nativeFallback.model`, or the active model when unset;
289
-
290
- ### 2. Pi-Native Auto-Compaction and Continuation
291
-
292
- **Pi 0.85.1+** owns automatic compaction. After tool results are appended and before the next assistant request, Pi checks its threshold, compacts eligible history and continues in the same run. Toolkit only supplies Remote v2 results and opaque replay through public hooks: no private host patches, extra compaction driver or hidden follow-up messages.
293
-
294
- - Configure `compaction.enabled`, `compaction.reserveTokens` and `compaction.keepRecentTokens` in Pi's `~/.pi/agent/settings.json` or project `.pi/settings.json`.
295
- - When Pi disables automatic compaction or has no eligible history, Toolkit does not start another driver. Manual `/compact` still uses the existing remote/native fallback chain.
296
- - The retired Toolkit `compaction.autoCompaction` setting is ignored as an unknown field; your settings file is not rewritten.
297
- - Remote v2 covers the complete compact input. A public `context` hook removes verified retained copies before encoding; persisted history is unchanged and new/transient messages survive.
298
- - Cache parameters follow Pi's actual selection: applicable GPT-5.6+ long-cache requests retain `prompt_cache_options.ttl: "30m"`, while those models retain `mode: "explicit"` when caching is disabled. Toolkit does not force long caching on every request, and a different compactor only receives supported cache fields.
299
-
300
- ### 3. Model-Scoped Web Search
301
-
302
- For allowlisted models using `openai-responses` or `openai-codex-responses`, the extension hooks into `before_provider_request` and `before_agent_start`:
303
-
304
- - Injects `{ "type": "web_search" }` tool definition into the payload.
305
- - Appends `web_search_call.action.sources` to the Responses `include` array.
306
- - Appends concise search prompting to the system instructions.
307
- - **Zero-Latency**: Uses Pi's existing connection, auth headers, and base URL without standalone HTTP overhead.
308
- - **Toolkit Ownership**: For an eligible model, the outgoing payload removes the local function tool named `web_search` so native search is the only search path. Switching to an ineligible model restores that local tool's previous active state.
309
-
310
- ### 4. Native Image Generation and Editing
311
-
312
- When `imageGeneration.enabled` is `true` and the active model speaks a Responses API, Pi exposes the sequential `openai_generate_image` tool:
313
-
314
- - **Isolated request**: Sends one non-streaming, `store: false` Responses request containing only the image prompt and explicitly approved references. It does not forward recent conversation history and does not automatically retry after dispatch, avoiding accidental duplicate charges.
315
- - **Generation and editing**: Supports text-to-image or editing with 1-5 explicitly supplied local PNG, JPEG, or WebP reference paths. Reference upload always requires interactive confirmation; headless sessions reject reference uploads.
316
- - **Same route, fixed image model**: Reuses the current model's effective base URL, authentication, and provider headers, but requests the hosted `gpt-image-2` tool. It does not use a separate Codex OAuth flow or switch the active Pi model.
317
- - **PNG artifacts**: Validates the returned PNG and saves it under `<Pi agent dir>/generated-images/<session-id>/<image-call-id>.png`. Existing files are never overwritten.
318
- - **Safe optional copy**: A relative output path is allowed only in a trusted project. Paths outside both the trusted project and Pi agent directory require interactive confirmation. Output is PNG-only and existing destinations are rejected.
319
- - **Compact session data**: Tool results contain paths and bounded metadata, never image base64. The Pi TUI preview reads the canonical artifact from disk when image display is supported; deleting the artifact removes the preview. Explicit reference path strings remain part of the tool-call arguments, but reference bytes do not.
320
- - **Headless behavior**: Text-to-image with the default artifact path remains available without a UI. Reference uploads and external output paths that require approval are rejected in headless sessions.
321
- - **Billing and verification boundary**: The configured gateway/provider remains the billing authority; the tool does not synthesize Pi usage or cost metadata. Deterministic tests and smoke checks never dispatch image generation, and no live paid probe runs without separate explicit approval.
322
-
323
- ### 5. Model-Reviewed Auto Mode
324
-
325
- Pi does not prompt before running `bash`, `write`, or `edit`; the only built-in trust prompt concerns project-local settings. This extension adds the approval gate and lets a reviewer model operate it, mirroring Codex's `approval_policy` plus `approvals_reviewer` pairing.
326
-
327
- - **Engagement is non-blocking**: `pi --auto`, `/auto on`, and `/auto all` only flip in-session state and update the footer status. No provider request happens at engagement time, so turning the mode on can never stall the current turn.
328
- - **Gate scope**: `side-effect` reviews `bash`, `write`, and `edit`; `extraTools` adds named tools; `/auto all` (or `gate: "all"`) reviews every tool call. Read-only tools pass through untouched in the default scope.
329
- - **Two independent axes, one derived outcome**: The reviewer scores the action's intrinsic risk (`low`/`medium`/`high`/`critical`) separately from how far the conversation actually authorizes it (`unknown`/`low`/`medium`/`high`), then derives `allow`/`deny` from a fixed table: `low` and `medium` risk are allowed, `high` requires at least `medium` authorization and a narrow scope, `critical` is always denied. Judging only "does this command look dangerous" is what makes an approval reviewer rubber-stamp or block everything.
330
- - **Bounded transcript**: The reviewer receives a compact view of the conversation built from Pi's session entries, with user turns protected under their own budget and tool output on a smaller separate one, so verbose command output cannot crowd out the human turns that establish authorization. Omitted history is marked `<truncated />` rather than silently dropped, and only `[user]` entries count as evidence of approval.
331
- - **The reviewer can investigate**: When `evidenceTools` is on, the reviewer runs as a short bounded agent loop over Pi's read-only tools (`read`, `grep`, `find`, `ls`). It can open the script it is about to allow, check whether a deletion target exists or is empty, or confirm a write path lies inside the project. This extension executes those calls; the reviewer is never handed `bash`, a write tool, or network access, which is what keeps "let the judge look around" safe.
332
- - **Lenient verdict contract**: Only the outcome is required. `{"outcome":"allow"}` is a complete answer; risk, authorization, and rationale are back-filled (an unstated risk on a deny is recorded as `high`, which keeps the audit conservative in the direction that matters). Both `outcome`/`rationale` and the older `decision`/`reason` spelling are accepted. Unreadable output is a failure, never a guess.
333
- - **Untrusted evidence stays untrusted**: Tool arguments, transcript text, and file contents are labelled as data. Claims of prior approval, urgency, or instructions to answer a particular way inside them are ignored by policy.
334
- - **Optional non-blocking pre-scorer**: With `classifier.enabled`, a cheap single-token classification (`high`/`low`) of the trajectory runs after each gated tool result. A fresh `low` score satisfies the next gated call without waiting for a full review; `high`, a stale score, a failed sample, or a repeat of a tool already denied this turn all fall through to the blocking reviewer. The classifier can never deny anything.
335
- - **Denials carry an anti-circumvention clause**: A block returns the risk, the authorization, and the reviewer's reason to the requesting model, plus an explicit prohibition on achieving the same outcome by workaround, renaming, splitting, or indirect execution. The model may take a materially safer alternative or ask you.
336
- - **A review that did not finish is not a safety verdict**: Timeout, cancellation, provider error, and unreadable output each report their own cause and tell the agent not to infer unsafety from the failure. Only an actual `deny` is worded as a rejection.
337
- - **Rejection circuit breaker**: Repeated denials in one turn end the turn rather than letting the agent and reviewer negotiate indefinitely, on either a consecutive run or a denial rate inside a sliding window. `turn_start` clears the counters.
338
- - **Human fallback**: When a review is unavailable in an interactive session, the extension asks you directly with the failure reason. In print (`-p`) and JSON mode there is nobody to ask, so the action fails closed and is blocked.
339
- - **Eligibility is rechecked live**: Switching to a model outside `autoMode.models`, clearing `reviewerModel`, or setting `enabled: false` disengages immediately. Returning to an allowlisted model does not re-engage automatically; you must ask again with `/auto on`.
340
- - **Bounded audit trail**: Every decision is persisted as a custom session entry (`pi-openai-toolkit.auto-mode-decision.v1`) containing the tool name, call id, decision, bounded rationale, reviewer model, risk level, user authorization, investigation rounds used, and decision source (`reviewer`, `classifier`, `human`, `policy`, or `circuit-breaker`). Custom entries never enter LLM context, and tool arguments are not recorded.
341
- - **Cost boundary**: Each gated call costs at least one reviewer completion, and enabling `evidenceTools` lets that review expand into up to `maxEvidenceRounds` extra completions. The pre-scorer adds one small completion per gated tool result when enabled. Reviewer completions run with prompt caching disabled, and the reviewer can execute nothing beyond the read-only tools listed above.
342
-
343
- ### 6. Codex GPT-6 Astra Compatibility
344
-
345
- GPT-6 Astra is a Codex-backend (ChatGPT OAuth) model with two wire behaviors that a plain OpenAI client does not get for free. This layer covers both, adapted from Oh My Pi 18.1.8 (MIT).
346
-
347
- - **Backend version gate**: The Codex backend admits or hides model SKUs by the `version` header, and `gpt-6-astra` requires at least `0.153.0`. The extension sets that pin on every live `openai-codex-responses` request via `before_provider_headers` (only when the host has not set one), and the package's own synthetic requests - remote compaction v2, native compact v1, hosted image generation - carry the same pin from the shared header builder. The pinned value tracks the upstream `CODEX_CLIENT_VERSION`; when OpenAI raises the gate, that constant is what changes.
348
- - **Stable effort with `configuration_update`**: OpenAI prompt caching compares the request from the first byte, and the request-level `reasoning.effort` sits at the top - changing thinking level mid-conversation normally busts the whole cached prefix. Astra instead accepts a `configuration_update` input item that changes effort from that point onward while the request-level field stays put. This extension implements that for the active conversation: the first request pins the baseline effort, every later change is spliced into the transcript at the position it should take effect (before the user message it applies to, or after the latest tool result inside a tool loop), and the same item is replayed at that position on every following request. The request body keeps the baseline byte-stable, so the cache prefix survives level changes.
349
- - **History-rewrite safety**: Each spliced item is anchored to a fingerprint of the transcript position it was inserted at. If a later request's history no longer matches - compaction, branch switch, `/clear`, anything rewrote the transcript - the baseline is discarded and the next request re-pins its own effort, rather than placing an update at a stale position.
350
- - **Compaction isolation**: The compact endpoints reject histories containing `configuration_update` items. This is enforced in two places: the payload rewriter never splices items into a `compaction_trigger`-shaped request, and both compaction clients strip any such item defensively from replayed input, so an Astra session can still be compacted by this package.
351
- - **Scope**: The rewrite applies only to models listed in `codexAstra.models` on either Responses wire family (Astra is the only SKU known to accept the item; anything else answers HTTP 400 on it - the allowlist is what encodes that knowledge for gateways that proxy it), only when the request actually carries a wire-level effort, and never to `off`/`none`. Gateway pass-through was verified live: a `configuration_update` item placed before the user turn it applies to returned HTTP 200 with a completed response. Everything runs inside a try/catch: any unexpected payload shape or planner failure leaves the request untouched. To avoid double-splicing when both this toolkit and a host that implements the same behavior (Oh My Pi itself) are active, enable this layer on only one side.
352
-
353
- Catalog note: Pi's bundled `openai-codex` model list does not include `gpt-6-astra` yet. Register it in `~/.pi/agent/models.json` under the built-in provider (custom models merge into the built-in list): `api: "openai-codex-responses"`, `baseUrl: "https://chatgpt.com/backend-api"`, `contextWindow: 272000`, `maxTokens: 128000`, and a `thinkingLevelMap` exposing `low` through `max`. Pi's Codex OAuth login supplies the token; this package reads it through Pi's `ModelRegistry` and never touches the credential store directly.
354
-
355
- ---
356
-
357
- ## Development & Testing
358
-
359
- ```bash
360
- # Typecheck TypeScript definitions
361
- npm run typecheck
362
-
363
- # Run full test suite with Bun
364
- bun test
365
-
366
- # Run Pi integration smoke tests
367
- npm run test:pi
368
-
369
- # Dry-run package archive
370
- npm pack --dry-run
371
- ```
372
-
373
- ---
374
-
375
- ## License & Acknowledgments
376
-
377
- - Licensed under the **MIT License**. See [LICENSE](./LICENSE) for details.
378
- - Native Web Search behavior was adapted from [`code-yeongyu/pi-openai-web-search`](https://github.com/code-yeongyu/pi-openai-web-search) (commit `39643380682f02f306b0de2673ff136c45ccc2a2`). See [NOTICE](./NOTICE).
379
- - [LINUX DO](https://linux.do/) community.
1
+ # pi-openai-toolkit
2
+
3
+ [![npm version](https://img.shields.io/npm/v/pi-openai-toolkit.svg)](https://www.npmjs.com/package/pi-openai-toolkit)
4
+ [![license: MIT](https://img.shields.io/npm/l/pi-openai-toolkit.svg)](./LICENSE)
5
+
6
+ [简体中文](./README.zh.md)
7
+
8
+ OpenAI toolkit for Pi: Codex Remote Context windows, remote compaction v2, hosted Web Search, image gen, auto mode.
9
+
10
+ `pi-openai-toolkit` bundles five Pi extensions for the OpenAI Responses wire family (`openai-responses` and `openai-codex-responses`):
11
+
12
+ 1. **Compaction & Remote Context** (`extensions/compaction.ts`): two long-context strategies. [Codex Remote Context management](#codex-remote-context-management) ports Codex's native window lifecycle to Pi — no-summary `new_context` rollover with a hard notes-checkpoint gate, cross-window `history` / `notes` tools with encrypted argument transport, and budgeted checkpoint reminders. With it off, the extension runs **Remote Compaction v2**: server-side opaque encrypted compaction that never re-summarizes your conversation into lossy text.
13
+ 2. **Web Search** (`extensions/web-search.ts`): hosted `web_search` injection for an exact `provider/model-id` allowlist, reusing the live model connection.
14
+ 3. **Image Generation** (`extensions/image-generation.ts`): a local `openai_generate_image` tool backed by the hosted `image_generation` tool, for text-to-image and explicit local-reference edits without putting image bytes into session history.
15
+ 4. **Auto Mode** (`extensions/auto-mode.ts`): a reviewer-model approval gate on state-changing tool calls so the agent keeps working without interrupting you.
16
+ 5. **Codex Astra** (`extensions/codex-astra.ts`): Codex backend version-gate headers and cache-preserving `configuration_update` effort changes for `gpt-6-astra`. Activated silently by model id; no configuration section.
17
+
18
+ The package is a Pi extension set, not an importable library: everything is configured through one JSON file and activated automatically inside Pi.
19
+
20
+ ## Table of Contents
21
+ - [Security](#security)
22
+ - [Background](#background)
23
+ - [Install](#install)
24
+ - [Usage](#usage)
25
+ - [Configuration](#configuration)
26
+ - [Feature guides](#feature-guides)
27
+ - [Development](#development)
28
+ - [API](#api)
29
+ - [Remote Context tools](#remote-context-tools)
30
+ - [HTTP protocol reference](#http-protocol-reference)
31
+ - [Maintainers](#maintainers)
32
+ - [Contributing](#contributing)
33
+ - [License](#license)
34
+
35
+ ## Security
36
+
37
+ - **No silent lossy summaries on covered models.** While `contextManagement: "remote"` covers a model, Pi-native compaction is cancelled on every path (threshold, manual `/compact`, overflow) even if the remote runtime is inactive, and v2 is never sent. If you additionally want host-level belt-and-braces, set `"compaction": { "enabled": false }` in Pi's `settings.json`; uncovered models keep Pi's normal policy either way.
38
+ - **Gateway isolation.** Gateway-mode Remote Context forwards only the configured data-plane key; OAuth tokens, account cookies, and account ids are stripped, and artifacts always redact credentials, account ids, and opaque encrypted payloads.
39
+ - **Checkpoint gate.** `new_context` cannot discard unsaved working state without either a successful notes write in the window or an explicit `force` the user authorized — the failure mode reported against Codex's own experimental rollout is blocked here.
40
+ - **Billing and review boundaries.** Image generation is opt-in and may incur charges; auto mode reviews run with caching disabled, grant the reviewer read-only tools only, and fail closed in headless sessions.
41
+
42
+ ## Background
43
+
44
+ Pi's built-in compaction summarizes old turns into text, which loses detail; the OpenAI Codex backend instead offers two lossless mechanisms that plain clients do not get for free: the `remote_compaction_v2` SSE protocol (an encrypted opaque checkpoint replaces the summarized prefix) and the experimental **context-window system** (`new_context`, `history`, `notes`) that rolls the window over without any summary at all. This toolkit implements both against the live backends, verified end to end on Codex OAuth and on a Codex-compatible gateway relay (NEWapi + CLIProxyAPI).
45
+
46
+ Provenance: the Remote Context protocol was reverse-engineered from `@howaboua/pi-codex-conversion@3.0.29` (source commit `7021ae48e8efe36a3becc5830d529696ff798e5e`); the Astra compatibility layer is adapted from Oh My Pi 18.1.8 (MIT); Web Search behavior was adapted from [`pi-openai-web-search`](https://github.com/code-yeongyu/pi-openai-web-search) (commit `3964338`). Attribution details are in [NOTICE](./NOTICE). The alpha `history`/`notes` endpoints may change upstream without notice; endpoint and header fixtures in this repository must be updated together with them.
47
+
48
+ Requires **Pi >= 0.85.1** and **Node.js >= 22.19.0**. Pi supplies the model catalog and Codex/API-key login; this toolkit never implements its own login flow and never touches the credential store directly.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ pi install npm:pi-openai-toolkit
54
+ ```
55
+
56
+ This registers the package in Pi's global settings; verify with `pi list`. For a single project instead:
57
+
58
+ ```bash
59
+ pi install npm:pi-openai-toolkit --local
60
+ ```
61
+
62
+ From git (development or pinned builds):
63
+
64
+ ```bash
65
+ pi install git:github.com/awoaCrim/pi-openai-toolkit
66
+ ```
67
+
68
+ ### Updating
69
+
70
+ `pi update --extensions` updates Pi packages including this toolkit. Published versions are on [npm](https://www.npmjs.com/package/pi-openai-toolkit).
71
+
72
+ ### Conflict warning
73
+
74
+ Do not run `pi-remote-compact`, `@lll9p/pi-better-compaction`, or a standalone `pi-openai-web-search` alongside this toolkit: duplicate hooks cause race conditions and duplicated system prompts.
75
+
76
+ ## Usage
77
+
78
+ All features are controlled by one configuration file, plus per-session commands. With no config file present, compaction runs with its defaults; Web Search, image generation, auto mode, and Remote Context stay opt-in. The Astra compatibility layer and gateway Remote Context are keyed off the built-in `gpt-6-astra` model id, not off any allowlist.
79
+
80
+ Create `~/.pi/agent/extensions/pi-openai-toolkit/config.json` (Windows: `C:\Users\<user>\.pi\agent\extensions\pi-openai-toolkit\config.json`):
81
+
82
+ ```json
83
+ {
84
+ "compaction": {
85
+ "enabled": true,
86
+ "contextManagement": "remote",
87
+ "contextReminderThresholdPercent": 10,
88
+ "allowCompactionContinuityBreak": false,
89
+ "remoteCompactModel": "uwoacrimson/gpt-5.6-luna",
90
+ "nativeFallback": { "enabled": true, "model": null, "thinkingLevel": "off" },
91
+ "responsesApis": ["openai-responses", "openai-codex-responses"],
92
+ "notifyOnLoad": false,
93
+ "debug": false,
94
+ "logProviderPayloads": false,
95
+ "logCompactResponses": false,
96
+ "redactSensitiveData": true,
97
+ "artifactRoot": "~/.pi/agent/artifacts/pi-openai-toolkit/compaction"
98
+ },
99
+ "webSearch": { "enabled": true, "models": ["uwoacrimson/gpt-5.6-luna"] },
100
+ "imageGeneration": { "enabled": false },
101
+ "autoMode": {
102
+ "enabled": true,
103
+ "models": ["uwoacrimson/gpt-5.6-luna"],
104
+ "reviewerModel": "uwoacrimson/gpt-5.6-luna",
105
+ "gate": "side-effect"
106
+ }
107
+ }
108
+ ```
109
+
110
+ Then start Pi as usual; the toolkit loads automatically and hooks every session:
111
+
112
+ ```bash
113
+ pi --model uwoacrimson/gpt-6-astra "resume the deploy task"
114
+ ```
115
+
116
+ ### Configuration
117
+
118
+ Every key is optional; unknown keys are ignored with a warning rather than written back to your file. `models`-style keys are exact `provider/model-id` allowlists — trimming only, no globbing — so each feature is off until you list a model for it.
119
+
120
+ #### `compaction`
121
+
122
+ | Key | Type / default | Meaning |
123
+ | --- | --- | --- |
124
+ | `enabled` | *boolean*, `true` | Master switch for the compaction extension's hooks. |
125
+ | `contextManagement` | `"off"` \| `"remote"`, `"off"` | Opt into Codex Remote Context management. Covered models are native Codex models plus `gpt-6-astra` on a Codex-compatible gateway (`openai-responses`); the match is built in, there is no allowlist. While it owns a covered model, `remote_compaction_v2` is never sent and Pi-native compaction is cancelled (see [Security](#security)). Set back to `"off"` to roll back. |
126
+ | `contextReminderThresholdPercent` | *integer* `0`-`100`, `5` | Remote Context: inject the once-per-window checkpoint reminder when remaining tokens fall below this percentage of the context window. `0` disables reminders; the exhausted-window fallback still fires. Set it comfortably above Pi's native reserve band (default 16384 tokens ≈ 6% of a 272k window) so the model can roll over before the native threshold. |
127
+ | `allowCompactionContinuityBreak` | *boolean*, `false` | v2 path: restart a fresh opaque chain from current session text when the latest compaction was made by another strategy (e.g. a text summary). |
128
+ | `remoteCompactModel` | *string \| null*, `null` | v2 path: `provider/model-id` used only for the synthetic `remote_compaction_v2` request; the session model never switches. Must resolve to the same effective base URL as the active model. |
129
+ | `nativeFallback.enabled` | *boolean*, `true` | Toolkit-driven native compaction with an explicit summary model when the remote request was attempted and failed. Never touches a successful remote chain. |
130
+ | `nativeFallback.model` | *string \| null*, `null` | Summary model for models that cannot use v2 at all (non-Responses API, or excluded via `responsesApis`). `null` keeps the active model. |
131
+ | `nativeFallback.thinkingLevel` | *string*, `"off"` | Thinking level passed to Pi's `compact()` when this extension supplies the model (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`). |
132
+ | `responsesApis` | *string[]*, both APIs | Narrow which Responses API identifiers may use remote compaction. Applies only when `contextManagement` is `"off"`. |
133
+ | `notifyOnLoad` | *boolean*, `false` | Startup notification banner. |
134
+ | `debug` | *boolean*, `false` | Write lifecycle and compaction artifacts under `artifactRoot`, including the Remote Context activation reason per `session_start`. |
135
+ | `logProviderPayloads` / `logCompactResponses` | *boolean*, `false` | Additionally write raw provider request payloads and compact SSE bodies to artifacts. Keep off unless inspecting a specific request. |
136
+ | `redactSensitiveData` | *boolean*, `true` | Full artifact redaction. Authorization credentials, API keys/tokens, Codex account ids, and opaque `encrypted_content` / `encrypted_output` are always redacted even when this is `false`. |
137
+ | `artifactRoot` | *string*, `~/.pi/agent/artifacts/pi-openai-toolkit/compaction` | Artifact directory root; relative paths resolve against the config directory. |
138
+
139
+ #### `webSearch`
140
+
141
+ | Key | Type / default | Meaning |
142
+ | --- | --- | --- |
143
+ | `enabled` | *boolean*, `true` | Master switch. |
144
+ | `models` | *string[]*, `[]` | Exact allowlist of `provider/model-id` sessions that receive hosted `web_search` injection on `openai-responses` / `openai-codex-responses`. For a listed model the local `web_search` function tool is removed from the payload so native search is the only path; switching away restores it. |
145
+
146
+ #### `imageGeneration`
147
+
148
+ | Key | Type / default | Meaning |
149
+ | --- | --- | --- |
150
+ | `enabled` | *boolean*, `false` | Single opt-in switch for the `openai_generate_image` tool. Off by default because every successful request may incur a charge. No model allowlist: the hosted tool is a capability of the Responses API, so it is exposed to every active model on a Responses wire and hidden elsewhere. |
151
+
152
+ #### `autoMode`
153
+
154
+ | Key | Type / default | Meaning |
155
+ | --- | --- | --- |
156
+ | `enabled` | *boolean*, `true` | Master switch; the mode still cannot engage until a model is allowlisted and `reviewerModel` is set. |
157
+ | `models` | *string[]*, `[]` | Allowlist of active session models permitted to run in auto mode. |
158
+ | `reviewerModel` | *string \| null*, `null` | Approving model (`provider/model-id`, resolved through Pi's registry). Used only for one-off reviews; never becomes the conversation model. |
159
+ | `gate` | `"side-effect"` \| `"all"`, `"side-effect"` | Which tool calls are reviewed. `/auto all` flips the session scope to everything. |
160
+ | `extraTools` | *string[]*, `[]` | Additional reviewed names on top of the side-effect set (`bash`, `write`, `edit`). |
161
+ | `timeoutMs` | *integer* 1000-120000, `30000` | Reviewer deadline across all rounds. Expiry is never approval. |
162
+ | `transcript` | *boolean*, `true` | Give the reviewer a bounded view of the conversation so it can judge authorization, not just intrinsic risk. |
163
+ | `evidenceTools` | *boolean*, `true` | Let the reviewer run Pi's read-only tools (`read`, `grep`, `find`, `ls`) to establish facts. It never receives `bash`, write tools, or network access. |
164
+ | `maxEvidenceRounds` | *integer* 0-8, `3` | Investigation rounds before the reviewer must answer; `0` is a single completion. |
165
+ | `classifier.*` | see code comments | Optional non-blocking low-risk pre-scorer (`enabled` `false`, `model`, `timeoutMs` `15000`, `maxLag` `2`). Can only fast-path ordinary calls, never deny. |
166
+ | `circuitBreaker.*` | — | Denials that end the turn instead of letting agent and reviewer negotiate forever (`consecutiveDenials` `3`, `recentDenials` `10` within `windowSize` `50`; `0` disables). |
167
+
168
+ #### `codexAstra`
169
+
170
+ Removed. The Astra compatibility layer (backend version-gate headers for all `openai-codex-responses` requests, plus the cache-preserving `configuration_update` effort rewrite) now activates silently for any model whose id is `gpt-6-astra` on a Responses-family API — no configuration needed, and old `codexAstra` sections in existing configs are ignored with an unknown-field warning. Only caveat left: do not run it together with another host that implements the same rewrite (e.g. Oh My Pi) to avoid double-splicing.
171
+
172
+ Catalog note: Pi's bundled `openai-codex` list may not include `gpt-6-astra` yet. Register it in `~/.pi/agent/models.json` under the built-in provider (`api: "openai-codex-responses"`, `baseUrl: "https://chatgpt.com/backend-api"`, `contextWindow: 272000`, `maxTokens: 128000`, `thinkingLevelMap` `low`…`max`); Pi's Codex OAuth supplies the token.
173
+
174
+ ### Feature guides
175
+
176
+ #### Codex Remote Context management
177
+
178
+ When `contextManagement` is `"remote"` and the session model is covered (native `openai-codex`, or `gpt-6-astra` on `openai-responses`; the model match is built in), the toolkit takes the session through the Codex window lifecycle:
179
+
180
+ - **Window identity.** `session_start` initializes a window (first/current/previous ids, window number) persisted as a `codex-context-window` custom message in the Pi session; boundaries replay on resume and rebuild after forks. Live requests carry `x-codex-window-id` and `x-codex-turn-metadata`.
181
+ - **No-summary rollover.** `new_context` installs a fresh window and trims the previous one from model context. Nothing is re-summarized; old turns stay retrievable server-side through `history`.
182
+ - **Checkpoint gate.** A rollover requires a *successful* `notes` `append_to_file` / `write_file` inside the current window, verified against the persisted session branch (so it survives restarts). Without it, `new_context` refuses; `force: true` is the explicit user-authorized escape, and the toolkit's exhausted-context fallback bypasses the gate automatically after instructing one final notes write.
183
+ - **Budget.** `get_context_remaining` reports the live window budget; `contextReminderThresholdPercent` controls the once-per-window checkpoint reminder.
184
+ - **Ownership.** For covered models the toolkit owns every compaction event: `remote_compaction_v2` is not sent, and Pi-native compaction is cancelled on all paths — including while the remote runtime is temporarily inactive, so no lossy summary can slip in behind its back. The inactive reason is surfaced as a notification (and in the `session_start` lifecycle artifact when `debug` is on); fix that cause rather than expecting compaction.
185
+
186
+ The native route reuses Pi's Codex OAuth through `ModelRegistry`; gateway route requests use the configured data-plane API key only — local OAuth credentials, account cookies, and account ids are never forwarded to a gateway.
187
+
188
+ **Verifying activation.** After `/reload` or a new session, the session should contain a `codex-context-window` boundary message and `new_context` / `get_context_remaining` / `history` / `notes` tools. With `debug: true`, each `session_start` writes a lifecycle artifact under `artifactRoot` whose `activation` field records `active` and, when inactive, the exact reason (e.g. `tool-name-conflict`, `missing-api-key`, `auth-resolution-failed`).
189
+
190
+ #### Remote Compaction v2
191
+
192
+ With `contextManagement` off, eligible Responses sessions compact through `remote_compaction_v2`: a `compaction_trigger` item appended to the live streaming request yields one output item of `type: "compaction"` with non-empty `encrypted_content`, stored in `CompactionEntry.details.compactedWindow`. On later requests the opaque checkpoint is replayed ahead of live turns — zero-loss, no text summary. Replay fails closed: if the summary anchor cannot be located, the request is aborted with a notification and a content-free failure artifact; the sentinel-only payload is never sent. Fallback tiers: a failed remote attempt may use Pi's native compaction (`remoteCompactModel`/active model); models that cannot use v2 at all use `nativeFallback`. Pi 0.85.1+ owns automatic compaction driving; the toolkit never starts its own driver.
193
+
194
+ #### Auto Mode
195
+
196
+ Engage per session with `pi --auto` or `/auto on` (footer shows state; engaging never stalls the current turn). Each gated call is reviewed by `reviewerModel`, which scores intrinsic risk and conversation authorization separately and derives `allow`/`deny` from a fixed table; it may investigate with read-only tools first; denials return the reason plus an anti-workaround clause; unfinished reviews are reported as failures, never safety verdicts. Every decision is persisted as a non-context session entry for audit. In headless (`-p`/JSON) sessions there is nobody to escalate to, so unavailable reviews block.
197
+
198
+ ## Development
199
+
200
+ ```bash
201
+ npm run typecheck # tsc project check
202
+ bun test # full unit suite
203
+ npm run test:pi # Pi integration smoke tests
204
+ npm pack --dry-run # inspect the published archive
205
+ ```
206
+
207
+ The Remote Context protocol fixtures (`src/context-management/`) must be updated together with any upstream alpha endpoint change.
208
+
209
+ ## API
210
+
211
+ ### Remote Context tools
212
+
213
+ The four tools the extension registers when Remote Context is active:
214
+
215
+ | Tool | Parameters | Result / errors |
216
+ | --- | --- | --- |
217
+ | `new_context` | `{ force?: boolean }` | Rolls to the next window without summarizing. Refuses unless a successful notes checkpoint exists in the current window (`force` overrides). Reports "already scheduled" if a rollover is pending. |
218
+ | `get_context_remaining` | none | Remaining tokens and window identity for the current budget; `unknown` when no usage source exists yet. |
219
+ | `history` | `{ action: "list_windows" \| "list_items" \| "read_item" \| "search_contents", ... }` | Reads prior windows. Pass returned `item_id` / window ids **unchanged**. Search text is sent under the encrypted-argument policy. |
220
+ | `notes` | `{ action: "list_files_by_prefix" \| "read_file" \| "search_contents" \| "append_to_file" \| "write_file", path, text, ... }` | Cross-window working memory. Paths resolve under the session agent (e.g. `/root/notes/<file>` or a relative note path); an invalid path is rejected by the backend. Successful append/write is what satisfies the `new_context` gate. |
221
+
222
+ All four throw explicit tool errors on timeout, abort, non-2xx, malformed JSON, authentication, or protocol failures — they never silently degrade.
223
+
224
+ ### HTTP protocol reference
225
+
226
+ Internal alpha endpoints, adapted from `@howaboua/pi-codex-conversion` (see [Background](#background)):
227
+
228
+ ```text
229
+ POST {base}/alpha/history/v2/list_windows | list_items | read_item | search_contents
230
+ POST {base}/alpha/notes/v2/list_files_by_prefix | read_file | search_contents | append_to_file | write_file
231
+ GET {base}/alpha/notes/v2/thread_hint
232
+ ```
233
+
234
+ Native route uses `{base} = <backend-api>/codex` with `Authorization: Bearer <oauth token>`, `ChatGPT-Account-ID`, and Codex CLI headers. Gateway route uses the configured `/v1` base with the data-plane API key, `originator: codex_cli_rs`, `X-Codex-Affinity-Scope`, and `X-Codex-Model` carrying the bare model id — never local credentials. Both set `Session-Id` / `X-Client-Request-Id` to the bounded Pi session id, `x-openai-tool-output-truncation-policy`, and `x-openai-encrypted-tool-arguments` for endpoints with encrypted parameters; encrypted results come back as `encrypted_output` and are re-encoded into later requests. These are alpha contracts: the upstream backend may change them at any time.
235
+
236
+ ## Maintainers
237
+
238
+ [awoaCrim](https://github.com/awoaCrim)
239
+
240
+ ## Contributing
241
+
242
+ Issues and pull requests are welcome at the [issue tracker](https://github.com/awoaCrim/pi-openai-toolkit/issues). For behavior-changing work, open an issue first so protocol assumptions (especially alpha `history`/`notes` contracts) can be discussed. Run `bun test` and `npm run typecheck` before submitting; new wire-protocol behavior needs fixture-based tests.
243
+
244
+ ## License
245
+
246
+ MIT © awoaCrim and contributors. See [LICENSE](./LICENSE) and the third-party attribution in [NOTICE](./NOTICE).