@narumitw/pi-codex-compact 0.52.0 → 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.
@@ -1,298 +1,276 @@
1
1
  import type { Usage } from "@earendil-works/pi-ai";
2
- import type { ResponsesCompactionApi } from "./model-api.js";
2
+ import type { ResponsesCompactionProfile } from "./model-api.js";
3
3
  import {
4
- CodexCompactionProtocolError,
5
- type CollectedCompactResponse,
6
- collectCompactResponse,
7
- expandRemoteCompactionPayload,
8
- type JsonObject,
4
+ CodexCompactionProtocolError,
5
+ type CollectedCompactResponse,
6
+ collectCompactResponse,
7
+ expandRemoteCompactionPayload,
8
+ type JsonObject,
9
9
  } from "./protocol.js";
10
10
  import { collectProviderUsage } from "./remote-shared.js";
11
11
  import {
12
- abortError,
13
- assertPreparedInput,
14
- isJsonObject,
15
- type RemoteCompactionRequest,
16
- type RemoteCompactionResponse,
12
+ abortError,
13
+ assertPreparedInput,
14
+ isJsonObject,
15
+ type RemoteCompactionRequest,
16
+ type RemoteCompactionResponse,
17
17
  } from "./remote-types.js";
18
18
 
19
19
  const OFFICIAL_COMPACT_FIELDS = [
20
- "model",
21
- "input",
22
- "instructions",
23
- "previous_response_id",
24
- "prompt_cache_key",
25
- "prompt_cache_retention",
26
- "service_tier",
20
+ "model",
21
+ "input",
22
+ "instructions",
23
+ "previous_response_id",
24
+ "prompt_cache_key",
25
+ "prompt_cache_retention",
26
+ "service_tier",
27
27
  ] as const;
28
28
 
29
29
  const CODEX_COMPACT_FIELDS = [
30
- "model",
31
- "input",
32
- "instructions",
33
- "tools",
34
- "parallel_tool_calls",
35
- "reasoning",
36
- "service_tier",
37
- "prompt_cache_key",
38
- "text",
39
- "access_programs",
30
+ "model",
31
+ "input",
32
+ "instructions",
33
+ "tools",
34
+ "parallel_tool_calls",
35
+ "reasoning",
36
+ "service_tier",
37
+ "prompt_cache_key",
38
+ "text",
39
+ "access_programs",
40
40
  ] as const;
41
41
 
