@howaboua/pi-codex-conversion 1.5.5-dev.25.f80a775 → 1.5.5
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/package.json +1 -1
- package/src/adapter/activation.ts +0 -1
- package/src/adapter/config.ts +0 -24
- package/src/adapter/provider-request.ts +2 -4
- package/src/adapter/tool-set.ts +1 -2
- package/src/codex-settings/command.ts +3 -16
- package/src/codex-settings/ui.ts +48 -126
- package/src/index.ts +18 -34
- package/src/providers/openai-codex-custom-provider.ts +1 -1
- package/src/providers/openai-responses-shared.ts +0 -2
- package/vendor/apply-patch/win32-arm64/apply_patch.exe +0 -0
- package/vendor/apply-patch/win32-x64/apply_patch.exe +0 -0
- package/src/adapter/compact-client.ts +0 -257
- package/src/adapter/compaction-output.ts +0 -80
- package/src/adapter/compaction-runtime.ts +0 -272
- package/src/adapter/compaction.ts +0 -261
- package/src/adapter/context-filter.ts +0 -20
- package/src/adapter/details-store.ts +0 -151
- package/src/adapter/payload-rewrite.ts +0 -550
- package/src/adapter/serializer.ts +0 -288
- package/src/adapter/types.ts +0 -220
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI, ExtensionContext, SessionBeforeCompactEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { clampThinkingLevel, type ModelThinkingLevel, type Tool } from "@earendil-works/pi-ai";
|
|
3
|
-
import { executeNativeCompaction } from "./compact-client.ts";
|
|
4
|
-
import { extractCompactionSummaryText, hasCompactionOutputItem, sanitizeCompactedWindow, summarizeCompactionOutputForDiagnostics } from "./compaction-output.ts";
|
|
5
|
-
import { resolveLatestNativeCompactionEntry } from "./details-store.ts";
|
|
6
|
-
import { rewriteResponsesPayloadWithNativeReplay, serializeLiveTailToResponsesInput } from "./payload-rewrite.ts";
|
|
7
|
-
import { resolveNativeCompactionEnvironment } from "./compaction-runtime.ts";
|
|
8
|
-
import { convertResponsesTools } from "../providers/openai-responses-shared.ts";
|
|
9
|
-
import {
|
|
10
|
-
serializeCompactionPreparationToRequest,
|
|
11
|
-
type NativeCompactionRequestBody,
|
|
12
|
-
type NativeCompactionRequestOptions,
|
|
13
|
-
type ResponsesInputItem,
|
|
14
|
-
} from "./serializer.ts";
|
|
15
|
-
import { createNativeCompactionDetails, createNativeCompactionShimResult, isNativeCompactionDetails, NATIVE_COMPACTION_SHIM_SUMMARY } from "./types.ts";
|
|
16
|
-
import { isOpenAICodexContext, isResponsesContext } from "./codex-model.ts";
|
|
17
|
-
import { shouldUseCodexAdapter } from "./activation.ts";
|
|
18
|
-
import type { AdapterState } from "./state.ts";
|
|
19
|
-
import { rewriteNativeImageGenerationTool } from "../tools/image-generation-tool.ts";
|
|
20
|
-
import { rewriteNativeWebSearchTool } from "../tools/web-search-tool.ts";
|
|
21
|
-
|
|
22
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
23
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function cloneCompactedWindow(window: readonly unknown[]): ResponsesInputItem[] | undefined {
|
|
27
|
-
if (!window.every(isRecord)) return undefined;
|
|
28
|
-
return window.map((item) => structuredClone(item));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function buildCompactionInstructions(systemPrompt: string, customInstructions?: string): string {
|
|
32
|
-
const guidance = customInstructions?.trim();
|
|
33
|
-
return guidance ? `${systemPrompt}\n\nAdditional user guidance for this manual /compact request:\n${guidance}` : systemPrompt;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function buildCompactionTools(pi: ExtensionAPI, ctx: ExtensionContext, state: AdapterState): unknown[] | undefined {
|
|
37
|
-
const activeToolNames = new Set(pi.getActiveTools());
|
|
38
|
-
const tools = pi
|
|
39
|
-
.getAllTools()
|
|
40
|
-
.filter((tool) => activeToolNames.has(tool.name))
|
|
41
|
-
.map((tool): Tool => ({ name: tool.name, description: tool.description, parameters: tool.parameters }));
|
|
42
|
-
if (tools.length === 0) return undefined;
|
|
43
|
-
let payload: { tools: unknown[] } = { tools: convertResponsesTools(tools, { strict: null }) };
|
|
44
|
-
if (isOpenAICodexContext(ctx) && state.config.webSearch) {
|
|
45
|
-
payload = rewriteNativeWebSearchTool(payload, ctx.model) as { tools: unknown[] };
|
|
46
|
-
}
|
|
47
|
-
if (isOpenAICodexContext(ctx) && state.config.imageGeneration) {
|
|
48
|
-
payload = rewriteNativeImageGenerationTool(payload, ctx.model) as { tools: unknown[] };
|
|
49
|
-
}
|
|
50
|
-
return payload.tools;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function buildCompactionReasoning(pi: ExtensionAPI, ctx: ExtensionContext, state: AdapterState, compactionModel: string): NativeCompactionRequestOptions["reasoning"] {
|
|
54
|
-
const model = ctx.model;
|
|
55
|
-
const level = state.config.compactionReasoning === "current" ? pi.getThinkingLevel() : state.config.compactionReasoning;
|
|
56
|
-
if (!model?.reasoning || level === "off") return undefined;
|
|
57
|
-
const clampedLevel = clampThinkingLevel(model, level as ModelThinkingLevel);
|
|
58
|
-
const rawEffort = model.thinkingLevelMap?.[clampedLevel] ?? clampedLevel;
|
|
59
|
-
const effort = typeof rawEffort === "string" && isOpenAICodexContext(ctx) ? clampCodexReasoningEffort(compactionModel, rawEffort) : rawEffort;
|
|
60
|
-
return effort === null ? undefined : { effort, summary: "auto" };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function clampCodexReasoningEffort(modelId: string, effort: string): string {
|
|
64
|
-
const id = modelId.includes("/") ? (modelId.split("/").pop() ?? modelId) : modelId;
|
|
65
|
-
const gpt5MinorMatch = /^gpt-5\.(\d+)/.exec(id);
|
|
66
|
-
const gpt5Minor = gpt5MinorMatch ? Number.parseInt(gpt5MinorMatch[1], 10) : undefined;
|
|
67
|
-
if (gpt5Minor !== undefined && gpt5Minor >= 2 && effort === "minimal") return "low";
|
|
68
|
-
if (id === "gpt-5.1" && effort === "xhigh") return "high";
|
|
69
|
-
if (id === "gpt-5.1-codex-mini") return effort === "high" || effort === "xhigh" ? "high" : "medium";
|
|
70
|
-
return effort;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function buildCompactionRequestOptions(pi: ExtensionAPI, ctx: ExtensionContext, state: AdapterState, compactionModel: string): NativeCompactionRequestOptions {
|
|
74
|
-
const tools = buildCompactionTools(pi, ctx, state);
|
|
75
|
-
const reasoning = buildCompactionReasoning(pi, ctx, state, compactionModel);
|
|
76
|
-
return {
|
|
77
|
-
parallel_tool_calls: true,
|
|
78
|
-
prompt_cache_key: ctx.sessionManager.getSessionId(),
|
|
79
|
-
...(isOpenAICodexContext(ctx) && state.config.fast ? { service_tier: "priority" } : {}),
|
|
80
|
-
text: { verbosity: state.config.verbosity },
|
|
81
|
-
...(tools ? { tools } : {}),
|
|
82
|
-
...(reasoning ? { reasoning } : {}),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function getCompactionIdentity(entry: { details?: unknown } | undefined) {
|
|
87
|
-
return isNativeCompactionDetails(entry?.details)
|
|
88
|
-
? { provider: entry.details.provider, api: entry.details.api, model: entry.details.model, baseUrl: entry.details.baseUrl }
|
|
89
|
-
: undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function formatCompactFailureMessage(compactResult: Awaited<ReturnType<typeof executeNativeCompaction>>): string {
|
|
93
|
-
if (compactResult.ok) return "OpenAI native compaction succeeded";
|
|
94
|
-
const status = compactResult.status ? ` HTTP ${compactResult.status}` : "";
|
|
95
|
-
const response = compactResult.responseText?.trim();
|
|
96
|
-
const detail = response ? `: ${response.slice(0, 500)}` : compactResult.errorMessage ? `: ${compactResult.errorMessage}` : "";
|
|
97
|
-
return `OpenAI native compaction failed (${compactResult.reason}${status})${detail}; Pi compaction was not run.`;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function formatCompactRequestDiagnostics(request: NativeCompactionRequestBody): string {
|
|
101
|
-
const reasoning = isRecord(request.reasoning) && typeof request.reasoning.effort === "string" ? request.reasoning.effort : "none";
|
|
102
|
-
const serviceTier = typeof request.service_tier === "string" ? request.service_tier : "none";
|
|
103
|
-
const tools = Array.isArray(request.tools) ? request.tools.length : 0;
|
|
104
|
-
return `model=${request.model}, input=${request.input.length}, tools=${tools}, reasoning=${reasoning}, service_tier=${serviceTier}`;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export async function handleCodexSessionBeforeCompact(event: SessionBeforeCompactEvent, ctx: ExtensionContext, state: AdapterState, pi: ExtensionAPI) {
|
|
108
|
-
if (!state.config.responsesCompaction || !shouldUseCodexAdapter(ctx, state.config)) {
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
return await handleCodexSessionBeforeCompactInner(event, ctx, state, pi);
|
|
114
|
-
} catch (error) {
|
|
115
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
116
|
-
ctx.ui.notify(`OpenAI native compaction failed unexpectedly: ${message}; Pi compaction was not run.`, "error");
|
|
117
|
-
return { cancel: true };
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async function handleCodexSessionBeforeCompactInner(event: SessionBeforeCompactEvent, ctx: ExtensionContext, state: AdapterState, pi: ExtensionAPI) {
|
|
122
|
-
if (!isOpenAICodexContext(ctx) && !isResponsesContext(ctx)) {
|
|
123
|
-
ctx.ui.notify("OpenAI native compaction is enabled, but the current model is not Responses-compatible; Pi compaction was not run.", "error");
|
|
124
|
-
return { cancel: true };
|
|
125
|
-
}
|
|
126
|
-
if (event.signal.aborted) return { cancel: true };
|
|
127
|
-
|
|
128
|
-
const resolution = await resolveNativeCompactionEnvironment(ctx, { enabled: true });
|
|
129
|
-
if (!resolution.ok) {
|
|
130
|
-
ctx.ui.notify(`OpenAI native compaction is enabled but unavailable (${resolution.reason}); Pi compaction was not run.`, "error");
|
|
131
|
-
return { cancel: true };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const runtime = resolution.runtime;
|
|
135
|
-
const compactionModel = state.config.compactionModel;
|
|
136
|
-
const compactionTargetModel = { ...runtime.currentModel, id: compactionModel };
|
|
137
|
-
const requestOptions = buildCompactionRequestOptions(pi, ctx, state, compactionModel);
|
|
138
|
-
const branchEntries = ctx.sessionManager.getBranch();
|
|
139
|
-
const latestNativeCompaction = resolveLatestNativeCompactionEntry(branchEntries, {
|
|
140
|
-
provider: runtime.provider,
|
|
141
|
-
api: runtime.api,
|
|
142
|
-
baseUrl: runtime.baseUrl,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
let request: NativeCompactionRequestBody;
|
|
146
|
-
let compactedKeptWindow = false;
|
|
147
|
-
if (latestNativeCompaction.ok) {
|
|
148
|
-
const compactedWindow = cloneCompactedWindow(latestNativeCompaction.entry.details?.compactedWindow ?? []);
|
|
149
|
-
if (!compactedWindow) {
|
|
150
|
-
ctx.ui.notify("OpenAI native compaction could not clone the previous compacted window; Pi compaction was not run.", "error");
|
|
151
|
-
return { cancel: true };
|
|
152
|
-
}
|
|
153
|
-
const liveTailEntries = branchEntries.slice(latestNativeCompaction.index + 1);
|
|
154
|
-
request = {
|
|
155
|
-
model: compactionModel,
|
|
156
|
-
input: [
|
|
157
|
-
...compactedWindow,
|
|
158
|
-
...serializeLiveTailToResponsesInput({ model: compactionTargetModel, entries: liveTailEntries }),
|
|
159
|
-
],
|
|
160
|
-
instructions: buildCompactionInstructions(ctx.getSystemPrompt(), event.customInstructions),
|
|
161
|
-
...requestOptions,
|
|
162
|
-
};
|
|
163
|
-
} else if (latestNativeCompaction.reason === "no-compaction") {
|
|
164
|
-
request = serializeCompactionPreparationToRequest({
|
|
165
|
-
model: compactionTargetModel,
|
|
166
|
-
preparation: event.preparation,
|
|
167
|
-
instructions: buildCompactionInstructions(ctx.getSystemPrompt(), event.customInstructions),
|
|
168
|
-
requestOptions,
|
|
169
|
-
});
|
|
170
|
-
if (request.input.length === 0) {
|
|
171
|
-
request = {
|
|
172
|
-
model: compactionModel,
|
|
173
|
-
input: serializeLiveTailToResponsesInput({ model: compactionTargetModel, entries: branchEntries }),
|
|
174
|
-
instructions: buildCompactionInstructions(ctx.getSystemPrompt(), event.customInstructions),
|
|
175
|
-
...requestOptions,
|
|
176
|
-
};
|
|
177
|
-
compactedKeptWindow = true;
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
void getCompactionIdentity(latestNativeCompaction.latestCompaction);
|
|
181
|
-
request = serializeCompactionPreparationToRequest({
|
|
182
|
-
model: compactionTargetModel,
|
|
183
|
-
preparation: event.preparation,
|
|
184
|
-
instructions: buildCompactionInstructions(ctx.getSystemPrompt(), event.customInstructions),
|
|
185
|
-
requestOptions,
|
|
186
|
-
});
|
|
187
|
-
if (request.input.length === 0) {
|
|
188
|
-
request = {
|
|
189
|
-
model: compactionModel,
|
|
190
|
-
input: serializeLiveTailToResponsesInput({ model: compactionTargetModel, entries: branchEntries }),
|
|
191
|
-
instructions: buildCompactionInstructions(ctx.getSystemPrompt(), event.customInstructions),
|
|
192
|
-
...requestOptions,
|
|
193
|
-
};
|
|
194
|
-
compactedKeptWindow = true;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (request.input.length === 0) {
|
|
199
|
-
ctx.ui.notify("OpenAI native compaction had no serializable conversation items; Pi compaction was not run.", "error");
|
|
200
|
-
return { cancel: true };
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const compactResult = await executeNativeCompaction({ runtime, request, signal: event.signal });
|
|
204
|
-
if (!compactResult.ok) {
|
|
205
|
-
if (compactResult.reason !== "aborted") {
|
|
206
|
-
ctx.ui.notify(formatCompactFailureMessage(compactResult), "error");
|
|
207
|
-
}
|
|
208
|
-
return { cancel: true };
|
|
209
|
-
}
|
|
210
|
-
const compactedWindow = sanitizeCompactedWindow(compactResult.compactedWindow);
|
|
211
|
-
if (compactedWindow.length === 0) {
|
|
212
|
-
ctx.ui.notify(`OpenAI native compaction returned no installable compacted context; Pi compaction was not run. Request: ${formatCompactRequestDiagnostics(request)}. Output: ${summarizeCompactionOutputForDiagnostics(compactResult.compactedWindow, compactedWindow)}`, "error");
|
|
213
|
-
return { cancel: true };
|
|
214
|
-
}
|
|
215
|
-
if (!hasCompactionOutputItem(compactedWindow)) {
|
|
216
|
-
ctx.ui.notify(`OpenAI native compaction did not return a compaction item; Pi compaction was not run. Response=${compactResult.compactResponseId ?? "<none>"}. Request: ${formatCompactRequestDiagnostics(request)}. Output: ${summarizeCompactionOutputForDiagnostics(compactResult.compactedWindow, compactedWindow)}`, "error");
|
|
217
|
-
return { cancel: true };
|
|
218
|
-
}
|
|
219
|
-
const encryptedSummary = extractCompactionSummaryText(compactedWindow);
|
|
220
|
-
if (!encryptedSummary) {
|
|
221
|
-
ctx.ui.notify(`OpenAI native compaction returned compacted context without a displayable summary; Pi compaction was not run. Response=${compactResult.compactResponseId ?? "<none>"}. Request: ${formatCompactRequestDiagnostics(request)}. Output: ${summarizeCompactionOutputForDiagnostics(compactResult.compactedWindow, compactedWindow)}`, "error");
|
|
222
|
-
return { cancel: true };
|
|
223
|
-
}
|
|
224
|
-
try {
|
|
225
|
-
const details = createNativeCompactionDetails({
|
|
226
|
-
provider: runtime.provider,
|
|
227
|
-
api: runtime.api,
|
|
228
|
-
model: compactionModel,
|
|
229
|
-
baseUrl: runtime.baseUrl,
|
|
230
|
-
compactedWindow,
|
|
231
|
-
compactResponseId: compactResult.compactResponseId,
|
|
232
|
-
createdAt: compactResult.createdAt,
|
|
233
|
-
requestMeta: { tokensBefore: event.preparation.tokensBefore, previousSummaryPresent: Boolean(event.preparation.previousSummary), compactedKeptWindow },
|
|
234
|
-
});
|
|
235
|
-
return { compaction: createNativeCompactionShimResult({ summary: NATIVE_COMPACTION_SHIM_SUMMARY, firstKeptEntryId: event.preparation.firstKeptEntryId, tokensBefore: event.preparation.tokensBefore, details }) };
|
|
236
|
-
} catch {
|
|
237
|
-
ctx.ui.notify("OpenAI native compaction produced details Pi could not store; Pi compaction was not run.", "error");
|
|
238
|
-
return { cancel: true };
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export async function rewriteCodexCompactedProviderRequest(payload: unknown, ctx: ExtensionContext, state: AdapterState): Promise<unknown | undefined> {
|
|
243
|
-
if (!state.config.responsesCompaction || !shouldUseCodexAdapter(ctx, state.config) || (!isOpenAICodexContext(ctx) && !isResponsesContext(ctx))) return undefined;
|
|
244
|
-
const resolution = await resolveNativeCompactionEnvironment(ctx, { enabled: true }, payload);
|
|
245
|
-
if (!resolution.ok) return undefined;
|
|
246
|
-
const runtime = resolution.runtime;
|
|
247
|
-
const branchEntries = ctx.sessionManager.getBranch();
|
|
248
|
-
const latestNativeCompaction = resolveLatestNativeCompactionEntry(branchEntries, {
|
|
249
|
-
provider: runtime.provider,
|
|
250
|
-
api: runtime.api,
|
|
251
|
-
baseUrl: runtime.baseUrl,
|
|
252
|
-
});
|
|
253
|
-
if (!latestNativeCompaction.ok) return undefined;
|
|
254
|
-
if (!runtime.payload) return undefined;
|
|
255
|
-
const rewrite = rewriteResponsesPayloadWithNativeReplay({ model: runtime.currentModel, payload: runtime.payload, branchEntries, compactionEntry: latestNativeCompaction.entry });
|
|
256
|
-
if (rewrite.ok) return rewrite.rewrittenPayload;
|
|
257
|
-
const detail = rewrite.parity?.mismatches.slice(0, 3).join("; ");
|
|
258
|
-
const message = `OpenAI native compaction replay failed (${rewrite.reason})${detail ? `: ${detail}` : ""}; request was not sent with placeholder compaction context.`;
|
|
259
|
-
ctx.ui.notify(message, "error");
|
|
260
|
-
throw new Error(message);
|
|
261
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import type { CustomMessageEntry } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import { IMAGE_SAVE_DISPLAY_MESSAGE_TYPE, WEB_SEARCH_ACTIVITY_MESSAGE_TYPE } from "../providers/openai-codex-custom-provider.ts";
|
|
4
|
-
import { WEB_SEARCH_SESSION_NOTE_TYPE } from "../tools/web-search-tool.ts";
|
|
5
|
-
import { NATIVE_COMPACTION_DISPLAY_MESSAGE_TYPE } from "./types.ts";
|
|
6
|
-
|
|
7
|
-
const ADAPTER_CONTEXT_EXCLUDED_CUSTOM_MESSAGE_TYPES = new Set([
|
|
8
|
-
WEB_SEARCH_SESSION_NOTE_TYPE,
|
|
9
|
-
WEB_SEARCH_ACTIVITY_MESSAGE_TYPE,
|
|
10
|
-
IMAGE_SAVE_DISPLAY_MESSAGE_TYPE,
|
|
11
|
-
NATIVE_COMPACTION_DISPLAY_MESSAGE_TYPE,
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
export function isAdapterContextExcludedCustomMessage(message: Pick<AgentMessage, "role"> & { customType?: string }): boolean {
|
|
15
|
-
return message.role === "custom" && typeof message.customType === "string" && ADAPTER_CONTEXT_EXCLUDED_CUSTOM_MESSAGE_TYPES.has(message.customType);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function isAdapterContextExcludedCustomMessageEntry(entry: CustomMessageEntry): boolean {
|
|
19
|
-
return ADAPTER_CONTEXT_EXCLUDED_CUSTOM_MESSAGE_TYPES.has(entry.customType);
|
|
20
|
-
}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import type { CompactionEntry, SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
isNativeCompactionDetails,
|
|
4
|
-
isNativeCompactionEntry,
|
|
5
|
-
type NativeCompactionDetails,
|
|
6
|
-
type NativeCompactionEntry,
|
|
7
|
-
type NativeCompactionIdentity,
|
|
8
|
-
} from "./types";
|
|
9
|
-
|
|
10
|
-
export type NativeCompactionEntryMatch = Partial<NativeCompactionIdentity>;
|
|
11
|
-
|
|
12
|
-
export type LatestNativeCompactionResolutionFailureReason =
|
|
13
|
-
| "no-compaction"
|
|
14
|
-
| "latest-compaction-not-native"
|
|
15
|
-
| "latest-native-compaction-mismatch";
|
|
16
|
-
|
|
17
|
-
export type LatestNativeCompactionResolution =
|
|
18
|
-
| {
|
|
19
|
-
ok: true;
|
|
20
|
-
entry: NativeCompactionEntry;
|
|
21
|
-
index: number;
|
|
22
|
-
latestCompactionIndex: number;
|
|
23
|
-
}
|
|
24
|
-
| {
|
|
25
|
-
ok: false;
|
|
26
|
-
reason: LatestNativeCompactionResolutionFailureReason;
|
|
27
|
-
latestCompactionIndex?: number;
|
|
28
|
-
latestCompaction?: CompactionEntry;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
function entryMatches(entry: NativeCompactionEntry, match: NativeCompactionEntryMatch): boolean {
|
|
32
|
-
const details = entry.details;
|
|
33
|
-
if (!details) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
(match.provider === undefined || details.provider === match.provider) &&
|
|
39
|
-
(match.api === undefined || details.api === match.api) &&
|
|
40
|
-
(match.model === undefined || details.model === match.model) &&
|
|
41
|
-
(match.baseUrl === undefined || details.baseUrl === match.baseUrl)
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function getNativeCompactionDetails(
|
|
46
|
-
entry: CompactionEntry | SessionEntry | undefined,
|
|
47
|
-
): NativeCompactionDetails | undefined {
|
|
48
|
-
if (!entry || entry.type !== "compaction") {
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return isNativeCompactionDetails(entry.details) ? entry.details : undefined;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function isPersistedNativeCompactionEntry(
|
|
56
|
-
entry: CompactionEntry | SessionEntry | undefined,
|
|
57
|
-
): entry is NativeCompactionEntry {
|
|
58
|
-
return isNativeCompactionEntry(entry);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function findLatestCompactionEntryIndex(entries: readonly SessionEntry[]): number | undefined {
|
|
62
|
-
for (let index = entries.length - 1; index >= 0; index--) {
|
|
63
|
-
if (entries[index]?.type === "compaction") {
|
|
64
|
-
return index;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function findLatestCompactionEntry(entries: readonly SessionEntry[]): CompactionEntry | undefined {
|
|
72
|
-
const index = findLatestCompactionEntryIndex(entries);
|
|
73
|
-
return index === undefined ? undefined : (entries[index] as CompactionEntry);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function findLatestNativeCompactionEntryIndex(
|
|
77
|
-
entries: readonly SessionEntry[],
|
|
78
|
-
match: NativeCompactionEntryMatch = {},
|
|
79
|
-
): number | undefined {
|
|
80
|
-
for (let index = entries.length - 1; index >= 0; index--) {
|
|
81
|
-
const entry = entries[index];
|
|
82
|
-
if (!isPersistedNativeCompactionEntry(entry)) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!entryMatches(entry, match)) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return index;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function findLatestNativeCompactionEntry(
|
|
97
|
-
entries: readonly SessionEntry[],
|
|
98
|
-
match: NativeCompactionEntryMatch = {},
|
|
99
|
-
): NativeCompactionEntry | undefined {
|
|
100
|
-
const index = findLatestNativeCompactionEntryIndex(entries, match);
|
|
101
|
-
return index === undefined ? undefined : (entries[index] as NativeCompactionEntry);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function findLatestNativeCompactionDetails(
|
|
105
|
-
entries: readonly SessionEntry[],
|
|
106
|
-
match: NativeCompactionEntryMatch = {},
|
|
107
|
-
): NativeCompactionDetails | undefined {
|
|
108
|
-
return findLatestNativeCompactionEntry(entries, match)?.details;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function resolveLatestNativeCompactionEntry(
|
|
112
|
-
entries: readonly SessionEntry[],
|
|
113
|
-
match: NativeCompactionEntryMatch = {},
|
|
114
|
-
): LatestNativeCompactionResolution {
|
|
115
|
-
const latestCompactionIndex = findLatestCompactionEntryIndex(entries);
|
|
116
|
-
if (latestCompactionIndex === undefined) {
|
|
117
|
-
return {
|
|
118
|
-
ok: false,
|
|
119
|
-
reason: "no-compaction",
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const latestCompaction = entries[latestCompactionIndex];
|
|
124
|
-
if (!latestCompaction || latestCompaction.type !== "compaction" || !isPersistedNativeCompactionEntry(latestCompaction)) {
|
|
125
|
-
return {
|
|
126
|
-
ok: false,
|
|
127
|
-
reason: "latest-compaction-not-native",
|
|
128
|
-
latestCompactionIndex,
|
|
129
|
-
latestCompaction:
|
|
130
|
-
latestCompaction && latestCompaction.type === "compaction"
|
|
131
|
-
? (latestCompaction as CompactionEntry)
|
|
132
|
-
: undefined,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (!entryMatches(latestCompaction, match)) {
|
|
137
|
-
return {
|
|
138
|
-
ok: false,
|
|
139
|
-
reason: "latest-native-compaction-mismatch",
|
|
140
|
-
latestCompactionIndex,
|
|
141
|
-
latestCompaction,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
ok: true,
|
|
147
|
-
entry: latestCompaction,
|
|
148
|
-
index: latestCompactionIndex,
|
|
149
|
-
latestCompactionIndex,
|
|
150
|
-
};
|
|
151
|
-
}
|