@artenx/dshb 0.1.15 → 0.1.17
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 +3 -1
- package/lib/auth/gate.d.ts +1 -1
- package/lib/auth/gate.js +3 -1
- package/lib/auth/gate.js.map +1 -1
- package/lib/auth/startup.js +2 -2
- package/lib/auth/startup.js.map +1 -1
- package/lib/auth/webserver.d.ts +1 -1
- package/lib/auth/webserver.js.map +1 -1
- package/lib/client.js +1 -1
- package/lib/client.js.map +1 -1
- package/lib/core/index.js +1 -1
- package/lib/core/workspace-instruction-context.d.ts +516 -29
- package/lib/core/workspace-instruction-context.js +1 -1
- package/lib/{workspace-instruction-context-DzHFTN87.js → workspace-instruction-context-DytAmaPY.js} +822 -51
- package/lib/workspace-instruction-context-DytAmaPY.js.map +1 -0
- package/package.json +35 -36
- package/lib/workspace-instruction-context-DzHFTN87.js.map +0 -1
package/lib/{workspace-instruction-context-DzHFTN87.js → workspace-instruction-context-DytAmaPY.js}
RENAMED
|
@@ -51,7 +51,7 @@ const REMOTE_METHOD_DESCRIPTOR = "@deepseek-ai/dsh-typert-protocol/remote-method
|
|
|
51
51
|
* a Host composition to read it.
|
|
52
52
|
* @param service - owning Service instance, normally `this`.
|
|
53
53
|
* @param serviceKey - exact Cordis service key.
|
|
54
|
-
* @param options - optional
|
|
54
|
+
* @param options - optional wire namespace.
|
|
55
55
|
* @returns a frozen, inspectable binding with no compiler-injected metadata.
|
|
56
56
|
*/
|
|
57
57
|
function bindTypertRemote(service, serviceKey, options = {}) {
|
|
@@ -59,7 +59,7 @@ function bindTypertRemote(service, serviceKey, options = {}) {
|
|
|
59
59
|
const namespace = options.namespace ?? serviceKey;
|
|
60
60
|
validateName("namespace", namespace);
|
|
61
61
|
const ctx = Reflect.get(service, "ctx");
|
|
62
|
-
if (ctx
|
|
62
|
+
if (Context.is(ctx)) provideInvocationAccessor(ctx);
|
|
63
63
|
return Object.freeze({
|
|
64
64
|
service,
|
|
65
65
|
serviceKey,
|
|
@@ -74,7 +74,7 @@ var TypertRemoteService = class extends Service {
|
|
|
74
74
|
* Register the Service and bind the same key to Typert Gateway.
|
|
75
75
|
* @param ctx - owning Cordis Context.
|
|
76
76
|
* @param serviceKey - exact Cordis service key and default wire namespace.
|
|
77
|
-
* @param options - optional
|
|
77
|
+
* @param options - optional wire namespace.
|
|
78
78
|
*/
|
|
79
79
|
constructor(ctx, serviceKey, options = {}) {
|
|
80
80
|
super(ctx, serviceKey);
|
|
@@ -94,21 +94,42 @@ function provideInvocationAccessor(ctx) {
|
|
|
94
94
|
function Remote(methodExportOrOptions, context) {
|
|
95
95
|
if (typeof methodExportOrOptions === "string") {
|
|
96
96
|
validateName("Remote export name", methodExportOrOptions);
|
|
97
|
-
return remoteDecorator({ kind: "direct" },
|
|
98
|
-
}
|
|
99
|
-
if (typeof methodExportOrOptions === "object") {
|
|
100
|
-
if (remoteOptionMode(methodExportOrOptions) !== "stream" || Reflect.ownKeys(methodExportOrOptions).length !== 1) throw new TypeError("typert-protocol: Remote options must contain exactly mode: \"stream\"");
|
|
101
|
-
return remoteDecorator({ kind: "direct" }, "stream");
|
|
97
|
+
return remoteDecorator({ kind: "direct" }, { exportName: methodExportOrOptions });
|
|
102
98
|
}
|
|
99
|
+
if (typeof methodExportOrOptions === "object") return remoteDecorator({ kind: "direct" }, markerOptions(methodExportOrOptions, REMOTE_OPTION_KEYS, "Remote options require name, mode: \"stream\", or resources"));
|
|
103
100
|
if (context === void 0) throw new TypeError("typert-protocol: Remote decorator context is missing");
|
|
104
101
|
addMarkerInitializer(context, { kind: "direct" });
|
|
105
102
|
}
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
const REMOTE_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
104
|
+
"name",
|
|
105
|
+
"mode",
|
|
106
|
+
"resources"
|
|
107
|
+
]);
|
|
108
|
+
/** Validate one decorator options object against its accepted keys and select the marker fields. */
|
|
109
|
+
function markerOptions(options, accepted, requirement) {
|
|
110
|
+
const keys = Reflect.ownKeys(options);
|
|
111
|
+
if (keys.length === 0 || keys.some((key) => typeof key !== "string" || !accepted.has(key)) || Object.hasOwn(options, "mode") && options.mode !== "stream") throw new TypeError(`typert-protocol: ${requirement}`);
|
|
112
|
+
const { mode, name, resources } = options;
|
|
113
|
+
if (name !== void 0) validateName("Remote export name", name);
|
|
114
|
+
return {
|
|
115
|
+
...mode === void 0 ? {} : { mode },
|
|
116
|
+
...name === void 0 ? {} : { exportName: name },
|
|
117
|
+
...resources === void 0 ? {} : { resources: resourceReaders(resources) }
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** Freeze declared readers into the marker record; a misdeclared reader fails at decoration. */
|
|
121
|
+
function resourceReaders(resources) {
|
|
122
|
+
const readers = {};
|
|
123
|
+
for (const [kind, reader] of Object.entries(resources)) {
|
|
124
|
+
if (typeof reader !== "function") throw new TypeError(`typert-protocol: Remote resource reader "${kind}" must be a function`);
|
|
125
|
+
readers[kind] = reader;
|
|
126
|
+
}
|
|
127
|
+
if (Object.keys(readers).length === 0) throw new TypeError("typert-protocol: Remote resources require at least one reader");
|
|
128
|
+
return Object.freeze(readers);
|
|
108
129
|
}
|
|
109
|
-
function remoteDecorator(invocation,
|
|
130
|
+
function remoteDecorator(invocation, options = {}) {
|
|
110
131
|
return function(_method, context) {
|
|
111
|
-
addMarkerInitializer(context, invocation,
|
|
132
|
+
addMarkerInitializer(context, invocation, options);
|
|
112
133
|
};
|
|
113
134
|
}
|
|
114
135
|
function readRemoteMethodDescriptor(prototype) {
|
|
@@ -122,26 +143,27 @@ function readRemoteMethodDescriptor(prototype) {
|
|
|
122
143
|
if (!Array.isArray(methods)) throw new TypeError("typert-protocol: Remote method descriptor methods must be an array");
|
|
123
144
|
return descriptor;
|
|
124
145
|
}
|
|
125
|
-
function addMarkerInitializer(context, invocation,
|
|
146
|
+
function addMarkerInitializer(context, invocation, options = {}) {
|
|
126
147
|
if (context.private || context.static || typeof context.name !== "string") throw new TypeError("typert-protocol: Remote decorators require a public instance method with a string name");
|
|
127
148
|
const method = context.name;
|
|
128
149
|
context.addInitializer(function() {
|
|
129
150
|
const prototype = Object.getPrototypeOf(this);
|
|
130
151
|
if (prototype === null) throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`);
|
|
131
|
-
mark(prototype, method, invocation,
|
|
152
|
+
mark(prototype, method, invocation, options);
|
|
132
153
|
});
|
|
133
154
|
}
|
|
134
|
-
function mark(prototype, method, invocation, mode, exportName) {
|
|
155
|
+
function mark(prototype, method, invocation, { mode, exportName, resources }) {
|
|
135
156
|
const descriptor = readRemoteMethodDescriptor(prototype);
|
|
136
157
|
const marker = Object.freeze({
|
|
137
158
|
method,
|
|
138
159
|
...exportName === void 0 || exportName === method ? {} : { exportName },
|
|
139
160
|
...mode === void 0 ? {} : { mode },
|
|
140
|
-
invocation: Object.freeze(invocation)
|
|
161
|
+
invocation: Object.freeze(invocation),
|
|
162
|
+
...resources === void 0 ? {} : { resources }
|
|
141
163
|
});
|
|
142
164
|
const current = descriptor?.methods.find((candidate) => candidate.method === method);
|
|
143
165
|
if (current !== void 0) {
|
|
144
|
-
if (current.exportName === marker.exportName && current.mode === marker.mode && sameInvocation(current.invocation, invocation)) return;
|
|
166
|
+
if (current.exportName === marker.exportName && current.mode === marker.mode && current.resources === marker.resources && sameInvocation(current.invocation, invocation)) return;
|
|
145
167
|
throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`);
|
|
146
168
|
}
|
|
147
169
|
Object.defineProperty(prototype, REMOTE_METHOD_DESCRIPTOR, {
|
|
@@ -163,6 +185,639 @@ function validateName(subject, value) {
|
|
|
163
185
|
//#endregion
|
|
164
186
|
//#region ../../node_modules/@deepseek-ai/dsh-util-values/lib/index.js
|
|
165
187
|
/**
|
|
188
|
+
* Lazily scanned view of one JSON object's top-level fields, built from text
|
|
189
|
+
* that may still be streaming or from an already parsed object. Nothing is
|
|
190
|
+
* scanned until a reader asks; the view remembers every question it answered
|
|
191
|
+
* and reports changed answers when the owner refreshes for publication.
|
|
192
|
+
* Used for model tool-call arguments: a row reads the fields it
|
|
193
|
+
* cares about at whatever granularity it displays, at every stage of the call.
|
|
194
|
+
* @module @deepseek-ai/dsh-util-values/src/partial-json
|
|
195
|
+
*/
|
|
196
|
+
const SIMPLE_ESCAPES = {
|
|
197
|
+
"\"": "\"",
|
|
198
|
+
"\\": "\\",
|
|
199
|
+
"/": "/",
|
|
200
|
+
b: "\b",
|
|
201
|
+
f: "\f",
|
|
202
|
+
n: "\n",
|
|
203
|
+
r: "\r",
|
|
204
|
+
t: " "
|
|
205
|
+
};
|
|
206
|
+
const CONTENT_ESCAPE = /[\\\u0000-\u001f]/u;
|
|
207
|
+
function isWhitespace(c) {
|
|
208
|
+
return c === " " || c === "\n" || c === "\r" || c === " ";
|
|
209
|
+
}
|
|
210
|
+
function isHex(c) {
|
|
211
|
+
return c >= "0" && c <= "9" || c >= "a" && c <= "f" || c >= "A" && c <= "F";
|
|
212
|
+
}
|
|
213
|
+
(class PartialArguments {
|
|
214
|
+
/** The view of a call with no arguments available. */
|
|
215
|
+
static EMPTY = PartialArguments.fromObject({});
|
|
216
|
+
/**
|
|
217
|
+
* View finished argument text without scanning it until a reader asks.
|
|
218
|
+
* @param text - the complete argument JSON text.
|
|
219
|
+
* @returns a sealed view.
|
|
220
|
+
*/
|
|
221
|
+
static fromText(text) {
|
|
222
|
+
const view = new PartialArguments();
|
|
223
|
+
view.append(text);
|
|
224
|
+
view.sealed = true;
|
|
225
|
+
return view;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* View an already parsed argument payload, such as a PTC dispatch object.
|
|
229
|
+
* @param value - the parsed argument value.
|
|
230
|
+
* @returns a sealed view; a non-object payload has no fields.
|
|
231
|
+
*/
|
|
232
|
+
static fromObject(value) {
|
|
233
|
+
const view = new PartialArguments();
|
|
234
|
+
view.object = typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
235
|
+
view.sealed = true;
|
|
236
|
+
return view;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The source: text so far or a parsed object, plus whether it can still grow.
|
|
240
|
+
* These are the only enumerable fields, so two views over the same source
|
|
241
|
+
* compare equal structurally however far each has been read.
|
|
242
|
+
*/
|
|
243
|
+
chunks = [];
|
|
244
|
+
object;
|
|
245
|
+
sealed = false;
|
|
246
|
+
#ends = [];
|
|
247
|
+
#size = 0;
|
|
248
|
+
#consumed = 0;
|
|
249
|
+
#mode = "root";
|
|
250
|
+
#escape = false;
|
|
251
|
+
#keyStart = 0;
|
|
252
|
+
#keyEscaped = false;
|
|
253
|
+
#key = "";
|
|
254
|
+
#current = null;
|
|
255
|
+
#nestedEnds = [];
|
|
256
|
+
#nestedInString = false;
|
|
257
|
+
#invalidAt;
|
|
258
|
+
#invalidValue = false;
|
|
259
|
+
#entries = /* @__PURE__ */ new Map();
|
|
260
|
+
#order = [];
|
|
261
|
+
#reads = /* @__PURE__ */ new Map();
|
|
262
|
+
/** Whether this view rejects further appends; does not scan text or register reads. */
|
|
263
|
+
get isSealed() {
|
|
264
|
+
return this.sealed;
|
|
265
|
+
}
|
|
266
|
+
/** Whether indexing or a content read found invalid JSON; unread value contents are not validated. */
|
|
267
|
+
get invalid() {
|
|
268
|
+
this.scan();
|
|
269
|
+
return this.#mode === "invalid" || this.#invalidValue;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Retain streamed argument text without scanning or comparing observed answers.
|
|
273
|
+
* @param fragment - the text following every fragment appended before.
|
|
274
|
+
*/
|
|
275
|
+
append(fragment) {
|
|
276
|
+
if (this.sealed) throw new Error("PartialArguments: cannot append to a sealed view");
|
|
277
|
+
if (fragment.length === 0) return;
|
|
278
|
+
this.chunks.push(fragment);
|
|
279
|
+
this.#size += fragment.length;
|
|
280
|
+
this.#ends.push(this.#size);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Reconcile a streamed prefix with authoritative complete text without joining the fragments.
|
|
284
|
+
* @param text - the final argument text, which replaces missing or conflicting deltas.
|
|
285
|
+
* @returns this view sealed with its caches retained when every character matches; otherwise a new sealed view.
|
|
286
|
+
*/
|
|
287
|
+
settle(text) {
|
|
288
|
+
if (this.object !== void 0 || text.length !== this.#size) return PartialArguments.fromText(text);
|
|
289
|
+
let offset = 0;
|
|
290
|
+
for (const chunk of this.chunks) {
|
|
291
|
+
if (!text.startsWith(chunk, offset)) return PartialArguments.fromText(text);
|
|
292
|
+
offset += chunk.length;
|
|
293
|
+
}
|
|
294
|
+
this.chunks = text.length === 0 ? [] : [text];
|
|
295
|
+
this.#ends = text.length === 0 ? [] : [text.length];
|
|
296
|
+
this.sealed = true;
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Compare observed answers and advance their publication baseline. Unread views remain unscanned.
|
|
301
|
+
* @returns whether any observed answer changed since its first read or the preceding refresh.
|
|
302
|
+
*/
|
|
303
|
+
refresh() {
|
|
304
|
+
if (this.#reads.size === 0) return false;
|
|
305
|
+
this.scan();
|
|
306
|
+
let changed = false;
|
|
307
|
+
let completions = false;
|
|
308
|
+
for (const read of this.#reads.values()) {
|
|
309
|
+
if (read.completion) {
|
|
310
|
+
completions = true;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
changed = this.refreshRead(read) || changed;
|
|
314
|
+
}
|
|
315
|
+
if (completions) {
|
|
316
|
+
for (const read of this.#reads.values()) if (read.completion) changed = this.refreshRead(read) || changed;
|
|
317
|
+
}
|
|
318
|
+
if (this.sealed) this.#reads.clear();
|
|
319
|
+
return changed;
|
|
320
|
+
}
|
|
321
|
+
refreshRead(read) {
|
|
322
|
+
const now = read.answer();
|
|
323
|
+
if (Object.is(now, read.last)) return false;
|
|
324
|
+
read.last = now;
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Check whether no further fields can arrive.
|
|
329
|
+
* @returns whether the outer object closed, indexing failed, or the view is sealed; unread values are not validated.
|
|
330
|
+
*/
|
|
331
|
+
closed() {
|
|
332
|
+
return this.remember("closed", "", () => this.closedNow());
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* List discovered fields in first-appearance order.
|
|
336
|
+
* @returns top-level keys seen so far, in first-appearance order.
|
|
337
|
+
*/
|
|
338
|
+
keys() {
|
|
339
|
+
return this.remember("keys", "", () => this.keysNow(), (keys) => keys.length);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Check whether a top-level field has appeared.
|
|
343
|
+
* @param key - argument name.
|
|
344
|
+
* @returns whether the field has appeared (a string opened or another value began).
|
|
345
|
+
*/
|
|
346
|
+
has(key) {
|
|
347
|
+
return this.remember("has", key, () => this.hasNow(key));
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Check whether a field's closing delimiter has arrived, without validating its contents.
|
|
351
|
+
* @param key - argument name.
|
|
352
|
+
* @returns whether its delimiter arrived and no content reader has reported an error for this value.
|
|
353
|
+
*/
|
|
354
|
+
complete(key) {
|
|
355
|
+
return this.remember("complete", key, () => this.completeNow(key));
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Read string length without materializing its text.
|
|
359
|
+
* @param key - argument name.
|
|
360
|
+
* @param options - change granularity for a streaming string.
|
|
361
|
+
* @returns decoded UTF-16 length of the string field so far; undefined when absent or not a string.
|
|
362
|
+
*/
|
|
363
|
+
stringLength(key, options) {
|
|
364
|
+
const step = Math.max(1, Math.floor(options?.step ?? 1));
|
|
365
|
+
const offset = options?.offset ?? 0;
|
|
366
|
+
return this.remember(`length:${step}:${offset}`, key, () => this.lengthNow(key), (length) => length === void 0 ? void 0 : Math.ceil((length + offset) / step));
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Check a string against a decoded UTF-16 length limit without materializing it.
|
|
370
|
+
* @param key - argument name.
|
|
371
|
+
* @param maxLength - decoded UTF-16 limit, floored to at least zero.
|
|
372
|
+
* @returns whether the string is longer than the limit; false when absent or not a string.
|
|
373
|
+
*/
|
|
374
|
+
stringExceeds(key, maxLength) {
|
|
375
|
+
const limit = Math.max(0, Math.floor(maxLength));
|
|
376
|
+
return this.remember(`exceeds:${limit}`, key, () => (this.lengthNow(key, limit + 1) ?? 0) > limit);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Read a decoded string, including a streaming prefix.
|
|
380
|
+
* @param key - argument name.
|
|
381
|
+
* @returns the string field's decoded text so far; undefined when absent or not a string.
|
|
382
|
+
*/
|
|
383
|
+
text(key) {
|
|
384
|
+
return this.remember("text", key, () => this.textNow(key));
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Read at most the first decoded UTF-16 units of a string.
|
|
388
|
+
* @param key - argument name.
|
|
389
|
+
* @param maxLength - maximum decoded UTF-16 length, floored to at least one.
|
|
390
|
+
* @returns the bounded string prefix; undefined when absent or not a string.
|
|
391
|
+
*/
|
|
392
|
+
textPrefix(key, maxLength) {
|
|
393
|
+
const limit = Math.max(1, Math.floor(maxLength));
|
|
394
|
+
return this.remember(`prefix:${limit}`, key, () => this.textPrefixNow(key, limit));
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Read a completed non-string argument.
|
|
398
|
+
* @param key - argument name.
|
|
399
|
+
* @returns the parsed non-string value once it closed; undefined while open, absent, or a string.
|
|
400
|
+
*/
|
|
401
|
+
value(key) {
|
|
402
|
+
return this.remember("value", key, () => this.valueNow(key));
|
|
403
|
+
}
|
|
404
|
+
/** Answer a question and, on a streaming view, remember it for change detection. */
|
|
405
|
+
remember(kind, key, read, comparison) {
|
|
406
|
+
this.scan();
|
|
407
|
+
const result = read();
|
|
408
|
+
if (!this.sealed) {
|
|
409
|
+
const id = `${kind}/${key}`;
|
|
410
|
+
if (!this.#reads.has(id)) this.#reads.set(id, {
|
|
411
|
+
completion: kind === "complete",
|
|
412
|
+
answer: comparison === void 0 ? read : () => comparison(read()),
|
|
413
|
+
last: comparison === void 0 ? result : comparison(result)
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
closedNow() {
|
|
419
|
+
return this.sealed || this.#mode === "closed" || this.#mode === "invalid";
|
|
420
|
+
}
|
|
421
|
+
keysNow() {
|
|
422
|
+
return this.object === void 0 ? this.#order : Object.keys(this.object);
|
|
423
|
+
}
|
|
424
|
+
hasNow(key) {
|
|
425
|
+
return this.object === void 0 ? this.#entries.has(key) : Object.hasOwn(this.object, key);
|
|
426
|
+
}
|
|
427
|
+
completeNow(key) {
|
|
428
|
+
if (this.object !== void 0) return Object.hasOwn(this.object, key);
|
|
429
|
+
const entry = this.#entries.get(key);
|
|
430
|
+
return entry !== void 0 && entry.end >= 0 && (entry.kind === "string" ? entry.invalidAt === void 0 : !entry.invalid);
|
|
431
|
+
}
|
|
432
|
+
lengthNow(key, limit = Number.POSITIVE_INFINITY) {
|
|
433
|
+
if (this.object !== void 0) {
|
|
434
|
+
const field = Object.hasOwn(this.object, key) ? this.object[key] : void 0;
|
|
435
|
+
return typeof field === "string" ? field.length : void 0;
|
|
436
|
+
}
|
|
437
|
+
const entry = this.#entries.get(key);
|
|
438
|
+
if (entry?.kind !== "string") return void 0;
|
|
439
|
+
if (entry.text !== void 0 && entry.text.at === entry.end) return entry.text.length;
|
|
440
|
+
const read = entry.length ??= {
|
|
441
|
+
at: entry.start,
|
|
442
|
+
length: 0,
|
|
443
|
+
text: ""
|
|
444
|
+
};
|
|
445
|
+
this.readString(entry, read, limit, false);
|
|
446
|
+
return read.length;
|
|
447
|
+
}
|
|
448
|
+
textNow(key) {
|
|
449
|
+
if (this.object !== void 0) {
|
|
450
|
+
const field = Object.hasOwn(this.object, key) ? this.object[key] : void 0;
|
|
451
|
+
return typeof field === "string" ? field : void 0;
|
|
452
|
+
}
|
|
453
|
+
const entry = this.#entries.get(key);
|
|
454
|
+
if (entry?.kind !== "string") return void 0;
|
|
455
|
+
if (entry.text === void 0 && entry.end >= 0 && entry.needsDecoding && entry.invalidAt === void 0) {
|
|
456
|
+
let text;
|
|
457
|
+
try {
|
|
458
|
+
text = JSON.parse(`"${this.slice(entry.start, entry.end)}"`);
|
|
459
|
+
} catch (_error) {}
|
|
460
|
+
if (text !== void 0) entry.text = {
|
|
461
|
+
at: entry.end,
|
|
462
|
+
length: text.length,
|
|
463
|
+
text
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const read = entry.text ??= {
|
|
467
|
+
at: entry.start,
|
|
468
|
+
length: 0,
|
|
469
|
+
text: ""
|
|
470
|
+
};
|
|
471
|
+
this.readString(entry, read, Number.POSITIVE_INFINITY, true);
|
|
472
|
+
return read.text;
|
|
473
|
+
}
|
|
474
|
+
textPrefixNow(key, maxLength) {
|
|
475
|
+
if (this.object !== void 0) {
|
|
476
|
+
const field = Object.hasOwn(this.object, key) ? this.object[key] : void 0;
|
|
477
|
+
return typeof field === "string" ? field.slice(0, maxLength) : void 0;
|
|
478
|
+
}
|
|
479
|
+
const entry = this.#entries.get(key);
|
|
480
|
+
if (entry?.kind !== "string") return void 0;
|
|
481
|
+
const prefixes = entry.prefixes ??= /* @__PURE__ */ new Map();
|
|
482
|
+
let read = prefixes.get(maxLength);
|
|
483
|
+
if (read === void 0) {
|
|
484
|
+
read = {
|
|
485
|
+
at: entry.start,
|
|
486
|
+
length: 0,
|
|
487
|
+
text: ""
|
|
488
|
+
};
|
|
489
|
+
prefixes.set(maxLength, read);
|
|
490
|
+
}
|
|
491
|
+
this.readString(entry, read, maxLength, true);
|
|
492
|
+
return read.text;
|
|
493
|
+
}
|
|
494
|
+
valueNow(key) {
|
|
495
|
+
if (this.object !== void 0) {
|
|
496
|
+
if (!Object.hasOwn(this.object, key)) return void 0;
|
|
497
|
+
const field = this.object[key];
|
|
498
|
+
return typeof field === "string" ? void 0 : field;
|
|
499
|
+
}
|
|
500
|
+
const entry = this.#entries.get(key);
|
|
501
|
+
if (entry?.kind !== "value" || entry.end < 0 || entry.invalid) return void 0;
|
|
502
|
+
if (entry.parsed === void 0) try {
|
|
503
|
+
entry.parsed = JSON.parse(this.slice(entry.start, entry.end));
|
|
504
|
+
} catch (_error) {
|
|
505
|
+
entry.invalid = true;
|
|
506
|
+
this.#invalidValue = true;
|
|
507
|
+
}
|
|
508
|
+
return entry.parsed;
|
|
509
|
+
}
|
|
510
|
+
chunkAt(at) {
|
|
511
|
+
let low = 0;
|
|
512
|
+
let high = this.#ends.length;
|
|
513
|
+
while (low < high) {
|
|
514
|
+
const mid = low + high >>> 1;
|
|
515
|
+
if (this.#ends[mid] <= at) low = mid + 1;
|
|
516
|
+
else high = mid;
|
|
517
|
+
}
|
|
518
|
+
return low;
|
|
519
|
+
}
|
|
520
|
+
/** Materialize only a requested range, never the cumulative source. */
|
|
521
|
+
slice(start, end) {
|
|
522
|
+
if (start >= end) return "";
|
|
523
|
+
const first = this.chunkAt(start);
|
|
524
|
+
const last = this.chunkAt(end - 1);
|
|
525
|
+
const base = first === 0 ? 0 : this.#ends[first - 1];
|
|
526
|
+
if (first === last) return this.chunks[first].slice(start - base, end - base);
|
|
527
|
+
const parts = [this.chunks[first].slice(start - base)];
|
|
528
|
+
for (let i = first + 1; i < last; i++) parts.push(this.chunks[i]);
|
|
529
|
+
parts.push(this.chunks[last].slice(0, end - this.#ends[last - 1]));
|
|
530
|
+
return parts.join("");
|
|
531
|
+
}
|
|
532
|
+
readString(entry, read, limit, materialize) {
|
|
533
|
+
const end = Math.min(entry.end < 0 ? this.#consumed : entry.end, entry.invalidAt ?? Number.POSITIVE_INFINITY, this.#invalidAt ?? Number.POSITIVE_INFINITY);
|
|
534
|
+
if (!entry.needsDecoding) {
|
|
535
|
+
const length = Math.min(end - read.at, limit - read.length);
|
|
536
|
+
if (length <= 0) return;
|
|
537
|
+
if (materialize) read.text += this.slice(read.at, read.at + length);
|
|
538
|
+
read.at += length;
|
|
539
|
+
read.length += length;
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
let chunkIndex = this.chunkAt(read.at);
|
|
543
|
+
while (read.at < end && read.length < limit) {
|
|
544
|
+
const base = chunkIndex === 0 ? 0 : this.#ends[chunkIndex - 1];
|
|
545
|
+
const chunk = this.chunks[chunkIndex];
|
|
546
|
+
const remaining = chunk.slice(read.at - base, Math.min(chunk.length, end - base));
|
|
547
|
+
const boundary = remaining.search(CONTENT_ESCAPE);
|
|
548
|
+
const length = Math.min(boundary < 0 ? remaining.length : boundary, limit - read.length);
|
|
549
|
+
if (length > 0) {
|
|
550
|
+
if (materialize) read.text += remaining.slice(0, length);
|
|
551
|
+
read.at += length;
|
|
552
|
+
read.length += length;
|
|
553
|
+
if (read.at === base + chunk.length) chunkIndex++;
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
const type = remaining.length > 1 ? remaining[1] : read.at + 1 < end ? this.chunks[chunkIndex + 1][0] : void 0;
|
|
557
|
+
let decoded;
|
|
558
|
+
let width = 2;
|
|
559
|
+
if (remaining[0] === "\\" && type === void 0 && entry.end < 0) return;
|
|
560
|
+
if (remaining[0] === "\\" && type === "u") {
|
|
561
|
+
const hex = this.slice(read.at + 2, Math.min(end, read.at + 6));
|
|
562
|
+
let valid = true;
|
|
563
|
+
for (let i = 0; i < hex.length; i++) if (!isHex(hex[i])) valid = false;
|
|
564
|
+
if (valid) {
|
|
565
|
+
if (hex.length < 4 && entry.end < 0) return;
|
|
566
|
+
if (hex.length === 4) decoded = String.fromCharCode(Number.parseInt(hex, 16));
|
|
567
|
+
}
|
|
568
|
+
width = 6;
|
|
569
|
+
} else if (remaining[0] === "\\" && type !== void 0) decoded = SIMPLE_ESCAPES[type];
|
|
570
|
+
if (decoded === void 0) {
|
|
571
|
+
entry.invalidAt = read.at;
|
|
572
|
+
this.#invalidValue = true;
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
if (materialize) read.text += decoded;
|
|
576
|
+
read.length++;
|
|
577
|
+
read.at += width;
|
|
578
|
+
while (chunkIndex < this.chunks.length && read.at >= this.#ends[chunkIndex]) chunkIndex++;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/** Locate new field ranges without decoding or parsing their contents. */
|
|
582
|
+
scan() {
|
|
583
|
+
if (this.object !== void 0 || this.#consumed === this.#size) return;
|
|
584
|
+
for (let i = this.chunkAt(this.#consumed); i < this.chunks.length && this.#invalidAt === void 0; i++) {
|
|
585
|
+
const pending = this.chunks[i];
|
|
586
|
+
const base = i === 0 ? 0 : this.#ends[i - 1];
|
|
587
|
+
for (let index = this.#consumed - base; index < pending.length && this.#mode !== "invalid"; index++) {
|
|
588
|
+
if (this.#mode === "string" || this.#mode === "nested" && this.#nestedInString) {
|
|
589
|
+
const end = this.stringBoundary(pending, index);
|
|
590
|
+
this.#consumed += end - index;
|
|
591
|
+
index = end;
|
|
592
|
+
if (index === pending.length) break;
|
|
593
|
+
}
|
|
594
|
+
this.step(pending[index], this.#consumed);
|
|
595
|
+
this.#consumed++;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
/** Only raw quotes and their preceding backslash runs can terminate a string. */
|
|
600
|
+
stringBoundary(fragment, start) {
|
|
601
|
+
let at = start;
|
|
602
|
+
while (true) {
|
|
603
|
+
const quote = fragment.indexOf("\"", at);
|
|
604
|
+
const end = quote < 0 ? fragment.length : quote;
|
|
605
|
+
if (this.#mode === "string") {
|
|
606
|
+
const entry = this.#current;
|
|
607
|
+
if (!entry.needsDecoding && CONTENT_ESCAPE.test(fragment.slice(at, end))) entry.needsDecoding = true;
|
|
608
|
+
}
|
|
609
|
+
let slashStart = end;
|
|
610
|
+
while (slashStart > at && fragment[slashStart - 1] === "\\") slashStart--;
|
|
611
|
+
const escaped = (end - slashStart) % 2 === 1 !== (slashStart === at && this.#escape);
|
|
612
|
+
this.#escape = quote < 0 && escaped;
|
|
613
|
+
if (quote < 0 || !escaped) return end;
|
|
614
|
+
at = quote + 1;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
step(c, at) {
|
|
618
|
+
switch (this.#mode) {
|
|
619
|
+
case "root":
|
|
620
|
+
if (isWhitespace(c)) return;
|
|
621
|
+
if (c === "{") {
|
|
622
|
+
this.#mode = "key-or-end";
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
this.fail();
|
|
626
|
+
return;
|
|
627
|
+
case "key-or-end":
|
|
628
|
+
if (isWhitespace(c)) return;
|
|
629
|
+
if (c === "}") {
|
|
630
|
+
this.#mode = "closed";
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
if (c === "\"") {
|
|
634
|
+
this.beginKey(at);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
this.fail();
|
|
638
|
+
return;
|
|
639
|
+
case "key-only":
|
|
640
|
+
if (isWhitespace(c)) return;
|
|
641
|
+
if (c === "\"") {
|
|
642
|
+
this.beginKey(at);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
this.fail();
|
|
646
|
+
return;
|
|
647
|
+
case "key":
|
|
648
|
+
this.stepKey(c, at);
|
|
649
|
+
return;
|
|
650
|
+
case "colon":
|
|
651
|
+
if (isWhitespace(c)) return;
|
|
652
|
+
if (c === ":") {
|
|
653
|
+
this.#mode = "value";
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
this.fail();
|
|
657
|
+
return;
|
|
658
|
+
case "value":
|
|
659
|
+
this.beginValue(c, at);
|
|
660
|
+
return;
|
|
661
|
+
case "string": {
|
|
662
|
+
const entry = this.#current;
|
|
663
|
+
entry.end = at;
|
|
664
|
+
this.#current = null;
|
|
665
|
+
this.#mode = "comma-or-end";
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
case "scalar":
|
|
669
|
+
this.stepScalar(c, at);
|
|
670
|
+
return;
|
|
671
|
+
case "nested":
|
|
672
|
+
this.stepNested(c, at);
|
|
673
|
+
return;
|
|
674
|
+
case "comma-or-end":
|
|
675
|
+
if (isWhitespace(c)) return;
|
|
676
|
+
if (c === ",") {
|
|
677
|
+
this.#mode = "key-only";
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (c === "}") {
|
|
681
|
+
this.#mode = "closed";
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
this.fail();
|
|
685
|
+
return;
|
|
686
|
+
case "closed":
|
|
687
|
+
if (isWhitespace(c)) return;
|
|
688
|
+
this.fail();
|
|
689
|
+
return;
|
|
690
|
+
/* v8 ignore next 2 -- scan() stops stepping once the view is invalid. */
|
|
691
|
+
case "invalid": return;
|
|
692
|
+
/* v8 ignore next 2 -- Every scanner mode has a handler above. */
|
|
693
|
+
default: assertNever(this.#mode);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
fail() {
|
|
697
|
+
this.#invalidAt = this.#consumed;
|
|
698
|
+
this.#mode = "invalid";
|
|
699
|
+
this.#current = null;
|
|
700
|
+
}
|
|
701
|
+
beginKey(at) {
|
|
702
|
+
this.#mode = "key";
|
|
703
|
+
this.#keyStart = at + 1;
|
|
704
|
+
this.#keyEscaped = false;
|
|
705
|
+
this.#escape = false;
|
|
706
|
+
}
|
|
707
|
+
stepKey(c, at) {
|
|
708
|
+
if (c < " ") {
|
|
709
|
+
this.fail();
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
if (this.#escape) {
|
|
713
|
+
this.#escape = false;
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (c === "\\") {
|
|
717
|
+
this.#escape = true;
|
|
718
|
+
this.#keyEscaped = true;
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
if (c !== "\"") return;
|
|
722
|
+
const raw = this.slice(this.#keyStart, at);
|
|
723
|
+
if (this.#keyEscaped) try {
|
|
724
|
+
this.#key = JSON.parse(`"${raw}"`);
|
|
725
|
+
} catch (_error) {
|
|
726
|
+
this.fail();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
else this.#key = raw;
|
|
730
|
+
this.#mode = "colon";
|
|
731
|
+
}
|
|
732
|
+
open(entry) {
|
|
733
|
+
if (!this.#entries.has(this.#key)) this.#order.push(this.#key);
|
|
734
|
+
this.#entries.set(this.#key, entry);
|
|
735
|
+
this.#current = entry;
|
|
736
|
+
}
|
|
737
|
+
beginValue(c, at) {
|
|
738
|
+
if (isWhitespace(c)) return;
|
|
739
|
+
if (c === "\"") {
|
|
740
|
+
this.open({
|
|
741
|
+
kind: "string",
|
|
742
|
+
start: at + 1,
|
|
743
|
+
end: -1,
|
|
744
|
+
needsDecoding: false,
|
|
745
|
+
invalidAt: void 0,
|
|
746
|
+
length: void 0,
|
|
747
|
+
text: void 0,
|
|
748
|
+
prefixes: void 0
|
|
749
|
+
});
|
|
750
|
+
this.#escape = false;
|
|
751
|
+
this.#mode = "string";
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
if (c === "}" || c === "," || c === ":" || c === "]") {
|
|
755
|
+
this.fail();
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
this.open({
|
|
759
|
+
kind: "value",
|
|
760
|
+
start: at,
|
|
761
|
+
end: -1,
|
|
762
|
+
parsed: void 0,
|
|
763
|
+
invalid: false
|
|
764
|
+
});
|
|
765
|
+
if (c === "{" || c === "[") {
|
|
766
|
+
this.#mode = "nested";
|
|
767
|
+
this.#nestedEnds = [c === "{" ? "}" : "]"];
|
|
768
|
+
this.#nestedInString = false;
|
|
769
|
+
this.#escape = false;
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
this.#mode = "scalar";
|
|
773
|
+
}
|
|
774
|
+
stepScalar(c, at) {
|
|
775
|
+
if (c !== "," && c !== "}" && !isWhitespace(c)) return;
|
|
776
|
+
this.closeValue(at);
|
|
777
|
+
this.#mode = c === "," ? "key-only" : c === "}" ? "closed" : "comma-or-end";
|
|
778
|
+
}
|
|
779
|
+
stepNested(c, at) {
|
|
780
|
+
if (this.#nestedInString) {
|
|
781
|
+
this.#nestedInString = false;
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
if (c === "\"") {
|
|
785
|
+
this.#nestedInString = true;
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
if (c === "{" || c === "[") {
|
|
789
|
+
this.#nestedEnds.push(c === "{" ? "}" : "]");
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
if (c === "}" || c === "]") {
|
|
793
|
+
if (this.#nestedEnds.pop() !== c) {
|
|
794
|
+
this.fail();
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (this.#nestedEnds.length === 0) {
|
|
798
|
+
this.closeValue(at + 1);
|
|
799
|
+
this.#mode = "comma-or-end";
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
closeValue(end) {
|
|
804
|
+
const entry = this.#current;
|
|
805
|
+
entry.end = end;
|
|
806
|
+
this.#current = null;
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
/** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */
|
|
810
|
+
/**
|
|
811
|
+
* Mark an unreachable closed-union branch.
|
|
812
|
+
* @param value - impossible value; an unhandled typed variant fails at the call site.
|
|
813
|
+
* @param context - optional switch-site label included in the failure message.
|
|
814
|
+
* @returns never; a runtime value that escaped its type always throws.
|
|
815
|
+
*/
|
|
816
|
+
function assertNever(value, context) {
|
|
817
|
+
const rendered = JSON.stringify(value) ?? String(value);
|
|
818
|
+
throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
166
821
|
* Deep-freeze an object graph in place while leaving live AbortSignal objects mutable.
|
|
167
822
|
* @param value - value to freeze.
|
|
168
823
|
* @returns the same value after every reachable enumerable child is frozen.
|
|
@@ -1170,7 +1825,7 @@ function createUserMessage(input) {
|
|
|
1170
1825
|
*/
|
|
1171
1826
|
/**
|
|
1172
1827
|
* Base class for all harness errors. Carries a `code` (stable, programmatic —
|
|
1173
|
-
* e.g. `NO_ADAPTER`, `INVALID_ARGS
|
|
1828
|
+
* e.g. `NO_ADAPTER`, `INVALID_ARGS`) distinct from the
|
|
1174
1829
|
* human-readable `message`, and supports `cause` chaining via the standard
|
|
1175
1830
|
* `ErrorOptions`. `name` defaults to the subclass constructor name.
|
|
1176
1831
|
*/
|
|
@@ -1497,10 +2152,93 @@ function projectImagesForTextModel(messages) {
|
|
|
1497
2152
|
};
|
|
1498
2153
|
});
|
|
1499
2154
|
}
|
|
2155
|
+
function withoutDeveloperMessages(messages) {
|
|
2156
|
+
const retained = messages.filter((message) => message.role !== "developer");
|
|
2157
|
+
return retained.length === messages.length ? messages : retained;
|
|
2158
|
+
}
|
|
2159
|
+
function toolDeclarations(tools, mode, history) {
|
|
2160
|
+
const declarations = new Map(history.tools.map((tool) => [tool.name, tool]));
|
|
2161
|
+
for (const update of history.updates) for (const tool of update.additions) if (!declarations.has(tool.name)) declarations.set(tool.name, {
|
|
2162
|
+
...tool,
|
|
2163
|
+
deferLoading: true
|
|
2164
|
+
});
|
|
2165
|
+
switch (mode) {
|
|
2166
|
+
case "in-history": return declarations;
|
|
2167
|
+
case "addition-only": {
|
|
2168
|
+
const activeNames = new Set(tools?.map((tool) => tool.name));
|
|
2169
|
+
for (const name of declarations.keys()) if (!activeNames.has(name)) declarations.delete(name);
|
|
2170
|
+
return declarations;
|
|
2171
|
+
}
|
|
2172
|
+
/* v8 ignore next 2 -- closed-union exhaustiveness guard */
|
|
2173
|
+
default: return assertNever(mode);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* Construct provider declarations from session-folded history without changing logged active tools.
|
|
2178
|
+
* Unsupported routes and incomplete history use current declarations without developer updates.
|
|
2179
|
+
* Explicitly deferred baseline tools become available only after their first retained addition.
|
|
2180
|
+
* @param messages - complete request inputs, or the prefix selected for an auxiliary call.
|
|
2181
|
+
* @param tools - currently active tool schemas.
|
|
2182
|
+
* @param toolUpdate - the resolved route's update mode.
|
|
2183
|
+
* @param history - immutable state folded from committed headers and developer messages.
|
|
2184
|
+
* @returns provider declarations and the corresponding filtered history.
|
|
2185
|
+
*/
|
|
2186
|
+
function projectToolUpdates(messages, tools, toolUpdate, history) {
|
|
2187
|
+
if (toolUpdate === void 0) {
|
|
2188
|
+
let immediateTools = tools;
|
|
2189
|
+
if (tools?.some((tool) => tool.deferLoading === true)) immediateTools = tools.map(({ deferLoading: _loading, ...tool }) => tool);
|
|
2190
|
+
return {
|
|
2191
|
+
messages: withoutDeveloperMessages(messages),
|
|
2192
|
+
tools: immediateTools
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
if (history === void 0) return {
|
|
2196
|
+
messages: withoutDeveloperMessages(messages),
|
|
2197
|
+
tools
|
|
2198
|
+
};
|
|
2199
|
+
const messageIds = new Set(messages.flatMap((message) => message.role === "developer" ? [message.id] : []));
|
|
2200
|
+
if (history.updates.some((update) => !messageIds.has(update.messageId))) return {
|
|
2201
|
+
messages: withoutDeveloperMessages(messages),
|
|
2202
|
+
tools
|
|
2203
|
+
};
|
|
2204
|
+
const declarations = toolDeclarations(tools, toolUpdate, history);
|
|
2205
|
+
const updateIds = new Set(history.updates.map((update) => update.messageId));
|
|
2206
|
+
const offered = new Set(history.tools.filter((tool) => !tool.deferLoading).map((tool) => tool.name));
|
|
2207
|
+
const projectedMessages = [];
|
|
2208
|
+
for (const message of messages) {
|
|
2209
|
+
if (message.role !== "developer") {
|
|
2210
|
+
projectedMessages.push(message);
|
|
2211
|
+
continue;
|
|
2212
|
+
}
|
|
2213
|
+
if (!updateIds.has(message.id)) continue;
|
|
2214
|
+
const content = message.content.filter((block) => {
|
|
2215
|
+
switch (block.type) {
|
|
2216
|
+
case "tool-addition":
|
|
2217
|
+
if (!declarations.has(block.toolName) || offered.has(block.toolName)) return false;
|
|
2218
|
+
offered.add(block.toolName);
|
|
2219
|
+
return true;
|
|
2220
|
+
case "tool-removal":
|
|
2221
|
+
if (toolUpdate !== "in-history") return false;
|
|
2222
|
+
return offered.delete(block.toolName);
|
|
2223
|
+
default: return true;
|
|
2224
|
+
}
|
|
2225
|
+
});
|
|
2226
|
+
if (content.length === 0) continue;
|
|
2227
|
+
if (content.length === message.content.length) projectedMessages.push(message);
|
|
2228
|
+
else projectedMessages.push({
|
|
2229
|
+
...message,
|
|
2230
|
+
content
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
return {
|
|
2234
|
+
messages: projectedMessages.length === messages.length && projectedMessages.every((message, index) => message === messages[index]) ? messages : projectedMessages,
|
|
2235
|
+
tools: [...declarations.values()]
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
1500
2238
|
/**
|
|
1501
2239
|
* Centralize the non-secret product identity every provider request sends as `User-Agent`, keeping
|
|
1502
2240
|
* adapters from drifting. See
|
|
1503
|
-
*
|
|
2241
|
+
* `docs/subsystems/llm-streaming.md#appidentity--app-attribution`.
|
|
1504
2242
|
*
|
|
1505
2243
|
* App-attribution vocabulary for provider requests.
|
|
1506
2244
|
* @module @deepseek-ai/dsh-llm/attribution
|
|
@@ -1641,20 +2379,14 @@ var LlmError = class extends HarnessError {
|
|
|
1641
2379
|
}
|
|
1642
2380
|
/** Notify topology observers without letting one broken listener veto the commit. */
|
|
1643
2381
|
emitAdaptersUpdated() {
|
|
1644
|
-
let invariantFailure;
|
|
1645
2382
|
for (const listener of this.ctx.events.dispatch("emit", ["llm/adapters-updated"])) try {
|
|
1646
2383
|
const returned = listener();
|
|
1647
2384
|
if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => {
|
|
1648
2385
|
this.warnAdaptersListenerFailure(error);
|
|
1649
2386
|
});
|
|
1650
2387
|
} catch (error) {
|
|
1651
|
-
if (error?.code === "INVARIANT") {
|
|
1652
|
-
invariantFailure ??= error;
|
|
1653
|
-
continue;
|
|
1654
|
-
}
|
|
1655
2388
|
this.warnAdaptersListenerFailure(error);
|
|
1656
2389
|
}
|
|
1657
|
-
if (invariantFailure !== void 0) throw invariantFailure;
|
|
1658
2390
|
}
|
|
1659
2391
|
/** Contained-listener diagnostic shared by the sync and async failure paths. */
|
|
1660
2392
|
warnAdaptersListenerFailure(error) {
|
|
@@ -1763,10 +2495,7 @@ var LlmError = class extends HarnessError {
|
|
|
1763
2495
|
if (entry.provider.length === 0 || entry.displayName.length === 0 || entry.settingsNs.length === 0) throw new LlmError("configurable providers need a non-empty provider, displayName, and settingsNs", "INVALID_DIRECTORY");
|
|
1764
2496
|
if (entry.settingsPath.some((segment) => segment.length === 0)) throw new LlmError(`configurable provider "${entry.provider}" has an empty settingsPath segment`, "INVALID_DIRECTORY");
|
|
1765
2497
|
if (this.directory.has(entry.provider) && !own.has(entry.provider) || detached.some((seen) => seen.provider === entry.provider)) throw new LlmError(`configurable provider "${entry.provider}" is already declared`, "DUPLICATE_DIRECTORY");
|
|
1766
|
-
detached.push(
|
|
1767
|
-
...entry,
|
|
1768
|
-
settingsPath: [...entry.settingsPath]
|
|
1769
|
-
});
|
|
2498
|
+
detached.push(detachDirectoryEntry(entry));
|
|
1770
2499
|
}
|
|
1771
2500
|
for (const entry of held) this.directory.delete(entry.provider);
|
|
1772
2501
|
for (const entry of detached) this.directory.set(entry.provider, entry);
|
|
@@ -1795,10 +2524,7 @@ var LlmError = class extends HarnessError {
|
|
|
1795
2524
|
* @returns detached directory entries in declaration order.
|
|
1796
2525
|
*/
|
|
1797
2526
|
listConfigurableProviders() {
|
|
1798
|
-
return [...this.directory.values()].map(
|
|
1799
|
-
...entry,
|
|
1800
|
-
settingsPath: [...entry.settingsPath]
|
|
1801
|
-
}));
|
|
2527
|
+
return [...this.directory.values()].map(detachDirectoryEntry);
|
|
1802
2528
|
}
|
|
1803
2529
|
/**
|
|
1804
2530
|
* Offer to interrogate provider endpoints on behalf of the settings
|
|
@@ -1890,6 +2616,16 @@ var LlmError = class extends HarnessError {
|
|
|
1890
2616
|
return this.adapters.get(provider)?.adapter.imageRequestPricing(provider, model);
|
|
1891
2617
|
}
|
|
1892
2618
|
/**
|
|
2619
|
+
* Resolve the image projection for an exact registered model route.
|
|
2620
|
+
* @param provider - registered provider route.
|
|
2621
|
+
* @param model - exact model id.
|
|
2622
|
+
* @param image - normalized image reference.
|
|
2623
|
+
* @returns dimensions and byte target used by the adapter's request serializer.
|
|
2624
|
+
*/
|
|
2625
|
+
imageRequestTarget(provider, model, image) {
|
|
2626
|
+
return this.registration(provider).adapter.imageRequestTarget(provider, model, image);
|
|
2627
|
+
}
|
|
2628
|
+
/**
|
|
1893
2629
|
* Resolve the exact text one durable file occurrence contributes to every
|
|
1894
2630
|
* provider request in the current execution environment.
|
|
1895
2631
|
* @param ref - durable verbatim file reference from model history.
|
|
@@ -1904,7 +2640,8 @@ var LlmError = class extends HarnessError {
|
|
|
1904
2640
|
}
|
|
1905
2641
|
/**
|
|
1906
2642
|
* Discover models advertised by one registered provider. Catalog membership
|
|
1907
|
-
*
|
|
2643
|
+
* does not constrain core routing. Catalog-driven entry points may restrict
|
|
2644
|
+
* selection and submission to the advertised models.
|
|
1908
2645
|
* @param provider - registered provider route to inspect.
|
|
1909
2646
|
* @returns detached model metadata in adapter-preferred order.
|
|
1910
2647
|
*/
|
|
@@ -1949,6 +2686,8 @@ var LlmError = class extends HarnessError {
|
|
|
1949
2686
|
const inputModalities = this.detachedModalities(resolved.inputModalities);
|
|
1950
2687
|
const systemPromptUpdate = resolved.systemPromptUpdate;
|
|
1951
2688
|
if (systemPromptUpdate !== void 0 && systemPromptUpdate !== "in-history") throw new LlmError(`adapter returned invalid system prompt update mode for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO");
|
|
2689
|
+
const toolUpdate = resolved.toolUpdate;
|
|
2690
|
+
if (toolUpdate !== void 0 && toolUpdate !== "in-history" && toolUpdate !== "addition-only") throw new LlmError(`adapter returned invalid tool update mode for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO");
|
|
1952
2691
|
const defaultMaxTokens = resolved.defaultMaxTokens;
|
|
1953
2692
|
if (defaultMaxTokens !== void 0 && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, "INVALID_MODEL_MAX_TOKENS");
|
|
1954
2693
|
const info = {
|
|
@@ -1959,7 +2698,8 @@ var LlmError = class extends HarnessError {
|
|
|
1959
2698
|
...inputModalities === void 0 ? {} : { inputModalities },
|
|
1960
2699
|
...context === void 0 ? {} : { context: { contextWindow: context.contextWindow } },
|
|
1961
2700
|
...defaultMaxTokens === void 0 ? {} : { defaultMaxTokens },
|
|
1962
|
-
...resolved.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: resolved.systemPromptUpdate }
|
|
2701
|
+
...resolved.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: resolved.systemPromptUpdate },
|
|
2702
|
+
...resolved.toolUpdate === void 0 ? {} : { toolUpdate: resolved.toolUpdate }
|
|
1963
2703
|
};
|
|
1964
2704
|
const reasoning = resolved.reasoning;
|
|
1965
2705
|
if (reasoning === void 0) return info;
|
|
@@ -2031,20 +2771,33 @@ var LlmError = class extends HarnessError {
|
|
|
2031
2771
|
* Resolve one call under its current adapter registration. The returned
|
|
2032
2772
|
* one-shot handle keeps that registration across header logging and dispatch,
|
|
2033
2773
|
* so HMR cannot combine one adapter's capability result with another adapter.
|
|
2034
|
-
*
|
|
2774
|
+
* An optional synchronous callback selects concrete controls using captured
|
|
2775
|
+
* model metadata. Defaults and validation apply to its result. Callback
|
|
2776
|
+
* failures and cancellation reject preparation before dispatch.
|
|
2777
|
+
* @param config - provider/model route and optional concrete request controls.
|
|
2035
2778
|
* @param signal - optional cancellation for adapter-owned capability lookup.
|
|
2779
|
+
* @param configure - pure control selection, called once before defaults and validation.
|
|
2036
2780
|
* @returns a prepared config and its registration-bound stream entry point.
|
|
2037
2781
|
*/
|
|
2038
|
-
async prepareCall(config, signal) {
|
|
2039
|
-
|
|
2040
|
-
const
|
|
2041
|
-
const
|
|
2042
|
-
const
|
|
2782
|
+
async prepareCall(config, signal, configure) {
|
|
2783
|
+
signal?.throwIfAborted();
|
|
2784
|
+
const { provider, model, ...controls } = config;
|
|
2785
|
+
const registration = this.registration(provider);
|
|
2786
|
+
const adapterCall = await registration.adapter.prepareCall(provider, model, signal);
|
|
2787
|
+
signal?.throwIfAborted();
|
|
2788
|
+
const modelInfo = this.normalizeModelInfo(registration, model, adapterCall.model);
|
|
2789
|
+
const proposed = configure === void 0 ? config : {
|
|
2790
|
+
...configure(deepFreeze(structuredClone(controls)), deepFreeze(modelInfo)),
|
|
2791
|
+
provider,
|
|
2792
|
+
model
|
|
2793
|
+
};
|
|
2794
|
+
signal?.throwIfAborted();
|
|
2795
|
+
const resolved = this.resolveCallWithInfo(proposed, modelInfo);
|
|
2043
2796
|
const resolvedConfig = deepFreeze(structuredClone(resolved.config));
|
|
2044
2797
|
const context = resolved.context === void 0 ? void 0 : deepFreeze(structuredClone(resolved.context));
|
|
2045
2798
|
const adapterDefaults = deepFreeze({
|
|
2046
|
-
...
|
|
2047
|
-
...
|
|
2799
|
+
...proposed.reasoningEffort === void 0 && resolvedConfig.reasoningEffort !== void 0 ? { reasoningEffort: true } : {},
|
|
2800
|
+
...proposed.maxTokens === void 0 && resolvedConfig.maxTokens !== void 0 ? { maxTokens: true } : {}
|
|
2048
2801
|
});
|
|
2049
2802
|
let dispatched = false;
|
|
2050
2803
|
return Object.freeze({
|
|
@@ -2054,6 +2807,7 @@ var LlmError = class extends HarnessError {
|
|
|
2054
2807
|
...context === void 0 ? {} : { context },
|
|
2055
2808
|
...modelInfo.inputModalities === void 0 ? {} : { inputModalities: Object.freeze([...modelInfo.inputModalities]) },
|
|
2056
2809
|
...modelInfo.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: modelInfo.systemPromptUpdate },
|
|
2810
|
+
...modelInfo.toolUpdate === void 0 ? {} : { toolUpdate: modelInfo.toolUpdate },
|
|
2057
2811
|
stream: (options) => {
|
|
2058
2812
|
if (dispatched) throw new LlmError("a prepared LLM call can only be dispatched once", "INVALID_PREPARED_CALL");
|
|
2059
2813
|
if (!callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL");
|
|
@@ -2143,13 +2897,17 @@ var LlmError = class extends HarnessError {
|
|
|
2143
2897
|
let projectedMessages = resolvedOptions.messages;
|
|
2144
2898
|
if (projectedMessages.some((message) => contentHasFile(message.content))) projectedMessages = projectFilesToText(projectedMessages, (ref) => this.fileReadPath(ref));
|
|
2145
2899
|
if (modelInfo.inputModalities !== void 0 && !modelInfo.inputModalities.includes("image") && projectedMessages.some((message) => contentHasImage(message.content))) projectedMessages = projectImagesForTextModel(projectedMessages);
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2900
|
+
const projectedTools = projectToolUpdates(projectedMessages, resolvedOptions.tools, modelInfo.toolUpdate, resolvedOptions.toolHistory);
|
|
2901
|
+
projectedMessages = projectedTools.messages;
|
|
2902
|
+
let projectedOptions = resolvedOptions;
|
|
2903
|
+
if (projectedMessages !== resolvedOptions.messages || projectedTools.tools !== resolvedOptions.tools) {
|
|
2904
|
+
projectedOptions = {
|
|
2905
|
+
...resolvedOptions,
|
|
2906
|
+
messages: projectedMessages,
|
|
2907
|
+
...projectedTools.tools === void 0 ? {} : { tools: projectedTools.tools }
|
|
2908
|
+
};
|
|
2909
|
+
if (Object.isFrozen(resolvedOptions)) deepFreeze(projectedOptions);
|
|
2910
|
+
}
|
|
2153
2911
|
iterator = dispatch(this.forAdapter(projectedOptions, adapter))[Symbol.asyncIterator]();
|
|
2154
2912
|
} catch (error) {
|
|
2155
2913
|
yield adapterFailureChunk(error, options.signal);
|
|
@@ -2216,6 +2974,19 @@ function adapterFailureChunk(error, signal) {
|
|
|
2216
2974
|
}
|
|
2217
2975
|
};
|
|
2218
2976
|
}
|
|
2977
|
+
/** Copy a directory entry, including its arrays, so neither side can mutate the other's copy. */
|
|
2978
|
+
function detachDirectoryEntry(entry) {
|
|
2979
|
+
const { nativeAuth } = entry;
|
|
2980
|
+
return {
|
|
2981
|
+
...entry,
|
|
2982
|
+
settingsPath: [...entry.settingsPath],
|
|
2983
|
+
...entry.baseURLEnv === void 0 ? {} : { baseURLEnv: [...entry.baseURLEnv] },
|
|
2984
|
+
...nativeAuth === void 0 ? {} : { nativeAuth: {
|
|
2985
|
+
...nativeAuth,
|
|
2986
|
+
env: [...nativeAuth.env]
|
|
2987
|
+
} }
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2219
2990
|
//#endregion
|
|
2220
2991
|
//#region src/core/workspace-instruction-context.ts
|
|
2221
2992
|
const SYSTEM_REMINDER_OPEN = "<system-reminder>";
|
|
@@ -2318,4 +3089,4 @@ const inject = ["workspaceRegistry"];
|
|
|
2318
3089
|
//#endregion
|
|
2319
3090
|
export { registerWorkspaceInstructionInjector as a, name as i, escapeInstructionFrameBody as n, renderInstructionMessageText as o, inject as r, resolveSnapshotForSession as s, createInstructionMessage as t };
|
|
2320
3091
|
|
|
2321
|
-
//# sourceMappingURL=workspace-instruction-context-
|
|
3092
|
+
//# sourceMappingURL=workspace-instruction-context-DytAmaPY.js.map
|