@narumitw/pi-codex-compact 0.51.3 → 0.53.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
@@ -2,21 +2,20 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@narumitw/pi-codex-compact)](https://www.npmjs.com/package/@narumitw/pi-codex-compact) [![Pi extension](https://img.shields.io/badge/Pi-extension-blue)](https://pi.dev) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)
4
4
 
5
- Use Codex Remote Compaction V2 in Pi instead of generating a local plaintext summary for models that use the `openai-codex-responses` API.
6
-
7
- The extension requests and stores an opaque server-generated checkpoint, then safely replays it in later Codex Responses requests.
8
-
9
- Pi still decides when compaction runs and retains its normal `/compact`, threshold, overflow, and session-publication behavior.
5
+ Use Responses compaction in Pi through Remote Compaction V2 or the unary `responses/compact` API.
6
+ The extension stores an opaque server-generated checkpoint and replays it in later compatible requests instead of generating a local plaintext summary.
7
+ Pi still decides when compaction runs and keeps its normal `/compact`, threshold, overflow, and session-publication behavior.
10
8
 
11
9
  ## ✨ Features
12
10
 
13
- - Uses the active Codex Responses provider and credentials without persisting secrets or request headers.
11
+ - Supports `openai-codex-responses`, `openai-responses`, and `azure-openai-responses`, plus explicitly profiled custom APIs.
12
+ - Uses Remote V2 or same-origin unary `responses/compact` through the active provider and credentials.
14
13
  - Handles manual, threshold, and overflow compaction through Pi's existing lifecycle.
15
14
  - Validates and persists one bounded opaque checkpoint that survives compatible reloads, resumes, and forks.
16
15
  - Replays the latest checkpoint while preserving newer conversation and extension context.
17
- - Supports repeated compaction by carrying the previous checkpoint into the next request.
16
+ - Supports repeated and cross-protocol compaction by carrying the previous checkpoint forward.
18
17
  - Falls back to Pi's native plaintext compaction on non-cancellation failures.
19
- - Provides `/codex-compact` for route status, settings, and manual compaction.
18
+ - Provides `/codex-compact` for effective-route status, settings, and manual compaction.
20
19
 
21
20
  ## 📦 Install
22
21
 
@@ -39,42 +38,35 @@ npm --workspace @narumitw/pi-codex-compact run build
39
38
  pi -e ./packages/pi-codex-compact
40
39
  ```
41
40
 
42
- The package declares `dist/index.ts`, so an unbuilt local checkout must be built before Pi loads the package directory.
43
- Loading the package enables Remote V2 with safe defaults.
44
- Avoid loading a global npm installation and the local workspace at the same time.
41
+ The package declares `dist/index.ts`, so build a local checkout before loading its package directory.
42
+ Loading the package enables automatic Responses compaction routing with the documented defaults.
43
+ Do not load a global npm installation and the local workspace at the same time.
44
+
45
+ Pi extensions run with your user permissions.
46
+ Review third-party extension source before installing it.
45
47
 
46
48
  ## 🚀 Quick start
47
49
 
48
- 1. Sign in through Pi's built-in OpenAI Codex provider, or configure a custom provider that routes to a compatible Codex backend.
49
- 2. Select a model whose API is `openai-codex-responses`.
50
- 3. Work normally.
51
- Pi's automatic compaction and built-in `/compact` continue to operate.
52
- 4. Run `/codex-compact` to inspect the effective route or choose **Compact now**.
53
- 5. After compaction, continue the session normally; compatible requests replay the opaque checkpoint.
50
+ 1. Sign in through Pi's built-in OpenAI, OpenAI Codex, or Azure OpenAI provider, or configure a compatible custom provider.
51
+ 2. Select a model using `openai-codex-responses`, `openai-responses`, or `azure-openai-responses`.
52
+ 3. Work normally; Pi's automatic compaction and built-in `/compact` continue to operate.
53
+
54
+ Run `/codex-compact` when you want to inspect the effective route or choose **Compact now**.
55
+ After compaction, compatible requests replay the opaque checkpoint automatically.
54
56
 
57
+ With the default `auto` protocol, Codex Responses uses Remote V2 while OpenAI and Azure OpenAI Responses use unary `responses/compact`.
55
58
  When the active model uses another API, compaction remains entirely Pi-native.
59
+ To opt in a compatible custom API, add it to `apiProfiles` as described below.
56
60
 
57
61
  ## 💬 Commands
58
62
 
59
- ```text
60
- /codex-compact
61
- ```
62
-
63
- In TUI mode, the root menu shows whether Remote V2 is enabled, the active model, and whether a manual compact will use **Codex Remote V2** or **Pi native**.
64
- It contains:
63
+ Run `/codex-compact` to inspect the effective compaction path, change settings, or request manual compaction in TUI mode.
64
+ It accepts no arguments.
65
+ RPC reports the manual settings path without compacting; print and JSON modes reject the command.
66
+ Closing the menu with Escape or Ctrl+C does not compact the session.
65
67
 
66
- ```text
67
- Compact now
68
- Settings
69
- Close
70
- ```
71
-
72
- **Compact now** closes the menu before asking Pi to compact the active session.
73
- Escape or Ctrl+C closes without compacting, and an obsolete menu cannot trigger work after session replacement or shutdown.
74
- **Settings** opens the bounded settings editor.
75
- In non-TUI modes, the command reports the manual settings path instead of opening custom UI or compacting.
76
-
77
- Pi's built-in `/compact` remains available and follows the same extension hook when the active model uses `openai-codex-responses`.
68
+ Manual compaction uses **Responses Remote V2**, **Responses Compact API**, or **Pi native**, as described in [Settings](#-settings).
69
+ Pi's built-in `/compact` remains available and follows the same extension hook.
78
70
 
79
71
  ## ⚙️ Settings
80
72
 
@@ -90,6 +82,10 @@ There is no environment-variable or project-level override.
90
82
  ```json
91
83
  {
92
84
  "enabled": true,
85
+ "protocol": "auto",
86
+ "apiProfiles": {
87
+ "custom-responses": "codex-responses-v1"
88
+ },
93
89
  "requestTimeoutMs": 300000,
94
90
  "maxRetries": 2,
95
91
  "replacementTokenBudget": 64000,
@@ -99,19 +95,21 @@ There is no environment-variable or project-level override.
99
95
 
100
96
  | Setting | Default | Accepted values | Behavior | Recommendation |
101
97
  | --- | ---: | --- | --- | --- |
102
- | `enabled` | `true` | Boolean | Attempt Remote V2 when the active model uses `openai-codex-responses`. | Keep enabled unless diagnosing provider behavior. |
98
+ | `enabled` | `true` | Boolean | Attempt a supported remote compaction route. | Keep enabled unless diagnosing provider behavior. |
99
+ | `protocol` | `"auto"` | `"auto"`, `"remote-v2"`, or `"responses-compact"` | Select by API or force one remote protocol. | Keep `auto`; force a route only when diagnosing a compatible backend. |
100
+ | `apiProfiles` | `{}` | Object mapping a custom API id to `"codex-responses-v1"` | Explicitly opts a non-built-in API into Codex-compatible request fields and replay. | Leave empty unless the provider documents Codex Responses compatibility. |
103
101
  | `requestTimeoutMs` | `300000` | Integer from 30,000 to 600,000 ms | Bound one extension-owned remote request. | Keep five minutes; increase only for a consistently slow connection. |
104
102
  | `maxRetries` | `2` | Integer from 0 to 2 | Retry transient provider transport failures before Pi fallback. | Keep two; use zero when diagnosing the first failure. |
105
103
  | `replacementTokenBudget` | `64000` | Integer from 8,000 to 128,000 tokens | Bound approximate retained user-message text beside the opaque item. | Keep 64K; lower it to reduce session size or raise it only when recent user context is being lost. |
106
- | `notifyOnFallback` | `true` | Boolean | Warn when Remote V2 fails and Pi-native compaction takes over. | Keep enabled so silent fallback does not hide protocol or entitlement problems. |
104
+ | `notifyOnFallback` | `true` | Boolean | Warn when remote compaction fails and Pi-native compaction takes over. | Keep enabled so silent fallback does not hide protocol or entitlement problems. |
107
105
 
108
106
  Missing fields use defaults.
109
107
  Settings reload on every `session_start`, including `/reload`, resume, and fork.
110
108
  Menu writes apply immediately, preserve unknown JSON fields, serialize within the current Pi process, and use a final conflict check plus same-directory atomic rename.
111
109
  On Unix, temporary files use mode `0600`.
112
110
 
113
- Malformed, invalid, oversized, or symlinked settings files are never overwritten.
114
- Safe defaults stay active, and the menu provides read-only repair guidance until the file is fixed and Pi is reloaded.
111
+ Malformed, invalid, oversized, or symlinked settings files remain unchanged.
112
+ Defaults stay active, and the menu remains read-only until the file is fixed and Pi is reloaded.
115
113
  Separate Pi processes do not share a mutation lock; a detected concurrent edit is rejected so the user can reopen Settings and retry.
116
114
 
117
115
  ### Relationship to Codex configuration
@@ -120,49 +118,59 @@ This extension does **not** read `~/.codex/config.toml`.
120
118
 
121
119
  | Codex setting | Extension behavior |
122
120
  | --- | --- |
123
- | `features.remote_compaction_v2` | Conceptually corresponds to this extension's `enabled`; it is not imported. |
121
+ | `features.remote_compaction_v2` | Conceptually corresponds to `protocol: "remote-v2"`; it is not imported. |
124
122
  | `model_auto_compact_token_limit` | Not duplicated. Pi's own compaction threshold remains authoritative. |
125
123
  | `model_auto_compact_token_limit_scope` | Not supported; Pi extensions do not own Codex's compact-window lineage. |
126
- | `compact_prompt` / `experimental_compact_prompt_file` | Not used by Remote V2, whose opaque checkpoint is generated by the server. |
124
+ | `compact_prompt` / `experimental_compact_prompt_file` | Not used by either remote protocol, whose opaque checkpoint is generated by the server. |
127
125
  | `features.token_budget` | Not supported; token-budget context reset is a different experimental strategy. |
128
126
 
129
127
  ## ✅ Requirements and compatibility
130
128
 
131
129
  - Pi APIs compatible with the package's declared peer dependencies.
132
- - API `openai-codex-responses` on the active model.
133
- - A built-in or custom provider that routes that API to a backend supporting `compaction_trigger` and opaque `compaction` replay.
134
- - Working credentials and Remote V2 entitlement for that backend.
135
-
136
- The built-in `openai-codex` provider is supported, and a custom provider or proxy is eligible when its model explicitly uses `openai-codex-responses`.
137
- Generic `openai-responses`, `azure-openai-responses`, GitHub Copilot, and other merely Responses-compatible API labels are not eligible.
138
- The extension does not probe provider capabilities before compaction; a provider that declares `openai-codex-responses` owns compatible routing, authentication, request transforms, SSE transport, and opaque replay.
139
- A failed Remote V2 compaction attempt falls back to Pi native, but an ordinary request cannot transparently recover after an incompatible provider has already received an existing opaque checkpoint.
130
+ - One of `openai-codex-responses`, `openai-responses`, or `azure-openai-responses` on the active model, or an explicit `apiProfiles` entry for a custom Codex-compatible API.
131
+ - A provider whose HTTP Responses adapter honors Pi's public `onPayload` and injected `fetch` options.
132
+ - A backend supporting the selected protocol and opaque `compaction` replay.
133
+ - Working credentials and any required compaction entitlement.
134
+
135
+ | Model API | `auto` route | Other selectable route |
136
+ | --- | --- | --- |
137
+ | `openai-codex-responses` | Responses Remote V2 | Responses Compact API |
138
+ | `openai-responses` | Responses Compact API | Responses Remote V2 |
139
+ | `azure-openai-responses` | Responses Compact API | Responses Remote V2 |
140
+
141
+ The installed built-in adapters are covered by deterministic transport tests.
142
+ A custom provider or proxy is eligible when its model explicitly uses one of these APIs, but its backend still owns compatible routing, authentication, request transforms, and opaque replay.
143
+ For a custom API label, eligibility is opt-in: `apiProfiles` must map that exact non-built-in label to `"codex-responses-v1"`. The default is empty, and an unconfigured custom API remains Pi-native.
144
+ `codex-responses-v1` uses Remote V2 in `auto` mode. With `responses-compact` explicitly selected, it retains the Codex Compact request fields, including tools and reasoning. The provider must honor Pi's public `transport: "sse"`, `onPayload`, and injected `fetch` options, and its backend must support the selected compaction protocol and opaque item replay. The profile declares compatibility; it does not probe the backend.
145
+ The extension does not send a separate capability probe or automatically retry a failed billable request through the other protocol.
146
+ A failed remote attempt falls back to Pi native, but an ordinary request cannot transparently recover after an incompatible provider has already received an existing opaque checkpoint.
140
147
  Provider provenance is stored for diagnosis but is not a replay gate.
141
- Switching providers can replay a checkpoint only when the API and exact model ID still match; switching model IDs leaves Pi's visible fallback marker plus retained recent messages in context.
148
+ Switching providers can replay a checkpoint only when the API label, compatibility profile, and exact model ID still match. Custom API checkpoints also require a current matching `apiProfiles` entry; removing or changing it leaves Pi's visible fallback marker plus retained recent messages in context.
142
149
 
143
150
  ## 🔄 How it works
144
151
 
145
152
  1. Pi prepares compaction and selects the recent message suffix it will retain.
146
153
  2. If an earlier compatible checkpoint is present, the extension identifies its boundary from the summary persisted on the active `CompactionEntry` and validates the retained suffix fingerprints.
147
- 3. It projects that checkpoint into the current Responses input, appends exactly one final `compaction_trigger`, and sends a normal authenticated Codex Responses SSE request with cache retention disabled.
148
- 4. It requires a completed response containing exactly one non-empty opaque `compaction` item.
149
- 5. It constructs bounded replacement history from recent raw user-role Responses items followed by the opaque item.
150
- 6. It stores that history and fingerprints of Pi's retained suffix in versioned `CompactionEntry.details`.
154
+ 3. Remote V2 projects that checkpoint into a normal Responses SSE request and appends exactly one final `compaction_trigger`.
155
+ 4. Unary compact captures the provider-built payload and authentication, rewrites only the same-origin `/responses` path to `/responses/compact`, and requests JSON without making a normal inference call.
156
+ 5. It requires one bounded non-empty opaque `compaction` item; unary output may precede it only with user-role retained messages.
157
+ 6. It constructs bounded replacement history and stores it with Pi suffix fingerprints, the real API label, and the resolved compatibility profile in versioned `CompactionEntry.details`.
151
158
  7. On later compatible requests, it replaces an exactly validated marker with the persisted replacement history immediately before provider dispatch.
152
159
 
153
160
  The persisted entry remains the summary identity source, so replay does not depend on the wording generated by the currently installed extension version.
154
161
  If persisted summary identity, fingerprints, model identity, payload shape, or marker count do not match exactly, the extension leaves Pi's visible fallback context unchanged instead of guessing.
162
+ Older v1 and v2 checkpoints are normalized to the current checkpoint format when read; their built-in API label determines the profile. They still replay only when the current route authorizes that API/profile/model combination.
155
163
 
156
164
  ## 🔒 Security and privacy
157
165
 
158
- Remote compaction sends the active conversation context, system prompt, and active tool schemas to the configured backend used by the selected Codex Responses provider.
166
+ Remote compaction sends the active conversation context and system prompt to the configured Responses backend; Remote V2 also sends active tool schemas.
159
167
  The Pi session stores the producing provider ID, encrypted compaction item, and bounded recent user-role Responses items.
160
168
  It does not store credentials, authorization headers, or request headers in checkpoint details.
161
169
 
162
170
  | Boundary | Limit |
163
171
  | --- | ---: |
164
- | Observed SSE stream | 8 MiB |
165
- | Serialized opaque compaction item | 2 MiB |
172
+ | Observed SSE stream or unary JSON response | 8 MiB |
173
+ | Serialized opaque compaction item or retained output item | 2 MiB |
166
174
  | Persisted replacement history | 8 MiB |
167
175
  | Retained user text | 64K approximate tokens by default; configurable from 8K to 128K |
168
176
  | Settings file | 64 KiB |
@@ -175,52 +183,29 @@ These hard byte ceilings are intentionally not configurable.
175
183
 
176
184
  ## 🚧 Limitations
177
185
 
178
- - The wire contract is undocumented and can change independently of Pi or this package.
179
- Keep backups of important sessions.
180
- - Full older history depends on this extension, the `openai-codex-responses` API, the exact checkpoint model ID, and a provider route whose backend accepts the opaque item.
186
+ - Codex Remote V2 remains an undocumented hosted contract and can change independently of Pi or this package; keep backups of important sessions.
187
+ - Full older history depends on this extension, the checkpoint API label and compatibility profile, the exact checkpoint model ID, and a provider route whose backend accepts the opaque item.
181
188
  Removing the extension exposes only the portability fallback marker and Pi-retained recent messages.
182
189
  - The package does not reproduce Codex core's context-window UUID/number lineage, previous-model compatibility fallback, exact pre-turn ordering, or exact mid-turn model-session ownership.
190
+ - Pi's public `getAllTools()` metadata does not expose `constrainedSampling`; Remote V2 preserves active tool order, names, descriptions, and parameter schemas but cannot reproduce that optional field.
183
191
  - Remote failure falls back to Pi's plaintext summary, so a session can contain both remote opaque and native compaction entries over time.
184
192
  - Settings concurrency is coordinated only within one Pi process; separate processes rely on the final conflict check.
185
193
 
186
- ## 🗂️ Package layout
187
-
188
- ```text
189
- src/index.ts Thin Pi entrypoint
190
- src/codex-compact.ts Pi lifecycle, command, provider projection, and fallback
191
- src/remote.ts Provider stream invocation, auth payload, timeout, and retry controls
192
- src/protocol.ts Bounded SSE parsing and Remote V2 payload/output validation
193
- src/checkpoint.ts Replacement history, fingerprints, persistence, and replay projection
194
- src/model-api.ts Codex Responses API detection for Remote V2 eligibility
195
- src/settings.ts Global settings validation and atomic persistence
196
- src/settings-menu.ts First-use manual compaction and settings TUI
197
-
198
- dist/ Generated source-mapped Jiti runtime and lazy menu chunk
199
- scripts/ Runtime builder
200
- benchmark/ Three-arm compaction benchmark, self-test, and methodology
201
- test/ Protocol, checkpoint, lifecycle, remote, settings, menu, and builder coverage
202
- ```
203
-
204
194
  ## 📊 Benchmark
205
195
 
206
- The repository includes a seeded three-arm benchmark for uncompressed full context, Pi-native plaintext compaction, and this extension's Codex Remote Compaction V2 path.
207
-
208
- It holds history length nearly fixed while varying information density across five state categories and ten history epochs.
209
-
196
+ The repository includes a seeded benchmark that compares uncompressed full context, Pi-native plaintext compaction, and this extension's Remote V2 path.
197
+ It keeps history length nearly fixed while varying information density across five state categories and ten history epochs.
210
198
  Benchmark v3 uses repeated artifacts, isolated evaluator probes, seed-level paired statistics, one Pi SDK estimator for dry and live fixtures, and committed protocol manifests for confirmatory candidates.
211
-
212
199
  It never treats nominal Pi 20K and Codex 20K settings as equal information capacity or automatically claims that protocol-conformant evidence was genuinely held out.
213
200
 
214
201
  Preview its exploratory diagnostic without making a provider request:
215
202
 
216
203
  ```bash
217
- just benchmark-codex-compact
204
+ npm run benchmark:codex-compact
218
205
  ```
219
206
 
220
- A live run requires an explicit `--live` flag, reviewed request and cost exposure, OpenAI Codex OAuth, and Remote V2 entitlement.
221
-
207
+ A live run requires `--live`, review of the request and cost exposure, OpenAI Codex OAuth, and Remote V2 entitlement.
222
208
  The repository preserves the explicitly labeled v2 matched-tail diagnostic and the v3 calibration evidence, while seeds 301–304 remain consumed and unavailable for future confirmatory protocols.
223
-
224
209
  See the [benchmark guide](https://github.com/narumiruna/pi-extensions/tree/main/packages/pi-codex-compact/benchmark) for manifests, repetitions, commands, privacy, cost semantics, and interpretation limits.
225
210
 
226
211
  ## 🧪 Development
@@ -230,14 +215,29 @@ From the repository root:
230
215
  ```bash
231
216
  npm --workspace @narumitw/pi-codex-compact run check
232
217
  npm test
233
- just pack codex-compact
218
+ npm run package:pack -- codex-compact
219
+ ```
220
+
221
+ See the [Codex compaction mechanism notes](https://github.com/narumiruna/pi-extensions/blob/main/docs/implementation-notes/codex-compaction-mechanism.md) for the underlying Codex mechanism research and the extension boundary.
222
+
223
+ ## 🗂️ Package layout
224
+
225
+ ```text
226
+ packages/pi-codex-compact/
227
+ ├── src/ # Authoritative implementation and helpers
228
+ │ ├── index.ts # Thin Pi entrypoint
229
+ │ └── codex-compact.ts # Compaction routing, replay, and fallback
230
+ ├── dist/ # Generated Jiti runtime
231
+ ├── scripts/build-runtime.mjs # Runtime builder
232
+ ├── benchmark/ # Repository-only benchmark and methodology
233
+ └── test/ # Behavior and lifecycle coverage
234
234
  ```
235
235
 
236
- See [`docs/implementation-notes/codex-compaction-mechanism.md`](../../docs/implementation-notes/codex-compaction-mechanism.md) for the underlying Codex mechanism research and the extension boundary.
236
+ The generated runtime is built from `src/index.ts` and does not import back into `src`.
237
237
 
238
238
  ## 🔎 Keywords
239
239
 
240
- Pi extension, Pi coding agent, OpenAI Codex, custom provider, proxy, Remote Compaction V2, opaque checkpoint, Responses API, context compaction.
240
+ Pi extension, Pi coding agent, OpenAI Codex, Azure OpenAI, custom provider, proxy, Remote Compaction V2, Responses Compact API, opaque checkpoint, Responses API, context compaction.
241
241
 
242
242
  ## 📄 License
243
243
 
@@ -0,0 +1,37 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- the generated entry uses a .ts extension for Pi's Jiti loader.
3
+
4
+ // src/model-api.ts
5
+ function resolveResponsesCompactionProfile(api, apiProfiles = {}) {
6
+ if (api === "openai-codex-responses") return "codex-responses-v1";
7
+ if (api === "openai-responses" || api === "azure-openai-responses") return "openai-responses-v1";
8
+ return api && Object.hasOwn(apiProfiles, api) && apiProfiles[api] === "codex-responses-v1" ? "codex-responses-v1" : void 0;
9
+ }
10
+ function resolveCompactionRouteForApi(api, options) {
11
+ if (!options.enabled) return { kind: "native", reason: "remote compaction is disabled" };
12
+ if (!api) return { kind: "native", reason: "no active model" };
13
+ const profile = resolveResponsesCompactionProfile(api, options.apiProfiles);
14
+ if (!profile) {
15
+ return { kind: "native", reason: `API ${api} does not support Responses compaction` };
16
+ }
17
+ const protocol = options.protocol === "auto" ? profile === "codex-responses-v1" ? "remote-v2" : "responses-compact" : options.protocol;
18
+ return { kind: "remote", protocol, api, profile };
19
+ }
20
+ function resolveCompactionRoute(model, options) {
21
+ return resolveCompactionRouteForApi(model?.api, options);
22
+ }
23
+
24
+ // src/terminal.ts
25
+ function terminalText(value) {
26
+ return Array.from(value, (character) => {
27
+ const codePoint = character.codePointAt(0) ?? 0;
28
+ return codePoint < 32 || codePoint >= 127 && codePoint <= 159 ? " " : character;
29
+ }).join("");
30
+ }
31
+
32
+ export {
33
+ resolveCompactionRouteForApi,
34
+ resolveCompactionRoute,
35
+ terminalText
36
+ };
37
+ //# sourceMappingURL=chunk-7H7JJ7ZV.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/model-api.ts", "../../src/terminal.ts"],
4
+ "sourcesContent": ["import type { Api, Model } from \"@earendil-works/pi-ai\";\nimport type { CodexCompactSettings } from \"./settings.js\";\n\nexport const RESPONSES_COMPACTION_APIS = [\n \"openai-codex-responses\",\n \"openai-responses\",\n \"azure-openai-responses\",\n] as const;\n\nexport type BuiltInResponsesCompactionApi = (typeof RESPONSES_COMPACTION_APIS)[number];\nexport type ResponsesCompactionApi = BuiltInResponsesCompactionApi;\nexport type ResponsesCompactionProfile = \"codex-responses-v1\" | \"openai-responses-v1\";\nexport type RemoteCompactionProtocol = \"remote-v2\" | \"responses-compact\";\nexport type RemoteCompactionProtocolSetting = \"auto\" | RemoteCompactionProtocol;\n\nexport type CompactionRoute =\n | { kind: \"remote\"; protocol: RemoteCompactionProtocol; api: Api; profile: ResponsesCompactionProfile }\n | { kind: \"native\"; reason: string };\n\nfunction resolveResponsesCompactionProfile(\n api: Api | undefined,\n apiProfiles: Readonly<Record<string, \"codex-responses-v1\">> = {},\n): ResponsesCompactionProfile | undefined {\n if (api === \"openai-codex-responses\") return \"codex-responses-v1\";\n if (api === \"openai-responses\" || api === \"azure-openai-responses\") return \"openai-responses-v1\";\n return api && Object.hasOwn(apiProfiles, api) && apiProfiles[api] === \"codex-responses-v1\"\n ? \"codex-responses-v1\"\n : undefined;\n}\n\nexport function resolveCompactionRouteForApi(\n api: Api | undefined,\n options: Pick<CodexCompactSettings, \"enabled\" | \"protocol\"> & {\n apiProfiles?: Readonly<Record<string, \"codex-responses-v1\">>;\n },\n): CompactionRoute {\n if (!options.enabled) return { kind: \"native\", reason: \"remote compaction is disabled\" };\n if (!api) return { kind: \"native\", reason: \"no active model\" };\n const profile = resolveResponsesCompactionProfile(api, options.apiProfiles);\n if (!profile) {\n return { kind: \"native\", reason: `API ${api} does not support Responses compaction` };\n }\n const protocol =\n options.protocol === \"auto\"\n ? profile === \"codex-responses-v1\"\n ? \"remote-v2\"\n : \"responses-compact\"\n : options.protocol;\n return { kind: \"remote\", protocol, api, profile };\n}\n\nexport function resolveCompactionRoute(\n model: Model<Api> | undefined,\n options: Pick<CodexCompactSettings, \"enabled\" | \"protocol\"> & {\n apiProfiles?: Readonly<Record<string, \"codex-responses-v1\">>;\n },\n): CompactionRoute {\n return resolveCompactionRouteForApi(model?.api, options);\n}\n", "export function terminalText(value: string): string {\n return Array.from(value, (character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint < 32 || (codePoint >= 127 && codePoint <= 159) ? \" \" : character;\n }).join(\"\");\n}\n"],
5
+ "mappings": ";;;;AAmBA,SAAS,kCACP,KACA,cAA8D,CAAC,GACvB;AACxC,MAAI,QAAQ,yBAA0B,QAAO;AAC7C,MAAI,QAAQ,sBAAsB,QAAQ,yBAA0B,QAAO;AAC3E,SAAO,OAAO,OAAO,OAAO,aAAa,GAAG,KAAK,YAAY,GAAG,MAAM,uBAClE,uBACA;AACN;AAEO,SAAS,6BACd,KACA,SAGiB;AACjB,MAAI,CAAC,QAAQ,QAAS,QAAO,EAAE,MAAM,UAAU,QAAQ,gCAAgC;AACvF,MAAI,CAAC,IAAK,QAAO,EAAE,MAAM,UAAU,QAAQ,kBAAkB;AAC7D,QAAM,UAAU,kCAAkC,KAAK,QAAQ,WAAW;AAC1E,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,MAAM,UAAU,QAAQ,OAAO,GAAG,yCAAyC;AAAA,EACtF;AACA,QAAM,WACJ,QAAQ,aAAa,SACjB,YAAY,uBACV,cACA,sBACF,QAAQ;AACd,SAAO,EAAE,MAAM,UAAU,UAAU,KAAK,QAAQ;AAClD;AAEO,SAAS,uBACd,OACA,SAGiB;AACjB,SAAO,6BAA6B,OAAO,KAAK,OAAO;AACzD;;;AC1DO,SAAS,aAAa,OAAuB;AAClD,SAAO,MAAM,KAAK,OAAO,CAAC,cAAc;AACtC,UAAM,YAAY,UAAU,YAAY,CAAC,KAAK;AAC9C,WAAO,YAAY,MAAO,aAAa,OAAO,aAAa,MAAO,MAAM;AAAA,EAC1E,CAAC,EAAE,KAAK,EAAE;AACZ;",
6
+ "names": []
7
+ }
@@ -1,31 +1,37 @@
1
1
  // @generated by scripts/build-runtime.mjs; do not edit.
2
2
  // @ts-nocheck -- the generated entry uses a .ts extension for Pi's Jiti loader.
3
3
  import {
4
- usesCodexResponsesApi
5
- } from "./chunk-6TZ2L2BM.js";
4
+ resolveCompactionRouteForApi,
5
+ terminalText
6
+ } from "./chunk-7H7JJ7ZV.js";
6
7
 
7
8
  // src/settings-menu.ts
8
- function safeText(value) {
9
- return Array.from(value, (character) => {
10
- const codePoint = character.codePointAt(0) ?? 0;
11
- return codePoint < 32 || codePoint >= 127 && codePoint <= 159 ? " " : character;
12
- }).join("");
13
- }
14
9
  function timeoutLabel(milliseconds) {
15
10
  return `${milliseconds / 6e4} min`;
16
11
  }
17
12
  function retentionLabel(tokens) {
18
13
  return `${tokens / 1e3}K tokens`;
19
14
  }
15
+ function protocolLabel(protocol) {
16
+ switch (protocol) {
17
+ case "auto":
18
+ return "Auto";
19
+ case "remote-v2":
20
+ return "Remote V2";
21
+ case "responses-compact":
22
+ return "Responses Compact";
23
+ }
24
+ }
20
25
  async function update(runtime, ctx, patch, signal) {
21
26
  try {
22
27
  await runtime.update(patch, signal);
23
- ctx.ui.notify("Codex compaction settings saved.", "info");
28
+ if (signal.aborted) return { kind: "rejected" };
29
+ ctx.ui.notify("Responses compaction settings saved.", "info");
24
30
  return { kind: "stay" };
25
31
  } catch (error) {
26
32
  if (signal.aborted) return { kind: "rejected" };
27
33
  ctx.ui.notify(
28
- `Could not save pi-codex-compact.json: ${safeText(error instanceof Error ? error.message : String(error))}`,
34
+ `Could not save pi-codex-compact.json: ${terminalText(error instanceof Error ? error.message : String(error))}`,
29
35
  "error"
30
36
  );
31
37
  return { kind: "rejected" };
@@ -37,11 +43,12 @@ function createCodexCompactMenu(runtime, options = {}) {
37
43
  screens: {
38
44
  main: ({ state }) => ({
39
45
  kind: "actions",
40
- title: "Codex Remote Compaction",
46
+ title: "Responses Compaction",
41
47
  lines: [
42
- `Remote V2: ${state.settings.enabled ? "On" : "Off"}`,
43
- `Active model: ${safeText(options.status?.model ?? "none")}`,
44
- `Compact route: ${safeText(compactRoute(state, options.status))}`
48
+ `Remote compaction: ${state.settings.enabled ? "On" : "Off"}`,
49
+ `Protocol setting: ${protocolLabel(state.settings.protocol)}`,
50
+ `Active model: ${terminalText(options.status?.model ?? "none")}`,
51
+ `Compact route: ${terminalText(compactRoute(state, options.status))}`
45
52
  ],
46
53
  items: [
47
54
  {
@@ -62,17 +69,25 @@ function createCodexCompactMenu(runtime, options = {}) {
62
69
  }),
63
70
  settings: ({ state }) => ({
64
71
  kind: "settings",
65
- title: "Codex Remote Compaction Settings",
66
- lines: [`User settings \xB7 ${safeText(state.path)}`],
72
+ title: "Responses Compaction Settings",
73
+ lines: [`User settings \xB7 ${terminalText(state.path)}`],
67
74
  items: [
68
75
  {
69
76
  id: "enabled",
70
77
  label: "Remote compaction",
71
- description: "Use Codex Remote V2 when the model uses openai-codex-responses.",
78
+ description: "Use a supported Responses compaction protocol.",
72
79
  currentValue: state.settings.enabled ? "On" : "Off",
73
80
  values: ["On", "Off"],
74
81
  action: "set-enabled"
75
82
  },
83
+ {
84
+ id: "protocol",
85
+ label: "Protocol",
86
+ description: "Choose automatically or force one supported remote protocol.",
87
+ currentValue: protocolLabel(state.settings.protocol),
88
+ values: ["Auto", "Remote V2", "Responses Compact"],
89
+ action: "set-protocol"
90
+ },
76
91
  {
77
92
  id: "requestTimeoutMs",
78
93
  label: "Request timeout",
@@ -100,7 +115,7 @@ function createCodexCompactMenu(runtime, options = {}) {
100
115
  {
101
116
  id: "notifyOnFallback",
102
117
  label: "Fallback notifications",
103
- description: "Warn when Remote V2 fails and native Pi compaction takes over.",
118
+ description: "Warn when remote compaction fails and Pi native takes over.",
104
119
  currentValue: state.settings.notifyOnFallback ? "On" : "Off",
105
120
  values: ["On", "Off"],
106
121
  action: "set-notify"
@@ -111,8 +126,8 @@ function createCodexCompactMenu(runtime, options = {}) {
111
126
  kind: "detail",
112
127
  title: "Codex Compact Settings \xB7 Read only",
113
128
  lines: [
114
- `Invalid settings file: ${safeText(state.path)}`,
115
- `Issue: ${safeText(state.issue ?? "unknown validation error")}`,
129
+ `Invalid settings file: ${terminalText(state.path)}`,
130
+ `Issue: ${terminalText(state.issue ?? "unknown validation error")}`,
116
131
  "Built-in defaults are active. Repair the file and run /reload; it will not be overwritten."
117
132
  ],
118
133
  hint: "back"
@@ -124,28 +139,29 @@ function createCodexCompactMenu(runtime, options = {}) {
124
139
  return { kind: "close" };
125
140
  },
126
141
  "set-enabled": ({ ctx, value, signal }) => update(runtime, ctx, { enabled: value === "On" }, signal),
127
- "set-timeout": ({ ctx, value, signal }) => update(
142
+ "set-protocol": ({ ctx, value, signal }) => update(
128
143
  runtime,
129
144
  ctx,
130
- { requestTimeoutMs: Number.parseInt(value ?? "5", 10) * 6e4 },
145
+ {
146
+ protocol: value === "Remote V2" ? "remote-v2" : value === "Responses Compact" ? "responses-compact" : "auto"
147
+ },
131
148
  signal
132
149
  ),
150
+ "set-timeout": ({ ctx, value, signal }) => update(runtime, ctx, { requestTimeoutMs: Number.parseInt(value ?? "5", 10) * 6e4 }, signal),
133
151
  "set-retries": ({ ctx, value, signal }) => update(runtime, ctx, { maxRetries: Number.parseInt(value ?? "2", 10) }, signal),
134
- "set-retention": ({ ctx, value, signal }) => update(
135
- runtime,
136
- ctx,
137
- { replacementTokenBudget: Number.parseInt(value ?? "64", 10) * 1e3 },
138
- signal
139
- ),
152
+ "set-retention": ({ ctx, value, signal }) => update(runtime, ctx, { replacementTokenBudget: Number.parseInt(value ?? "64", 10) * 1e3 }, signal),
140
153
  "set-notify": ({ ctx, value, signal }) => update(runtime, ctx, { notifyOnFallback: value === "On" }, signal)
141
154
  }
142
155
  };
143
156
  }
144
157
  async function showCodexCompactMenu(runtime, ctx, owner) {
145
- if (ctx.mode !== "tui") {
146
- ctx.ui.notify(`Edit Codex compaction settings at ${safeText(runtime.get().path)}.`, "info");
158
+ if (ctx.mode === "rpc" && ctx.hasUI) {
159
+ ctx.ui.notify(`Edit Responses compaction settings at ${terminalText(runtime.get().path)}.`, "info");
147
160
  return;
148
161
  }
162
+ if (ctx.mode !== "tui") {
163
+ throw new Error("/codex-compact requires TUI or RPC UI support");
164
+ }
149
165
  const { runMenu } = await import("@narumitw/pi-tui-kit");
150
166
  if (owner.signal.aborted || !owner.isCurrent()) return;
151
167
  let compactRequested = false;
@@ -167,7 +183,7 @@ async function showCodexCompactMenu(runtime, ctx, owner) {
167
183
  ctx.compact({
168
184
  onError: (error) => {
169
185
  if (!owner.signal.aborted && owner.isCurrent()) {
170
- ctx.ui.notify(`Compaction failed: ${safeText(error.message)}`, "error");
186
+ ctx.ui.notify(`Compaction failed: ${terminalText(error.message)}`, "error");
171
187
  }
172
188
  }
173
189
  });
@@ -176,16 +192,17 @@ function compactMenuStatus(ctx) {
176
192
  const model = ctx.model;
177
193
  return {
178
194
  model: model ? `${model.provider}/${model.id}` : "none",
179
- remoteEligible: usesCodexResponsesApi(model)
195
+ api: model?.api
180
196
  };
181
197
  }
182
198
  function compactRoute(state, status) {
183
- if (!state.settings.enabled) return "Pi native (Remote V2 off)";
184
- return status?.remoteEligible ? "Codex Remote V2" : "Pi native (requires openai-codex-responses)";
199
+ const route = resolveCompactionRouteForApi(status?.api, state.settings);
200
+ if (route.kind === "native") return `Pi native (${route.reason})`;
201
+ return route.protocol === "remote-v2" ? "Responses Remote V2" : "Responses Compact API";
185
202
  }
186
203
  export {
187
204
  compactMenuStatus,
188
205
  createCodexCompactMenu,
189
206
  showCodexCompactMenu
190
207
  };
191
- //# sourceMappingURL=settings-menu-PEDLURUH.js.map
208
+ //# sourceMappingURL=settings-menu-TVWWDPBF.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/settings-menu.ts"],
4
+ "sourcesContent": ["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport type { MenuDefinition } from \"@narumitw/pi-tui-kit\";\nimport { resolveCompactionRouteForApi } from \"./model-api.js\";\nimport type { CodexCompactSettings, CodexCompactSettingsRuntime, CodexCompactSettingsState } from \"./settings.js\";\nimport { terminalText as safeText } from \"./terminal.js\";\n\ntype Screen = \"main\" | \"settings\" | \"invalid\";\ntype Action =\n | \"compact-now\"\n | \"set-enabled\"\n | \"set-protocol\"\n | \"set-timeout\"\n | \"set-retries\"\n | \"set-retention\"\n | \"set-notify\";\n\nexport interface SettingsMenuOwner {\n signal: AbortSignal;\n isCurrent(): boolean;\n}\n\ninterface CompactMenuStatus {\n model: string;\n api?: Api;\n}\n\nfunction timeoutLabel(milliseconds: number): string {\n return `${milliseconds / 60_000} min`;\n}\n\nfunction retentionLabel(tokens: number): string {\n return `${tokens / 1000}K tokens`;\n}\n\nfunction protocolLabel(protocol: CodexCompactSettings[\"protocol\"]): string {\n switch (protocol) {\n case \"auto\":\n return \"Auto\";\n case \"remote-v2\":\n return \"Remote V2\";\n case \"responses-compact\":\n return \"Responses Compact\";\n }\n}\n\nasync function update(\n runtime: CodexCompactSettingsRuntime,\n ctx: ExtensionCommandContext,\n patch: Partial<CodexCompactSettings>,\n signal: AbortSignal,\n) {\n try {\n await runtime.update(patch, signal);\n if (signal.aborted) return { kind: \"rejected\" as const };\n ctx.ui.notify(\"Responses compaction settings saved.\", \"info\");\n return { kind: \"stay\" as const };\n } catch (error) {\n if (signal.aborted) return { kind: \"rejected\" as const };\n ctx.ui.notify(\n `Could not save pi-codex-compact.json: ${safeText(error instanceof Error ? error.message : String(error))}`,\n \"error\",\n );\n return { kind: \"rejected\" as const };\n }\n}\n\nexport function createCodexCompactMenu(\n runtime: CodexCompactSettingsRuntime,\n options: { onCompactRequested?: () => void; status?: CompactMenuStatus } = {},\n): MenuDefinition<CodexCompactSettingsState, Screen, Action, ExtensionCommandContext> {\n return {\n start: \"main\",\n screens: {\n main: ({ state }) => ({\n kind: \"actions\",\n title: \"Responses Compaction\",\n lines: [\n `Remote compaction: ${state.settings.enabled ? \"On\" : \"Off\"}`,\n `Protocol setting: ${protocolLabel(state.settings.protocol)}`,\n `Active model: ${safeText(options.status?.model ?? \"none\")}`,\n `Compact route: ${safeText(compactRoute(state, options.status))}`,\n ],\n items: [\n {\n id: \"compact-now\",\n label: \"Compact now\",\n description: \"Close this menu and compact the active session immediately.\",\n action: \"compact-now\",\n },\n state.kind === \"invalid\"\n ? {\n id: \"settings\",\n label: \"Settings\",\n description: \"Read-only until the invalid settings file is repaired.\",\n to: \"invalid\" as const,\n }\n : { id: \"settings\", label: \"Settings\", to: \"settings\" as const },\n { id: \"close\", label: \"Close\", close: true },\n ],\n hint: \"close\",\n }),\n settings: ({ state }) => ({\n kind: \"settings\",\n title: \"Responses Compaction Settings\",\n lines: [`User settings \u00B7 ${safeText(state.path)}`],\n items: [\n {\n id: \"enabled\",\n label: \"Remote compaction\",\n description: \"Use a supported Responses compaction protocol.\",\n currentValue: state.settings.enabled ? \"On\" : \"Off\",\n values: [\"On\", \"Off\"],\n action: \"set-enabled\",\n },\n {\n id: \"protocol\",\n label: \"Protocol\",\n description: \"Choose automatically or force one supported remote protocol.\",\n currentValue: protocolLabel(state.settings.protocol),\n values: [\"Auto\", \"Remote V2\", \"Responses Compact\"],\n action: \"set-protocol\",\n },\n {\n id: \"requestTimeoutMs\",\n label: \"Request timeout\",\n description: \"Maximum time for the extension-owned remote compaction request.\",\n currentValue: timeoutLabel(state.settings.requestTimeoutMs),\n values: [\"2 min\", \"5 min\", \"10 min\"],\n action: \"set-timeout\",\n },\n {\n id: \"maxRetries\",\n label: \"Transport retries\",\n description: \"Retry transient provider failures before falling back to Pi.\",\n currentValue: String(state.settings.maxRetries),\n values: [\"0\", \"1\", \"2\"],\n action: \"set-retries\",\n },\n {\n id: \"replacementTokenBudget\",\n label: \"Retained user history\",\n description: \"Approximate user-message budget kept beside the opaque checkpoint.\",\n currentValue: retentionLabel(state.settings.replacementTokenBudget),\n values: [\"32K tokens\", \"64K tokens\", \"96K tokens\", \"128K tokens\"],\n action: \"set-retention\",\n },\n {\n id: \"notifyOnFallback\",\n label: \"Fallback notifications\",\n description: \"Warn when remote compaction fails and Pi native takes over.\",\n currentValue: state.settings.notifyOnFallback ? \"On\" : \"Off\",\n values: [\"On\", \"Off\"],\n action: \"set-notify\",\n },\n ],\n }),\n invalid: ({ state }) => ({\n kind: \"detail\",\n title: \"Codex Compact Settings \u00B7 Read only\",\n lines: [\n `Invalid settings file: ${safeText(state.path)}`,\n `Issue: ${safeText(state.issue ?? \"unknown validation error\")}`,\n \"Built-in defaults are active. Repair the file and run /reload; it will not be overwritten.\",\n ],\n hint: \"back\",\n }),\n },\n actions: {\n \"compact-now\": async () => {\n options.onCompactRequested?.();\n return { kind: \"close\" };\n },\n \"set-enabled\": ({ ctx, value, signal }) => update(runtime, ctx, { enabled: value === \"On\" }, signal),\n \"set-protocol\": ({ ctx, value, signal }) =>\n update(\n runtime,\n ctx,\n {\n protocol:\n value === \"Remote V2\" ? \"remote-v2\" : value === \"Responses Compact\" ? \"responses-compact\" : \"auto\",\n },\n signal,\n ),\n \"set-timeout\": ({ ctx, value, signal }) =>\n update(runtime, ctx, { requestTimeoutMs: Number.parseInt(value ?? \"5\", 10) * 60_000 }, signal),\n \"set-retries\": ({ ctx, value, signal }) =>\n update(runtime, ctx, { maxRetries: Number.parseInt(value ?? \"2\", 10) }, signal),\n \"set-retention\": ({ ctx, value, signal }) =>\n update(runtime, ctx, { replacementTokenBudget: Number.parseInt(value ?? \"64\", 10) * 1000 }, signal),\n \"set-notify\": ({ ctx, value, signal }) => update(runtime, ctx, { notifyOnFallback: value === \"On\" }, signal),\n },\n };\n}\n\nexport async function showCodexCompactMenu(\n runtime: CodexCompactSettingsRuntime,\n ctx: ExtensionCommandContext,\n owner: SettingsMenuOwner,\n): Promise<void> {\n if (ctx.mode === \"rpc\" && ctx.hasUI) {\n ctx.ui.notify(`Edit Responses compaction settings at ${safeText(runtime.get().path)}.`, \"info\");\n return;\n }\n if (ctx.mode !== \"tui\") {\n throw new Error(\"/codex-compact requires TUI or RPC UI support\");\n }\n const { runMenu } = await import(\"@narumitw/pi-tui-kit\");\n if (owner.signal.aborted || !owner.isCurrent()) return;\n let compactRequested = false;\n await runMenu(\n ctx,\n createCodexCompactMenu(runtime, {\n onCompactRequested: () => {\n compactRequested = true;\n },\n status: compactMenuStatus(ctx),\n }),\n {\n getState: () => runtime.get(),\n signal: owner.signal,\n isCurrent: owner.isCurrent,\n },\n );\n if (!compactRequested || owner.signal.aborted || !owner.isCurrent()) return;\n ctx.compact({\n onError: (error) => {\n if (!owner.signal.aborted && owner.isCurrent()) {\n ctx.ui.notify(`Compaction failed: ${safeText(error.message)}`, \"error\");\n }\n },\n });\n}\n\nexport function compactMenuStatus(ctx: ExtensionCommandContext): CompactMenuStatus {\n const model = ctx.model;\n return {\n model: model ? `${model.provider}/${model.id}` : \"none\",\n api: model?.api,\n };\n}\n\nfunction compactRoute(state: Readonly<CodexCompactSettingsState>, status: CompactMenuStatus | undefined): string {\n const route = resolveCompactionRouteForApi(status?.api, state.settings);\n if (route.kind === \"native\") return `Pi native (${route.reason})`;\n return route.protocol === \"remote-v2\" ? \"Responses Remote V2\" : \"Responses Compact API\";\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }