dsh-lcx-codex 0.4.2 → 0.4.3-pre.2

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.
Files changed (47) hide show
  1. package/README.md +116 -202
  2. package/cordis.patch.yml +3 -20
  3. package/lib/client.js +273 -146
  4. package/lib/compact-v2.js +218 -199
  5. package/lib/dsh-compat.js +227 -100
  6. package/lib/dsh-responses.js +445 -277
  7. package/lib/index.js +851 -757
  8. package/lib/json-store.js +50 -31
  9. package/lib/native-checkpoint.js +520 -194
  10. package/lib/responses-request.js +106 -121
  11. package/lib/responses-stream.js +972 -443
  12. package/lib/route.js +229 -355
  13. package/lib/service-mutex.js +73 -64
  14. package/lib/token-budget.js +176 -108
  15. package/lib/transport.js +277 -67
  16. package/lib/types/client/index.d.ts +6 -0
  17. package/lib/types/compact-v2.d.ts +104 -0
  18. package/lib/types/dsh-compat.d.ts +78 -0
  19. package/lib/types/dsh-responses.d.ts +82 -0
  20. package/lib/types/index.d.ts +83 -0
  21. package/lib/types/json-store.d.ts +10 -0
  22. package/lib/types/native-checkpoint.d.ts +213 -0
  23. package/lib/types/responses-request.d.ts +58 -0
  24. package/lib/types/responses-stream.d.ts +51 -0
  25. package/lib/types/route.d.ts +132 -0
  26. package/lib/types/service-mutex.d.ts +14 -0
  27. package/lib/types/token-budget.d.ts +50 -0
  28. package/lib/types/transport.d.ts +20 -0
  29. package/lib/types/web-run-output.d.ts +29 -0
  30. package/lib/types/web-search-alpha.d.ts +286 -0
  31. package/lib/types/web-search-capability.d.ts +26 -0
  32. package/lib/types/web-search-hosted.d.ts +246 -0
  33. package/lib/types/web-search-ref-store.d.ts +22 -0
  34. package/lib/web-run-output.js +167 -18
  35. package/lib/web-search-alpha.js +865 -163
  36. package/lib/web-search-capability.js +55 -65
  37. package/lib/web-search-hosted.js +210 -32
  38. package/lib/web-search-ref-store.js +63 -59
  39. package/package.json +79 -27
  40. package/ARCHITECTURE.md +0 -117
  41. package/CHANGELOG.md +0 -224
  42. package/README_EN.md +0 -277
  43. package/assets/dsh-lcx-codex-banner.jpg +0 -0
  44. package/lib/legacy-v3.js +0 -20
  45. package/lib/responses-replay.js +0 -68
  46. package/scripts/probe-alpha.mjs +0 -43
  47. package/scripts/validate-dsh-schema.mjs +0 -31
