@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 +90 -90
- package/dist/chunks/chunk-7H7JJ7ZV.js +37 -0
- package/dist/chunks/chunk-7H7JJ7ZV.js.map +7 -0
- package/dist/chunks/{settings-menu-PEDLURUH.js → settings-menu-TVWWDPBF.js} +52 -35
- package/dist/chunks/settings-menu-TVWWDPBF.js.map +7 -0
- package/dist/index.ts +541 -101
- package/dist/index.ts.map +4 -4
- package/package.json +53 -57
- package/src/checkpoint.ts +265 -218
- package/src/codex-compact.ts +252 -229
- package/src/model-api.ts +56 -5
- package/src/protocol.ts +318 -179
- package/src/remote-compact.ts +276 -0
- package/src/remote-shared.ts +16 -0
- package/src/remote-types.ts +46 -0
- package/src/remote-v2.ts +66 -0
- package/src/remote.ts +14 -116
- package/src/settings-menu.ts +213 -201
- package/src/settings.ts +228 -176
- package/src/terminal.ts +6 -0
- package/dist/chunks/chunk-6TZ2L2BM.js +0 -13
- package/dist/chunks/chunk-6TZ2L2BM.js.map +0 -7
- package/dist/chunks/settings-menu-PEDLURUH.js.map +0 -7
package/src/settings-menu.ts
CHANGED
|
@@ -1,235 +1,247 @@
|
|
|
1
|
+
import type { Api } from "@earendil-works/pi-ai";
|
|
1
2
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
3
|
import type { MenuDefinition } from "@narumitw/pi-tui-kit";
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
CodexCompactSettingsRuntime,
|
|
7
|
-
CodexCompactSettingsState,
|
|
8
|
-
} from "./settings.js";
|
|
4
|
+
import { resolveCompactionRouteForApi } from "./model-api.js";
|
|
5
|
+
import type { CodexCompactSettings, CodexCompactSettingsRuntime, CodexCompactSettingsState } from "./settings.js";
|
|
6
|
+
import { terminalText as safeText } from "./terminal.js";
|
|
9
7
|
|
|
10
8
|
type Screen = "main" | "settings" | "invalid";
|
|
11
9
|
type Action =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
| "compact-now"
|
|
11
|
+
| "set-enabled"
|
|
12
|
+
| "set-protocol"
|
|
13
|
+
| "set-timeout"
|
|
14
|
+
| "set-retries"
|
|
15
|
+
| "set-retention"
|
|
16
|
+
| "set-notify";
|
|
18
17
|
|
|
19
18
|
export interface SettingsMenuOwner {
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
isCurrent(): boolean;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
interface CompactMenuStatus {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function safeText(value: string): string {
|
|
30
|
-
return Array.from(value, (character) => {
|
|
31
|
-
const codePoint = character.codePointAt(0) ?? 0;
|
|
32
|
-
return codePoint < 32 || (codePoint >= 127 && codePoint <= 159) ? " " : character;
|
|
33
|
-
}).join("");
|
|
24
|
+
model: string;
|
|
25
|
+
api?: Api;
|
|
34
26
|
}
|
|
35
27
|
|
|
36
28
|
function timeoutLabel(milliseconds: number): string {
|
|
37
|
-
|
|
29
|
+
return `${milliseconds / 60_000} min`;
|
|
38
30
|
}
|
|
39
31
|
|
|
40
32
|
function retentionLabel(tokens: number): string {
|
|
41
|
-
|
|
33
|
+
return `${tokens / 1000}K tokens`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function protocolLabel(protocol: CodexCompactSettings["protocol"]): string {
|
|
37
|
+
switch (protocol) {
|
|
38
|
+
case "auto":
|
|
39
|
+
return "Auto";
|
|
40
|
+
case "remote-v2":
|
|
41
|
+
return "Remote V2";
|
|
42
|
+
case "responses-compact":
|
|
43
|
+
return "Responses Compact";
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
async function update(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
runtime: CodexCompactSettingsRuntime,
|
|
49
|
+
ctx: ExtensionCommandContext,
|
|
50
|
+
patch: Partial<CodexCompactSettings>,
|
|
51
|
+
signal: AbortSignal,
|
|
49
52
|
) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
try {
|
|
54
|
+
await runtime.update(patch, signal);
|
|
55
|
+
if (signal.aborted) return { kind: "rejected" as const };
|
|
56
|
+
ctx.ui.notify("Responses compaction settings saved.", "info");
|
|
57
|
+
return { kind: "stay" as const };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (signal.aborted) return { kind: "rejected" as const };
|
|
60
|
+
ctx.ui.notify(
|
|
61
|
+
`Could not save pi-codex-compact.json: ${safeText(error instanceof Error ? error.message : String(error))}`,
|
|
62
|
+
"error",
|
|
63
|
+
);
|
|
64
|
+
return { kind: "rejected" as const };
|
|
65
|
+
}
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
export function createCodexCompactMenu(
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
runtime: CodexCompactSettingsRuntime,
|
|
70
|
+
options: { onCompactRequested?: () => void; status?: CompactMenuStatus } = {},
|
|
67
71
|
): MenuDefinition<CodexCompactSettingsState, Screen, Action, ExtensionCommandContext> {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
72
|
+
return {
|
|
73
|
+
start: "main",
|
|
74
|
+
screens: {
|
|
75
|
+
main: ({ state }) => ({
|
|
76
|
+
kind: "actions",
|
|
77
|
+
title: "Responses Compaction",
|
|
78
|
+
lines: [
|
|
79
|
+
`Remote compaction: ${state.settings.enabled ? "On" : "Off"}`,
|
|
80
|
+
`Protocol setting: ${protocolLabel(state.settings.protocol)}`,
|
|
81
|
+
`Active model: ${safeText(options.status?.model ?? "none")}`,
|
|
82
|
+
`Compact route: ${safeText(compactRoute(state, options.status))}`,
|
|
83
|
+
],
|
|
84
|
+
items: [
|
|
85
|
+
{
|
|
86
|
+
id: "compact-now",
|
|
87
|
+
label: "Compact now",
|
|
88
|
+
description: "Close this menu and compact the active session immediately.",
|
|
89
|
+
action: "compact-now",
|
|
90
|
+
},
|
|
91
|
+
state.kind === "invalid"
|
|
92
|
+
? {
|
|
93
|
+
id: "settings",
|
|
94
|
+
label: "Settings",
|
|
95
|
+
description: "Read-only until the invalid settings file is repaired.",
|
|
96
|
+
to: "invalid" as const,
|
|
97
|
+
}
|
|
98
|
+
: { id: "settings", label: "Settings", to: "settings" as const },
|
|
99
|
+
{ id: "close", label: "Close", close: true },
|
|
100
|
+
],
|
|
101
|
+
hint: "close",
|
|
102
|
+
}),
|
|
103
|
+
settings: ({ state }) => ({
|
|
104
|
+
kind: "settings",
|
|
105
|
+
title: "Responses Compaction Settings",
|
|
106
|
+
lines: [`User settings · ${safeText(state.path)}`],
|
|
107
|
+
items: [
|
|
108
|
+
{
|
|
109
|
+
id: "enabled",
|
|
110
|
+
label: "Remote compaction",
|
|
111
|
+
description: "Use a supported Responses compaction protocol.",
|
|
112
|
+
currentValue: state.settings.enabled ? "On" : "Off",
|
|
113
|
+
values: ["On", "Off"],
|
|
114
|
+
action: "set-enabled",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "protocol",
|
|
118
|
+
label: "Protocol",
|
|
119
|
+
description: "Choose automatically or force one supported remote protocol.",
|
|
120
|
+
currentValue: protocolLabel(state.settings.protocol),
|
|
121
|
+
values: ["Auto", "Remote V2", "Responses Compact"],
|
|
122
|
+
action: "set-protocol",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: "requestTimeoutMs",
|
|
126
|
+
label: "Request timeout",
|
|
127
|
+
description: "Maximum time for the extension-owned remote compaction request.",
|
|
128
|
+
currentValue: timeoutLabel(state.settings.requestTimeoutMs),
|
|
129
|
+
values: ["2 min", "5 min", "10 min"],
|
|
130
|
+
action: "set-timeout",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: "maxRetries",
|
|
134
|
+
label: "Transport retries",
|
|
135
|
+
description: "Retry transient provider failures before falling back to Pi.",
|
|
136
|
+
currentValue: String(state.settings.maxRetries),
|
|
137
|
+
values: ["0", "1", "2"],
|
|
138
|
+
action: "set-retries",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "replacementTokenBudget",
|
|
142
|
+
label: "Retained user history",
|
|
143
|
+
description: "Approximate user-message budget kept beside the opaque checkpoint.",
|
|
144
|
+
currentValue: retentionLabel(state.settings.replacementTokenBudget),
|
|
145
|
+
values: ["32K tokens", "64K tokens", "96K tokens", "128K tokens"],
|
|
146
|
+
action: "set-retention",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "notifyOnFallback",
|
|
150
|
+
label: "Fallback notifications",
|
|
151
|
+
description: "Warn when remote compaction fails and Pi native takes over.",
|
|
152
|
+
currentValue: state.settings.notifyOnFallback ? "On" : "Off",
|
|
153
|
+
values: ["On", "Off"],
|
|
154
|
+
action: "set-notify",
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
}),
|
|
158
|
+
invalid: ({ state }) => ({
|
|
159
|
+
kind: "detail",
|
|
160
|
+
title: "Codex Compact Settings · Read only",
|
|
161
|
+
lines: [
|
|
162
|
+
`Invalid settings file: ${safeText(state.path)}`,
|
|
163
|
+
`Issue: ${safeText(state.issue ?? "unknown validation error")}`,
|
|
164
|
+
"Built-in defaults are active. Repair the file and run /reload; it will not be overwritten.",
|
|
165
|
+
],
|
|
166
|
+
hint: "back",
|
|
167
|
+
}),
|
|
168
|
+
},
|
|
169
|
+
actions: {
|
|
170
|
+
"compact-now": async () => {
|
|
171
|
+
options.onCompactRequested?.();
|
|
172
|
+
return { kind: "close" };
|
|
173
|
+
},
|
|
174
|
+
"set-enabled": ({ ctx, value, signal }) => update(runtime, ctx, { enabled: value === "On" }, signal),
|
|
175
|
+
"set-protocol": ({ ctx, value, signal }) =>
|
|
176
|
+
update(
|
|
177
|
+
runtime,
|
|
178
|
+
ctx,
|
|
179
|
+
{
|
|
180
|
+
protocol:
|
|
181
|
+
value === "Remote V2" ? "remote-v2" : value === "Responses Compact" ? "responses-compact" : "auto",
|
|
182
|
+
},
|
|
183
|
+
signal,
|
|
184
|
+
),
|
|
185
|
+
"set-timeout": ({ ctx, value, signal }) =>
|
|
186
|
+
update(runtime, ctx, { requestTimeoutMs: Number.parseInt(value ?? "5", 10) * 60_000 }, signal),
|
|
187
|
+
"set-retries": ({ ctx, value, signal }) =>
|
|
188
|
+
update(runtime, ctx, { maxRetries: Number.parseInt(value ?? "2", 10) }, signal),
|
|
189
|
+
"set-retention": ({ ctx, value, signal }) =>
|
|
190
|
+
update(runtime, ctx, { replacementTokenBudget: Number.parseInt(value ?? "64", 10) * 1000 }, signal),
|
|
191
|
+
"set-notify": ({ ctx, value, signal }) => update(runtime, ctx, { notifyOnFallback: value === "On" }, signal),
|
|
192
|
+
},
|
|
193
|
+
};
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
export async function showCodexCompactMenu(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
runtime: CodexCompactSettingsRuntime,
|
|
198
|
+
ctx: ExtensionCommandContext,
|
|
199
|
+
owner: SettingsMenuOwner,
|
|
189
200
|
): Promise<void> {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
201
|
+
if (ctx.mode === "rpc" && ctx.hasUI) {
|
|
202
|
+
ctx.ui.notify(`Edit Responses compaction settings at ${safeText(runtime.get().path)}.`, "info");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (ctx.mode !== "tui") {
|
|
206
|
+
throw new Error("/codex-compact requires TUI or RPC UI support");
|
|
207
|
+
}
|
|
208
|
+
const { runMenu } = await import("@narumitw/pi-tui-kit");
|
|
209
|
+
if (owner.signal.aborted || !owner.isCurrent()) return;
|
|
210
|
+
let compactRequested = false;
|
|
211
|
+
await runMenu(
|
|
212
|
+
ctx,
|
|
213
|
+
createCodexCompactMenu(runtime, {
|
|
214
|
+
onCompactRequested: () => {
|
|
215
|
+
compactRequested = true;
|
|
216
|
+
},
|
|
217
|
+
status: compactMenuStatus(ctx),
|
|
218
|
+
}),
|
|
219
|
+
{
|
|
220
|
+
getState: () => runtime.get(),
|
|
221
|
+
signal: owner.signal,
|
|
222
|
+
isCurrent: owner.isCurrent,
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
if (!compactRequested || owner.signal.aborted || !owner.isCurrent()) return;
|
|
226
|
+
ctx.compact({
|
|
227
|
+
onError: (error) => {
|
|
228
|
+
if (!owner.signal.aborted && owner.isCurrent()) {
|
|
229
|
+
ctx.ui.notify(`Compaction failed: ${safeText(error.message)}`, "error");
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
});
|
|
219
233
|
}
|
|
220
234
|
|
|
221
235
|
export function compactMenuStatus(ctx: ExtensionCommandContext): CompactMenuStatus {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
236
|
+
const model = ctx.model;
|
|
237
|
+
return {
|
|
238
|
+
model: model ? `${model.provider}/${model.id}` : "none",
|
|
239
|
+
api: model?.api,
|
|
240
|
+
};
|
|
227
241
|
}
|
|
228
242
|
|
|
229
|
-
function compactRoute(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (!state.settings.enabled) return "Pi native (Remote V2 off)";
|
|
234
|
-
return status?.remoteEligible ? "Codex Remote V2" : "Pi native (requires openai-codex-responses)";
|
|
243
|
+
function compactRoute(state: Readonly<CodexCompactSettingsState>, status: CompactMenuStatus | undefined): string {
|
|
244
|
+
const route = resolveCompactionRouteForApi(status?.api, state.settings);
|
|
245
|
+
if (route.kind === "native") return `Pi native (${route.reason})`;
|
|
246
|
+
return route.protocol === "remote-v2" ? "Responses Remote V2" : "Responses Compact API";
|
|
235
247
|
}
|