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.
- package/README.md +116 -202
- package/cordis.patch.yml +3 -20
- package/lib/client.js +273 -146
- package/lib/compact-v2.js +218 -199
- package/lib/dsh-compat.js +227 -100
- package/lib/dsh-responses.js +445 -277
- package/lib/index.js +851 -757
- package/lib/json-store.js +50 -31
- package/lib/native-checkpoint.js +520 -194
- package/lib/responses-request.js +106 -121
- package/lib/responses-stream.js +972 -443
- package/lib/route.js +229 -355
- package/lib/service-mutex.js +73 -64
- package/lib/token-budget.js +176 -108
- package/lib/transport.js +277 -67
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/compact-v2.d.ts +104 -0
- package/lib/types/dsh-compat.d.ts +78 -0
- package/lib/types/dsh-responses.d.ts +82 -0
- package/lib/types/index.d.ts +83 -0
- package/lib/types/json-store.d.ts +10 -0
- package/lib/types/native-checkpoint.d.ts +213 -0
- package/lib/types/responses-request.d.ts +58 -0
- package/lib/types/responses-stream.d.ts +51 -0
- package/lib/types/route.d.ts +132 -0
- package/lib/types/service-mutex.d.ts +14 -0
- package/lib/types/token-budget.d.ts +50 -0
- package/lib/types/transport.d.ts +20 -0
- package/lib/types/web-run-output.d.ts +29 -0
- package/lib/types/web-search-alpha.d.ts +286 -0
- package/lib/types/web-search-capability.d.ts +26 -0
- package/lib/types/web-search-hosted.d.ts +246 -0
- package/lib/types/web-search-ref-store.d.ts +22 -0
- package/lib/web-run-output.js +167 -18
- package/lib/web-search-alpha.js +865 -163
- package/lib/web-search-capability.js +55 -65
- package/lib/web-search-hosted.js +210 -32
- package/lib/web-search-ref-store.js +63 -59
- package/package.json +79 -27
- package/ARCHITECTURE.md +0 -117
- package/CHANGELOG.md +0 -224
- package/README_EN.md +0 -277
- package/assets/dsh-lcx-codex-banner.jpg +0 -0
- package/lib/legacy-v3.js +0 -20
- package/lib/responses-replay.js +0 -68
- package/scripts/probe-alpha.mjs +0 -43
- package/scripts/validate-dsh-schema.mjs +0 -31
package/lib/transport.js
CHANGED
|
@@ -1,81 +1,291 @@
|
|
|
1
|
-
const DEFAULT_TIMEOUT_MS = 300_000
|
|
2
|
-
const DEFAULT_MAX_BYTES = 8 * 1024 * 1024
|
|
3
|
-
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
2
|
+
const DEFAULT_MAX_BYTES = 8 * 1024 * 1024;
|
|
3
|
+
const MAX_ERROR_BYTES = 512 * 1024;
|
|
4
|
+
function errorFacts(value) {
|
|
5
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
6
|
+
}
|
|
4
7
|
export function abortIfNeeded(signal) {
|
|
5
|
-
|
|
8
|
+
if (signal?.aborted)
|
|
9
|
+
throw (signal.reason ??
|
|
10
|
+
Object.assign(new Error("request aborted"), { code: "LCX_ABORTED" }));
|
|
11
|
+
}
|
|
12
|
+
function makeError(message, code, extra = {}) {
|
|
13
|
+
const error = new Error(message);
|
|
14
|
+
error.code = code;
|
|
15
|
+
Object.assign(error, extra);
|
|
16
|
+
return error;
|
|
17
|
+
}
|
|
18
|
+
function retryableStatus(status) {
|
|
19
|
+
return (status === 408 ||
|
|
20
|
+
status === 409 ||
|
|
21
|
+
status === 425 ||
|
|
22
|
+
status === 429 ||
|
|
23
|
+
(status >= 500 && status <= 599));
|
|
6
24
|
}
|
|
7
|
-
function makeError(message, code, extra = {}) { const error = new Error(message); error.code = code; Object.assign(error, extra); return error }
|
|
8
|
-
function retryableStatus(status) { return status === 408 || status === 409 || status === 425 || status === 429 || (status >= 500 && status <= 599) }
|
|
9
25
|
function retryAfterFromHeaders(headers) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
26
|
+
const rawMillis = headers?.get?.("retry-after-ms");
|
|
27
|
+
const millis = Number(rawMillis);
|
|
28
|
+
if (rawMillis !== null &&
|
|
29
|
+
rawMillis !== undefined &&
|
|
30
|
+
rawMillis !== "" &&
|
|
31
|
+
Number.isFinite(millis) &&
|
|
32
|
+
millis >= 0)
|
|
33
|
+
return Math.min(millis, 30_000);
|
|
34
|
+
const retryAfter = headers?.get?.("retry-after");
|
|
35
|
+
if (retryAfter) {
|
|
36
|
+
const seconds = Number(retryAfter);
|
|
37
|
+
if (Number.isFinite(seconds) && seconds >= 0)
|
|
38
|
+
return Math.min(seconds * 1000, 30_000);
|
|
39
|
+
const date = Date.parse(retryAfter);
|
|
40
|
+
if (!Number.isNaN(date))
|
|
41
|
+
return Math.min(Math.max(0, date - Date.now()), 30_000);
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
13
44
|
}
|
|
14
45
|
function delayFromHeaders(headers, attempt) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
46
|
+
const retryAfter = retryAfterFromHeaders(headers);
|
|
47
|
+
if (retryAfter !== undefined)
|
|
48
|
+
return retryAfter;
|
|
49
|
+
return Math.min(10_000, 500 * 2 ** Math.max(0, attempt - 1));
|
|
18
50
|
}
|
|
19
|
-
async function sleep(ms, signal) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
51
|
+
async function sleep(ms, signal) {
|
|
52
|
+
if (ms === undefined || ms <= 0)
|
|
53
|
+
return;
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
if (signal?.aborted)
|
|
56
|
+
return reject(signal.reason);
|
|
57
|
+
const timer = setTimeout(resolve, ms);
|
|
58
|
+
signal?.addEventListener("abort", () => {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
reject(signal.reason);
|
|
61
|
+
}, { once: true });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function combinedSignal(signal, timeoutMs) {
|
|
65
|
+
if (!(typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0))
|
|
66
|
+
return signal;
|
|
67
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
68
|
+
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
69
|
+
}
|
|
70
|
+
async function readLimited(response, maxBytes = DEFAULT_MAX_BYTES) {
|
|
71
|
+
if (!response.body)
|
|
72
|
+
return "";
|
|
73
|
+
const reader = response.body.getReader();
|
|
74
|
+
const decoder = new TextDecoder();
|
|
75
|
+
let bytes = 0;
|
|
76
|
+
let text = "";
|
|
27
77
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
78
|
+
while (true) {
|
|
79
|
+
const { done, value } = await reader.read();
|
|
80
|
+
if (done)
|
|
81
|
+
return text + decoder.decode();
|
|
82
|
+
bytes += value.byteLength;
|
|
83
|
+
if (bytes > maxBytes)
|
|
84
|
+
throw makeError(`response exceeds ${maxBytes} bytes`, "LCX_RESPONSE_TOO_LARGE", { status: response.status });
|
|
85
|
+
text += decoder.decode(value, { stream: true });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
try {
|
|
90
|
+
await reader.cancel();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Cleanup must not replace the read/size error.
|
|
94
|
+
}
|
|
95
|
+
reader.releaseLock();
|
|
45
96
|
}
|
|
46
|
-
}
|
|
47
|
-
throw last ?? makeError('request failed', 'LCX_REQUEST_FAILED')
|
|
48
97
|
}
|
|
49
|
-
|
|
98
|
+
export async function fetchJsonWithRetry(url, body, headers = {}, signal, timeoutMs = DEFAULT_TIMEOUT_MS, options = {}) {
|
|
99
|
+
const maxAttempts = Math.max(1, Math.min(6, Number(options.maxAttempts ?? 3)));
|
|
100
|
+
const maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_BYTES;
|
|
101
|
+
let last;
|
|
102
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
103
|
+
abortIfNeeded(signal);
|
|
104
|
+
try {
|
|
105
|
+
const requestSignal = combinedSignal(signal, timeoutMs);
|
|
106
|
+
const response = await fetch(url, {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: {
|
|
109
|
+
"content-type": "application/json",
|
|
110
|
+
accept: "application/json",
|
|
111
|
+
...headers,
|
|
112
|
+
},
|
|
113
|
+
body: JSON.stringify(body),
|
|
114
|
+
signal: requestSignal,
|
|
115
|
+
redirect: "error",
|
|
116
|
+
});
|
|
117
|
+
const text = await readLimited(response, response.ok ? maxResponseBytes : Math.min(maxResponseBytes, MAX_ERROR_BYTES));
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const retryable = retryableStatus(response.status);
|
|
120
|
+
const providerRetryAfterMs = retryAfterFromHeaders(response.headers);
|
|
121
|
+
const error = makeError(`HTTP ${response.status}`, retryable ? "LCX_HTTP_RETRYABLE" : "LCX_HTTP_ERROR", {
|
|
122
|
+
status: response.status,
|
|
123
|
+
retryable,
|
|
124
|
+
requestId: response.headers.get("x-request-id") ??
|
|
125
|
+
response.headers.get("request-id") ??
|
|
126
|
+
undefined,
|
|
127
|
+
...(providerRetryAfterMs === undefined
|
|
128
|
+
? {}
|
|
129
|
+
: { providerRetryAfterMs }),
|
|
130
|
+
});
|
|
131
|
+
if (!error.retryable || attempt >= maxAttempts)
|
|
132
|
+
throw error;
|
|
133
|
+
last = error;
|
|
134
|
+
await sleep(delayFromHeaders(response.headers, attempt), signal);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = text ? JSON.parse(text) : {};
|
|
140
|
+
}
|
|
141
|
+
catch (cause) {
|
|
142
|
+
throw makeError(`invalid JSON response from ${url}`, "LCX_INVALID_JSON", { status: response.status, cause });
|
|
143
|
+
}
|
|
144
|
+
return parsed;
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (signal?.aborted)
|
|
148
|
+
throw signal.reason ?? error;
|
|
149
|
+
const details = errorFacts(error);
|
|
150
|
+
const retryable = details.retryable === true ||
|
|
151
|
+
details.code === "LCX_HTTP_RETRYABLE" ||
|
|
152
|
+
error instanceof TypeError ||
|
|
153
|
+
[
|
|
154
|
+
"ECONNRESET",
|
|
155
|
+
"ECONNREFUSED",
|
|
156
|
+
"ETIMEDOUT",
|
|
157
|
+
"EAI_AGAIN",
|
|
158
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
159
|
+
].includes(details.code ?? "");
|
|
160
|
+
if (!retryable || attempt >= maxAttempts) {
|
|
161
|
+
if (attempt >= maxAttempts && retryable)
|
|
162
|
+
throw makeError(`request failed after ${maxAttempts} attempts`, "LCX_RETRY_EXHAUSTED", { cause: error, retryable: true });
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
last = error;
|
|
166
|
+
await sleep(Math.min(10_000, 500 * 2 ** (attempt - 1)), signal);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
throw last ?? makeError("request failed", "LCX_REQUEST_FAILED");
|
|
170
|
+
}
|
|
50
171
|
export async function fetchSseWithRetry(url, body, headers = {}, signal, timeoutMs = DEFAULT_TIMEOUT_MS, options = {}) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
172
|
+
const maxAttempts = Math.max(1, Math.min(6, Number(options.maxAttempts ?? 3)));
|
|
173
|
+
let last;
|
|
174
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
175
|
+
abortIfNeeded(signal);
|
|
176
|
+
try {
|
|
177
|
+
const requestSignal = combinedSignal(signal, timeoutMs);
|
|
178
|
+
const response = await fetch(url, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: {
|
|
181
|
+
"content-type": "application/json",
|
|
182
|
+
accept: "text/event-stream",
|
|
183
|
+
...headers,
|
|
184
|
+
},
|
|
185
|
+
body: JSON.stringify(body),
|
|
186
|
+
signal: requestSignal,
|
|
187
|
+
redirect: "error",
|
|
188
|
+
});
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
await readLimited(response, Math.min(options.maxResponseBytes ?? DEFAULT_MAX_BYTES, MAX_ERROR_BYTES));
|
|
191
|
+
const retryable = retryableStatus(response.status);
|
|
192
|
+
const providerRetryAfterMs = retryAfterFromHeaders(response.headers);
|
|
193
|
+
const error = makeError(`HTTP ${response.status}`, retryable ? "LCX_HTTP_RETRYABLE" : "LCX_HTTP_ERROR", {
|
|
194
|
+
status: response.status,
|
|
195
|
+
retryable,
|
|
196
|
+
requestId: response.headers.get("x-request-id") ??
|
|
197
|
+
response.headers.get("request-id") ??
|
|
198
|
+
undefined,
|
|
199
|
+
...(providerRetryAfterMs === undefined
|
|
200
|
+
? {}
|
|
201
|
+
: { providerRetryAfterMs }),
|
|
202
|
+
});
|
|
203
|
+
if (!retryable || attempt >= maxAttempts)
|
|
204
|
+
throw error;
|
|
205
|
+
last = error;
|
|
206
|
+
await sleep(delayFromHeaders(response.headers, attempt), signal);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (typeof options.consume === "function")
|
|
210
|
+
return await options.consume(response, { requestSignal });
|
|
211
|
+
return response;
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
if (signal?.aborted)
|
|
215
|
+
throw signal.reason ?? error;
|
|
216
|
+
const details = errorFacts(error);
|
|
217
|
+
const retryable = details.retryable === true ||
|
|
218
|
+
details.code === "LCX_HTTP_RETRYABLE" ||
|
|
219
|
+
error instanceof TypeError ||
|
|
220
|
+
[
|
|
221
|
+
"ECONNRESET",
|
|
222
|
+
"ECONNREFUSED",
|
|
223
|
+
"ETIMEDOUT",
|
|
224
|
+
"EAI_AGAIN",
|
|
225
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
226
|
+
].includes(details.code ?? "");
|
|
227
|
+
if (!retryable || attempt >= maxAttempts) {
|
|
228
|
+
if (attempt >= maxAttempts && retryable)
|
|
229
|
+
throw makeError(`request failed after ${maxAttempts} attempts`, "LCX_RETRY_EXHAUSTED", { cause: error, retryable: true });
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
last = error;
|
|
233
|
+
await sleep(Math.min(10_000, 500 * 2 ** (attempt - 1)), signal);
|
|
234
|
+
}
|
|
68
235
|
}
|
|
69
|
-
|
|
70
|
-
throw last ?? makeError('request failed', 'LCX_REQUEST_FAILED')
|
|
236
|
+
throw last ?? makeError("request failed", "LCX_REQUEST_FAILED");
|
|
71
237
|
}
|
|
72
|
-
|
|
73
238
|
export async function consumeSse(response, onEvent, options = {}) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
239
|
+
if (!response.body)
|
|
240
|
+
throw makeError("SSE response has no body", "LCX_INVALID_SSE");
|
|
241
|
+
const maxBytes = options.maxResponseBytes ?? DEFAULT_MAX_BYTES;
|
|
242
|
+
const reader = response.body.getReader();
|
|
243
|
+
const decoder = new TextDecoder();
|
|
244
|
+
let pending = "";
|
|
245
|
+
let dataLines = [];
|
|
246
|
+
let bytes = 0;
|
|
247
|
+
const dispatch = () => {
|
|
248
|
+
if (dataLines.length === 0)
|
|
249
|
+
return;
|
|
250
|
+
const data = dataLines.join("\n");
|
|
251
|
+
dataLines = [];
|
|
252
|
+
if (data === "[DONE]")
|
|
253
|
+
return;
|
|
254
|
+
let event;
|
|
255
|
+
try {
|
|
256
|
+
event = JSON.parse(data);
|
|
257
|
+
}
|
|
258
|
+
catch (cause) {
|
|
259
|
+
throw makeError("malformed SSE JSON", "LCX_INVALID_SSE", { cause });
|
|
260
|
+
}
|
|
261
|
+
onEvent(event);
|
|
262
|
+
};
|
|
263
|
+
try {
|
|
264
|
+
while (true) {
|
|
265
|
+
abortIfNeeded(options.signal);
|
|
266
|
+
const { done, value } = await reader.read();
|
|
267
|
+
if (done)
|
|
268
|
+
break;
|
|
269
|
+
bytes += value.byteLength;
|
|
270
|
+
if (bytes > maxBytes)
|
|
271
|
+
throw makeError(`SSE response exceeds ${maxBytes} bytes`, "LCX_RESPONSE_TOO_LARGE");
|
|
272
|
+
pending += decoder.decode(value, { stream: true });
|
|
273
|
+
let newline;
|
|
274
|
+
while ((newline = pending.indexOf("\n")) >= 0) {
|
|
275
|
+
const line = pending.slice(0, newline).replace(/\r$/u, "");
|
|
276
|
+
pending = pending.slice(newline + 1);
|
|
277
|
+
if (line === "")
|
|
278
|
+
dispatch();
|
|
279
|
+
else if (!line.startsWith(":") && line.startsWith("data:"))
|
|
280
|
+
dataLines.push(line.slice(5).replace(/^ /u, ""));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
pending += decoder.decode();
|
|
284
|
+
if (pending.startsWith("data:"))
|
|
285
|
+
dataLines.push(pending.slice(5).replace(/^ /u, ""));
|
|
286
|
+
dispatch();
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
await reader.cancel().catch(() => undefined);
|
|
290
|
+
}
|
|
81
291
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { buildCompactionResponsesBody } from "./responses-request.js";
|
|
2
|
+
type HeaderMap = Record<string, string>;
|
|
3
|
+
type CompactionItem = {
|
|
4
|
+
type: "compaction";
|
|
5
|
+
encrypted_content: string;
|
|
6
|
+
};
|
|
7
|
+
type FunctionCallItem = {
|
|
8
|
+
type: "function_call";
|
|
9
|
+
call_id: string;
|
|
10
|
+
};
|
|
11
|
+
type FunctionCallOutputItem = {
|
|
12
|
+
type: "function_call_output";
|
|
13
|
+
call_id: string;
|
|
14
|
+
};
|
|
15
|
+
type ValidatedOutputItem = CompactionItem | FunctionCallItem | FunctionCallOutputItem | {
|
|
16
|
+
type: string;
|
|
17
|
+
};
|
|
18
|
+
type CanonicalUsage = {
|
|
19
|
+
inputTokens: number;
|
|
20
|
+
outputTokens: number;
|
|
21
|
+
cacheReadTokens?: number;
|
|
22
|
+
cacheWriteTokens?: number;
|
|
23
|
+
reasoningTokens?: number;
|
|
24
|
+
};
|
|
25
|
+
type GenerationControls = {
|
|
26
|
+
reasoningEffort?: unknown;
|
|
27
|
+
temperature?: unknown;
|
|
28
|
+
maxTokens?: unknown;
|
|
29
|
+
};
|
|
30
|
+
type GenerationEnvelope = {
|
|
31
|
+
reasoning?: {
|
|
32
|
+
effort: string;
|
|
33
|
+
summary: "auto";
|
|
34
|
+
};
|
|
35
|
+
include?: string[];
|
|
36
|
+
temperature?: number;
|
|
37
|
+
max_output_tokens?: number;
|
|
38
|
+
};
|
|
39
|
+
type NativeCompactionBodyOptions = GenerationControls & {
|
|
40
|
+
model: string;
|
|
41
|
+
modelDescriptor?: Exclude<Parameters<typeof buildCompactionResponsesBody>[0]["model"], string>;
|
|
42
|
+
input: unknown[];
|
|
43
|
+
tools?: unknown;
|
|
44
|
+
promptCacheKey?: string;
|
|
45
|
+
promptCacheRetention?: string;
|
|
46
|
+
cacheRetention?: "none" | "short" | "long";
|
|
47
|
+
};
|
|
48
|
+
type NativeCompactionRequestOptions = NativeCompactionBodyOptions & {
|
|
49
|
+
baseURL: string;
|
|
50
|
+
idempotencyKey?: string;
|
|
51
|
+
headers?: HeaderMap;
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
timeoutMs?: number;
|
|
54
|
+
maxAttempts?: number;
|
|
55
|
+
maxResponseBytes?: number;
|
|
56
|
+
};
|
|
57
|
+
type SseParseOptions = {
|
|
58
|
+
signal?: AbortSignal;
|
|
59
|
+
maxResponseBytes?: number;
|
|
60
|
+
};
|
|
61
|
+
type NativeCompactionResult = {
|
|
62
|
+
object: unknown;
|
|
63
|
+
id?: string;
|
|
64
|
+
output: ValidatedOutputItem[];
|
|
65
|
+
compaction: CompactionItem;
|
|
66
|
+
usage?: CanonicalUsage;
|
|
67
|
+
};
|
|
68
|
+
export declare const REMOTE_COMPACTION_V2_FEATURE = "remote_compaction_v2";
|
|
69
|
+
/**
|
|
70
|
+
* @param {HeaderMap} [headers]
|
|
71
|
+
* @returns {HeaderMap}
|
|
72
|
+
*/
|
|
73
|
+
export declare function mergeFeatureHeader(headers?: HeaderMap): HeaderMap;
|
|
74
|
+
/**
|
|
75
|
+
* @param {GenerationControls} [controls]
|
|
76
|
+
* @returns {GenerationEnvelope}
|
|
77
|
+
*/
|
|
78
|
+
export declare function responsesGenerationEnvelope(controls?: GenerationControls): GenerationEnvelope;
|
|
79
|
+
/**
|
|
80
|
+
* @param {NativeCompactionBodyOptions} options
|
|
81
|
+
* @returns {NativeCompactionBody}
|
|
82
|
+
*/
|
|
83
|
+
export declare function buildNativeCompactionBody({ model, modelDescriptor, input, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, }: NativeCompactionBodyOptions): {
|
|
84
|
+
[x: string]: unknown;
|
|
85
|
+
} & {
|
|
86
|
+
model: string;
|
|
87
|
+
input: unknown[];
|
|
88
|
+
stream: boolean;
|
|
89
|
+
store: boolean;
|
|
90
|
+
tool_choice?: string;
|
|
91
|
+
parallel_tool_calls?: boolean;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Provider SSE events enter as unknown; response.completed remains authoritative.
|
|
95
|
+
* @param {Response} response
|
|
96
|
+
* @param {SseParseOptions} [options]
|
|
97
|
+
* @returns {Promise<NativeCompactionResult>}
|
|
98
|
+
*/
|
|
99
|
+
export declare function parseNativeCompactionSse(response: Response, options?: SseParseOptions): Promise<NativeCompactionResult>;
|
|
100
|
+
/**
|
|
101
|
+
* @param {NativeCompactionRequestOptions} options
|
|
102
|
+
*/
|
|
103
|
+
export declare function requestNativeCompaction({ baseURL, model, modelDescriptor, input, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, idempotencyKey, headers, signal, timeoutMs, maxAttempts, maxResponseBytes, }: NativeCompactionRequestOptions): Promise<NativeCompactionResult>;
|
|
104
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Session, type SessionStore } from "@deepseek-ai/dsh-session";
|
|
2
|
+
import type { ToolRuntime } from "@deepseek-ai/dsh-tools";
|
|
3
|
+
import { ServiceMutex } from "./service-mutex.js";
|
|
4
|
+
type CompatMethod = (this: object, agent: unknown, trigger: string, signal: AbortSignal) => Promise<unknown>;
|
|
5
|
+
type PrunerMethod = (...args: unknown[]) => unknown;
|
|
6
|
+
type MutableService = Record<PropertyKey, unknown>;
|
|
7
|
+
interface CompactionService extends MutableService {
|
|
8
|
+
compactIfNeeded: CompatMethod;
|
|
9
|
+
}
|
|
10
|
+
export interface CompactionPatchRecord {
|
|
11
|
+
compaction: CompactionService;
|
|
12
|
+
original: CompatMethod;
|
|
13
|
+
wrapper: CompatMethod;
|
|
14
|
+
mutex: ServiceMutex;
|
|
15
|
+
lifecycle: AbortController;
|
|
16
|
+
}
|
|
17
|
+
export type CompactionPatchRecords = Map<object, CompactionPatchRecord>;
|
|
18
|
+
export type CompactionPatchBehavior = (agent: unknown, trigger: string, signal: AbortSignal, callOriginal: (signal: AbortSignal) => Promise<unknown>) => Promise<unknown>;
|
|
19
|
+
interface PrunerService extends MutableService {
|
|
20
|
+
pruneSession: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface PrunerPatchRecord {
|
|
23
|
+
pruner: PrunerService;
|
|
24
|
+
original: unknown;
|
|
25
|
+
replacement: PrunerMethod;
|
|
26
|
+
}
|
|
27
|
+
interface ConfigService extends MutableService {
|
|
28
|
+
config: unknown;
|
|
29
|
+
}
|
|
30
|
+
export interface ConfigPatchRecord {
|
|
31
|
+
service: ConfigService;
|
|
32
|
+
original: unknown;
|
|
33
|
+
installed: unknown;
|
|
34
|
+
}
|
|
35
|
+
export declare function agentSessionId(agent: unknown): string;
|
|
36
|
+
export declare function agentUsesSession(agent: unknown, session: Session): boolean;
|
|
37
|
+
export declare function sessionFromAgent(agent: unknown): Session | undefined;
|
|
38
|
+
export declare function readAgentRouteState(agent: unknown): {
|
|
39
|
+
requestConfig: unknown;
|
|
40
|
+
options: unknown;
|
|
41
|
+
sessionId: string;
|
|
42
|
+
};
|
|
43
|
+
export declare function scopedToolRuntime(agent: unknown): Pick<ToolRuntime, "register"> | undefined;
|
|
44
|
+
export declare function tokenMeterTotal(value: unknown, session: Session): number | undefined;
|
|
45
|
+
export declare function sessionsService(ctx: unknown): Pick<SessionStore, "get"> | undefined;
|
|
46
|
+
export declare function sessionFor(ctx: unknown, sessionId: string): Session | undefined;
|
|
47
|
+
export declare function readWebSearchProvider(ctx: unknown): unknown;
|
|
48
|
+
export declare function writeWebSearchProvider(ctx: unknown, providerId: unknown): boolean;
|
|
49
|
+
export declare function contextService(ctx: unknown, name: string): unknown;
|
|
50
|
+
export declare function resolveContextService(ctx: unknown, name: string): unknown;
|
|
51
|
+
export declare function resolveScopedService(agent: unknown, name: string): unknown;
|
|
52
|
+
export declare function resolveAgentService(ctx: unknown, agent: unknown, name: string): unknown;
|
|
53
|
+
export declare function concreteService(value: unknown): unknown;
|
|
54
|
+
export declare function compactionPatchCandidate(value: unknown, records: ReadonlyMap<object, CompactionPatchRecord>): Pick<CompactionPatchRecord, "compaction" | "original"> | undefined;
|
|
55
|
+
export declare function installCompactionPatch(records: CompactionPatchRecords, candidate: Pick<CompactionPatchRecord, "compaction" | "original">, mutex: ServiceMutex, lifecycle: AbortController, behavior: CompactionPatchBehavior): boolean;
|
|
56
|
+
export declare function restoreCompactionPatches(records: Map<object, CompactionPatchRecord>, entries?: Iterable<CompactionPatchRecord>): void;
|
|
57
|
+
export declare function toolResultPrunerState(value: unknown): {
|
|
58
|
+
pruner: PrunerService | undefined;
|
|
59
|
+
original: unknown;
|
|
60
|
+
};
|
|
61
|
+
export declare function patchToolResultPruner(state: {
|
|
62
|
+
pruner: PrunerService | undefined;
|
|
63
|
+
original: unknown;
|
|
64
|
+
}, replacement: PrunerMethod): PrunerPatchRecord | undefined;
|
|
65
|
+
export declare function restoreToolResultPruner(record: PrunerPatchRecord | undefined): void;
|
|
66
|
+
export declare function compactionConfigState(service: unknown): {
|
|
67
|
+
service: ConfigService | undefined;
|
|
68
|
+
original: unknown;
|
|
69
|
+
};
|
|
70
|
+
export declare function patchCompactionConfig(state: {
|
|
71
|
+
service: ConfigService | undefined;
|
|
72
|
+
original: unknown;
|
|
73
|
+
}, createConfig: (originalConfig: unknown) => unknown): ConfigPatchRecord | undefined;
|
|
74
|
+
export declare function restoreCompactionConfig(record: ConfigPatchRecord | undefined): void;
|
|
75
|
+
export declare function patchVisibleWebSearchTimeout(agent: unknown, getTimeoutMs: () => number | undefined, patchedDefinitions: Map<MutableService, unknown>): void;
|
|
76
|
+
export declare function refreshVisibleWebSearchTimeouts(patchedDefinitions: ReadonlyMap<MutableService, unknown>, timeoutMs: number | undefined): void;
|
|
77
|
+
export declare function restoreVisibleWebSearchTimeouts(patchedDefinitions: Map<MutableService, unknown>): void;
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { requestImageHandleText, type Message } from "@deepseek-ai/dsh-llm";
|
|
2
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
import type { ResponseInputItem } from "openai/resources/responses/responses.js";
|
|
4
|
+
type ImageAttachmentRef = Parameters<typeof requestImageHandleText>[0];
|
|
5
|
+
import type { Model as PiModel, Tool as PiToolValue } from "@earendil-works/pi-ai";
|
|
6
|
+
declare const DEFAULT_MAX_REQUEST_IMAGE_BYTES: number;
|
|
7
|
+
declare const DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET: number;
|
|
8
|
+
declare const DEFAULT_REQUEST_IMAGE_MAX_BYTES: number;
|
|
9
|
+
export { DEFAULT_MAX_REQUEST_IMAGE_BYTES, DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET, DEFAULT_REQUEST_IMAGE_MAX_BYTES, };
|
|
10
|
+
type WireRecord = Record<string, unknown>;
|
|
11
|
+
type ImageSupport = "supported" | "unsupported" | "unknown";
|
|
12
|
+
type PiTool = PiToolValue;
|
|
13
|
+
type DshContext = Pick<Context, "attachments" | "llm" | "fs">;
|
|
14
|
+
type ImageOptions = {
|
|
15
|
+
imageSupport: ImageSupport;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
maxRequestImageBytes: number;
|
|
18
|
+
requestImagePixelBudget: number;
|
|
19
|
+
requestImageMaxBytes: number;
|
|
20
|
+
};
|
|
21
|
+
type SerializeOptions = Partial<ImageOptions> & {
|
|
22
|
+
route?: unknown;
|
|
23
|
+
model?: unknown;
|
|
24
|
+
responsesCompat?: unknown;
|
|
25
|
+
systemPrompt?: unknown;
|
|
26
|
+
includeSystemPrompt?: boolean;
|
|
27
|
+
onReplayDegrade?: unknown;
|
|
28
|
+
tools?: PiTool[];
|
|
29
|
+
};
|
|
30
|
+
type ReplayBlock = WireRecord & {
|
|
31
|
+
type: "text" | "reasoning" | "tool-call";
|
|
32
|
+
};
|
|
33
|
+
type ReplayResponse = WireRecord & {
|
|
34
|
+
kind: "pi-ai";
|
|
35
|
+
version: 2;
|
|
36
|
+
api: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
model: string;
|
|
39
|
+
stopReason: "stop" | "length" | "toolUse" | "error" | "aborted";
|
|
40
|
+
};
|
|
41
|
+
export declare function responseInputItems(value: unknown): ResponseInputItem[];
|
|
42
|
+
export declare function resolveModelImageSupport(ctx: DshContext | undefined, route: {
|
|
43
|
+
provider?: unknown;
|
|
44
|
+
model?: unknown;
|
|
45
|
+
}, signal?: AbortSignal): Promise<ImageSupport>;
|
|
46
|
+
export declare function readDshPiReplayState(value: unknown): {
|
|
47
|
+
response: ReplayResponse;
|
|
48
|
+
blocks: ReplayBlock[];
|
|
49
|
+
};
|
|
50
|
+
export declare function resolvePiResponsesModel(options: {
|
|
51
|
+
imageSupport: unknown;
|
|
52
|
+
route?: unknown;
|
|
53
|
+
model?: unknown;
|
|
54
|
+
responsesCompat?: unknown;
|
|
55
|
+
}): {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
api: string;
|
|
59
|
+
provider: string;
|
|
60
|
+
baseUrl: string;
|
|
61
|
+
reasoning: boolean;
|
|
62
|
+
input: any[];
|
|
63
|
+
cost: {};
|
|
64
|
+
contextWindow: number;
|
|
65
|
+
maxTokens: number;
|
|
66
|
+
compat?: {
|
|
67
|
+
[x: string]: unknown;
|
|
68
|
+
} | undefined;
|
|
69
|
+
};
|
|
70
|
+
export declare function serializeDshMessages(messages: readonly Message[], ctx: DshContext | undefined, options?: SerializeOptions): Promise<{
|
|
71
|
+
input: import("openai/resources/responses/responses.js").ResponseInput;
|
|
72
|
+
imageMap: Map<string, import("@deepseek-ai/dsh-attachment").ImageAttachmentRef>;
|
|
73
|
+
tools: import("openai/resources/responses/responses.js").Tool[] | undefined;
|
|
74
|
+
model: PiModel<"openai-responses">;
|
|
75
|
+
grammarToolInputProperties: ReadonlyMap<string, string>;
|
|
76
|
+
deferredToolsMode: string | undefined;
|
|
77
|
+
}>;
|
|
78
|
+
export declare function responsesTools(tools: readonly PiTool[] | undefined): any[] | undefined;
|
|
79
|
+
export declare function persistNativeImageReferences(output: readonly unknown[], imageMap: ReadonlyMap<string, ImageAttachmentRef>): unknown[];
|
|
80
|
+
export declare function hydrateNativeImageReferences(output: unknown, ctx: DshContext | undefined, options?: Partial<ImageOptions> & {
|
|
81
|
+
imageMap?: unknown;
|
|
82
|
+
}): Promise<unknown[]>;
|