package/lib/compact-v2.js CHANGED
@@ -1,184 +1,158 @@
1
- // @ts-check
2
-
3
- import { consumeSse, fetchSseWithRetry } from './transport.js'
4
- import { buildCompactionResponsesBody, responsesGenerationEnvelope as standardGenerationEnvelope } from './responses-request.js'
5
-
6
- /** @typedef {Record<string, unknown>} UnknownRecord */
7
- /** @typedef {Record<string, string>} HeaderMap */
8
- /** @typedef {Error & { code?: string, status?: number, providerCode?: string, providerType?: string, providerParam?: string }} LcxError */
9
- /** @typedef {{ type: 'compaction', encrypted_content: string }} CompactionItem */
10
- /** @typedef {{ type: 'function_call', call_id: string }} FunctionCallItem */
11
- /** @typedef {{ type: 'function_call_output', call_id: string }} FunctionCallOutputItem */
12
- /** @typedef {CompactionItem | FunctionCallItem | FunctionCallOutputItem | { type: string }} ValidatedOutputItem */
13
- /** @typedef {{ inputTokens: number, outputTokens: number, cacheReadTokens?: number, cacheWriteTokens?: number, reasoningTokens?: number }} CanonicalUsage */
14
- /** @typedef {{ reasoningEffort?: unknown, temperature?: unknown, maxTokens?: unknown }} GenerationControls */
15
- /** @typedef {{ reasoning?: { effort: string, summary: 'auto' }, include?: string[], temperature?: number, max_output_tokens?: number }} GenerationEnvelope */
16
- /**
17
- * @typedef {object} NativeCompactionBodyOptions
18
- * @property {string} model
19
- * @property {unknown} [modelDescriptor]
20
- * @property {unknown[]} input
21
- * @property {string} [instructions]
22
- * @property {unknown} [tools]
23
- * @property {string} [promptCacheKey]
24
- * @property {string} [promptCacheRetention]
25
- * @property {'none' | 'short' | 'long'} [cacheRetention]
26
- * @property {unknown} [reasoningEffort]
27
- * @property {unknown} [temperature]
28
- * @property {unknown} [maxTokens]
29
- */
30
- /**
31
- * @typedef {object} NativeCompactionBody
32
- * @property {string} model
33
- * @property {unknown[]} input
34
- * @property {true} stream
35
- * @property {false} store
36
- * @property {'auto'} tool_choice
37
- * @property {true} parallel_tool_calls
38
- * @property {string} [instructions]
39
- * @property {unknown[]} [tools]
40
- * @property {string} [prompt_cache_key]
41
- * @property {string} [prompt_cache_retention]
42
- * @property {{ mode?: 'explicit', ttl?: '30m' }} [prompt_cache_options]
43
- * @property {{ effort: string, summary: 'auto' }} [reasoning]
44
- * @property {string[]} [include]
45
- * @property {number} [temperature]
46
- * @property {number} [max_output_tokens]
47
- */
48
- /**
49
- * @typedef {NativeCompactionBodyOptions & {
50
- * baseURL: string,
51
- * idempotencyKey?: string,
52
- * headers?: HeaderMap,
53
- * signal?: AbortSignal,
54
- * timeoutMs?: number,
55
- * maxAttempts?: number,
56
- * maxResponseBytes?: number
57
- * }} NativeCompactionRequestOptions
58
- */
59
- /** @typedef {{ signal?: AbortSignal, maxResponseBytes?: number }} SseParseOptions */
60
- /** @typedef {{ object: unknown, id?: string, output: ValidatedOutputItem[], compaction: CompactionItem, usage?: CanonicalUsage }} NativeCompactionResult */
61
-
62
- export const REMOTE_COMPACTION_V2_FEATURE = 'remote_compaction_v2'
63
-
1
+ import { consumeSse, fetchSseWithRetry } from "./transport.js";
2
+ import { buildCompactionResponsesBody, responsesGenerationEnvelope as standardGenerationEnvelope, } from "./responses-request.js";
3
+ export const REMOTE_COMPACTION_V2_FEATURE = "remote_compaction_v2";
64
4
  /**
65
5
  * @param {unknown} value
66
6
  * @returns {value is UnknownRecord}
67
7
  */
68
- function isObject(value) { return value !== null && typeof value === 'object' && !Array.isArray(value) }
8
+ function isObject(value) {
9
+ return value !== null && typeof value === "object" && !Array.isArray(value);
10
+ }
69
11
  /**
70
12
  * @param {string} message
71
13
  * @param {string} [code]
72
14
  * @returns {LcxError}
73
15
  */