42
- function compactPayload(payload: JsonObject, api: ResponsesCompactionApi): JsonObject {
43
- const fields = api === "openai-codex-responses" ? CODEX_COMPACT_FIELDS : OFFICIAL_COMPACT_FIELDS;
44
- const result: JsonObject = {};
45
- for (const field of fields) {
46
- if (Object.hasOwn(payload, field) && payload[field] !== undefined) {
47
- result[field] = structuredClone(payload[field]);
48
- }
49
- }
50
- if (typeof result.model !== "string" || result.model.length === 0) {
51
- throw new CodexCompactionProtocolError("Responses payload is missing a model");
52
- }
53
- assertPreparedInput(result);
54
- return result;
42
+ function compactPayload(payload: JsonObject, profile: ResponsesCompactionProfile): JsonObject {
43
+ const fields = profile === "codex-responses-v1" ? CODEX_COMPACT_FIELDS : OFFICIAL_COMPACT_FIELDS;
44
+ const result: JsonObject = {};
45
+ for (const field of fields) {
46
+ if (Object.hasOwn(payload, field) && payload[field] !== undefined) {
47
+ result[field] = structuredClone(payload[field]);
48
+ }
49
+ }
50
+ if (typeof result.model !== "string" || result.model.length === 0) {
51
+ throw new CodexCompactionProtocolError("Responses payload is missing a model");
52
+ }
53
+ assertPreparedInput(result);
54
+ return result;
55
55
  }
56
56
 
57
57
  function requestUrl(input: string | URL | Request): URL {
58
- return new URL(input instanceof Request ? input.url : String(input));
58
+ return new URL(input instanceof Request ? input.url : String(input));
59
59
  }
60
60
 
61
61
  export function responsesCompactUrl(input: string | URL | Request): URL {
62
- const original = requestUrl(input);
63
- if (!original.pathname.endsWith("/responses")) {
64
- throw new CodexCompactionProtocolError(
65
- "Provider request URL does not end with the Responses endpoint",
66
- );
67
- }
68
- const compact = new URL(original);
69
- compact.pathname = `${compact.pathname}/compact`;
70
- if (compact.origin !== original.origin) {
71
- throw new CodexCompactionProtocolError("Responses Compact URL changed origin");
72
- }
73
- return compact;
62
+ const original = requestUrl(input);
63
+ if (!original.pathname.endsWith("/responses")) {
64
+ throw new CodexCompactionProtocolError("Provider request URL does not end with the Responses endpoint");
65
+ }
66
+ const compact = new URL(original);
67
+ compact.pathname = `${compact.pathname}/compact`;
68
+ if (compact.origin !== original.origin) {
69
+ throw new CodexCompactionProtocolError("Responses Compact URL changed origin");
70
+ }
71
+ return compact;
74
72
  }
75
73
 
76
74
  function mergedHeaders(input: string | URL | Request, init?: RequestInit): Headers {
77
- const headers = new Headers(input instanceof Request ? input.headers : undefined);
78
- new Headers(init?.headers).forEach((value, name) => {
79
- headers.set(name, value);
80
- });
81
- headers.delete("content-encoding");
82
- headers.delete("content-length");
83
- headers.set("accept", "application/json");
84
- headers.set("content-type", "application/json");
85
- return headers;
75
+ const headers = new Headers(input instanceof Request ? input.headers : undefined);
76
+ new Headers(init?.headers).forEach((value, name) => {
77
+ headers.set(name, value);
78
+ });
79
+ headers.delete("content-encoding");
80
+ headers.delete("content-length");
81
+ headers.set("accept", "application/json");
82
+ headers.set("content-type", "application/json");
83
+ return headers;
86
84
  }
87
85
 
88
86
  function mergedSignal(
89
- input: string | URL | Request,
90
- init: RequestInit | undefined,
91
- ownerSignal: AbortSignal,
87
+ input: string | URL | Request,
88
+ init: RequestInit | undefined,
89
+ ownerSignal: AbortSignal,
92
90
  ): AbortSignal {
93
- const signals = [ownerSignal];
94
- if (input instanceof Request) signals.push(input.signal);
95
- if (init?.signal) signals.push(init.signal);
96
- return signals.length === 1 ? ownerSignal : AbortSignal.any(signals);
91
+ const signals = [ownerSignal];
92
+ if (input instanceof Request) signals.push(input.signal);
93
+ if (init?.signal) signals.push(init.signal);
94
+ return signals.length === 1 ? ownerSignal : AbortSignal.any(signals);
97
95
  }
98
96
 
99
97
  function nonRetryableBridgeFailure(error: unknown): Response {
100
- const message = error instanceof Error ? error.message : String(error);
101
- return Response.json(
102
- {
103
- error: {
104
- message,
105
- type: "invalid_request_error",
106
- code: "invalid_compact_response",
107
- },
108
- },
109
- { status: 400 },
110
- );
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ return Response.json(
100
+ {
101
+ error: {
102
+ message,
103
+ type: "invalid_request_error",
104
+ code: "invalid_compact_response",
105
+ },
106
+ },
107
+ { status: 400 },
108
+ );
111
109
  }
112
110
 
113
111
  function nonNegativeInteger(value: unknown): value is number {
114
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
112
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
115
113
  }
116
114
 
117
115
  function optionalUsageDetail(details: unknown, field: string): number {
118
- if (details === undefined || details === null) return 0;
119
- if (!isJsonObject(details)) {
120
- throw new CodexCompactionProtocolError("Responses Compact response has invalid usage details");
121
- }
122
- const value = details[field];
123
- if (value === undefined || value === null) return 0;
124
- if (!nonNegativeInteger(value)) {
125
- throw new CodexCompactionProtocolError(
126
- `Responses Compact response has invalid usage detail ${field}`,
127
- );
128
- }
129
- return value;
116
+ if (details === undefined || details === null) return 0;
117
+ if (!isJsonObject(details)) {
118
+ throw new CodexCompactionProtocolError("Responses Compact response has invalid usage details");
119
+ }
120
+ const value = details[field];
121
+ if (value === undefined || value === null) return 0;
122
+ if (!nonNegativeInteger(value)) {
123
+ throw new CodexCompactionProtocolError(`Responses Compact response has invalid usage detail ${field}`);
124
+ }
125
+ return value;
130
126
  }
131
127
 
132
128
  function validatedUsage(response: JsonObject): JsonObject {
133
- const usage = response.usage;
134
- if (!isJsonObject(usage)) {
135
- throw new CodexCompactionProtocolError("Responses Compact response is missing usage");
136
- }
137
- for (const field of ["input_tokens", "output_tokens", "total_tokens"] as const) {
138
- if (!nonNegativeInteger(usage[field])) {
139
- throw new CodexCompactionProtocolError(`Responses Compact response has invalid ${field}`);
140
- }
141
- }
142
- const inputTokens = usage.input_tokens as number;
143
- const outputTokens = usage.output_tokens as number;
144
- const totalTokens = usage.total_tokens as number;
145
- const cachedTokens = optionalUsageDetail(usage.input_tokens_details, "cached_tokens");
146
- const cacheWriteTokens = optionalUsageDetail(usage.input_tokens_details, "cache_write_tokens");
147
- const reasoningTokens = optionalUsageDetail(usage.output_tokens_details, "reasoning_tokens");
148
- if (cachedTokens + cacheWriteTokens > inputTokens || reasoningTokens > outputTokens) {
149
- throw new CodexCompactionProtocolError(
150
- "Responses Compact response has inconsistent usage details",
151
- );
152
- }
153
- if (totalTokens !== inputTokens + outputTokens) {
154
- throw new CodexCompactionProtocolError(
155
- "Responses Compact response has inconsistent total usage",
156
- );
157
- }
158
- return structuredClone(usage);
129
+ const usage = response.usage;
130
+ if (!isJsonObject(usage)) {
131
+ throw new CodexCompactionProtocolError("Responses Compact response is missing usage");
132
+ }
133
+ for (const field of ["input_tokens", "output_tokens", "total_tokens"] as const) {
134
+ if (!nonNegativeInteger(usage[field])) {
135
+ throw new CodexCompactionProtocolError(`Responses Compact response has invalid ${field}`);
136
+ }
137
+ }
138
+ const inputTokens = usage.input_tokens as number;
139
+ const outputTokens = usage.output_tokens as number;
140
+ const totalTokens = usage.total_tokens as number;
141
+ const cachedTokens = optionalUsageDetail(usage.input_tokens_details, "cached_tokens");
142
+ const cacheWriteTokens = optionalUsageDetail(usage.input_tokens_details, "cache_write_tokens");
143
+ const reasoningTokens = optionalUsageDetail(usage.output_tokens_details, "reasoning_tokens");
144
+ if (cachedTokens + cacheWriteTokens > inputTokens || reasoningTokens > outputTokens) {
145
+ throw new CodexCompactionProtocolError("Responses Compact response has inconsistent usage details");
146
+ }
147
+ if (totalTokens !== inputTokens + outputTokens) {
148
+ throw new CodexCompactionProtocolError("Responses Compact response has inconsistent total usage");
149
+ }
150
+ return structuredClone(usage);
159
151
  }
160
152
 
161
153
  function syntheticCompletion(result: CollectedCompactResponse, payload: JsonObject): Response {
162
- const completed = {
163
- id: typeof result.response.id === "string" ? result.response.id : "resp_pi_compact_bridge",
164
- object: "response",
165
- created_at:
166
- typeof result.response.created_at === "number"
167
- ? result.response.created_at
168
- : Math.floor(Date.now() / 1000),
169
- status: "completed",
170
- model: payload.model,
171
- output: [],
172
- parallel_tool_calls: false,
173
- tool_choice: "auto",
174
- tools: [],
175
- usage: validatedUsage(result.response),
176
- };
177
- const events = [
178
- { type: "response.created", response: { ...completed, status: "in_progress" } },
179
- { type: "response.completed", response: completed },
180
- ];
181
- return new Response(events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(""), {
182
- status: 200,
183
- headers: { "content-type": "text/event-stream" },
184
- });
154
+ const completed = {
155
+ id: typeof result.response.id === "string" ? result.response.id : "resp_pi_compact_bridge",
156
+ object: "response",
157
+ created_at:
158
+ typeof result.response.created_at === "number" ? result.response.created_at : Math.floor(Date.now() / 1000),
159
+ status: "completed",
160
+ model: payload.model,
161
+ output: [],
162
+ parallel_tool_calls: false,
163
+ tool_choice: "auto",
164
+ tools: [],
165
+ usage: validatedUsage(result.response),
166
+ };
167
+ const events = [
168
+ { type: "response.created", response: { ...completed, status: "in_progress" } },
169
+ { type: "response.completed", response: completed },
170
+ ];
171
+ return new Response(events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join(""), {
172
+ status: 200,
173
+ headers: { "content-type": "text/event-stream" },
174
+ });
185
175
  }
186
176
 
187
- export async function requestResponsesCompact(
188
- request: RemoteCompactionRequest,
189
- ): Promise<RemoteCompactionResponse> {
190
- if (request.signal.aborted) throw abortError();
191
- let preparedPayload: JsonObject | undefined;
192
- let sentInput: JsonObject[] | undefined;
193
- let compactResult: CollectedCompactResponse | undefined;
194
- let bridgeError: unknown;
195
- let dispatchInFlight = false;
196
- let successfulResponses = 0;
197
- const baseFetch = request.fetch ?? globalThis.fetch;
198
- const bridgeFetch: typeof globalThis.fetch = async (input, init) => {
199
- if (request.signal.aborted) throw abortError();
200
- if (successfulResponses > 0) {
201
- bridgeError = new CodexCompactionProtocolError(
202
- "Provider dispatched again after Responses Compact succeeded",
203
- );
204
- return nonRetryableBridgeFailure(bridgeError);
205
- }
206
- if (dispatchInFlight) {
207
- bridgeError = new CodexCompactionProtocolError(
208
- "Provider dispatched overlapping Responses Compact requests",
209
- );
210
- return nonRetryableBridgeFailure(bridgeError);
211
- }
212
- if (!preparedPayload) {
213
- bridgeError = new CodexCompactionProtocolError(
214
- "Provider dispatched before exposing its request payload",
215
- );
216
- return nonRetryableBridgeFailure(bridgeError);
217
- }
218
- let compactUrl: URL;
219
- try {
220
- compactUrl = responsesCompactUrl(input);
221
- } catch (error) {
222
- bridgeError = error;
223
- return nonRetryableBridgeFailure(error);
224
- }
225
- const signal = mergedSignal(input, init, request.signal);
226
- dispatchInFlight = true;
227
- try {
228
- const response = await baseFetch(compactUrl, {
229
- ...init,
230
- method: "POST",
231
- headers: mergedHeaders(input, init),
232
- body: JSON.stringify(preparedPayload),
233
- signal,
234
- });
235
- if (!response.ok) return response;
236
- try {
237
- const result = await collectCompactResponse(response, { signal });
238
- successfulResponses += 1;
239
- if (successfulResponses !== 1) {
240
- throw new CodexCompactionProtocolError(
241
- "Provider returned more than one successful Responses Compact response",
242
- );
243
- }
244
- compactResult = result;
245
- return syntheticCompletion(result, preparedPayload);
246
- } catch (error) {
247
- bridgeError = error;
248
- return nonRetryableBridgeFailure(error);
249
- }
250
- } finally {
251
- dispatchInFlight = false;
252
- }
253
- };
177
+ export async function requestResponsesCompact(request: RemoteCompactionRequest): Promise<RemoteCompactionResponse> {
178
+ if (request.signal.aborted) throw abortError();
179
+ let preparedPayload: JsonObject | undefined;
180
+ let sentInput: JsonObject[] | undefined;
181
+ let compactResult: CollectedCompactResponse | undefined;
182
+ let bridgeError: unknown;
183
+ let dispatchInFlight = false;
184
+ let successfulResponses = 0;
185
+ const baseFetch = request.fetch ?? globalThis.fetch;
186
+ const bridgeFetch: typeof globalThis.fetch = async (input, init) => {
187
+ if (request.signal.aborted) throw abortError();
188
+ if (successfulResponses > 0) {
189
+ bridgeError = new CodexCompactionProtocolError("Provider dispatched again after Responses Compact succeeded");
190
+ return nonRetryableBridgeFailure(bridgeError);
191
+ }
192
+ if (dispatchInFlight) {
193
+ bridgeError = new CodexCompactionProtocolError("Provider dispatched overlapping Responses Compact requests");
194
+ return nonRetryableBridgeFailure(bridgeError);
195
+ }
196
+ if (!preparedPayload) {
197
+ bridgeError = new CodexCompactionProtocolError("Provider dispatched before exposing its request payload");
198
+ return nonRetryableBridgeFailure(bridgeError);
199
+ }
200
+ let compactUrl: URL;
201
+ try {
202
+ compactUrl = responsesCompactUrl(input);
203
+ } catch (error) {
204
+ bridgeError = error;
205
+ return nonRetryableBridgeFailure(error);
206
+ }
207
+ const signal = mergedSignal(input, init, request.signal);
208
+ dispatchInFlight = true;
209
+ try {
210
+ const response = await baseFetch(compactUrl, {
211
+ ...init,
212
+ method: "POST",
213
+ headers: mergedHeaders(input, init),
214
+ body: JSON.stringify(preparedPayload),
215
+ signal,
216
+ });
217
+ if (!response.ok) return response;
218
+ try {
219
+ const result = await collectCompactResponse(response, { signal });
220
+ successfulResponses += 1;
221
+ if (successfulResponses !== 1) {
222
+ throw new CodexCompactionProtocolError(
223
+ "Provider returned more than one successful Responses Compact response",
224
+ );
225
+ }
226
+ compactResult = result;
227
+ return syntheticCompletion(result, preparedPayload);
228
+ } catch (error) {
229
+ bridgeError = error;
230
+ return nonRetryableBridgeFailure(error);
231
+ }
232
+ } finally {
233
+ dispatchInFlight = false;
234
+ }
235
+ };
254
236
 
255
- const stream = request.provider.stream(request.model, request.context, {
256
- apiKey: request.apiKey,
257
- headers: request.headers,
258
- env: request.env,
259
- signal: request.signal,
260
- transport: "sse",
261
- cacheRetention: "none",
262
- timeoutMs: request.requestTimeoutMs ?? 5 * 60 * 1000,
263
- maxRetries: request.maxRetries ?? 2,
264
- fetch: bridgeFetch,
265
- onPayload: (payload) => {
266
- if (preparedPayload) {
267
- throw new CodexCompactionProtocolError(
268
- "Provider exposed more than one compaction request payload",
269
- );
270
- }
271
- const expanded = expandRemoteCompactionPayload(payload, request.priorCheckpoint);
272
- preparedPayload = compactPayload(expanded, request.model.api);
273
- sentInput = assertPreparedInput(preparedPayload);
274
- return expanded;
275
- },
276
- });
237
+ const stream = request.provider.stream(request.model, request.context, {
238
+ apiKey: request.apiKey,
239
+ headers: request.headers,
240
+ env: request.env,
241
+ signal: request.signal,
242
+ transport: "sse",
243
+ cacheRetention: "none",
244
+ timeoutMs: request.requestTimeoutMs ?? 5 * 60 * 1000,
245
+ maxRetries: request.maxRetries ?? 2,
246
+ fetch: bridgeFetch,
247
+ onPayload: (payload) => {
248
+ if (preparedPayload) {
249
+ throw new CodexCompactionProtocolError("Provider exposed more than one compaction request payload");
250
+ }
251
+ const expanded = expandRemoteCompactionPayload(payload, request.priorCheckpoint);
252
+ preparedPayload = compactPayload(expanded, request.profile);
253
+ sentInput = assertPreparedInput(preparedPayload);
254
+ return expanded;
255
+ },
256
+ });
277
257
 
278
- let usage: Usage;
279
- try {
280
- usage = await collectProviderUsage(stream, request.signal);
281
- } catch (error) {
282
- if (bridgeError) throw bridgeError;
283
- throw error;
284
- }
285
- if (request.signal.aborted) throw abortError();
286
- if (bridgeError) throw bridgeError;
287
- if (!preparedPayload || !sentInput || !compactResult || successfulResponses !== 1) {
288
- throw new CodexCompactionProtocolError(
289
- "Provider did not complete exactly one Responses Compact request",
290
- );
291
- }
292
- return {
293
- item: compactResult.item,
294
- promptInput: sentInput,
295
- compactedOutput: compactResult.output,
296
- usage,
297
- };
258
+ let usage: Usage;
259
+ try {
260
+ usage = await collectProviderUsage(stream, request.signal);
261
+ } catch (error) {
262
+ if (bridgeError) throw bridgeError;
263
+ throw error;
264
+ }
265
+ if (request.signal.aborted) throw abortError();
266
+ if (bridgeError) throw bridgeError;
267
+ if (!preparedPayload || !sentInput || !compactResult || successfulResponses !== 1) {
268
+ throw new CodexCompactionProtocolError("Provider did not complete exactly one Responses Compact request");
269
+ }
270
+ return {
271
+ item: compactResult.item,
272
+ promptInput: sentInput,
273
+ compactedOutput: compactResult.output,
274
+ usage,
275
+ };
298
276
  }
@@ -1,19 +1,16 @@
1
1
  import type { AssistantMessageEventStream, Usage } from "@earendil-works/pi-ai";
2
2
  import { abortError } from "./remote-types.js";
3
3
 
4
- export async function collectProviderUsage(
5
- stream: AssistantMessageEventStream,
6
- signal: AbortSignal,
7
- ): Promise<Usage> {
8
- let usage: Usage | undefined;
9
- for await (const event of stream) {
10
- if (signal.aborted) throw abortError();
11
- if (event.type === "error") {
12
- throw new Error(event.error.errorMessage ?? "Responses compaction request failed");
13
- }
14
- if (event.type === "done") usage = event.message.usage;
15
- }
16
- if (signal.aborted) throw abortError();
17
- if (!usage) throw new Error("Responses provider stream ended without completion usage");
18
- return usage;
4
+ export async function collectProviderUsage(stream: AssistantMessageEventStream, signal: AbortSignal): Promise<Usage> {
5
+ let usage: Usage | undefined;
6
+ for await (const event of stream) {
7
+ if (signal.aborted) throw abortError();
8
+ if (event.type === "error") {
9
+ throw new Error(event.error.errorMessage ?? "Responses compaction request failed");
10
+ }
11
+ if (event.type === "done") usage = event.message.usage;
12
+ }
13
+ if (signal.aborted) throw abortError();
14
+ if (!usage) throw new Error("Responses provider stream ended without completion usage");
15
+ return usage;
19
16
  }
@@ -1,45 +1,46 @@
1
- import type { Context, Model, Provider, ProviderHeaders, Usage } from "@earendil-works/pi-ai";
2
- import type { RemoteCompactionProtocol, ResponsesCompactionApi } from "./model-api.js";
1
+ import type { Api, Context, Model, Provider, ProviderHeaders, Usage } from "@earendil-works/pi-ai";
2
+ import type { RemoteCompactionProtocol, ResponsesCompactionProfile } from "./model-api.js";
3
3
  import type { JsonObject } from "./protocol.js";
4
4
 
5
5
  export interface PriorCheckpointPayload {
6
- marker: string;
7
- replacementHistory: readonly unknown[];
6
+ marker: string;
7
+ replacementHistory: readonly unknown[];
8
8
  }
9
9
 
10
10
  export interface RemoteCompactionRequest {
11
- provider: Provider;
12
- model: Model<ResponsesCompactionApi>;
13
- context: Context;
14
- protocol: RemoteCompactionProtocol;
15
- apiKey?: string;
16
- headers?: ProviderHeaders;
17
- env?: Record<string, string>;
18
- signal: AbortSignal;
19
- priorCheckpoint?: PriorCheckpointPayload;
20
- requestTimeoutMs?: number;
21
- maxRetries?: number;
22
- fetch?: typeof globalThis.fetch;
11
+ provider: Provider;
12
+ model: Model<Api>;
13
+ profile: ResponsesCompactionProfile;
14
+ context: Context;
15
+ protocol: RemoteCompactionProtocol;
16
+ apiKey?: string;
17
+ headers?: ProviderHeaders;
18
+ env?: Record<string, string>;
19
+ signal: AbortSignal;
20
+ priorCheckpoint?: PriorCheckpointPayload;
21
+ requestTimeoutMs?: number;
22
+ maxRetries?: number;
23
+ fetch?: typeof globalThis.fetch;
23
24
  }
24
25
 
25
26
  export interface RemoteCompactionResponse {
26
- item: JsonObject;
27
- promptInput: JsonObject[];
28
- compactedOutput?: JsonObject[];
29
- usage: Usage;
27
+ item: JsonObject;
28
+ promptInput: JsonObject[];
29
+ compactedOutput?: JsonObject[];
30
+ usage: Usage;
30
31
  }
31
32
 
32
33
  export function isJsonObject(value: unknown): value is JsonObject {
33
- return typeof value === "object" && value !== null && !Array.isArray(value);
34
+ return typeof value === "object" && value !== null && !Array.isArray(value);
34
35
  }
35
36
 
36
37
  export function abortError(): DOMException {
37
- return new DOMException("Compaction aborted", "AbortError");
38
+ return new DOMException("Compaction aborted", "AbortError");
38
39
  }
39
40
 
40
41
  export function assertPreparedInput(payload: JsonObject): JsonObject[] {
41
- if (!Array.isArray(payload.input) || !payload.input.every(isJsonObject)) {
42
- throw new Error("Prepared compaction payload has invalid input items");
43
- }
44
- return structuredClone(payload.input);
42
+ if (!Array.isArray(payload.input) || !payload.input.every(isJsonObject)) {
43
+ throw new Error("Prepared compaction payload has invalid input items");
44
+ }
45
+ return structuredClone(payload.input);
45
46
  }