dsh-lcx-codex 0.4.3 → 0.4.4-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/abort-error.js +47 -0
- package/lib/client.js +97 -98
- package/lib/dsh-responses.js +70 -33
- package/lib/index.js +27 -11
- package/lib/invocation-policy-scope.js +4 -8
- package/lib/native-checkpoint.js +42 -3
- package/lib/pi-responses-runtime.js +251 -97
- package/lib/responses-request.js +2 -2
- package/lib/responses-stream.js +35 -8
- package/lib/search-usage.js +5 -13
- package/lib/service-mutex.js +4 -8
- package/lib/transport.js +6 -6
- package/package.json +28 -27
package/lib/responses-request.js
CHANGED
|
@@ -66,7 +66,7 @@ export function responsesGenerationEnvelope({ model = "unknown", reasoningEffort
|
|
|
66
66
|
return result;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
* Build the shared LCX-owned request envelope while retaining Pi 0.
|
|
69
|
+
* Build the shared LCX-owned request envelope while retaining Pi 0.86.0 Responses semantics.
|
|
70
70
|
* Production LCX ordinary/compact/replay construction places the DSH system prompt in canonical input.
|
|
71
71
|
* @param {BuildResponsesBodyOptions} options
|
|
72
72
|
*/
|
|
@@ -84,7 +84,7 @@ export function buildResponsesBody({ model, input, tools, sessionId, promptCache
|
|
|
84
84
|
const longRetention = retention === "long" && compat.supportsExplicitPromptCacheMode !== true
|
|
85
85
|
? promptCacheRetention ?? (compat.supportsLongCacheRetention === true ? "24h" : undefined)
|
|
86
86
|
: undefined;
|
|
87
|
-
// Pi 0.
|
|
87
|
+
// Pi 0.86.0 uses explicit 30m only for long retention; short is implicit.
|
|
88
88
|
const currentCache = retention === "long" && compat.supportsLongCacheRetention === true && compat.supportsExplicitPromptCacheMode === true;
|
|
89
89
|
const explicitCache = retention === "none" && compat.supportsExplicitPromptCacheMode === true;
|
|
90
90
|
const promptCacheOptions = currentCache
|
package/lib/responses-stream.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { createAssistantMessageEventStream, processResponsesStream, } from "./pi-responses-runtime.js";
|
|
3
|
-
import {
|
|
3
|
+
import { abortError } from "./abort-error.js";
|
|
4
|
+
import { IMAGE_OFFLOAD_REQUIRED_CODE, ToolCallId } from "@deepseek-ai/dsh-llm";
|
|
4
5
|
import { fetchSseWithRetry } from "./transport.js";
|
|
5
6
|
import { createGrokNativeReplayEnvelope, grokPendingSourcesStart, sanitizeGrokVisibleText, } from "./grok-native-search.js";
|
|
6
7
|
function emptyUsage() {
|
|
@@ -159,7 +160,35 @@ export function managedFailure(error, signal) {
|
|
|
159
160
|
};
|
|
160
161
|
}
|
|
161
162
|
/** @param {unknown} error @param {AbortSignal} [signal] */
|
|
163
|
+
/**
|
|
164
|
+
* The host image-offload contract, when this failure carries it.
|
|
165
|
+
*
|
|
166
|
+
* `IMAGE_OFFLOAD_REQUIRED` is not an LCX failure class: it is a request the
|
|
167
|
+
* route makes of DSH's durable image-offload owner, which matches on the exact
|
|
168
|
+
* code and `offloadImages` count before recording an `image/offload` decision
|
|
169
|
+
* and retrying. Normalizing it into the closed LCX taxonomy would drop both
|
|
170
|
+
* fields and turn a recoverable step into a terminal turn failure.
|
|
171
|
+
* @param {unknown} error
|
|
172
|
+
* @returns {LlmFailure | undefined}
|
|
173
|
+
*/
|
|
174
|
+
function imageOffloadFailure(error) {
|
|
175
|
+
if (!isObject(error))
|
|
176
|
+
return undefined;
|
|
177
|
+
const source = isObject(error.failure) ? error.failure : error;
|
|
178
|
+
if (source.code !== IMAGE_OFFLOAD_REQUIRED_CODE)
|
|
179
|
+
return undefined;
|
|
180
|
+
const offloadImages = source.offloadImages;
|
|
181
|
+
if (!Number.isSafeInteger(offloadImages) || offloadImages <= 0)
|
|
182
|
+
return undefined;
|
|
183
|
+
const message = typeof source.message === "string" && source.message.length > 0
|
|
184
|
+
? source.message
|
|
185
|
+
: "Request images exceed the route budget";
|
|
186
|
+
return { message, code: IMAGE_OFFLOAD_REQUIRED_CODE, offloadImages: offloadImages };
|
|
187
|
+
}
|
|
162
188
|
export function managedFailureChunk(error, signal) {
|
|
189
|
+
const offload = imageOffloadFailure(error);
|
|
190
|
+
if (offload !== undefined)
|
|
191
|
+
return { type: "finish", reason: { kind: "error", failure: offload } };
|
|
163
192
|
const managed = managedFailure(error, signal);
|
|
164
193
|
const failure = {
|
|
165
194
|
message: managed.message,
|
|
@@ -180,9 +209,9 @@ async function readWithSignal(reader, signal) {
|
|
|
180
209
|
if (!signal)
|
|
181
210
|
return reader.read();
|
|
182
211
|
if (signal.aborted)
|
|
183
|
-
throw signal
|
|
212
|
+
throw abortError(signal);
|
|
184
213
|
return new Promise((resolve, reject) => {
|
|
185
|
-
const onAbort = () => reject(signal
|
|
214
|
+
const onAbort = () => reject(abortError(signal));
|
|
186
215
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
187
216
|
reader.read().then(resolve, reject).finally(() => {
|
|
188
217
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -285,8 +314,7 @@ async function* responseEvents(response, options = {}) {
|
|
|
285
314
|
try {
|
|
286
315
|
while (true) {
|
|
287
316
|
if (options.signal?.aborted)
|
|
288
|
-
throw (options.signal
|
|
289
|
-
Object.assign(new Error("request aborted"), { code: "LCX_ABORTED" }));
|
|
317
|
+
throw abortError(options.signal);
|
|
290
318
|
const { done, value } = await readWithSignal(reader, options.signal);
|
|
291
319
|
if (done)
|
|
292
320
|
break;
|
|
@@ -1312,8 +1340,7 @@ export async function* streamResponsesRequest({ baseURL, provider, model, piMode
|
|
|
1312
1340
|
wireMeta.responseModel.length > 0)
|
|
1313
1341
|
output.responseModel = wireMeta.responseModel;
|
|
1314
1342
|
if (signal?.aborted)
|
|
1315
|
-
throw (signal
|
|
1316
|
-
Object.assign(new Error("request aborted"), { code: "LCX_ABORTED" }));
|
|
1343
|
+
throw abortError(signal);
|
|
1317
1344
|
if (output.stopReason === "pending")
|
|
1318
1345
|
throw Object.assign(new Error("Responses stream ended without a stop reason"), { code: "LCX_INVALID_SSE" });
|
|
1319
1346
|
if (output.stopReason === "aborted" || output.stopReason === "error")
|
|
@@ -1344,7 +1371,7 @@ export async function* streamResponsesRequest({ baseURL, provider, model, piMode
|
|
|
1344
1371
|
while (true) {
|
|
1345
1372
|
const result = await chunks.next();
|
|
1346
1373
|
if (watchdog.signal.aborted)
|
|
1347
|
-
throw watchdog.signal
|
|
1374
|
+
throw abortError(watchdog.signal);
|
|
1348
1375
|
if (result.done) {
|
|
1349
1376
|
exhausted = true;
|
|
1350
1377
|
watchdog.disarm();
|
package/lib/search-usage.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { SessionSeq } from '@deepseek-ai/dsh-session';
|
|
3
2
|
import { addUsage, aggregateContextOf, auxiliaryUsageOf, isSearchTool, zeroBuckets } from './search-accounting.js';
|
|
4
3
|
const n = z.number().int().nonnegative();
|
|
5
4
|
const schema = z.object({ auxiliary: z.object({ uncachedInputTokens: n, outputTokens: n, cacheReadTokens: n, cacheWriteTokens: n }).strict(), aggregateContext: z.boolean() }).strict();
|
|
@@ -26,7 +25,7 @@ export const searchUsageProjection = {
|
|
|
26
25
|
};
|
|
27
26
|
const installed = new WeakMap();
|
|
28
27
|
/** Own a reversible adapter on the public measure method, never a DSH file or private fold. */
|
|
29
|
-
export function installSearchMeasurement(meter) {
|
|
28
|
+
export function installSearchMeasurement(meter, projections) {
|
|
30
29
|
const existing = installed.get(meter);
|
|
31
30
|
if (existing) {
|
|
32
31
|
existing.refs++;
|
|
@@ -37,17 +36,10 @@ export function installSearchMeasurement(meter) {
|
|
|
37
36
|
} };
|
|
38
37
|
}
|
|
39
38
|
const original = meter.measure, descriptor = Object.getOwnPropertyDescriptor(meter, 'measure');
|
|
40
|
-
const cursors = new WeakMap();
|
|
41
39
|
function measure(session, header) {
|
|
42
40
|
const value = original.call(this, session, header);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const e = session.eventAt(SessionSeq(state.seq++));
|
|
46
|
-
if (e?.type === 'assistant/message')
|
|
47
|
-
state.aggregate = aggregateContextOf(e) ?? false;
|
|
48
|
-
}
|
|
49
|
-
cursors.set(session, state);
|
|
50
|
-
if (!state.aggregate || value.baseline.kind !== 'usage')
|
|
41
|
+
const state = projections.stateOf(session, 'lcxSearchUsage');
|
|
42
|
+
if (!state?.aggregateContext || value.baseline.kind !== 'usage')
|
|
51
43
|
return value;
|
|
52
44
|
// The official measure already prices retained images/files and surface replacements.
|
|
53
45
|
// Only discard its unsuitable aggregate anchor; keep its current surface and node prices.
|
|
@@ -80,7 +72,7 @@ function release(meter) {
|
|
|
80
72
|
}
|
|
81
73
|
export function installSearchUsage(ctx) {
|
|
82
74
|
ctx.inject(['sessionProjections'], c => { c.sessionProjections.register(searchUsageProjection); });
|
|
83
|
-
ctx.inject(['tokenMeter'], c => {
|
|
84
|
-
c.effect(() => installSearchMeasurement(c.tokenMeter), 'lcx search context measurement');
|
|
75
|
+
ctx.inject(['tokenMeter', 'sessionProjections'], c => {
|
|
76
|
+
c.effect(() => installSearchMeasurement(c.tokenMeter, c.sessionProjections), 'lcx search context measurement');
|
|
85
77
|
});
|
|
86
78
|
}
|
package/lib/service-mutex.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
if (signal?.reason instanceof Error)
|
|
3
|
-
return signal.reason;
|
|
4
|
-
return new DOMException("The operation was aborted", "AbortError");
|
|
5
|
-
}
|
|
1
|
+
import { abortError } from "./abort-error.js";
|
|
6
2
|
export class ServiceMutex {
|
|
7
3
|
locked = false;
|
|
8
4
|
closed = false;
|
|
@@ -14,7 +10,7 @@ export class ServiceMutex {
|
|
|
14
10
|
if (this.closed)
|
|
15
11
|
return Promise.reject(this.closeReason ?? new Error("service mutex closed"));
|
|
16
12
|
if (signal?.aborted)
|
|
17
|
-
return Promise.reject(
|
|
13
|
+
return Promise.reject(abortError(signal));
|
|
18
14
|
if (!this.locked) {
|
|
19
15
|
this.locked = true;
|
|
20
16
|
return Promise.resolve(() => this.release());
|
|
@@ -27,7 +23,7 @@ export class ServiceMutex {
|
|
|
27
23
|
if (index >= 0)
|
|
28
24
|
this.queue.splice(index, 1);
|
|
29
25
|
signal.removeEventListener("abort", onAbort);
|
|
30
|
-
reject(
|
|
26
|
+
reject(abortError(signal));
|
|
31
27
|
};
|
|
32
28
|
waiter.onAbort = onAbort;
|
|
33
29
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
@@ -43,7 +39,7 @@ export class ServiceMutex {
|
|
|
43
39
|
if (waiter.signal && waiter.onAbort)
|
|
44
40
|
waiter.signal.removeEventListener("abort", waiter.onAbort);
|
|
45
41
|
if (waiter.signal?.aborted) {
|
|
46
|
-
waiter.reject(
|
|
42
|
+
waiter.reject(abortError(waiter.signal));
|
|
47
43
|
continue;
|
|
48
44
|
}
|
|
49
45
|
waiter.resolve(() => this.release());
|
package/lib/transport.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { abortError } from "./abort-error.js";
|
|
1
2
|
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
2
3
|
const DEFAULT_MAX_BYTES = 8 * 1024 * 1024;
|
|
3
4
|
const MAX_ERROR_BYTES = 512 * 1024;
|
|
@@ -6,8 +7,7 @@ function errorFacts(value) {
|
|
|
6
7
|
}
|
|
7
8
|
export function abortIfNeeded(signal) {
|
|
8
9
|
if (signal?.aborted)
|
|
9
|
-
throw (signal
|
|
10
|
-
Object.assign(new Error("request aborted"), { code: "LCX_ABORTED" }));
|
|
10
|
+
throw abortError(signal);
|
|
11
11
|
}
|
|
12
12
|
function makeError(message, code, extra = {}) {
|
|
13
13
|
const error = new Error(message);
|
|
@@ -63,11 +63,11 @@ async function sleep(ms, signal) {
|
|
|
63
63
|
return;
|
|
64
64
|
await new Promise((resolve, reject) => {
|
|
65
65
|
if (signal?.aborted)
|
|
66
|
-
return reject(signal
|
|
66
|
+
return reject(abortError(signal));
|
|
67
67
|
const onAbort = () => {
|
|
68
68
|
clearTimeout(timer);
|
|
69
69
|
signal?.removeEventListener("abort", onAbort);
|
|
70
|
-
reject(signal
|
|
70
|
+
reject(abortError(signal));
|
|
71
71
|
};
|
|
72
72
|
const timer = setTimeout(() => {
|
|
73
73
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -161,7 +161,7 @@ export async function fetchJsonWithRetry(url, body, headers = {}, signal, timeou
|
|
|
161
161
|
}
|
|
162
162
|
catch (error) {
|
|
163
163
|
if (signal?.aborted)
|
|
164
|
-
throw signal
|
|
164
|
+
throw abortError(signal, error);
|
|
165
165
|
const details = errorFacts(error);
|
|
166
166
|
const retryable = details.retryable === true ||
|
|
167
167
|
details.code === "LCX_HTTP_RETRYABLE" ||
|
|
@@ -231,7 +231,7 @@ export async function fetchSseWithRetry(url, body, headers = {}, signal, timeout
|
|
|
231
231
|
}
|
|
232
232
|
catch (error) {
|
|
233
233
|
if (signal?.aborted)
|
|
234
|
-
throw signal
|
|
234
|
+
throw abortError(signal, error);
|
|
235
235
|
const details = errorFacts(error);
|
|
236
236
|
const retryable = details.retryable === true ||
|
|
237
237
|
details.code === "LCX_HTTP_RETRYABLE" ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-lcx-codex",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4-pre.1",
|
|
4
4
|
"description": "Model-scoped DSH plugin: GPT Responses lifecycle, Native V2 compaction and Hosted/Alpha Search; Grok native Web/X Search",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -56,13 +56,13 @@
|
|
|
56
56
|
"inject": [
|
|
57
57
|
"@deepseek-ai/dsh-client-ui-chat",
|
|
58
58
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
59
|
-
"@deepseek-ai/dsh-client-ui-
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager"
|
|
60
60
|
]
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@deepseek-ai/dsh": "0.1.
|
|
65
|
-
"@earendil-works/pi-ai": "0.
|
|
64
|
+
"@deepseek-ai/dsh": "0.1.6-alpha.2",
|
|
65
|
+
"@earendil-works/pi-ai": "0.86.0",
|
|
66
66
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
67
67
|
"@types/node": "^22.20.0",
|
|
68
68
|
"@types/react": "~18.3.1",
|
|
@@ -72,27 +72,27 @@
|
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
75
|
-
"@deepseek-ai/dsh-agent": ">=0.1.
|
|
76
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.
|
|
77
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.
|
|
78
|
-
"@deepseek-ai/dsh-client-modules": ">=0.1.
|
|
79
|
-
"@deepseek-ai/dsh-client-store": ">=0.1.
|
|
80
|
-
"@deepseek-ai/dsh-client-ui-chat": ">=0.1.
|
|
81
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.
|
|
82
|
-
"@deepseek-ai/dsh-client-ui-
|
|
83
|
-
"@deepseek-ai/dsh-compaction": ">=0.1.
|
|
84
|
-
"@deepseek-ai/dsh-credentials": ">=0.1.
|
|
85
|
-
"@deepseek-ai/dsh-fs": ">=0.1.
|
|
86
|
-
"@deepseek-ai/dsh-llm": ">=0.1.
|
|
87
|
-
"@deepseek-ai/dsh-session": ">=0.1.
|
|
88
|
-
"@deepseek-ai/dsh-settings": ">=0.1.
|
|
89
|
-
"@deepseek-ai/dsh-tool-web": ">=0.1.
|
|
90
|
-
"@deepseek-ai/dsh-tools": ">=0.1.
|
|
91
|
-
"@deepseek-ai/dsh-web": ">=0.1.
|
|
75
|
+
"@deepseek-ai/dsh-agent": ">=0.1.6-alpha.2 <0.1.7",
|
|
76
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.6-alpha.2 <0.1.7",
|
|
77
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.6-alpha.2 <0.1.7",
|
|
78
|
+
"@deepseek-ai/dsh-client-modules": ">=0.1.6-alpha.2 <0.1.7",
|
|
79
|
+
"@deepseek-ai/dsh-client-store": ">=0.1.6-alpha.2 <0.1.7",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-chat": ">=0.1.6-alpha.2 <0.1.7",
|
|
81
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.6-alpha.2 <0.1.7",
|
|
82
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": ">=0.1.6-alpha.2 <0.1.7",
|
|
83
|
+
"@deepseek-ai/dsh-compaction": ">=0.1.6-alpha.2 <0.1.7",
|
|
84
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.6-alpha.2 <0.1.7",
|
|
85
|
+
"@deepseek-ai/dsh-fs": ">=0.1.6-alpha.2 <0.1.7",
|
|
86
|
+
"@deepseek-ai/dsh-llm": ">=0.1.6-alpha.2 <0.1.7",
|
|
87
|
+
"@deepseek-ai/dsh-session": ">=0.1.6-alpha.2 <0.1.7",
|
|
88
|
+
"@deepseek-ai/dsh-settings": ">=0.1.6-alpha.2 <0.1.7",
|
|
89
|
+
"@deepseek-ai/dsh-tool-web": ">=0.1.6-alpha.2 <0.1.7",
|
|
90
|
+
"@deepseek-ai/dsh-tools": ">=0.1.6-alpha.2 <0.1.7",
|
|
91
|
+
"@deepseek-ai/dsh-web": ">=0.1.6-alpha.2 <0.1.7",
|
|
92
92
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
93
93
|
"react": "^18.2.0",
|
|
94
|
-
"@deepseek-ai/dsh-token-meter": ">=0.1.
|
|
95
|
-
"@deepseek-ai/dsh-session-projection": ">=0.1.
|
|
94
|
+
"@deepseek-ai/dsh-token-meter": ">=0.1.6-alpha.2 <0.1.7",
|
|
95
|
+
"@deepseek-ai/dsh-session-projection": ">=0.1.6-alpha.2 <0.1.7",
|
|
96
96
|
"zod": "^4.5.4"
|
|
97
97
|
},
|
|
98
98
|
"peerDependenciesMeta": {
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"@deepseek-ai/dsh-client-ui-conversation": {
|
|
118
118
|
"optional": true
|
|
119
119
|
},
|
|
120
|
-
"@deepseek-ai/dsh-client-ui-
|
|
120
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": {
|
|
121
121
|
"optional": true
|
|
122
122
|
},
|
|
123
123
|
"@deepseek-ai/dsh-compaction": {
|
|
@@ -166,8 +166,9 @@
|
|
|
166
166
|
},
|
|
167
167
|
"license": "MIT",
|
|
168
168
|
"lcxCompatibility": {
|
|
169
|
-
"dshInstallRange": ">=0.1.
|
|
170
|
-
"verifiedDsh": "0.1.
|
|
171
|
-
"verifiedHostPi": "0.85.1"
|
|
169
|
+
"dshInstallRange": ">=0.1.6-alpha.2 <0.1.7",
|
|
170
|
+
"verifiedDsh": "0.1.6-alpha.2",
|
|
171
|
+
"verifiedHostPi": "0.85.1",
|
|
172
|
+
"verifiedPluginPi": "0.86.0"
|
|
172
173
|
}
|
|
173
174
|
}
|