74
- function fail(message, code = 'LCX_COMPACT_INVALID_RESPONSE') {
75
- /** @type {LcxError} */
76
- const e = new Error(message)
77
- e.code = code
78
- return e
16
+ function fail(message, code = "LCX_COMPACT_INVALID_RESPONSE") {
17
+ const e = new Error(message);
18
+ e.code = code;
19
+ return e;
79
20
  }
80
21
  /** @param {unknown} value */
81
22
  function safeMachineField(value) {
82
- if (typeof value !== 'string' || value.length === 0 || value.length > 96) return undefined
83
- return /^[A-Za-z0-9_.:\[\]-]+$/u.test(value) ? value : undefined
23
+ if (typeof value !== "string" || value.length === 0 || value.length > 96)
24
+ return undefined;
25
+ return /^[A-Za-z0-9_.:\[\]-]+$/u.test(value) ? value : undefined;
84
26
  }
85
-
86
27
  /**
87
28
  * @param {HeaderMap} [headers]
88
29
  * @returns {HeaderMap}
89
30
  */
90
31
  export function mergeFeatureHeader(headers = {}) {
91
- const result = { ...headers }
92
- const key = Object.keys(result).find((name) => name.toLowerCase() === 'x-codex-beta-features')
93
- const values = String(key ? result[key] ?? '' : '').split(',').map((x) => x.trim()).filter(Boolean)
94
- if (!values.includes(REMOTE_COMPACTION_V2_FEATURE)) values.push(REMOTE_COMPACTION_V2_FEATURE)
95
- result[key ?? 'x-codex-beta-features'] = values.join(',')
96
- return result
32
+ const result = { ...headers };
33
+ const key = Object.keys(result).find((name) => name.toLowerCase() === "x-codex-beta-features");
34
+ const values = String(key ? (result[key] ?? "") : "")
35
+ .split(",")
36
+ .map((x) => x.trim())
37
+ .filter(Boolean);
38
+ if (!values.includes(REMOTE_COMPACTION_V2_FEATURE))
39
+ values.push(REMOTE_COMPACTION_V2_FEATURE);
40
+ result[key ?? "x-codex-beta-features"] = values.join(",");
41
+ return result;
97
42
  }
98
-
99
43
  /**
100
44
  * @param {GenerationControls} [controls]
101
45
  * @returns {GenerationEnvelope}
102
46
  */
103
47
  export function responsesGenerationEnvelope(controls = {}) {
104
- return standardGenerationEnvelope(controls)
48
+ return standardGenerationEnvelope({
49
+ model: "unknown",
50
+ reasoningEffort: controls.reasoningEffort,
51
+ temperature: controls.temperature,
52
+ maxTokens: controls.maxTokens,
53
+ });
105
54
  }
106
-
107
55
  /**
108
56
  * @param {NativeCompactionBodyOptions} options
109
57
  * @returns {NativeCompactionBody}
110
58
  */
111
- export function buildNativeCompactionBody({ model, modelDescriptor, input, instructions, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens }) {
112
- return /** @type {NativeCompactionBody} */ (/** @type {unknown} */ (buildCompactionResponsesBody({
113
- model: /** @type {any} */ (modelDescriptor ?? model),
114
- input,
115
- instructions,
116
- tools,
117
- promptCacheKey,
118
- promptCacheRetention,
119
- cacheRetention: cacheRetention ?? (promptCacheKey ? (promptCacheRetention ? 'long' : 'short') : 'none'),
120
- reasoningEffort,
121
- temperature,
122
- maxTokens,
123
- })))
59
+ export function buildNativeCompactionBody({ model, modelDescriptor, input, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, }) {
60
+ return buildCompactionResponsesBody({
61
+ model: modelDescriptor ?? model,
62
+ input,
63
+ tools,
64
+ promptCacheKey,
65
+ promptCacheRetention,
66
+ cacheRetention: cacheRetention ??
67
+ (promptCacheKey ? (promptCacheRetention ? "long" : "short") : "none"),
68
+ reasoningEffort,
69
+ temperature,
70
+ maxTokens,
71
+ });
124
72
  }
125
-
126
73
  /**
127
74
  * Provider usage stays unknown until the object guard and numeric normalization.
128
75
  * @param {unknown} raw
129
76
  * @returns {CanonicalUsage | undefined}
130
77
  */
131
78
  function usageFrom(raw) {
132
- if (!isObject(raw)) return undefined
133
- const inputTotal = Number(raw.input_tokens ?? 0)
134
- const output = Number(raw.output_tokens ?? 0)
135
- const details = /** @type {UnknownRecord} */ (raw.input_tokens_details ?? raw.input_token_details ?? raw.prompt_tokens_details ?? {})
136
- const cacheRead = Number(details.cached_tokens ?? 0)
137
- const cacheWrite = Number(details.cache_write_tokens ?? 0)
138
- /** @type {CanonicalUsage} */
139
- const result = {
140
- inputTokens: Math.max(0, Number.isFinite(inputTotal) ? inputTotal - (Number.isFinite(cacheRead) ? cacheRead : 0) - (Number.isFinite(cacheWrite) ? cacheWrite : 0) : 0),
141
- outputTokens: Number.isFinite(output) && output > 0 ? output : 0,
142
- }
143
- if (Number.isFinite(cacheRead) && cacheRead > 0) result.cacheReadTokens = cacheRead
144
- if (Number.isFinite(cacheWrite) && cacheWrite > 0) result.cacheWriteTokens = cacheWrite
145
- const reasoning = Number(/** @type {UnknownRecord | undefined} */ (raw.output_tokens_details)?.reasoning_tokens ?? /** @type {UnknownRecord | undefined} */ (raw.output_token_details)?.reasoning_tokens ?? 0)
146
- if (Number.isFinite(reasoning) && reasoning > 0) result.reasoningTokens = reasoning
147
- return Object.values(result).some((v) => Number(v) > 0) ? result : undefined
79
+ if (!isObject(raw))
80
+ return undefined;
81
+ const inputTotal = Number(raw.input_tokens ?? 0);
82
+ const output = Number(raw.output_tokens ?? 0);
83
+ const detailsValue = raw.input_tokens_details ?? raw.input_token_details ?? raw.prompt_tokens_details;
84
+ const details = isObject(detailsValue) ? detailsValue : {};
85
+ const cacheRead = Number(details.cached_tokens ?? 0);
86
+ const cacheWrite = Number(details.cache_write_tokens ?? 0);
87
+ const result = {
88
+ inputTokens: Math.max(0, Number.isFinite(inputTotal)
89
+ ? inputTotal -
90
+ (Number.isFinite(cacheRead) ? cacheRead : 0) -
91
+ (Number.isFinite(cacheWrite) ? cacheWrite : 0)
92
+ : 0),
93
+ outputTokens: Number.isFinite(output) && output > 0 ? output : 0,
94
+ };
95
+ if (Number.isFinite(cacheRead) && cacheRead > 0)
96
+ result.cacheReadTokens = cacheRead;
97
+ if (Number.isFinite(cacheWrite) && cacheWrite > 0)
98
+ result.cacheWriteTokens = cacheWrite;
99
+ const outputDetails = isObject(raw.output_tokens_details)
100
+ ? raw.output_tokens_details
101
+ : isObject(raw.output_token_details)
102
+ ? raw.output_token_details
103
+ : {};
104
+ const reasoning = Number(outputDetails.reasoning_tokens ?? 0);
105
+ if (Number.isFinite(reasoning) && reasoning > 0)
106
+ result.reasoningTokens = reasoning;
107
+ return Object.values(result).some((v) => Number(v) > 0) ? result : undefined;
148
108
  }
149
-
150
109
  /**
151
110
  * @param {unknown} output
152
111
  * @returns {{ output: ValidatedOutputItem[], compaction: CompactionItem }}
153
112
  */
154
113
  function validateOutput(output) {
155
- if (!Array.isArray(output) || output.length === 0) throw fail('native compaction output is empty')
156
- const compactions = output.filter((item) => isObject(item) && item.type === 'compaction')
157
- if (compactions.length !== 1) throw fail(`native compaction must return exactly one compaction item, got ${compactions.length}`)
158
- const compact = compactions[0]
159
- if (typeof compact.encrypted_content !== 'string' || compact.encrypted_content.length === 0) throw fail('native compaction item has no encrypted_content')
160
- /** @type {Set<string>} */
161
- const calls = new Set()
162
- /** @type {Set<string>} */
163
- const results = new Set()
164
- for (const item of output) {
165
- if (!isObject(item) || typeof item.type !== 'string') throw fail('native compaction output contains a malformed item')
166
- if (item.type === 'function_call') {
167
- if (typeof item.call_id !== 'string' || !item.call_id || calls.has(item.call_id)) throw fail('native compaction output contains an invalid function_call')
168
- calls.add(item.call_id)
169
- } else if (item.type === 'function_call_output') {
170
- if (typeof item.call_id !== 'string' || !item.call_id || results.has(item.call_id)) throw fail('native compaction output contains an invalid function_call_output')
171
- results.add(item.call_id)
114
+ if (!Array.isArray(output) || output.length === 0)
115
+ throw fail("native compaction output is empty");
116
+ const compactions = output.filter((item) => isObject(item) && item.type === "compaction");
117
+ if (compactions.length !== 1)
118
+ throw fail(`native compaction must return exactly one compaction item, got ${compactions.length}`);
119
+ const compact = compactions[0];
120
+ if (typeof compact.encrypted_content !== "string" ||
121
+ compact.encrypted_content.length === 0)
122
+ throw fail("native compaction item has no encrypted_content");
123
+ /** @type {Set<string>} */
124
+ const calls = new Set();
125
+ /** @type {Set<string>} */
126
+ const results = new Set();
127
+ for (const item of output) {
128
+ if (!isObject(item) || typeof item.type !== "string")
129
+ throw fail("native compaction output contains a malformed item");
130
+ if (item.type === "function_call") {
131
+ if (typeof item.call_id !== "string" ||
132
+ !item.call_id ||
133
+ calls.has(item.call_id))
134
+ throw fail("native compaction output contains an invalid function_call");
135
+ calls.add(item.call_id);
136
+ }
137
+ else if (item.type === "function_call_output") {
138
+ if (typeof item.call_id !== "string" ||
139
+ !item.call_id ||
140
+ results.has(item.call_id))
141
+ throw fail("native compaction output contains an invalid function_call_output");
142
+ results.add(item.call_id);
143
+ }
172
144
  }
173
- }
174
- for (const id of calls) if (!results.has(id)) throw fail(`native compaction output has orphan function_call ${id}`)
175
- for (const id of results) if (!calls.has(id)) throw fail(`native compaction output has orphan function_call_output ${id}`)
176
- return {
177
- output: /** @type {ValidatedOutputItem[]} */ (structuredClone(output)),
178
- compaction: /** @type {CompactionItem} */ (structuredClone(compact)),
179
- }
145
+ for (const id of calls)
146
+ if (!results.has(id))
147
+ throw fail(`native compaction output has orphan function_call ${id}`);
148
+ for (const id of results)
149
+ if (!calls.has(id))
150
+ throw fail(`native compaction output has orphan function_call_output ${id}`);
151
+ return {
152
+ output: structuredClone(output),
153
+ compaction: structuredClone(compact),
154
+ };
180
155
  }
181
-
182
156
  /**
183
157
  * Provider SSE events enter as unknown; response.completed remains authoritative.
184
158
  * @param {Response} response
@@ -186,70 +160,115 @@ function validateOutput(output) {
186
160
  * @returns {Promise<NativeCompactionResult>}
187
161
  */
188
162
  export async function parseNativeCompactionSse(response, options = {}) {
189
- /** @type {Map<number, UnknownRecord>} */
190
- const byIndex = new Map()
191
- /** @type {Map<string, UnknownRecord>} */
192
- const byId = new Map()
193
- /** @type {UnknownRecord | undefined} */
194
- let terminal
195
- /** @param {UnknownRecord} event */
196
- const mergeItem = (event) => {
197
- if (!isObject(event?.item)) return
198
- const index = Number.isInteger(event.output_index) ? /** @type {number} */ (event.output_index) : undefined
199
- const id = typeof event.item.id === 'string' ? event.item.id : typeof event.item_id === 'string' ? event.item_id : undefined
200
- let record = (index !== undefined ? byIndex.get(index) : undefined) ?? (id ? byId.get(id) : undefined)
201
- if (!record) record = {}
202
- const encrypted = record.encrypted_content
203
- Object.assign(record, structuredClone(event.item))
204
- if (typeof record.encrypted_content !== 'string' && typeof encrypted === 'string') record.encrypted_content = encrypted
205
- if (index !== undefined) byIndex.set(index, record)
206
- if (id) byId.set(id, record)
207
- }
208
- await consumeSse(response, (/** @type {unknown} */ event) => {
209
- if (!isObject(event)) return
210
- if (event.type === 'error' || event.type === 'response.failed' || event.type === 'response.incomplete') {
211
- const upstream = event.type === 'response.failed' ? /** @type {{ error?: unknown } | undefined} */ (event.response)?.error : event.error
212
- const providerCode = safeMachineField(/** @type {UnknownRecord | undefined} */ (upstream)?.code)
213
- const providerType = safeMachineField(/** @type {UnknownRecord | undefined} */ (upstream)?.type)
214
- const providerParam = safeMachineField(/** @type {UnknownRecord | undefined} */ (upstream)?.param)
215
- const diagnostics = [
216
- providerCode ? `providerCode=${providerCode}` : '',
217
- providerType ? `providerType=${providerType}` : '',
218
- providerParam ? `providerParam=${providerParam}` : '',
219
- ].filter(Boolean).join(' ')
220
- /** @type {LcxError} */
221
- const e = fail(`native compaction ended with ${event.type}${diagnostics ? ` ${diagnostics}` : ''}`, 'LCX_COMPACT_UPSTREAM_ERROR')
222
- if (Number.isInteger(/** @type {UnknownRecord | undefined} */ (upstream)?.status ?? /** @type {UnknownRecord | undefined} */ (event.error)?.status)) e.status = /** @type {number} */ (/** @type {UnknownRecord | undefined} */ (upstream)?.status ?? /** @type {UnknownRecord | undefined} */ (event.error)?.status)
223
- if (providerCode) e.providerCode = providerCode
224
- if (providerType) e.providerType = providerType
225
- if (providerParam) e.providerParam = providerParam
226
- throw e
227
- }
228
- if (event.type === 'response.output_item.added' || event.type === 'response.output_item.done') mergeItem(event)
229
- if (event.type === 'response.completed') terminal = /** @type {UnknownRecord} */ (event.response)
230
- }, options)
231
- if (!isObject(terminal)) throw fail('native compaction stream ended without response.completed', 'LCX_COMPACT_INCOMPLETE_SSE')
232
- if (terminal.status !== 'completed') throw fail('native compaction response.completed did not carry completed status', 'LCX_COMPACT_INCOMPLETE_SSE')
233
- const eventItems = [...new Set([...byIndex.values(), ...byId.values()])]
234
- const output = Array.isArray(terminal.output) && terminal.output.length > 0 ? terminal.output : eventItems
235
- const normalized = validateOutput(output)
236
- return {
237
- object: terminal.object ?? 'response.compaction',
238
- ...(typeof terminal.id === 'string' ? { id: terminal.id } : {}),
239
- ...normalized,
240
- usage: usageFrom(terminal.usage),
241
- }
163
+ const byIndex = new Map();
164
+ const byId = new Map();
165
+ let terminal;
166
+ const mergeItem = (event) => {
167
+ if (!isObject(event.item))
168
+ return;
169
+ const index = Number.isInteger(event.output_index)
170
+ ? Number(event.output_index)
171
+ : undefined;
172
+ const id = typeof event.item.id === "string"
173
+ ? event.item.id
174
+ : typeof event.item_id === "string"
175
+ ? event.item_id
176
+ : undefined;
177
+ let record = (index !== undefined ? byIndex.get(index) : undefined) ??
178
+ (id ? byId.get(id) : undefined);
179
+ if (!record)
180
+ record = {};
181
+ const encrypted = record.encrypted_content;
182
+ Object.assign(record, structuredClone(event.item));
183
+ if (typeof record.encrypted_content !== "string" &&
184
+ typeof encrypted === "string")
185
+ record.encrypted_content = encrypted;
186
+ if (index !== undefined)
187
+ byIndex.set(index, record);
188
+ if (id)
189
+ byId.set(id, record);
190
+ };
191
+ await consumeSse(response, (event) => {
192
+ if (!isObject(event))
193
+ return;
194
+ if (event.type === "error" ||
195
+ event.type === "response.failed" ||
196
+ event.type === "response.incomplete") {
197
+ const upstreamValue = event.type === "response.failed"
198
+ ? isObject(event.response)
199
+ ? event.response.error
200
+ : undefined
201
+ : event.error;
202
+ const upstream = isObject(upstreamValue) ? upstreamValue : {};
203
+ const providerCode = safeMachineField(upstream.code);
204
+ const providerType = safeMachineField(upstream.type);
205
+ const providerParam = safeMachineField(upstream.param);
206
+ const diagnostics = [
207
+ providerCode ? `providerCode=${providerCode}` : "",
208
+ providerType ? `providerType=${providerType}` : "",
209
+ providerParam ? `providerParam=${providerParam}` : "",
210
+ ]
211
+ .filter(Boolean)
212
+ .join(" ");
213
+ const e = fail(`native compaction ended with ${event.type}${diagnostics ? ` ${diagnostics}` : ""}`, "LCX_COMPACT_UPSTREAM_ERROR");
214
+ if (Number.isInteger(upstream.status ?? (isObject(event.error) ? event.error.status : undefined)))
215
+ e.status = Number(upstream.status ?? (isObject(event.error) ? event.error.status : undefined));
216
+ if (providerCode)
217
+ e.providerCode = providerCode;
218
+ if (providerType)
219
+ e.providerType = providerType;
220
+ if (providerParam)
221
+ e.providerParam = providerParam;
222
+ throw e;
223
+ }
224
+ if (event.type === "response.output_item.added" ||
225
+ event.type === "response.output_item.done")
226
+ mergeItem(event);
227
+ if (event.type === "response.completed")
228
+ terminal = isObject(event.response) ? event.response : undefined;
229
+ }, options);
230
+ if (!isObject(terminal))
231
+ throw fail("native compaction stream ended without response.completed", "LCX_COMPACT_INCOMPLETE_SSE");
232
+ if (terminal.status !== "completed")
233
+ throw fail("native compaction response.completed did not carry completed status", "LCX_COMPACT_INCOMPLETE_SSE");
234
+ const eventItems = [...new Set([...byIndex.values(), ...byId.values()])];
235
+ const output = Array.isArray(terminal.output) && terminal.output.length > 0
236
+ ? terminal.output
237
+ : eventItems;
238
+ const normalized = validateOutput(output);
239
+ return {
240
+ object: terminal.object ?? "response.compaction",
241
+ ...(typeof terminal.id === "string" ? { id: terminal.id } : {}),
242
+ ...normalized,
243
+ usage: usageFrom(terminal.usage),
244
+ };
242
245
  }
243
-
244
246
  /**
245
247
  * @param {NativeCompactionRequestOptions} options
246
248
  */
247
- export async function requestNativeCompaction({ baseURL, model, modelDescriptor, input, instructions, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, idempotencyKey, headers, signal, timeoutMs, maxAttempts, maxResponseBytes }) {
248
- const body = buildNativeCompactionBody({ model, modelDescriptor, input, instructions, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens })
249
- const requestHeaders = mergeFeatureHeader({ ...headers, ...(idempotencyKey ? { 'idempotency-key': String(idempotencyKey) } : {}) })
250
- return fetchSseWithRetry(`${String(baseURL).replace(/\/+$/u, '')}/responses`, body, requestHeaders, signal, timeoutMs, {
251
- maxAttempts,
252
- maxResponseBytes,
253
- consume: (/** @type {Response} */ response, /** @type {{ requestSignal?: AbortSignal }} */ consumeOptions) => parseNativeCompactionSse(response, { signal: consumeOptions.requestSignal ?? signal, maxResponseBytes }),
254
- })
249
+ export async function requestNativeCompaction({ baseURL, model, modelDescriptor, input, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, idempotencyKey, headers, signal, timeoutMs, maxAttempts, maxResponseBytes, }) {
250
+ const body = buildNativeCompactionBody({
251
+ model,
252
+ modelDescriptor,
253
+ input,
254
+ tools,
255
+ promptCacheKey,
256
+ promptCacheRetention,
257
+ cacheRetention,
258
+ reasoningEffort,
259
+ temperature,
260
+ maxTokens,
261
+ });
262
+ const requestHeaders = mergeFeatureHeader({
263
+ ...headers,
264
+ ...(idempotencyKey ? { "idempotency-key": String(idempotencyKey) } : {}),
265
+ });
266
+ return fetchSseWithRetry(`${String(baseURL).replace(/\/+$/u, "")}/responses`, body, requestHeaders, signal, timeoutMs, {
267
+ maxAttempts,
268
+ maxResponseBytes,
269
+ consume: (response, consumeOptions) => parseNativeCompactionSse(response, {
270
+ signal: consumeOptions.requestSignal ?? signal,
271
+ maxResponseBytes,
272
+ }),
273
+ });
255
274
  }