@narumitw/pi-codex-compact 0.52.0 → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -46
- package/dist/chunks/{chunk-JYXZMCXD.js → chunk-7H7JJ7ZV.js} +9 -15
- package/dist/chunks/chunk-7H7JJ7ZV.js.map +7 -0
- package/dist/chunks/{settings-menu-VYQ6ABCP.js → settings-menu-OAWFW2PH.js} +5 -15
- package/dist/chunks/settings-menu-OAWFW2PH.js.map +7 -0
- package/dist/index.ts +91 -94
- package/dist/index.ts.map +2 -2
- package/package.json +53 -54
- package/src/checkpoint.ts +261 -249
- package/src/codex-compact.ts +250 -254
- package/src/model-api.ts +40 -29
- package/src/protocol.ts +293 -312
- package/src/remote-compact.ts +230 -252
- package/src/remote-shared.ts +12 -15
- package/src/remote-types.ts +27 -26
- package/src/remote-v2.ts +57 -61
- package/src/remote.ts +7 -9
- package/src/settings-menu.ts +207 -231
- package/src/settings.ts +227 -190
- package/src/terminal.ts +4 -4
- package/dist/chunks/chunk-JYXZMCXD.js.map +0 -7
- package/dist/chunks/settings-menu-VYQ6ABCP.js.map +0 -7
package/src/settings.ts
CHANGED
|
@@ -9,234 +9,271 @@ export const CODEX_COMPACT_SETTINGS_FILE = "pi-codex-compact.json";
|
|
|
9
9
|
export const MAX_SETTINGS_BYTES = 64 * 1024;
|
|
10
10
|
|
|
11
11
|
export interface CodexCompactSettings {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
protocol: RemoteCompactionProtocolSetting;
|
|
14
|
+
apiProfiles: Record<string, "codex-responses-v1">;
|
|
15
|
+
requestTimeoutMs: number;
|
|
16
|
+
maxRetries: number;
|
|
17
|
+
replacementTokenBudget: number;
|
|
18
|
+
notifyOnFallback: boolean;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export const DEFAULT_CODEX_COMPACT_SETTINGS: Readonly<CodexCompactSettings> = Object.freeze({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
enabled: true,
|
|
23
|
+
protocol: "auto",
|
|
24
|
+
apiProfiles: {},
|
|
25
|
+
requestTimeoutMs: 300_000,
|
|
26
|
+
maxRetries: 2,
|
|
27
|
+
replacementTokenBudget: 64_000,
|
|
28
|
+
notifyOnFallback: true,
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
const LIMITS = Object.freeze({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
requestTimeoutMs: { minimum: 30_000, maximum: 600_000 },
|
|
33
|
+
maxRetries: { minimum: 0, maximum: 2 },
|
|
34
|
+
replacementTokenBudget: { minimum: 8_000, maximum: 128_000 },
|
|
33
35
|
});
|
|
34
36
|
|
|
37
|
+
const BUILT_IN_APIS = new Set([
|
|
38
|
+
"openai-completions",
|
|
39
|
+
"mistral-conversations",
|
|
40
|
+
"openai-codex-responses",
|
|
41
|
+
"openai-responses",
|
|
42
|
+
"azure-openai-responses",
|
|
43
|
+
"anthropic-messages",
|
|
44
|
+
"bedrock-converse-stream",
|
|
45
|
+
"google-generative-ai",
|
|
46
|
+
"google-vertex",
|
|
47
|
+
"pi-messages",
|
|
48
|
+
]);
|
|
49
|
+
const MAX_API_PROFILE_ID_LENGTH = 256;
|
|
50
|
+
|
|
35
51
|
export interface CodexCompactSettingsState {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
kind: "missing" | "loaded" | "invalid";
|
|
53
|
+
path: string;
|
|
54
|
+
settings: CodexCompactSettings;
|
|
55
|
+
document?: Record<string, unknown>;
|
|
56
|
+
issue?: string;
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
export interface CodexCompactSettingsRuntime {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
signal?: AbortSignal,
|
|
49
|
-
): Promise<Readonly<CodexCompactSettingsState>>;
|
|
50
|
-
flush(): Promise<void>;
|
|
60
|
+
get(): Readonly<CodexCompactSettingsState>;
|
|
61
|
+
reload(signal?: AbortSignal): Promise<Readonly<CodexCompactSettingsState>>;
|
|
62
|
+
update(patch: Partial<CodexCompactSettings>, signal?: AbortSignal): Promise<Readonly<CodexCompactSettingsState>>;
|
|
63
|
+
flush(): Promise<void>;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
54
|
-
|
|
67
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
function validInteger(value: unknown, minimum: number, maximum: number): value is number {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= minimum && value <= maximum;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function hasWhitespaceOrControl(value: string): boolean {
|
|
75
|
+
return [...value].some((character) => {
|
|
76
|
+
const code = character.codePointAt(0) ?? 0;
|
|
77
|
+
return code <= 0x20 || code === 0x7f;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function normalizeApiProfiles(value: unknown): Record<string, "codex-responses-v1"> | undefined {
|
|
82
|
+
if (
|
|
83
|
+
!isRecord(value) ||
|
|
84
|
+
(Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
|
|
85
|
+
) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const profiles: Record<string, "codex-responses-v1"> = {};
|
|
89
|
+
for (const [api, profile] of Object.entries(value)) {
|
|
90
|
+
if (
|
|
91
|
+
api.length === 0 ||
|
|
92
|
+
api.length > MAX_API_PROFILE_ID_LENGTH ||
|
|
93
|
+
api.trim() !== api ||
|
|
94
|
+
hasWhitespaceOrControl(api) ||
|
|
95
|
+
BUILT_IN_APIS.has(api) ||
|
|
96
|
+
api === "__proto__" ||
|
|
97
|
+
api === "constructor" ||
|
|
98
|
+
api === "prototype" ||
|
|
99
|
+
profile !== "codex-responses-v1"
|
|
100
|
+
) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
profiles[api] = profile;
|
|
104
|
+
}
|
|
105
|
+
return profiles;
|
|
61
106
|
}
|
|
62
107
|
|
|
63
108
|
export function normalizeCodexCompactSettings(value: unknown): CodexCompactSettings | undefined {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
typeof value.notifyOnFallback === "boolean"
|
|
108
|
-
? value.notifyOnFallback
|
|
109
|
-
: DEFAULT_CODEX_COMPACT_SETTINGS.notifyOnFallback,
|
|
110
|
-
};
|
|
109
|
+
if (!isRecord(value)) return undefined;
|
|
110
|
+
if (Object.hasOwn(value, "enabled") && typeof value.enabled !== "boolean") return undefined;
|
|
111
|
+
if (
|
|
112
|
+
Object.hasOwn(value, "protocol") &&
|
|
113
|
+
value.protocol !== "auto" &&
|
|
114
|
+
value.protocol !== "remote-v2" &&
|
|
115
|
+
value.protocol !== "responses-compact"
|
|
116
|
+
) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
if (Object.hasOwn(value, "notifyOnFallback") && typeof value.notifyOnFallback !== "boolean") {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
if (Object.hasOwn(value, "apiProfiles") && normalizeApiProfiles(value.apiProfiles) === undefined) return undefined;
|
|
123
|
+
for (const [field, limits] of Object.entries(LIMITS) as [
|
|
124
|
+
keyof typeof LIMITS,
|
|
125
|
+
{ minimum: number; maximum: number },
|
|
126
|
+
][]) {
|
|
127
|
+
if (Object.hasOwn(value, field) && !validInteger(value[field], limits.minimum, limits.maximum)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
enabled: typeof value.enabled === "boolean" ? value.enabled : DEFAULT_CODEX_COMPACT_SETTINGS.enabled,
|
|
133
|
+
protocol:
|
|
134
|
+
value.protocol === "remote-v2" || value.protocol === "responses-compact"
|
|
135
|
+
? value.protocol
|
|
136
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.protocol,
|
|
137
|
+
apiProfiles: normalizeApiProfiles(value.apiProfiles) ?? structuredClone(DEFAULT_CODEX_COMPACT_SETTINGS.apiProfiles),
|
|
138
|
+
requestTimeoutMs:
|
|
139
|
+
typeof value.requestTimeoutMs === "number"
|
|
140
|
+
? value.requestTimeoutMs
|
|
141
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.requestTimeoutMs,
|
|
142
|
+
maxRetries: typeof value.maxRetries === "number" ? value.maxRetries : DEFAULT_CODEX_COMPACT_SETTINGS.maxRetries,
|
|
143
|
+
replacementTokenBudget:
|
|
144
|
+
typeof value.replacementTokenBudget === "number"
|
|
145
|
+
? value.replacementTokenBudget
|
|
146
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.replacementTokenBudget,
|
|
147
|
+
notifyOnFallback:
|
|
148
|
+
typeof value.notifyOnFallback === "boolean"
|
|
149
|
+
? value.notifyOnFallback
|
|
150
|
+
: DEFAULT_CODEX_COMPACT_SETTINGS.notifyOnFallback,
|
|
151
|
+
};
|
|
111
152
|
}
|
|
112
153
|
|
|
113
154
|
export function codexCompactSettingsPath(): string {
|
|
114
|
-
|
|
155
|
+
return join(getAgentDir(), CODEX_COMPACT_SETTINGS_FILE);
|
|
115
156
|
}
|
|
116
157
|
|
|
117
158
|
function aborted(signal?: AbortSignal): void {
|
|
118
|
-
|
|
159
|
+
if (signal?.aborted) throw new DOMException("Settings operation aborted", "AbortError");
|
|
119
160
|
}
|
|
120
161
|
|
|
121
162
|
export async function loadCodexCompactSettings(
|
|
122
|
-
|
|
123
|
-
|
|
163
|
+
path = codexCompactSettingsPath(),
|
|
164
|
+
signal?: AbortSignal,
|
|
124
165
|
): Promise<CodexCompactSettingsState> {
|
|
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
|
-
|
|
166
|
+
aborted(signal);
|
|
167
|
+
try {
|
|
168
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
169
|
+
let text: string;
|
|
170
|
+
try {
|
|
171
|
+
const stats = await handle.stat();
|
|
172
|
+
aborted(signal);
|
|
173
|
+
if (!stats.isFile()) throw new Error("settings path is not a regular file");
|
|
174
|
+
if (stats.size > MAX_SETTINGS_BYTES) throw new Error("settings file exceeds 64 KiB");
|
|
175
|
+
text = await handle.readFile("utf8");
|
|
176
|
+
} finally {
|
|
177
|
+
await handle.close();
|
|
178
|
+
}
|
|
179
|
+
aborted(signal);
|
|
180
|
+
const document = JSON.parse(text) as unknown;
|
|
181
|
+
const settings = normalizeCodexCompactSettings(document);
|
|
182
|
+
if (!settings || !isRecord(document)) throw new Error("invalid settings shape or bounds");
|
|
183
|
+
return { kind: "loaded", path, settings, document };
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (signal?.aborted) throw error;
|
|
186
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
187
|
+
return {
|
|
188
|
+
kind: "missing",
|
|
189
|
+
path,
|
|
190
|
+
settings: { ...DEFAULT_CODEX_COMPACT_SETTINGS },
|
|
191
|
+
document: {},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
kind: "invalid",
|
|
196
|
+
path,
|
|
197
|
+
settings: { ...DEFAULT_CODEX_COMPACT_SETTINGS },
|
|
198
|
+
issue:
|
|
199
|
+
isNodeError(error) && error.code === "ELOOP"
|
|
200
|
+
? "symbolic links are not accepted"
|
|
201
|
+
: error instanceof Error
|
|
202
|
+
? error.message
|
|
203
|
+
: String(error),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
165
206
|
}
|
|
166
207
|
|
|
167
208
|
async function savePatch(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
209
|
+
path: string,
|
|
210
|
+
patch: Partial<CodexCompactSettings>,
|
|
211
|
+
signal?: AbortSignal,
|
|
171
212
|
): Promise<CodexCompactSettingsState> {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
return { kind: "loaded", path, settings, document };
|
|
213
|
+
const latest = await loadCodexCompactSettings(path, signal);
|
|
214
|
+
if (latest.kind === "invalid") {
|
|
215
|
+
throw new Error("Cannot overwrite an invalid pi-codex-compact.json; repair it and reload first");
|
|
216
|
+
}
|
|
217
|
+
const document = { ...latest.document, ...patch };
|
|
218
|
+
const settings = normalizeCodexCompactSettings(document);
|
|
219
|
+
if (!settings) throw new Error("Refusing to save invalid Codex compaction settings");
|
|
220
|
+
const temporaryPath = join(dirname(path), `.${basename(path)}.${randomUUID()}.tmp`);
|
|
221
|
+
await mkdir(dirname(path), { recursive: true });
|
|
222
|
+
aborted(signal);
|
|
223
|
+
try {
|
|
224
|
+
await writeFile(temporaryPath, `${JSON.stringify(document, null, 2)}\n`, {
|
|
225
|
+
encoding: "utf8",
|
|
226
|
+
flag: "wx",
|
|
227
|
+
mode: 0o600,
|
|
228
|
+
});
|
|
229
|
+
aborted(signal);
|
|
230
|
+
const current = await loadCodexCompactSettings(path, signal);
|
|
231
|
+
if (
|
|
232
|
+
current.kind === "invalid" ||
|
|
233
|
+
current.kind !== latest.kind ||
|
|
234
|
+
JSON.stringify(current.document) !== JSON.stringify(latest.document)
|
|
235
|
+
) {
|
|
236
|
+
throw new Error("pi-codex-compact.json changed while saving; reopen settings and retry");
|
|
237
|
+
}
|
|
238
|
+
await rename(temporaryPath, path);
|
|
239
|
+
} finally {
|
|
240
|
+
await rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
241
|
+
}
|
|
242
|
+
return { kind: "loaded", path, settings, document };
|
|
204
243
|
}
|
|
205
244
|
|
|
206
|
-
export function createCodexCompactSettingsRuntime(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
flush: () => queue,
|
|
237
|
-
};
|
|
245
|
+
export function createCodexCompactSettingsRuntime(path = codexCompactSettingsPath()): CodexCompactSettingsRuntime {
|
|
246
|
+
let state: CodexCompactSettingsState = {
|
|
247
|
+
kind: "missing",
|
|
248
|
+
path,
|
|
249
|
+
settings: { ...DEFAULT_CODEX_COMPACT_SETTINGS },
|
|
250
|
+
document: {},
|
|
251
|
+
};
|
|
252
|
+
let queue = Promise.resolve();
|
|
253
|
+
const enqueue = <T>(operation: () => Promise<T>): Promise<T> => {
|
|
254
|
+
const result = queue.then(operation, operation);
|
|
255
|
+
queue = result.then(
|
|
256
|
+
() => undefined,
|
|
257
|
+
() => undefined,
|
|
258
|
+
);
|
|
259
|
+
return result;
|
|
260
|
+
};
|
|
261
|
+
return {
|
|
262
|
+
get: () => structuredClone(state),
|
|
263
|
+
reload: (signal) =>
|
|
264
|
+
enqueue(async () => {
|
|
265
|
+
state = await loadCodexCompactSettings(path, signal);
|
|
266
|
+
return structuredClone(state);
|
|
267
|
+
}),
|
|
268
|
+
update: (patch, signal) =>
|
|
269
|
+
enqueue(async () => {
|
|
270
|
+
state = await savePatch(path, patch, signal);
|
|
271
|
+
return structuredClone(state);
|
|
272
|
+
}),
|
|
273
|
+
flush: () => queue,
|
|
274
|
+
};
|
|
238
275
|
}
|
|
239
276
|
|
|
240
277
|
function isNodeError(error: unknown): error is NodeJS.ErrnoException {
|
|
241
|
-
|
|
278
|
+
return error instanceof Error && "code" in error;
|
|
242
279
|
}
|
package/src/terminal.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function terminalText(value: string): string {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
return Array.from(value, (character) => {
|
|
3
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
4
|
+
return codePoint < 32 || (codePoint >= 127 && codePoint <= 159) ? " " : character;
|
|
5
|
+
}).join("");
|
|
6
6
|
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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 { hasApi } from \"@earendil-works/pi-ai\";\n\nexport const RESPONSES_COMPACTION_APIS = [\n\t\"openai-codex-responses\",\n\t\"openai-responses\",\n\t\"azure-openai-responses\",\n] as const;\n\nexport type ResponsesCompactionApi = (typeof RESPONSES_COMPACTION_APIS)[number];\nexport type RemoteCompactionProtocol = \"remote-v2\" | \"responses-compact\";\nexport type RemoteCompactionProtocolSetting = \"auto\" | RemoteCompactionProtocol;\n\nexport type CompactionRoute =\n\t| { kind: \"remote\"; protocol: RemoteCompactionProtocol; api: ResponsesCompactionApi }\n\t| { kind: \"native\"; reason: string };\n\nexport function usesResponsesCompactionApi(\n\tmodel: Model<Api> | undefined,\n): model is Model<ResponsesCompactionApi> {\n\treturn model !== undefined && RESPONSES_COMPACTION_APIS.some((api) => hasApi(model, api));\n}\n\nexport function resolveCompactionRouteForApi(\n\tapi: Api | undefined,\n\toptions: { enabled: boolean; protocol: RemoteCompactionProtocolSetting },\n): CompactionRoute {\n\tif (!options.enabled) return { kind: \"native\", reason: \"remote compaction is disabled\" };\n\tif (!api) return { kind: \"native\", reason: \"no active model\" };\n\tif (!RESPONSES_COMPACTION_APIS.includes(api as ResponsesCompactionApi)) {\n\t\treturn { kind: \"native\", reason: `API ${api} does not support Responses compaction` };\n\t}\n\tconst supportedApi = api as ResponsesCompactionApi;\n\tconst protocol =\n\t\toptions.protocol === \"auto\"\n\t\t\t? supportedApi === \"openai-codex-responses\"\n\t\t\t\t? \"remote-v2\"\n\t\t\t\t: \"responses-compact\"\n\t\t\t: options.protocol;\n\treturn { kind: \"remote\", protocol, api: supportedApi };\n}\n\nexport function resolveCompactionRoute(\n\tmodel: Model<Api> | undefined,\n\toptions: { enabled: boolean; protocol: RemoteCompactionProtocolSetting },\n): CompactionRoute {\n\treturn resolveCompactionRouteForApi(model?.api, options);\n}\n", "export function terminalText(value: string): string {\n\treturn Array.from(value, (character) => {\n\t\tconst codePoint = character.codePointAt(0) ?? 0;\n\t\treturn codePoint < 32 || (codePoint >= 127 && codePoint <= 159) ? \" \" : character;\n\t}).join(\"\");\n}\n"],
|
|
5
|
-
"mappings": ";;;;AACA,SAAS,cAAc;AAEhB,IAAM,4BAA4B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACD;AAUO,SAAS,2BACf,OACyC;AACzC,SAAO,UAAU,UAAa,0BAA0B,KAAK,CAAC,QAAQ,OAAO,OAAO,GAAG,CAAC;AACzF;AAEO,SAAS,6BACf,KACA,SACkB;AAClB,MAAI,CAAC,QAAQ,QAAS,QAAO,EAAE,MAAM,UAAU,QAAQ,gCAAgC;AACvF,MAAI,CAAC,IAAK,QAAO,EAAE,MAAM,UAAU,QAAQ,kBAAkB;AAC7D,MAAI,CAAC,0BAA0B,SAAS,GAA6B,GAAG;AACvE,WAAO,EAAE,MAAM,UAAU,QAAQ,OAAO,GAAG,yCAAyC;AAAA,EACrF;AACA,QAAM,eAAe;AACrB,QAAM,WACL,QAAQ,aAAa,SAClB,iBAAiB,2BAChB,cACA,sBACD,QAAQ;AACZ,SAAO,EAAE,MAAM,UAAU,UAAU,KAAK,aAAa;AACtD;AAEO,SAAS,uBACf,OACA,SACkB;AAClB,SAAO,6BAA6B,OAAO,KAAK,OAAO;AACxD;;;AC/CO,SAAS,aAAa,OAAuB;AACnD,SAAO,MAAM,KAAK,OAAO,CAAC,cAAc;AACvC,UAAM,YAAY,UAAU,YAAY,CAAC,KAAK;AAC9C,WAAO,YAAY,MAAO,aAAa,OAAO,aAAa,MAAO,MAAM;AAAA,EACzE,CAAC,EAAE,KAAK,EAAE;AACX;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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 {\n\tCodexCompactSettings,\n\tCodexCompactSettingsRuntime,\n\tCodexCompactSettingsState,\n} from \"./settings.js\";\nimport { terminalText as safeText } from \"./terminal.js\";\n\ntype Screen = \"main\" | \"settings\" | \"invalid\";\ntype Action =\n\t| \"compact-now\"\n\t| \"set-enabled\"\n\t| \"set-protocol\"\n\t| \"set-timeout\"\n\t| \"set-retries\"\n\t| \"set-retention\"\n\t| \"set-notify\";\n\nexport interface SettingsMenuOwner {\n\tsignal: AbortSignal;\n\tisCurrent(): boolean;\n}\n\ninterface CompactMenuStatus {\n\tmodel: string;\n\tapi?: Api;\n}\n\nfunction timeoutLabel(milliseconds: number): string {\n\treturn `${milliseconds / 60_000} min`;\n}\n\nfunction retentionLabel(tokens: number): string {\n\treturn `${tokens / 1000}K tokens`;\n}\n\nfunction protocolLabel(protocol: CodexCompactSettings[\"protocol\"]): string {\n\tswitch (protocol) {\n\t\tcase \"auto\":\n\t\t\treturn \"Auto\";\n\t\tcase \"remote-v2\":\n\t\t\treturn \"Remote V2\";\n\t\tcase \"responses-compact\":\n\t\t\treturn \"Responses Compact\";\n\t}\n}\n\nasync function update(\n\truntime: CodexCompactSettingsRuntime,\n\tctx: ExtensionCommandContext,\n\tpatch: Partial<CodexCompactSettings>,\n\tsignal: AbortSignal,\n) {\n\ttry {\n\t\tawait runtime.update(patch, signal);\n\t\tif (signal.aborted) return { kind: \"rejected\" as const };\n\t\tctx.ui.notify(\"Responses compaction settings saved.\", \"info\");\n\t\treturn { kind: \"stay\" as const };\n\t} catch (error) {\n\t\tif (signal.aborted) return { kind: \"rejected\" as const };\n\t\tctx.ui.notify(\n\t\t\t`Could not save pi-codex-compact.json: ${safeText(error instanceof Error ? error.message : String(error))}`,\n\t\t\t\"error\",\n\t\t);\n\t\treturn { kind: \"rejected\" as const };\n\t}\n}\n\nexport function createCodexCompactMenu(\n\truntime: CodexCompactSettingsRuntime,\n\toptions: { onCompactRequested?: () => void; status?: CompactMenuStatus } = {},\n): MenuDefinition<CodexCompactSettingsState, Screen, Action, ExtensionCommandContext> {\n\treturn {\n\t\tstart: \"main\",\n\t\tscreens: {\n\t\t\tmain: ({ state }) => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: \"Responses Compaction\",\n\t\t\t\tlines: [\n\t\t\t\t\t`Remote compaction: ${state.settings.enabled ? \"On\" : \"Off\"}`,\n\t\t\t\t\t`Protocol setting: ${protocolLabel(state.settings.protocol)}`,\n\t\t\t\t\t`Active model: ${safeText(options.status?.model ?? \"none\")}`,\n\t\t\t\t\t`Compact route: ${safeText(compactRoute(state, options.status))}`,\n\t\t\t\t],\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"compact-now\",\n\t\t\t\t\t\tlabel: \"Compact now\",\n\t\t\t\t\t\tdescription: \"Close this menu and compact the active session immediately.\",\n\t\t\t\t\t\taction: \"compact-now\",\n\t\t\t\t\t},\n\t\t\t\t\tstate.kind === \"invalid\"\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tid: \"settings\",\n\t\t\t\t\t\t\t\tlabel: \"Settings\",\n\t\t\t\t\t\t\t\tdescription: \"Read-only until the invalid settings file is repaired.\",\n\t\t\t\t\t\t\t\tto: \"invalid\" as const,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: { id: \"settings\", label: \"Settings\", to: \"settings\" as const },\n\t\t\t\t\t{ id: \"close\", label: \"Close\", close: true },\n\t\t\t\t],\n\t\t\t\thint: \"close\",\n\t\t\t}),\n\t\t\tsettings: ({ state }) => ({\n\t\t\t\tkind: \"settings\",\n\t\t\t\ttitle: \"Responses Compaction Settings\",\n\t\t\t\tlines: [`User settings \u00B7 ${safeText(state.path)}`],\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"enabled\",\n\t\t\t\t\t\tlabel: \"Remote compaction\",\n\t\t\t\t\t\tdescription: \"Use a supported Responses compaction protocol.\",\n\t\t\t\t\t\tcurrentValue: state.settings.enabled ? \"On\" : \"Off\",\n\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\taction: \"set-enabled\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"protocol\",\n\t\t\t\t\t\tlabel: \"Protocol\",\n\t\t\t\t\t\tdescription: \"Choose automatically or force one supported remote protocol.\",\n\t\t\t\t\t\tcurrentValue: protocolLabel(state.settings.protocol),\n\t\t\t\t\t\tvalues: [\"Auto\", \"Remote V2\", \"Responses Compact\"],\n\t\t\t\t\t\taction: \"set-protocol\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"requestTimeoutMs\",\n\t\t\t\t\t\tlabel: \"Request timeout\",\n\t\t\t\t\t\tdescription: \"Maximum time for the extension-owned remote compaction request.\",\n\t\t\t\t\t\tcurrentValue: timeoutLabel(state.settings.requestTimeoutMs),\n\t\t\t\t\t\tvalues: [\"2 min\", \"5 min\", \"10 min\"],\n\t\t\t\t\t\taction: \"set-timeout\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"maxRetries\",\n\t\t\t\t\t\tlabel: \"Transport retries\",\n\t\t\t\t\t\tdescription: \"Retry transient provider failures before falling back to Pi.\",\n\t\t\t\t\t\tcurrentValue: String(state.settings.maxRetries),\n\t\t\t\t\t\tvalues: [\"0\", \"1\", \"2\"],\n\t\t\t\t\t\taction: \"set-retries\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"replacementTokenBudget\",\n\t\t\t\t\t\tlabel: \"Retained user history\",\n\t\t\t\t\t\tdescription: \"Approximate user-message budget kept beside the opaque checkpoint.\",\n\t\t\t\t\t\tcurrentValue: retentionLabel(state.settings.replacementTokenBudget),\n\t\t\t\t\t\tvalues: [\"32K tokens\", \"64K tokens\", \"96K tokens\", \"128K tokens\"],\n\t\t\t\t\t\taction: \"set-retention\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"notifyOnFallback\",\n\t\t\t\t\t\tlabel: \"Fallback notifications\",\n\t\t\t\t\t\tdescription: \"Warn when remote compaction fails and Pi native takes over.\",\n\t\t\t\t\t\tcurrentValue: state.settings.notifyOnFallback ? \"On\" : \"Off\",\n\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\taction: \"set-notify\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}),\n\t\t\tinvalid: ({ state }) => ({\n\t\t\t\tkind: \"detail\",\n\t\t\t\ttitle: \"Codex Compact Settings \u00B7 Read only\",\n\t\t\t\tlines: [\n\t\t\t\t\t`Invalid settings file: ${safeText(state.path)}`,\n\t\t\t\t\t`Issue: ${safeText(state.issue ?? \"unknown validation error\")}`,\n\t\t\t\t\t\"Built-in defaults are active. Repair the file and run /reload; it will not be overwritten.\",\n\t\t\t\t],\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\t\"compact-now\": async () => {\n\t\t\t\toptions.onCompactRequested?.();\n\t\t\t\treturn { kind: \"close\" };\n\t\t\t},\n\t\t\t\"set-enabled\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(runtime, ctx, { enabled: value === \"On\" }, signal),\n\t\t\t\"set-protocol\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(\n\t\t\t\t\truntime,\n\t\t\t\t\tctx,\n\t\t\t\t\t{\n\t\t\t\t\t\tprotocol:\n\t\t\t\t\t\t\tvalue === \"Remote V2\"\n\t\t\t\t\t\t\t\t? \"remote-v2\"\n\t\t\t\t\t\t\t\t: value === \"Responses Compact\"\n\t\t\t\t\t\t\t\t\t? \"responses-compact\"\n\t\t\t\t\t\t\t\t\t: \"auto\",\n\t\t\t\t\t},\n\t\t\t\t\tsignal,\n\t\t\t\t),\n\t\t\t\"set-timeout\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(\n\t\t\t\t\truntime,\n\t\t\t\t\tctx,\n\t\t\t\t\t{ requestTimeoutMs: Number.parseInt(value ?? \"5\", 10) * 60_000 },\n\t\t\t\t\tsignal,\n\t\t\t\t),\n\t\t\t\"set-retries\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(runtime, ctx, { maxRetries: Number.parseInt(value ?? \"2\", 10) }, signal),\n\t\t\t\"set-retention\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(\n\t\t\t\t\truntime,\n\t\t\t\t\tctx,\n\t\t\t\t\t{ replacementTokenBudget: Number.parseInt(value ?? \"64\", 10) * 1000 },\n\t\t\t\t\tsignal,\n\t\t\t\t),\n\t\t\t\"set-notify\": ({ ctx, value, signal }) =>\n\t\t\t\tupdate(runtime, ctx, { notifyOnFallback: value === \"On\" }, signal),\n\t\t},\n\t};\n}\n\nexport async function showCodexCompactMenu(\n\truntime: CodexCompactSettingsRuntime,\n\tctx: ExtensionCommandContext,\n\towner: SettingsMenuOwner,\n): Promise<void> {\n\tif (ctx.mode === \"rpc\" && ctx.hasUI) {\n\t\tctx.ui.notify(`Edit Responses compaction settings at ${safeText(runtime.get().path)}.`, \"info\");\n\t\treturn;\n\t}\n\tif (ctx.mode !== \"tui\") {\n\t\tthrow new Error(\"/codex-compact requires TUI or RPC UI support\");\n\t}\n\tconst { runMenu } = await import(\"@narumitw/pi-tui-kit\");\n\tif (owner.signal.aborted || !owner.isCurrent()) return;\n\tlet compactRequested = false;\n\tawait runMenu(\n\t\tctx,\n\t\tcreateCodexCompactMenu(runtime, {\n\t\t\tonCompactRequested: () => {\n\t\t\t\tcompactRequested = true;\n\t\t\t},\n\t\t\tstatus: compactMenuStatus(ctx),\n\t\t}),\n\t\t{\n\t\t\tgetState: () => runtime.get(),\n\t\t\tsignal: owner.signal,\n\t\t\tisCurrent: owner.isCurrent,\n\t\t},\n\t);\n\tif (!compactRequested || owner.signal.aborted || !owner.isCurrent()) return;\n\tctx.compact({\n\t\tonError: (error) => {\n\t\t\tif (!owner.signal.aborted && owner.isCurrent()) {\n\t\t\t\tctx.ui.notify(`Compaction failed: ${safeText(error.message)}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport function compactMenuStatus(ctx: ExtensionCommandContext): CompactMenuStatus {\n\tconst model = ctx.model;\n\treturn {\n\t\tmodel: model ? `${model.provider}/${model.id}` : \"none\",\n\t\tapi: model?.api,\n\t};\n}\n\nfunction compactRoute(\n\tstate: Readonly<CodexCompactSettingsState>,\n\tstatus: CompactMenuStatus | undefined,\n): string {\n\tconst route = resolveCompactionRouteForApi(status?.api, state.settings);\n\tif (route.kind === \"native\") return `Pi native (${route.reason})`;\n\treturn route.protocol === \"remote-v2\" ? \"Responses Remote V2\" : \"Responses Compact API\";\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|