@oai404iao/pi-codex-core 0.1.0-alpha.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/LICENSE +28 -0
- package/LICENSES/Apache-2.0.txt +201 -0
- package/LICENSES/OpenAI-Codex-NOTICE.txt +6 -0
- package/README.md +26 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/package.json +84 -0
- package/provenance/openai-codex-eb9dceba-reserved-tools.json +140 -0
- package/src/adapter/compaction/checkpoint.ts +159 -0
- package/src/adapter/compaction/collect.ts +51 -0
- package/src/adapter/compaction/http.ts +101 -0
- package/src/adapter/compaction/request.ts +159 -0
- package/src/adapter/compaction/transport.ts +125 -0
- package/src/adapter/compaction/websocket.ts +119 -0
- package/src/extension/prewarm-snapshot.ts +27 -0
- package/src/extension/provider-runtime.ts +101 -0
- package/src/extension/startup-prewarm.ts +264 -0
- package/src/fast-mode.ts +124 -0
- package/src/index.ts +257 -0
- package/src/native-compaction.ts +392 -0
- package/src/patch/apply.ts +338 -0
- package/src/patch/parser.ts +224 -0
- package/src/patch/render.ts +201 -0
- package/src/provider-native-tools.ts +75 -0
- package/src/providers/codex-apply-patch-tool.ts +23 -0
- package/src/providers/codex-apply-patch.lark +19 -0
- package/src/providers/openai-codex/cache-key.ts +52 -0
- package/src/providers/openai-codex/captured-stream.ts +50 -0
- package/src/providers/openai-codex/constants.ts +61 -0
- package/src/providers/openai-codex/continuation.ts +110 -0
- package/src/providers/openai-codex/errors.ts +130 -0
- package/src/providers/openai-codex/events.ts +123 -0
- package/src/providers/openai-codex/headers.ts +224 -0
- package/src/providers/openai-codex/lite.ts +24 -0
- package/src/providers/openai-codex/message.ts +33 -0
- package/src/providers/openai-codex/prewarm.ts +76 -0
- package/src/providers/openai-codex/proxy.ts +55 -0
- package/src/providers/openai-codex/reasoning.ts +54 -0
- package/src/providers/openai-codex/request-body.ts +149 -0
- package/src/providers/openai-codex/request-context.ts +20 -0
- package/src/providers/openai-codex/request-metadata.ts +137 -0
- package/src/providers/openai-codex/retry.ts +154 -0
- package/src/providers/openai-codex/runtime.ts +1 -0
- package/src/providers/openai-codex/sse.ts +93 -0
- package/src/providers/openai-codex/stream.ts +367 -0
- package/src/providers/openai-codex/urls.ts +24 -0
- package/src/providers/openai-codex/usage.ts +60 -0
- package/src/providers/openai-codex/websocket-connection.ts +216 -0
- package/src/providers/openai-codex/websocket-events.ts +210 -0
- package/src/providers/openai-codex/websocket-session.ts +192 -0
- package/src/providers/openai-codex/websocket-socket.ts +18 -0
- package/src/providers/openai-codex/websocket-stream.ts +151 -0
- package/src/tools/apply-patch.ts +84 -0
- package/src/tools/view-image.ts +98 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import type { Api, AssistantMessage, Context, Model, ThinkingLevel, Tool } from "@earendil-works/pi-ai";
|
|
2
|
+
import type {
|
|
3
|
+
CompactionEntry,
|
|
4
|
+
ExtensionAPI,
|
|
5
|
+
ExtensionContext,
|
|
6
|
+
SessionBeforeCompactEvent,
|
|
7
|
+
SessionContext,
|
|
8
|
+
SessionEntry,
|
|
9
|
+
} from "@earendil-works/pi-coding-agent";
|
|
10
|
+
import { buildSessionContext } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { sanitizeNativeCompactionOutput } from "./adapter/compaction/checkpoint.js";
|
|
12
|
+
import { requestOpenAINativeCompaction } from "./adapter/compaction/request.js";
|
|
13
|
+
import type { ModelLike } from "@oai404iao/pi-codex-runtime/internal/capabilities";
|
|
14
|
+
import { hasCodexRequestAuth } from "@oai404iao/pi-codex-runtime/internal/codex-http";
|
|
15
|
+
import { resolveModelProfile } from "@oai404iao/pi-codex-runtime/internal/model-catalog/catalog";
|
|
16
|
+
import { loadModelSettings } from "@oai404iao/pi-codex-runtime/internal/model-catalog/runtime";
|
|
17
|
+
import type { OpenAIResponsesProviderController } from "@oai404iao/pi-codex-runtime/internal/providers/openai-codex/types";
|
|
18
|
+
import {
|
|
19
|
+
type CodexMinimalToolsSettings,
|
|
20
|
+
} from "@oai404iao/pi-codex-runtime/internal/settings";
|
|
21
|
+
|
|
22
|
+
export const NATIVE_COMPACTION_DETAILS_KIND = "openai-native-compaction";
|
|
23
|
+
export const NATIVE_COMPACTION_DETAILS_VERSION = 3;
|
|
24
|
+
|
|
25
|
+
export type NativeCompactionMode = Exclude<CodexMinimalToolsSettings["compactionMode"], "pi">;
|
|
26
|
+
type StoredNativeCompactionMode = NativeCompactionMode | "responses-context-management";
|
|
27
|
+
|
|
28
|
+
export interface NativeCompactionDetails {
|
|
29
|
+
kind: typeof NATIVE_COMPACTION_DETAILS_KIND;
|
|
30
|
+
version: 1 | 2 | typeof NATIVE_COMPACTION_DETAILS_VERSION;
|
|
31
|
+
mode: StoredNativeCompactionMode;
|
|
32
|
+
provider: string;
|
|
33
|
+
model: string;
|
|
34
|
+
api: string;
|
|
35
|
+
profileHash?: string;
|
|
36
|
+
output: unknown[];
|
|
37
|
+
/** Legacy context-management checkpoint source. New Responses compactions omit this. */
|
|
38
|
+
sourceEntryId?: string;
|
|
39
|
+
/** Legacy context-management checkpoint block. New Responses compactions omit this. */
|
|
40
|
+
sourceBlockIndex?: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface IndexedNativeCompactionEntry {
|
|
44
|
+
entry: CompactionEntry<NativeCompactionDetails>;
|
|
45
|
+
index: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type PiMessage = SessionContext["messages"][number];
|
|
49
|
+
type PiMessages = SessionContext["messages"];
|
|
50
|
+
|
|
51
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
52
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
53
|
+
? value as Record<string, unknown>
|
|
54
|
+
: undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function isNativeCompactionDetails(value: unknown): value is NativeCompactionDetails {
|
|
58
|
+
const details = asRecord(value);
|
|
59
|
+
return details?.kind === NATIVE_COMPACTION_DETAILS_KIND
|
|
60
|
+
&& (details.version === 1 || details.version === 2 || details.version === NATIVE_COMPACTION_DETAILS_VERSION)
|
|
61
|
+
&& (
|
|
62
|
+
details.mode === "responses"
|
|
63
|
+
|| details.mode === "responses-compact"
|
|
64
|
+
|| (details.version === 1 && details.mode === "responses-context-management")
|
|
65
|
+
)
|
|
66
|
+
&& typeof details.provider === "string"
|
|
67
|
+
&& typeof details.model === "string"
|
|
68
|
+
&& typeof details.api === "string"
|
|
69
|
+
&& Array.isArray(details.output);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalizedNativeCompactionMode(details: NativeCompactionDetails): NativeCompactionMode {
|
|
73
|
+
return details.mode === "responses-context-management" ? "responses" : details.mode;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isNativeCompactionSignature(signature: unknown): boolean {
|
|
77
|
+
if (typeof signature !== "string" || !signature.startsWith("{")) return false;
|
|
78
|
+
try {
|
|
79
|
+
const item = asRecord(JSON.parse(signature));
|
|
80
|
+
return item?.type === "compaction" || item?.type === "context_compaction";
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function findLegacyMarkerBlockIndex(message: unknown): number | undefined {
|
|
87
|
+
const candidate = asRecord(message);
|
|
88
|
+
if (candidate?.role !== "assistant" || !Array.isArray(candidate.content)) return undefined;
|
|
89
|
+
for (let index = candidate.content.length - 1; index >= 0; index--) {
|
|
90
|
+
const block = asRecord(candidate.content[index]);
|
|
91
|
+
if (block?.type === "thinking" && isNativeCompactionSignature(block.thinkingSignature)) {
|
|
92
|
+
return index;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function latestCompactionIndex(entries: readonly SessionEntry[]): number {
|
|
99
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
100
|
+
if (entries[index]?.type === "compaction") return index;
|
|
101
|
+
}
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function latestNativeCompactionEntry(entries: readonly SessionEntry[]): IndexedNativeCompactionEntry | undefined {
|
|
106
|
+
const index = latestCompactionIndex(entries);
|
|
107
|
+
if (index < 0) return undefined;
|
|
108
|
+
const entry = entries[index];
|
|
109
|
+
if (entry?.type !== "compaction" || !isNativeCompactionDetails(entry.details)) return undefined;
|
|
110
|
+
return {
|
|
111
|
+
entry: entry as CompactionEntry<NativeCompactionDetails>,
|
|
112
|
+
index,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function matchesModelIdentity(
|
|
117
|
+
value: { provider: string; model: string; api: string; profileHash?: string },
|
|
118
|
+
model: Model<Api>,
|
|
119
|
+
): boolean {
|
|
120
|
+
if (value.provider !== model.provider || value.model !== model.id || value.api !== model.api) return false;
|
|
121
|
+
if (!value.profileHash) return true;
|
|
122
|
+
return resolveModelProfile(model as ModelLike)?.profileHash === value.profileHash;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function syntheticNativeAssistant(
|
|
126
|
+
output: readonly unknown[],
|
|
127
|
+
model: Model<Api>,
|
|
128
|
+
timestamp: number,
|
|
129
|
+
): AssistantMessage {
|
|
130
|
+
return {
|
|
131
|
+
role: "assistant",
|
|
132
|
+
api: model.api,
|
|
133
|
+
provider: model.provider,
|
|
134
|
+
model: model.id,
|
|
135
|
+
content: output.map((item) => ({
|
|
136
|
+
type: "thinking",
|
|
137
|
+
thinking: "",
|
|
138
|
+
thinkingSignature: JSON.stringify(item),
|
|
139
|
+
redacted: true,
|
|
140
|
+
})) as AssistantMessage["content"],
|
|
141
|
+
usage: {
|
|
142
|
+
input: 0,
|
|
143
|
+
output: 0,
|
|
144
|
+
cacheRead: 0,
|
|
145
|
+
cacheWrite: 0,
|
|
146
|
+
totalTokens: 0,
|
|
147
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
148
|
+
},
|
|
149
|
+
stopReason: "stop",
|
|
150
|
+
timestamp,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function withoutCompactionSummary(messages: PiMessages): PiMessages {
|
|
155
|
+
return messages.filter((message) => message.role !== "compactionSummary");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function legacyTailAfterContextManagementMarker(
|
|
159
|
+
messages: PiMessages,
|
|
160
|
+
sourceBlockIndex: number | undefined,
|
|
161
|
+
): PiMessages {
|
|
162
|
+
if (messages.length === 0) return messages;
|
|
163
|
+
const first = messages[0];
|
|
164
|
+
if (first?.role !== "assistant") return messages;
|
|
165
|
+
const blockIndex = findLegacyMarkerBlockIndex(first) ?? sourceBlockIndex;
|
|
166
|
+
if (blockIndex === undefined) return messages;
|
|
167
|
+
const prefix = first.content.slice(0, blockIndex);
|
|
168
|
+
const suffix = first.content.slice(blockIndex + 1);
|
|
169
|
+
const resultIds = new Set(
|
|
170
|
+
messages
|
|
171
|
+
.filter((message): message is Extract<PiMessage, { role: "toolResult" }> => message.role === "toolResult")
|
|
172
|
+
.map((message) => message.toolCallId),
|
|
173
|
+
);
|
|
174
|
+
const recoverTerminalMarker = suffix.length === 0 && prefix.some(
|
|
175
|
+
(block) => block.type === "toolCall" && resultIds.has(block.id),
|
|
176
|
+
);
|
|
177
|
+
if (recoverTerminalMarker) {
|
|
178
|
+
// Older versions appended a compaction discovered only in
|
|
179
|
+
// response.completed after already-streamed output, even when its
|
|
180
|
+
// authoritative output_index was first. Rotate that terminal marker back
|
|
181
|
+
// in front so the call arguments and matching results survive replay.
|
|
182
|
+
return prefix.length > 0 ? [{ ...first, content: prefix }, ...messages.slice(1)] : messages.slice(1);
|
|
183
|
+
}
|
|
184
|
+
return suffix.length > 0 ? [{ ...first, content: suffix }, ...messages.slice(1)] : messages.slice(1);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function messageTimestamp(message: PiMessage): number {
|
|
188
|
+
return typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function messagesAfterEntry(entries: readonly SessionEntry[], entryIndex: number): PiMessages {
|
|
192
|
+
const suffix = entries.slice(entryIndex + 1);
|
|
193
|
+
if (suffix.length === 0) return [];
|
|
194
|
+
return buildSessionContext(
|
|
195
|
+
suffix as SessionEntry[],
|
|
196
|
+
suffix[suffix.length - 1]?.id,
|
|
197
|
+
).messages;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Responses requires every function/custom-tool output to have a matching call.
|
|
202
|
+
* Compaction can expose malformed local history if a boundary lands inside a
|
|
203
|
+
* tool turn, so rebuild tool turns atomically: drop orphan/duplicate results and
|
|
204
|
+
* synthesize an aborted output for a surviving call with no result.
|
|
205
|
+
*/
|
|
206
|
+
export function normalizeNativeCompactionToolPairs(messages: PiMessages): PiMessages {
|
|
207
|
+
const resultByCallId = new Map<string, Extract<PiMessage, { role: "toolResult" }>>();
|
|
208
|
+
for (const message of messages) {
|
|
209
|
+
if (message.role === "toolResult" && !resultByCallId.has(message.toolCallId)) {
|
|
210
|
+
resultByCallId.set(message.toolCallId, message);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let changed = false;
|
|
215
|
+
const normalized: PiMessage[] = [];
|
|
216
|
+
const retainedResults = new Set<string>();
|
|
217
|
+
for (const message of messages) {
|
|
218
|
+
if (message.role === "toolResult") {
|
|
219
|
+
changed = true;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
normalized.push(message);
|
|
223
|
+
if (message.role !== "assistant") continue;
|
|
224
|
+
|
|
225
|
+
for (const block of message.content) {
|
|
226
|
+
if (block.type !== "toolCall" || retainedResults.has(block.id)) continue;
|
|
227
|
+
retainedResults.add(block.id);
|
|
228
|
+
const existing = resultByCallId.get(block.id);
|
|
229
|
+
if (existing) {
|
|
230
|
+
normalized.push(existing);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
changed = true;
|
|
234
|
+
normalized.push({
|
|
235
|
+
role: "toolResult",
|
|
236
|
+
toolCallId: block.id,
|
|
237
|
+
toolName: block.name,
|
|
238
|
+
content: [{ type: "text", text: "aborted" }],
|
|
239
|
+
isError: true,
|
|
240
|
+
timestamp: messageTimestamp(message),
|
|
241
|
+
} as PiMessage);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (retainedResults.size !== resultByCallId.size) changed = true;
|
|
246
|
+
return changed ? normalized : messages;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Replace Pi's textual compaction summary with the opaque native Responses
|
|
251
|
+
* items saved in CompactionEntry.details. The opaque payload is replayed only
|
|
252
|
+
* to the same provider, model, API, and current model-profile hash.
|
|
253
|
+
*/
|
|
254
|
+
export function applyNativeCompactionContext(
|
|
255
|
+
messages: PiMessages,
|
|
256
|
+
branchEntries: readonly SessionEntry[],
|
|
257
|
+
model: Model<Api> | undefined,
|
|
258
|
+
): PiMessages {
|
|
259
|
+
if (!model || !resolveModelProfile(model as ModelLike)?.effective.enabled) return messages;
|
|
260
|
+
|
|
261
|
+
const installed = latestNativeCompactionEntry(branchEntries);
|
|
262
|
+
if (installed) {
|
|
263
|
+
const details = installed.entry.details;
|
|
264
|
+
if (!isNativeCompactionDetails(details)) return messages;
|
|
265
|
+
if (!matchesModelIdentity(details, model)) return messages;
|
|
266
|
+
const output = normalizedNativeCompactionMode(details) === "responses-compact"
|
|
267
|
+
? sanitizeNativeCompactionOutput(details.output)
|
|
268
|
+
: details.output;
|
|
269
|
+
const withoutSummary = withoutCompactionSummary(messages);
|
|
270
|
+
let tail: PiMessages;
|
|
271
|
+
if (details.sourceEntryId) {
|
|
272
|
+
tail = legacyTailAfterContextManagementMarker(withoutSummary, details.sourceBlockIndex);
|
|
273
|
+
} else {
|
|
274
|
+
// The compaction entry is the semantic history boundary. Timestamps are
|
|
275
|
+
// not safe here because messages queued while compaction is running can
|
|
276
|
+
// be appended after the entry with an earlier creation timestamp.
|
|
277
|
+
tail = messagesAfterEntry(branchEntries, installed.index);
|
|
278
|
+
}
|
|
279
|
+
return normalizeNativeCompactionToolPairs([
|
|
280
|
+
syntheticNativeAssistant(output, model, new Date(installed.entry.timestamp).getTime()),
|
|
281
|
+
...tail,
|
|
282
|
+
]);
|
|
283
|
+
}
|
|
284
|
+
return messages;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function activeTools(pi: ExtensionAPI): Tool[] {
|
|
288
|
+
const active = new Set(pi.getActiveTools());
|
|
289
|
+
return pi.getAllTools()
|
|
290
|
+
.filter((tool) => active.has(tool.name))
|
|
291
|
+
.map((tool) => ({
|
|
292
|
+
name: tool.name,
|
|
293
|
+
description: tool.description,
|
|
294
|
+
parameters: tool.parameters,
|
|
295
|
+
})) as Tool[];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function compactionSummary(mode: NativeCompactionMode): string {
|
|
299
|
+
return mode === "responses"
|
|
300
|
+
? "OpenAI Responses compaction replaced the earlier conversation. The opaque encrypted compaction state is preserved in this session by pi-codex-minimal-tools."
|
|
301
|
+
: "OpenAI Responses /responses/compact replaced the earlier conversation. The opaque encrypted compaction state is preserved in this session by pi-codex-minimal-tools.";
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async function buildNativeCompactionContext(
|
|
305
|
+
pi: ExtensionAPI,
|
|
306
|
+
event: SessionBeforeCompactEvent,
|
|
307
|
+
ctx: ExtensionContext,
|
|
308
|
+
model: Model<Api>,
|
|
309
|
+
): Promise<Context> {
|
|
310
|
+
const session = buildSessionContext(event.branchEntries, ctx.sessionManager.getLeafId());
|
|
311
|
+
return {
|
|
312
|
+
systemPrompt: ctx.getSystemPrompt(),
|
|
313
|
+
messages: applyNativeCompactionContext(
|
|
314
|
+
session.messages,
|
|
315
|
+
event.branchEntries,
|
|
316
|
+
model,
|
|
317
|
+
) as Context["messages"],
|
|
318
|
+
tools: activeTools(pi),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export function registerNativeCompaction(
|
|
323
|
+
pi: ExtensionAPI,
|
|
324
|
+
providerController?: OpenAIResponsesProviderController,
|
|
325
|
+
): void {
|
|
326
|
+
pi.on("context", (event, ctx) => {
|
|
327
|
+
const settings = loadModelSettings(ctx.model as ModelLike | undefined, ctx.cwd);
|
|
328
|
+
if (!settings.enabled || settings.compactionMode === "pi") return undefined;
|
|
329
|
+
const messages = applyNativeCompactionContext(
|
|
330
|
+
event.messages as PiMessages,
|
|
331
|
+
ctx.sessionManager.getBranch(),
|
|
332
|
+
ctx.model as Model<Api> | undefined,
|
|
333
|
+
);
|
|
334
|
+
return messages === event.messages ? undefined : { messages: messages as typeof event.messages };
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
pi.on("session_before_compact", async (event, ctx) => {
|
|
338
|
+
const model = ctx.model as Model<Api> | undefined;
|
|
339
|
+
const settings = loadModelSettings(model as ModelLike | undefined, ctx.cwd);
|
|
340
|
+
const mode = settings.compactionMode;
|
|
341
|
+
if (!settings.enabled || mode === "pi" || !model || !settings.modelProfile?.effective.enabled) return undefined;
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
345
|
+
if (
|
|
346
|
+
!auth.ok
|
|
347
|
+
|| !hasCodexRequestAuth({
|
|
348
|
+
modelHeaders: model.headers,
|
|
349
|
+
auth: { apiKey: auth.apiKey, headers: auth.headers },
|
|
350
|
+
})
|
|
351
|
+
) {
|
|
352
|
+
throw new Error(auth.ok ? "OpenAI request authentication is unavailable" : auth.error);
|
|
353
|
+
}
|
|
354
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
355
|
+
const context = await buildNativeCompactionContext(pi, event, ctx, model);
|
|
356
|
+
const output = await requestOpenAINativeCompaction(model, context, {
|
|
357
|
+
ownsNativeTool: providerController?.ownsNativeTool,
|
|
358
|
+
mode,
|
|
359
|
+
apiKey: auth.apiKey ?? "",
|
|
360
|
+
headers: auth.headers,
|
|
361
|
+
signal: event.signal,
|
|
362
|
+
reasoning: pi.getThinkingLevel() as ThinkingLevel,
|
|
363
|
+
sessionId,
|
|
364
|
+
turnId: providerController?.getCurrentTurnId(sessionId),
|
|
365
|
+
settings,
|
|
366
|
+
});
|
|
367
|
+
return {
|
|
368
|
+
compaction: {
|
|
369
|
+
summary: compactionSummary(mode),
|
|
370
|
+
firstKeptEntryId: event.preparation.firstKeptEntryId,
|
|
371
|
+
tokensBefore: event.preparation.tokensBefore,
|
|
372
|
+
details: {
|
|
373
|
+
kind: NATIVE_COMPACTION_DETAILS_KIND,
|
|
374
|
+
version: NATIVE_COMPACTION_DETAILS_VERSION,
|
|
375
|
+
mode,
|
|
376
|
+
provider: model.provider,
|
|
377
|
+
model: model.id,
|
|
378
|
+
api: model.api,
|
|
379
|
+
profileHash: settings.modelProfileHash,
|
|
380
|
+
output,
|
|
381
|
+
} satisfies NativeCompactionDetails,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
} catch (error) {
|
|
385
|
+
if (!event.signal.aborted) {
|
|
386
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
387
|
+
ctx.ui.notify(`OpenAI native compaction failed; falling back to Pi compaction: ${message}`, "warning");
|
|
388
|
+
}
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|