llmz 0.9.11 → 0.9.13
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/dist/{common-DJkSpeqw.cjs → common-CaWHSEW4.cjs} +25 -5
- package/dist/{common-DuEhn6u3.js → common-P6vdw8Vv.js} +25 -5
- package/dist/{custom-client-BXhs5PpQ.cjs → custom-client-C3EnKARC.cjs} +1 -1
- package/dist/{custom-client-BvA4375q.js → custom-client-CZVu-wF4.js} +1 -1
- package/dist/{dual-modes-D3_Jtxv1.js → dual-modes-BdZuONje.js} +2 -2
- package/dist/{dual-modes-zxiDUl2A.cjs → dual-modes-D3cSQ8j4.cjs} +2 -2
- package/dist/{execute-BTImw3Hx.cjs → execute-DBMmurHH.cjs} +57 -11
- package/dist/{execute-Cr_TyTIE.js → execute-hoM7wiQS.js} +58 -12
- package/dist/index.cjs +7 -7
- package/dist/index.js +7 -7
- package/dist/index.workerd.js +69 -16
- package/dist/message-stream/response-parser.d.ts +12 -0
- package/package.json +2 -2
|
@@ -599,6 +599,13 @@ var StreamingMessageParser = class {
|
|
|
599
599
|
};
|
|
600
600
|
//#endregion
|
|
601
601
|
//#region src/message-stream/response-parser.ts
|
|
602
|
+
/**
|
|
603
|
+
* Text a model may write before ■start. Some models stream junk for minutes
|
|
604
|
+
* without ever opening the envelope; past this many characters, give up.
|
|
605
|
+
*/
|
|
606
|
+
const MAX_PREAMBLE_LENGTH = 8e3;
|
|
607
|
+
/** Text a model may write after ■end before the rest of its stream is ignored. */
|
|
608
|
+
const MAX_TRAILER_LENGTH = 2e3;
|
|
602
609
|
/** One wire format: a complete ■start … ■end envelope containing valid blocks. */
|
|
603
610
|
var ResponseParser = class {
|
|
604
611
|
_parser = new StreamingMessageParser();
|
|
@@ -611,9 +618,19 @@ var ResponseParser = class {
|
|
|
611
618
|
_finished = false;
|
|
612
619
|
_failure;
|
|
613
620
|
_trailer = "";
|
|
621
|
+
_preambleLength = 0;
|
|
614
622
|
get framed() {
|
|
615
623
|
return this._mode === "framed";
|
|
616
624
|
}
|
|
625
|
+
/** Whether ■end was received. Later text is only kept as a diagnostic. */
|
|
626
|
+
get closed() {
|
|
627
|
+
return this._closed;
|
|
628
|
+
}
|
|
629
|
+
/** The model is writing junk past either boundary: stop reading the stream. */
|
|
630
|
+
get done() {
|
|
631
|
+
if (this._closed) return this._trailer.length > MAX_TRAILER_LENGTH;
|
|
632
|
+
return this._mode === "detect" && this._preambleLength > 8e3;
|
|
633
|
+
}
|
|
617
634
|
get valid() {
|
|
618
635
|
return this._finished && this._closed && !this._failure;
|
|
619
636
|
}
|
|
@@ -637,7 +654,13 @@ var ResponseParser = class {
|
|
|
637
654
|
forward = "";
|
|
638
655
|
};
|
|
639
656
|
for (const char of chunk) {
|
|
657
|
+
if (this._closed) {
|
|
658
|
+
this._trailer += char;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (this.done) continue;
|
|
640
662
|
if (this._mode === "detect") {
|
|
663
|
+
this._preambleLength++;
|
|
641
664
|
if (this._discardPrefixLine) {
|
|
642
665
|
if (char === "\n") this._discardPrefixLine = false;
|
|
643
666
|
continue;
|
|
@@ -668,10 +691,6 @@ var ResponseParser = class {
|
|
|
668
691
|
}
|
|
669
692
|
continue;
|
|
670
693
|
}
|
|
671
|
-
if (this._closed) {
|
|
672
|
-
this._trailer += char;
|
|
673
|
-
continue;
|
|
674
|
-
}
|
|
675
694
|
if (this._boundary || char === "■") {
|
|
676
695
|
this._boundary += char;
|
|
677
696
|
if (this._boundary === "■end") {
|
|
@@ -693,7 +712,8 @@ var ResponseParser = class {
|
|
|
693
712
|
this._finished = true;
|
|
694
713
|
const events = [];
|
|
695
714
|
if (this._mode === "detect") {
|
|
696
|
-
if (this.
|
|
715
|
+
if (this.done) this._fail(`Missing ■start: no response envelope within ${MAX_PREAMBLE_LENGTH} characters`);
|
|
716
|
+
else if (this._prefix.trim() === "■start") this._mode = "framed";
|
|
697
717
|
else this._fail("Missing ■start: every response must begin with the response envelope");
|
|
698
718
|
this._prefix = "";
|
|
699
719
|
}
|
|
@@ -599,6 +599,13 @@ var StreamingMessageParser = class {
|
|
|
599
599
|
};
|
|
600
600
|
//#endregion
|
|
601
601
|
//#region src/message-stream/response-parser.ts
|
|
602
|
+
/**
|
|
603
|
+
* Text a model may write before ■start. Some models stream junk for minutes
|
|
604
|
+
* without ever opening the envelope; past this many characters, give up.
|
|
605
|
+
*/
|
|
606
|
+
const MAX_PREAMBLE_LENGTH = 8e3;
|
|
607
|
+
/** Text a model may write after ■end before the rest of its stream is ignored. */
|
|
608
|
+
const MAX_TRAILER_LENGTH = 2e3;
|
|
602
609
|
/** One wire format: a complete ■start … ■end envelope containing valid blocks. */
|
|
603
610
|
var ResponseParser = class {
|
|
604
611
|
_parser = new StreamingMessageParser();
|
|
@@ -611,9 +618,19 @@ var ResponseParser = class {
|
|
|
611
618
|
_finished = false;
|
|
612
619
|
_failure;
|
|
613
620
|
_trailer = "";
|
|
621
|
+
_preambleLength = 0;
|
|
614
622
|
get framed() {
|
|
615
623
|
return this._mode === "framed";
|
|
616
624
|
}
|
|
625
|
+
/** Whether ■end was received. Later text is only kept as a diagnostic. */
|
|
626
|
+
get closed() {
|
|
627
|
+
return this._closed;
|
|
628
|
+
}
|
|
629
|
+
/** The model is writing junk past either boundary: stop reading the stream. */
|
|
630
|
+
get done() {
|
|
631
|
+
if (this._closed) return this._trailer.length > MAX_TRAILER_LENGTH;
|
|
632
|
+
return this._mode === "detect" && this._preambleLength > 8e3;
|
|
633
|
+
}
|
|
617
634
|
get valid() {
|
|
618
635
|
return this._finished && this._closed && !this._failure;
|
|
619
636
|
}
|
|
@@ -637,7 +654,13 @@ var ResponseParser = class {
|
|
|
637
654
|
forward = "";
|
|
638
655
|
};
|
|
639
656
|
for (const char of chunk) {
|
|
657
|
+
if (this._closed) {
|
|
658
|
+
this._trailer += char;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (this.done) continue;
|
|
640
662
|
if (this._mode === "detect") {
|
|
663
|
+
this._preambleLength++;
|
|
641
664
|
if (this._discardPrefixLine) {
|
|
642
665
|
if (char === "\n") this._discardPrefixLine = false;
|
|
643
666
|
continue;
|
|
@@ -668,10 +691,6 @@ var ResponseParser = class {
|
|
|
668
691
|
}
|
|
669
692
|
continue;
|
|
670
693
|
}
|
|
671
|
-
if (this._closed) {
|
|
672
|
-
this._trailer += char;
|
|
673
|
-
continue;
|
|
674
|
-
}
|
|
675
694
|
if (this._boundary || char === "■") {
|
|
676
695
|
this._boundary += char;
|
|
677
696
|
if (this._boundary === "■end") {
|
|
@@ -693,7 +712,8 @@ var ResponseParser = class {
|
|
|
693
712
|
this._finished = true;
|
|
694
713
|
const events = [];
|
|
695
714
|
if (this._mode === "detect") {
|
|
696
|
-
if (this.
|
|
715
|
+
if (this.done) this._fail(`Missing ■start: no response envelope within ${MAX_PREAMBLE_LENGTH} characters`);
|
|
716
|
+
else if (this._prefix.trim() === "■start") this._mode = "framed";
|
|
697
717
|
else this._fail("Missing ■start: every response must begin with the response envelope");
|
|
698
718
|
this._prefix = "";
|
|
699
719
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dual_modes = require("./dual-modes-
|
|
1
|
+
const require_dual_modes = require("./dual-modes-D3cSQ8j4.cjs");
|
|
2
2
|
const require__overArg = require("./_overArg-C5Hy7oCi.cjs");
|
|
3
3
|
const require__baseIteratee = require("./_baseIteratee-CF4qP2a8.cjs");
|
|
4
4
|
const require_utils = require("./utils-DGQ4sRke.cjs");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as flatRest, i as inspect, o as copyArray, r as extractType, s as baseCreate, t as DualModePrompt } from "./dual-modes-
|
|
1
|
+
import { a as flatRest, i as inspect, o as copyArray, r as extractType, s as baseCreate, t as DualModePrompt } from "./dual-modes-BdZuONje.js";
|
|
2
2
|
import { a as Symbol, n as isArray, o as root, r as isObjectLike } from "./_overArg-CRYbj1NH.js";
|
|
3
3
|
import { D as isBuffer, E as baseUnary, M as baseAssignValue, R as isObject, T as nodeUtil, _ as baseGet, c as _getTag_default, f as getSymbols, h as Stack, k as isPrototype, s as Uint8Array, u as getAllKeys, v as toKey, x as keys, y as castPath, z as arrayMap } from "./_baseIteratee-P_firB7b.js";
|
|
4
4
|
import { _ as getSymbolsIn, b as keysIn, g as getAllKeysIn, i as getErrorMessage, o as getTokenizer, x as assignValue, y as baseSlice } from "./utils-UBeAFeEI.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.js";
|
|
2
|
-
import { l as NAME_REGEX, n as parseAssistantResponse, r as replacePlaceholders } from "./common-
|
|
2
|
+
import { l as NAME_REGEX, n as parseAssistantResponse, r as replacePlaceholders } from "./common-P6vdw8Vv.js";
|
|
3
3
|
import { a as Symbol, n as isArray, r as isObjectLike } from "./_overArg-CRYbj1NH.js";
|
|
4
4
|
import { A as isArrayLike, B as isSymbol, E as baseUnary, F as WeakMap, L as identity, M as baseAssignValue, O as isArguments, P as defineProperty, R as isObject, _ as baseGet, c as _getTag_default, g as arrayPush, i as mapToArray, m as arrayFilter, t as baseIteratee, x as keys, z as arrayMap } from "./_baseIteratee-P_firB7b.js";
|
|
5
5
|
import { n as noop, t as uniq } from "./uniq-eZWVMz0r.js";
|
|
@@ -754,7 +754,7 @@ const renderExamples = async (examples, components, exits) => {
|
|
|
754
754
|
if (!examples.length) return "";
|
|
755
755
|
const registry = new ComponentRegistry(components.map(componentToProtocolDefinition));
|
|
756
756
|
const exitDefinitions = exits.map(exitToProtocolDefinition);
|
|
757
|
-
const { parseAssistantResponse } = await import("./common-
|
|
757
|
+
const { parseAssistantResponse } = await import("./common-P6vdw8Vv.js").then((n) => n.t);
|
|
758
758
|
const render = (output) => {
|
|
759
759
|
var _response$diagnostics;
|
|
760
760
|
const response = parseAssistantResponse(`■start\n${output}\n■end`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_compiler = require("./compiler-BJJUmNS9.cjs");
|
|
2
|
-
const require_common = require("./common-
|
|
2
|
+
const require_common = require("./common-CaWHSEW4.cjs");
|
|
3
3
|
const require__overArg = require("./_overArg-C5Hy7oCi.cjs");
|
|
4
4
|
const require__baseIteratee = require("./_baseIteratee-CF4qP2a8.cjs");
|
|
5
5
|
const require_uniq = require("./uniq-BWs20_o8.cjs");
|
|
@@ -755,7 +755,7 @@ const renderExamples = async (examples, components, exits) => {
|
|
|
755
755
|
if (!examples.length) return "";
|
|
756
756
|
const registry = new ComponentRegistry(components.map(componentToProtocolDefinition));
|
|
757
757
|
const exitDefinitions = exits.map(exitToProtocolDefinition);
|
|
758
|
-
const { parseAssistantResponse } = await Promise.resolve().then(() => require("./common-
|
|
758
|
+
const { parseAssistantResponse } = await Promise.resolve().then(() => require("./common-CaWHSEW4.cjs")).then((n) => n.common_exports);
|
|
759
759
|
const render = (output) => {
|
|
760
760
|
var _response$diagnostics;
|
|
761
761
|
const response = parseAssistantResponse(`■start\n${output}\n■end`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_compiler = require("./compiler-BJJUmNS9.cjs");
|
|
2
|
-
const require_dual_modes = require("./dual-modes-
|
|
3
|
-
const require_common = require("./common-
|
|
2
|
+
const require_dual_modes = require("./dual-modes-D3cSQ8j4.cjs");
|
|
3
|
+
const require_common = require("./common-CaWHSEW4.cjs");
|
|
4
4
|
const require__baseIteratee = require("./_baseIteratee-CF4qP2a8.cjs");
|
|
5
|
-
const require_custom_client = require("./custom-client-
|
|
5
|
+
const require_custom_client = require("./custom-client-C3EnKARC.cjs");
|
|
6
6
|
const require_utils = require("./utils-DGQ4sRke.cjs");
|
|
7
7
|
const require_jsx = require("./jsx-BJ6GWXI2.cjs");
|
|
8
8
|
const require_stack_traces = require("./stack-traces-ntw_qhoy.cjs");
|
|
@@ -157,11 +157,44 @@ const RESPONSE_LENGTH_BUFFER = {
|
|
|
157
157
|
};
|
|
158
158
|
/** Maximum time to wait between two stream chunks before considering the stream stalled. */
|
|
159
159
|
const STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
160
|
+
/**
|
|
161
|
+
* How long to keep reading after ■end for the provider's final chunk. Models
|
|
162
|
+
* that ignore the stop sequence can otherwise stream junk until the caller's deadline.
|
|
163
|
+
*/
|
|
164
|
+
const STREAM_END_GRACE_PERIOD = 1e3;
|
|
160
165
|
/** A syntactically valid prefix must not execute when generation did not finish successfully. */
|
|
161
166
|
const assertSuccessfulGeneration = (metadata) => {
|
|
162
167
|
if (metadata.provider === "unknown") throw new require_errors.CognitiveError("LLM generation failed: received error metadata with unknown provider");
|
|
163
168
|
if (metadata.stopReason === "max_tokens" || metadata.stopReason === "content_filter" || metadata.stopReason === "other") throw new require_errors.CognitiveError(`LLM generation did not complete: stopReason=${metadata.stopReason}`);
|
|
164
169
|
};
|
|
170
|
+
/**
|
|
171
|
+
* Cognitive sends usage only in the final chunk, which is never read when the
|
|
172
|
+
* stream is closed early. Estimate it from the messages sent and the output.
|
|
173
|
+
*/
|
|
174
|
+
const estimateMetadata = (model, messages, output) => {
|
|
175
|
+
const tokenizer = require_utils.getTokenizer();
|
|
176
|
+
const countMessage = (message) => {
|
|
177
|
+
if (typeof message.content === "string") return tokenizer.count(message.content);
|
|
178
|
+
return (message.content ?? []).map((part) => part.type === "text" ? part.text ?? "" : "").reduce((sum, text) => sum + tokenizer.count(text), 0);
|
|
179
|
+
};
|
|
180
|
+
const inputTokens = messages.reduce((total, message) => total + countMessage(message), 0);
|
|
181
|
+
const outputTokens = tokenizer.count(output);
|
|
182
|
+
const inputCost = inputTokens * model.input.costPer1MTokens / 1e6;
|
|
183
|
+
const outputCost = outputTokens * model.output.costPer1MTokens / 1e6;
|
|
184
|
+
const [provider, ...name] = model.id.split(":");
|
|
185
|
+
return {
|
|
186
|
+
provider,
|
|
187
|
+
model: name.join(":"),
|
|
188
|
+
usage: {
|
|
189
|
+
inputTokens,
|
|
190
|
+
inputCost,
|
|
191
|
+
outputTokens,
|
|
192
|
+
outputCost
|
|
193
|
+
},
|
|
194
|
+
cost: inputCost + outputCost,
|
|
195
|
+
stopReason: "stop"
|
|
196
|
+
};
|
|
197
|
+
};
|
|
165
198
|
const getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
166
199
|
const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, onSend, onSendDelta, onRunStart }) => {
|
|
167
200
|
const startedAt = Date.now();
|
|
@@ -279,16 +312,14 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
279
312
|
} } : {}
|
|
280
313
|
}, { signal: streamController.signal });
|
|
281
314
|
const inactivityTimeout = Math.max(STREAM_INACTIVITY_TIMEOUT, ctx.maxTimeToFirstToken ?? 0);
|
|
282
|
-
|
|
315
|
+
/** Resolves to undefined when no chunk arrives within the timeout. */
|
|
316
|
+
const nextChunk = async (timeout) => {
|
|
283
317
|
let timer;
|
|
284
|
-
const
|
|
285
|
-
timer = setTimeout(() =>
|
|
286
|
-
streamController.abort("LLM stream stalled");
|
|
287
|
-
reject(/* @__PURE__ */ new Error(`LLM stream stalled: no data received for ${inactivityTimeout}ms`));
|
|
288
|
-
}, inactivityTimeout);
|
|
318
|
+
const expired = new Promise((resolve) => {
|
|
319
|
+
timer = setTimeout(() => resolve(void 0), timeout);
|
|
289
320
|
});
|
|
290
321
|
try {
|
|
291
|
-
return await Promise.race([stream.next(),
|
|
322
|
+
return await Promise.race([stream.next(), expired]);
|
|
292
323
|
} finally {
|
|
293
324
|
clearTimeout(timer);
|
|
294
325
|
}
|
|
@@ -296,15 +327,22 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
296
327
|
raw = "";
|
|
297
328
|
let streamCompleted = false;
|
|
298
329
|
let accepted = false;
|
|
330
|
+
let closedAt;
|
|
331
|
+
let servedModel = model.id;
|
|
299
332
|
try {
|
|
300
333
|
while (true) {
|
|
301
334
|
var _chunk$value, _chunk$value2, _chunk$value3, _chunk$value4;
|
|
302
335
|
let chunk;
|
|
303
336
|
try {
|
|
304
|
-
chunk = await nextChunk();
|
|
337
|
+
chunk = await nextChunk(closedAt === void 0 ? inactivityTimeout : closedAt + STREAM_END_GRACE_PERIOD - Date.now());
|
|
305
338
|
} catch (thrown) {
|
|
306
339
|
throw new require_errors.CognitiveError(`LLM generation failed: ${require_utils.getErrorMessage(thrown)}`);
|
|
307
340
|
}
|
|
341
|
+
if (!chunk && closedAt !== void 0) break;
|
|
342
|
+
if (!chunk) {
|
|
343
|
+
streamController.abort("LLM stream stalled");
|
|
344
|
+
throw new require_errors.CognitiveError(`LLM generation failed: LLM stream stalled: no data received for ${inactivityTimeout}ms`);
|
|
345
|
+
}
|
|
308
346
|
if (chunk.done) {
|
|
309
347
|
streamCompleted = true;
|
|
310
348
|
break;
|
|
@@ -323,12 +361,14 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
323
361
|
completions = [];
|
|
324
362
|
accepted = false;
|
|
325
363
|
parser = new require_common.ResponseParser();
|
|
364
|
+
closedAt = void 0;
|
|
326
365
|
liveItems.clear();
|
|
327
366
|
liveContent.clear();
|
|
328
367
|
codeGenerationTraced = false;
|
|
329
368
|
runCompleted = false;
|
|
330
369
|
responseMetadata = void 0;
|
|
331
370
|
attempt = chunk.value.restart.attempt;
|
|
371
|
+
servedModel = chunk.value.restart.toModel;
|
|
332
372
|
await preview({
|
|
333
373
|
...chunk.value.restart,
|
|
334
374
|
restart: true,
|
|
@@ -345,6 +385,12 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
345
385
|
timeToFirstToken ??= timeToLastToken;
|
|
346
386
|
raw += delta;
|
|
347
387
|
await dispatchSends(parser.push(delta));
|
|
388
|
+
if (parser.done) break;
|
|
389
|
+
if (parser.closed) closedAt ??= Date.now();
|
|
390
|
+
}
|
|
391
|
+
if (!responseMetadata && !streamCompleted) {
|
|
392
|
+
const served = models.find((details) => details.id === servedModel) ?? await cognitive.getModelDetails(servedModel).catch(() => model);
|
|
393
|
+
responseMetadata = estimateMetadata(served, messages, raw);
|
|
348
394
|
}
|
|
349
395
|
if (!responseMetadata) throw new require_errors.CognitiveError("LLM streaming completed without metadata");
|
|
350
396
|
assertSuccessfulGeneration(responseMetadata);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { c as toNumber } from "./dual-modes-
|
|
2
|
-
import { a as ResponseParser, i as toParsedAssistantResponse } from "./common-
|
|
1
|
+
import { c as toNumber } from "./dual-modes-BdZuONje.js";
|
|
2
|
+
import { a as ResponseParser, i as toParsedAssistantResponse } from "./common-P6vdw8Vv.js";
|
|
3
3
|
import { n as baseIsEqual } from "./_baseIteratee-P_firB7b.js";
|
|
4
|
-
import { d as Snapshot, f as parseExit, l as PartialExecutionResult, n as Context, s as ErrorExecutionResult, t as _CustomModelClient, u as SuccessExecutionResult } from "./custom-client-
|
|
5
|
-
import { d as stripInvalidIdentifiers, i as getErrorMessage, r as fromJSONSchemaCompat, s as init } from "./utils-UBeAFeEI.js";
|
|
4
|
+
import { d as Snapshot, f as parseExit, l as PartialExecutionResult, n as Context, s as ErrorExecutionResult, t as _CustomModelClient, u as SuccessExecutionResult } from "./custom-client-CZVu-wF4.js";
|
|
5
|
+
import { d as stripInvalidIdentifiers, i as getErrorMessage, o as getTokenizer, r as fromJSONSchemaCompat, s as init } from "./utils-UBeAFeEI.js";
|
|
6
6
|
import { t as createJsxComponent } from "./jsx-CIgdGGVs.js";
|
|
7
7
|
import { t as cleanStackTrace } from "./stack-traces-BIE_5Xwf.js";
|
|
8
8
|
import { a as InvalidCodeError, c as SnapshotSignal, i as CognitiveError, l as ThinkSignal, n as CodeExecutionError, o as LoopExceededError, s as Signals, t as AssignmentError } from "./errors-Cg1G0Awu.js";
|
|
@@ -156,11 +156,44 @@ const RESPONSE_LENGTH_BUFFER = {
|
|
|
156
156
|
};
|
|
157
157
|
/** Maximum time to wait between two stream chunks before considering the stream stalled. */
|
|
158
158
|
const STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
159
|
+
/**
|
|
160
|
+
* How long to keep reading after ■end for the provider's final chunk. Models
|
|
161
|
+
* that ignore the stop sequence can otherwise stream junk until the caller's deadline.
|
|
162
|
+
*/
|
|
163
|
+
const STREAM_END_GRACE_PERIOD = 1e3;
|
|
159
164
|
/** A syntactically valid prefix must not execute when generation did not finish successfully. */
|
|
160
165
|
const assertSuccessfulGeneration = (metadata) => {
|
|
161
166
|
if (metadata.provider === "unknown") throw new CognitiveError("LLM generation failed: received error metadata with unknown provider");
|
|
162
167
|
if (metadata.stopReason === "max_tokens" || metadata.stopReason === "content_filter" || metadata.stopReason === "other") throw new CognitiveError(`LLM generation did not complete: stopReason=${metadata.stopReason}`);
|
|
163
168
|
};
|
|
169
|
+
/**
|
|
170
|
+
* Cognitive sends usage only in the final chunk, which is never read when the
|
|
171
|
+
* stream is closed early. Estimate it from the messages sent and the output.
|
|
172
|
+
*/
|
|
173
|
+
const estimateMetadata = (model, messages, output) => {
|
|
174
|
+
const tokenizer = getTokenizer();
|
|
175
|
+
const countMessage = (message) => {
|
|
176
|
+
if (typeof message.content === "string") return tokenizer.count(message.content);
|
|
177
|
+
return (message.content ?? []).map((part) => part.type === "text" ? part.text ?? "" : "").reduce((sum, text) => sum + tokenizer.count(text), 0);
|
|
178
|
+
};
|
|
179
|
+
const inputTokens = messages.reduce((total, message) => total + countMessage(message), 0);
|
|
180
|
+
const outputTokens = tokenizer.count(output);
|
|
181
|
+
const inputCost = inputTokens * model.input.costPer1MTokens / 1e6;
|
|
182
|
+
const outputCost = outputTokens * model.output.costPer1MTokens / 1e6;
|
|
183
|
+
const [provider, ...name] = model.id.split(":");
|
|
184
|
+
return {
|
|
185
|
+
provider,
|
|
186
|
+
model: name.join(":"),
|
|
187
|
+
usage: {
|
|
188
|
+
inputTokens,
|
|
189
|
+
inputCost,
|
|
190
|
+
outputTokens,
|
|
191
|
+
outputCost
|
|
192
|
+
},
|
|
193
|
+
cost: inputCost + outputCost,
|
|
194
|
+
stopReason: "stop"
|
|
195
|
+
};
|
|
196
|
+
};
|
|
164
197
|
const getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
165
198
|
const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, onSend, onSendDelta, onRunStart }) => {
|
|
166
199
|
const startedAt = Date.now();
|
|
@@ -278,16 +311,14 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
278
311
|
} } : {}
|
|
279
312
|
}, { signal: streamController.signal });
|
|
280
313
|
const inactivityTimeout = Math.max(STREAM_INACTIVITY_TIMEOUT, ctx.maxTimeToFirstToken ?? 0);
|
|
281
|
-
|
|
314
|
+
/** Resolves to undefined when no chunk arrives within the timeout. */
|
|
315
|
+
const nextChunk = async (timeout) => {
|
|
282
316
|
let timer;
|
|
283
|
-
const
|
|
284
|
-
timer = setTimeout(() =>
|
|
285
|
-
streamController.abort("LLM stream stalled");
|
|
286
|
-
reject(/* @__PURE__ */ new Error(`LLM stream stalled: no data received for ${inactivityTimeout}ms`));
|
|
287
|
-
}, inactivityTimeout);
|
|
317
|
+
const expired = new Promise((resolve) => {
|
|
318
|
+
timer = setTimeout(() => resolve(void 0), timeout);
|
|
288
319
|
});
|
|
289
320
|
try {
|
|
290
|
-
return await Promise.race([stream.next(),
|
|
321
|
+
return await Promise.race([stream.next(), expired]);
|
|
291
322
|
} finally {
|
|
292
323
|
clearTimeout(timer);
|
|
293
324
|
}
|
|
@@ -295,15 +326,22 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
295
326
|
raw = "";
|
|
296
327
|
let streamCompleted = false;
|
|
297
328
|
let accepted = false;
|
|
329
|
+
let closedAt;
|
|
330
|
+
let servedModel = model.id;
|
|
298
331
|
try {
|
|
299
332
|
while (true) {
|
|
300
333
|
var _chunk$value, _chunk$value2, _chunk$value3, _chunk$value4;
|
|
301
334
|
let chunk;
|
|
302
335
|
try {
|
|
303
|
-
chunk = await nextChunk();
|
|
336
|
+
chunk = await nextChunk(closedAt === void 0 ? inactivityTimeout : closedAt + STREAM_END_GRACE_PERIOD - Date.now());
|
|
304
337
|
} catch (thrown) {
|
|
305
338
|
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
306
339
|
}
|
|
340
|
+
if (!chunk && closedAt !== void 0) break;
|
|
341
|
+
if (!chunk) {
|
|
342
|
+
streamController.abort("LLM stream stalled");
|
|
343
|
+
throw new CognitiveError(`LLM generation failed: LLM stream stalled: no data received for ${inactivityTimeout}ms`);
|
|
344
|
+
}
|
|
307
345
|
if (chunk.done) {
|
|
308
346
|
streamCompleted = true;
|
|
309
347
|
break;
|
|
@@ -322,12 +360,14 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
322
360
|
completions = [];
|
|
323
361
|
accepted = false;
|
|
324
362
|
parser = new ResponseParser();
|
|
363
|
+
closedAt = void 0;
|
|
325
364
|
liveItems.clear();
|
|
326
365
|
liveContent.clear();
|
|
327
366
|
codeGenerationTraced = false;
|
|
328
367
|
runCompleted = false;
|
|
329
368
|
responseMetadata = void 0;
|
|
330
369
|
attempt = chunk.value.restart.attempt;
|
|
370
|
+
servedModel = chunk.value.restart.toModel;
|
|
331
371
|
await preview({
|
|
332
372
|
...chunk.value.restart,
|
|
333
373
|
restart: true,
|
|
@@ -344,6 +384,12 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
344
384
|
timeToFirstToken ??= timeToLastToken;
|
|
345
385
|
raw += delta;
|
|
346
386
|
await dispatchSends(parser.push(delta));
|
|
387
|
+
if (parser.done) break;
|
|
388
|
+
if (parser.closed) closedAt ??= Date.now();
|
|
389
|
+
}
|
|
390
|
+
if (!responseMetadata && !streamCompleted) {
|
|
391
|
+
const served = models.find((details) => details.id === servedModel) ?? await cognitive.getModelDetails(servedModel).catch(() => model);
|
|
392
|
+
responseMetadata = estimateMetadata(served, messages, raw);
|
|
347
393
|
}
|
|
348
394
|
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
349
395
|
assertSuccessfulGeneration(responseMetadata);
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dual_modes = require("./dual-modes-
|
|
3
|
-
const require_common = require("./common-
|
|
4
|
-
const require_custom_client = require("./custom-client-
|
|
2
|
+
const require_dual_modes = require("./dual-modes-D3cSQ8j4.cjs");
|
|
3
|
+
const require_common = require("./common-CaWHSEW4.cjs");
|
|
4
|
+
const require_custom_client = require("./custom-client-C3EnKARC.cjs");
|
|
5
5
|
const require_utils = require("./utils-DGQ4sRke.cjs");
|
|
6
6
|
const require_tool = require("./tool-ikMsh-TB.cjs");
|
|
7
7
|
const require_errors = require("./errors-C962uJdS.cjs");
|
|
@@ -12,7 +12,7 @@ const require_truncator = require("./truncator-DmCu9M4m.cjs");
|
|
|
12
12
|
const require_quickjs_variant = require("./quickjs-variant-CsIwTVFC.cjs");
|
|
13
13
|
let _bpinternal_zui = require("@bpinternal/zui");
|
|
14
14
|
//#region package.json
|
|
15
|
-
var version = "0.9.
|
|
15
|
+
var version = "0.9.13";
|
|
16
16
|
//#endregion
|
|
17
17
|
//#region src/hoist.ts
|
|
18
18
|
/**
|
|
@@ -1693,7 +1693,7 @@ const utils = {
|
|
|
1693
1693
|
* })
|
|
1694
1694
|
*/
|
|
1695
1695
|
const execute = async (props) => {
|
|
1696
|
-
const { executeContext } = await Promise.resolve().then(() => require("./execute-
|
|
1696
|
+
const { executeContext } = await Promise.resolve().then(() => require("./execute-DBMmurHH.cjs"));
|
|
1697
1697
|
return executeContext(props);
|
|
1698
1698
|
};
|
|
1699
1699
|
/**
|
|
@@ -1702,7 +1702,7 @@ const execute = async (props) => {
|
|
|
1702
1702
|
* It's recommended to call this function at the beginning of your application without awaiting it (void init())
|
|
1703
1703
|
*/
|
|
1704
1704
|
const init = async () => {
|
|
1705
|
-
await Promise.resolve().then(() => require("./execute-
|
|
1705
|
+
await Promise.resolve().then(() => require("./execute-DBMmurHH.cjs"));
|
|
1706
1706
|
await Promise.resolve().then(() => require("./component-CPKXe6Ca.cjs")).then((n) => n.component_exports);
|
|
1707
1707
|
await Promise.resolve().then(() => require("./tool-ikMsh-TB.cjs")).then((n) => n.tool_exports);
|
|
1708
1708
|
await Promise.resolve().then(() => require("./exit-DTDB1SJ3.cjs")).then((n) => n.exit_exports);
|
|
@@ -1711,7 +1711,7 @@ const init = async () => {
|
|
|
1711
1711
|
await Promise.resolve().then(() => require("./utils-DGQ4sRke.cjs")).then((n) => n.utils_exports);
|
|
1712
1712
|
await Promise.resolve().then(() => require("./truncator-DmCu9M4m.cjs")).then((n) => n.truncator_exports);
|
|
1713
1713
|
await Promise.resolve().then(() => require("./typings-DXJMu59O.cjs")).then((n) => n.typings_exports);
|
|
1714
|
-
await Promise.resolve().then(() => require("./dual-modes-
|
|
1714
|
+
await Promise.resolve().then(() => require("./dual-modes-D3cSQ8j4.cjs")).then((n) => n.dual_modes_exports);
|
|
1715
1715
|
};
|
|
1716
1716
|
//#endregion
|
|
1717
1717
|
exports.BaseResponse = BaseResponse;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { d as validateComponent, f as validateProps, l as Example, p as ComponentRegistry, u as generateInstructions } from "./dual-modes-
|
|
2
|
-
import { c as MARKER, l as NAME_REGEX, o as StreamingMessageParser, s as tryParseJson } from "./common-
|
|
3
|
-
import { a as ThinkExit, c as ExecutionResult, d as Snapshot, f as parseExit, i as ListenExit, l as PartialExecutionResult, o as getValue, r as DefaultExit, s as ErrorExecutionResult, t as _CustomModelClient, u as SuccessExecutionResult } from "./custom-client-
|
|
1
|
+
import { d as validateComponent, f as validateProps, l as Example, p as ComponentRegistry, u as generateInstructions } from "./dual-modes-BdZuONje.js";
|
|
2
|
+
import { c as MARKER, l as NAME_REGEX, o as StreamingMessageParser, s as tryParseJson } from "./common-P6vdw8Vv.js";
|
|
3
|
+
import { a as ThinkExit, c as ExecutionResult, d as Snapshot, f as parseExit, i as ListenExit, l as PartialExecutionResult, o as getValue, r as DefaultExit, s as ErrorExecutionResult, t as _CustomModelClient, u as SuccessExecutionResult } from "./custom-client-CZVu-wF4.js";
|
|
4
4
|
import { a as getMultilineComment, c as isJsonSchema, l as isValidIdentifier, m as toValidObjectName, n as escapeString, p as toValidFunctionName, t as configureTokenizer, u as isZuiSchema, v as upperFirst } from "./utils-UBeAFeEI.js";
|
|
5
5
|
import { t as Tool } from "./tool-BoXBgZeM.js";
|
|
6
6
|
import { c as SnapshotSignal, l as ThinkSignal, o as LoopExceededError, r as CodeFormattingError } from "./errors-Cg1G0Awu.js";
|
|
@@ -11,7 +11,7 @@ import { i as wrapContent, n as truncateWrappedContent, t as stripTruncationTags
|
|
|
11
11
|
import { t as configureQuickJS } from "./quickjs-variant-BYhMBpwU.js";
|
|
12
12
|
import { transforms, z } from "@bpinternal/zui";
|
|
13
13
|
//#region package.json
|
|
14
|
-
var version = "0.9.
|
|
14
|
+
var version = "0.9.13";
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/hoist.ts
|
|
17
17
|
/**
|
|
@@ -1692,7 +1692,7 @@ const utils = {
|
|
|
1692
1692
|
* })
|
|
1693
1693
|
*/
|
|
1694
1694
|
const execute = async (props) => {
|
|
1695
|
-
const { executeContext } = await import("./execute-
|
|
1695
|
+
const { executeContext } = await import("./execute-hoM7wiQS.js");
|
|
1696
1696
|
return executeContext(props);
|
|
1697
1697
|
};
|
|
1698
1698
|
/**
|
|
@@ -1701,7 +1701,7 @@ const execute = async (props) => {
|
|
|
1701
1701
|
* It's recommended to call this function at the beginning of your application without awaiting it (void init())
|
|
1702
1702
|
*/
|
|
1703
1703
|
const init = async () => {
|
|
1704
|
-
await import("./execute-
|
|
1704
|
+
await import("./execute-hoM7wiQS.js");
|
|
1705
1705
|
await import("./component-DGG7d_Mz.js").then((n) => n.r);
|
|
1706
1706
|
await import("./tool-BoXBgZeM.js").then((n) => n.n);
|
|
1707
1707
|
await import("./exit-AwQk1cyW.js").then((n) => n.n);
|
|
@@ -1710,7 +1710,7 @@ const init = async () => {
|
|
|
1710
1710
|
await import("./utils-UBeAFeEI.js").then((n) => n.h);
|
|
1711
1711
|
await import("./truncator-CD7QtE84.js").then((n) => n.r);
|
|
1712
1712
|
await import("./typings-CrBa7Tyy.js").then((n) => n.n);
|
|
1713
|
-
await import("./dual-modes-
|
|
1713
|
+
await import("./dual-modes-BdZuONje.js").then((n) => n.n);
|
|
1714
1714
|
};
|
|
1715
1715
|
//#endregion
|
|
1716
1716
|
export { BaseResponse, Chat, CitationsManager, Component, ComponentRegistry, DefaultComponents, DefaultExit, ErrorExecutionResult, Example, ExecutionResult, Exit, ListenExit, LoopExceededError, MARKER, NAME_REGEX, NextResponse, ObjectInstance, PartialExecutionResult, ReplayableAsyncIterable, RunResponse, SendResponse, Snapshot, SnapshotSignal, StreamingMessageParser, SuccessExecutionResult, ThinkExit, ThinkSignal, Tool, _CustomModelClient, assertValidComponent, collectText, configureQuickJS, configureTokenizer, execute, generateInstructions, getValue, init, isAnyComponent, isComponent, normalizeComponentDefinition, normalizeComponentName, normalizePropsSchema, parseExit, parseStream, parseText, sanitizeMessageText, tryParseJson, utils, validateComponent, validateProps, version };
|
package/dist/index.workerd.js
CHANGED
|
@@ -52,7 +52,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
52
52
|
}) : target, mod));
|
|
53
53
|
//#endregion
|
|
54
54
|
//#region package.json
|
|
55
|
-
var version = "0.9.
|
|
55
|
+
var version = "0.9.13", quoteExample, quotePartialExample, exampleBoundaryInstructions, quoteResponseExample;
|
|
56
56
|
var init_example_format = __esmMin((() => {
|
|
57
57
|
quoteExample = (output) => `"""\n${output}\n"""`;
|
|
58
58
|
quotePartialExample = (output) => quoteExample(`(...)\n${output}\n(...)`);
|
|
@@ -1746,10 +1746,12 @@ var init_parser = __esmMin((() => {
|
|
|
1746
1746
|
}));
|
|
1747
1747
|
//#endregion
|
|
1748
1748
|
//#region src/message-stream/response-parser.ts
|
|
1749
|
-
var ResponseParser;
|
|
1749
|
+
var MAX_PREAMBLE_LENGTH, MAX_TRAILER_LENGTH, ResponseParser;
|
|
1750
1750
|
var init_response_parser = __esmMin((() => {
|
|
1751
1751
|
init_compiler();
|
|
1752
1752
|
init_parser();
|
|
1753
|
+
MAX_PREAMBLE_LENGTH = 8e3;
|
|
1754
|
+
MAX_TRAILER_LENGTH = 2e3;
|
|
1753
1755
|
ResponseParser = class {
|
|
1754
1756
|
_parser = new StreamingMessageParser();
|
|
1755
1757
|
_mode = "detect";
|
|
@@ -1761,9 +1763,19 @@ var init_response_parser = __esmMin((() => {
|
|
|
1761
1763
|
_finished = false;
|
|
1762
1764
|
_failure;
|
|
1763
1765
|
_trailer = "";
|
|
1766
|
+
_preambleLength = 0;
|
|
1764
1767
|
get framed() {
|
|
1765
1768
|
return this._mode === "framed";
|
|
1766
1769
|
}
|
|
1770
|
+
/** Whether ■end was received. Later text is only kept as a diagnostic. */
|
|
1771
|
+
get closed() {
|
|
1772
|
+
return this._closed;
|
|
1773
|
+
}
|
|
1774
|
+
/** The model is writing junk past either boundary: stop reading the stream. */
|
|
1775
|
+
get done() {
|
|
1776
|
+
if (this._closed) return this._trailer.length > MAX_TRAILER_LENGTH;
|
|
1777
|
+
return this._mode === "detect" && this._preambleLength > 8e3;
|
|
1778
|
+
}
|
|
1767
1779
|
get valid() {
|
|
1768
1780
|
return this._finished && this._closed && !this._failure;
|
|
1769
1781
|
}
|
|
@@ -1787,7 +1799,13 @@ var init_response_parser = __esmMin((() => {
|
|
|
1787
1799
|
forward = "";
|
|
1788
1800
|
};
|
|
1789
1801
|
for (const char of chunk) {
|
|
1802
|
+
if (this._closed) {
|
|
1803
|
+
this._trailer += char;
|
|
1804
|
+
continue;
|
|
1805
|
+
}
|
|
1806
|
+
if (this.done) continue;
|
|
1790
1807
|
if (this._mode === "detect") {
|
|
1808
|
+
this._preambleLength++;
|
|
1791
1809
|
if (this._discardPrefixLine) {
|
|
1792
1810
|
if (char === "\n") this._discardPrefixLine = false;
|
|
1793
1811
|
continue;
|
|
@@ -1818,10 +1836,6 @@ var init_response_parser = __esmMin((() => {
|
|
|
1818
1836
|
}
|
|
1819
1837
|
continue;
|
|
1820
1838
|
}
|
|
1821
|
-
if (this._closed) {
|
|
1822
|
-
this._trailer += char;
|
|
1823
|
-
continue;
|
|
1824
|
-
}
|
|
1825
1839
|
if (this._boundary || char === "■") {
|
|
1826
1840
|
this._boundary += char;
|
|
1827
1841
|
if (this._boundary === "■end") {
|
|
@@ -1843,7 +1857,8 @@ var init_response_parser = __esmMin((() => {
|
|
|
1843
1857
|
this._finished = true;
|
|
1844
1858
|
const events = [];
|
|
1845
1859
|
if (this._mode === "detect") {
|
|
1846
|
-
if (this.
|
|
1860
|
+
if (this.done) this._fail(`Missing ■start: no response envelope within ${MAX_PREAMBLE_LENGTH} characters`);
|
|
1861
|
+
else if (this._prefix.trim() === "■start") this._mode = "framed";
|
|
1847
1862
|
else this._fail("Missing ■start: every response must begin with the response envelope");
|
|
1848
1863
|
this._prefix = "";
|
|
1849
1864
|
}
|
|
@@ -18113,7 +18128,7 @@ var init_vm = __esmMin((() => {
|
|
|
18113
18128
|
}));
|
|
18114
18129
|
//#endregion
|
|
18115
18130
|
//#region src/runtime/generate.ts
|
|
18116
|
-
var RESPONSE_LENGTH_BUFFER, STREAM_INACTIVITY_TIMEOUT, assertSuccessfulGeneration, getModelOutputLimit, generateCode;
|
|
18131
|
+
var RESPONSE_LENGTH_BUFFER, STREAM_INACTIVITY_TIMEOUT, STREAM_END_GRACE_PERIOD, assertSuccessfulGeneration, estimateMetadata, getModelOutputLimit, generateCode;
|
|
18117
18132
|
var init_generate = __esmMin((() => {
|
|
18118
18133
|
init_lodash();
|
|
18119
18134
|
init_abort_signal();
|
|
@@ -18128,10 +18143,35 @@ var init_generate = __esmMin((() => {
|
|
|
18128
18143
|
PERCENTAGE: .1
|
|
18129
18144
|
};
|
|
18130
18145
|
STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
18146
|
+
STREAM_END_GRACE_PERIOD = 1e3;
|
|
18131
18147
|
assertSuccessfulGeneration = (metadata) => {
|
|
18132
18148
|
if (metadata.provider === "unknown") throw new CognitiveError("LLM generation failed: received error metadata with unknown provider");
|
|
18133
18149
|
if (metadata.stopReason === "max_tokens" || metadata.stopReason === "content_filter" || metadata.stopReason === "other") throw new CognitiveError(`LLM generation did not complete: stopReason=${metadata.stopReason}`);
|
|
18134
18150
|
};
|
|
18151
|
+
estimateMetadata = (model, messages, output) => {
|
|
18152
|
+
const tokenizer = getTokenizer();
|
|
18153
|
+
const countMessage = (message) => {
|
|
18154
|
+
if (typeof message.content === "string") return tokenizer.count(message.content);
|
|
18155
|
+
return (message.content ?? []).map((part) => part.type === "text" ? part.text ?? "" : "").reduce((sum, text) => sum + tokenizer.count(text), 0);
|
|
18156
|
+
};
|
|
18157
|
+
const inputTokens = messages.reduce((total, message) => total + countMessage(message), 0);
|
|
18158
|
+
const outputTokens = tokenizer.count(output);
|
|
18159
|
+
const inputCost = inputTokens * model.input.costPer1MTokens / 1e6;
|
|
18160
|
+
const outputCost = outputTokens * model.output.costPer1MTokens / 1e6;
|
|
18161
|
+
const [provider, ...name] = model.id.split(":");
|
|
18162
|
+
return {
|
|
18163
|
+
provider,
|
|
18164
|
+
model: name.join(":"),
|
|
18165
|
+
usage: {
|
|
18166
|
+
inputTokens,
|
|
18167
|
+
inputCost,
|
|
18168
|
+
outputTokens,
|
|
18169
|
+
outputCost
|
|
18170
|
+
},
|
|
18171
|
+
cost: inputCost + outputCost,
|
|
18172
|
+
stopReason: "stop"
|
|
18173
|
+
};
|
|
18174
|
+
};
|
|
18135
18175
|
getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
18136
18176
|
generateCode = async ({ iteration, ctx, cognitive, controller, metadata, onSend, onSendDelta, onRunStart }) => {
|
|
18137
18177
|
const startedAt = Date.now();
|
|
@@ -18249,16 +18289,14 @@ var init_generate = __esmMin((() => {
|
|
|
18249
18289
|
} } : {}
|
|
18250
18290
|
}, { signal: streamController.signal });
|
|
18251
18291
|
const inactivityTimeout = Math.max(STREAM_INACTIVITY_TIMEOUT, ctx.maxTimeToFirstToken ?? 0);
|
|
18252
|
-
|
|
18292
|
+
/** Resolves to undefined when no chunk arrives within the timeout. */
|
|
18293
|
+
const nextChunk = async (timeout) => {
|
|
18253
18294
|
let timer;
|
|
18254
|
-
const
|
|
18255
|
-
timer = setTimeout(() =>
|
|
18256
|
-
streamController.abort("LLM stream stalled");
|
|
18257
|
-
reject(/* @__PURE__ */ new Error(`LLM stream stalled: no data received for ${inactivityTimeout}ms`));
|
|
18258
|
-
}, inactivityTimeout);
|
|
18295
|
+
const expired = new Promise((resolve) => {
|
|
18296
|
+
timer = setTimeout(() => resolve(void 0), timeout);
|
|
18259
18297
|
});
|
|
18260
18298
|
try {
|
|
18261
|
-
return await Promise.race([stream.next(),
|
|
18299
|
+
return await Promise.race([stream.next(), expired]);
|
|
18262
18300
|
} finally {
|
|
18263
18301
|
clearTimeout(timer);
|
|
18264
18302
|
}
|
|
@@ -18266,14 +18304,21 @@ var init_generate = __esmMin((() => {
|
|
|
18266
18304
|
raw = "";
|
|
18267
18305
|
let streamCompleted = false;
|
|
18268
18306
|
let accepted = false;
|
|
18307
|
+
let closedAt;
|
|
18308
|
+
let servedModel = model.id;
|
|
18269
18309
|
try {
|
|
18270
18310
|
while (true) {
|
|
18271
18311
|
let chunk;
|
|
18272
18312
|
try {
|
|
18273
|
-
chunk = await nextChunk();
|
|
18313
|
+
chunk = await nextChunk(closedAt === void 0 ? inactivityTimeout : closedAt + STREAM_END_GRACE_PERIOD - Date.now());
|
|
18274
18314
|
} catch (thrown) {
|
|
18275
18315
|
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
18276
18316
|
}
|
|
18317
|
+
if (!chunk && closedAt !== void 0) break;
|
|
18318
|
+
if (!chunk) {
|
|
18319
|
+
streamController.abort("LLM stream stalled");
|
|
18320
|
+
throw new CognitiveError(`LLM generation failed: LLM stream stalled: no data received for ${inactivityTimeout}ms`);
|
|
18321
|
+
}
|
|
18277
18322
|
if (chunk.done) {
|
|
18278
18323
|
streamCompleted = true;
|
|
18279
18324
|
break;
|
|
@@ -18292,12 +18337,14 @@ var init_generate = __esmMin((() => {
|
|
|
18292
18337
|
completions = [];
|
|
18293
18338
|
accepted = false;
|
|
18294
18339
|
parser = new ResponseParser();
|
|
18340
|
+
closedAt = void 0;
|
|
18295
18341
|
liveItems.clear();
|
|
18296
18342
|
liveContent.clear();
|
|
18297
18343
|
codeGenerationTraced = false;
|
|
18298
18344
|
runCompleted = false;
|
|
18299
18345
|
responseMetadata = void 0;
|
|
18300
18346
|
attempt = chunk.value.restart.attempt;
|
|
18347
|
+
servedModel = chunk.value.restart.toModel;
|
|
18301
18348
|
await preview({
|
|
18302
18349
|
...chunk.value.restart,
|
|
18303
18350
|
restart: true,
|
|
@@ -18314,6 +18361,12 @@ var init_generate = __esmMin((() => {
|
|
|
18314
18361
|
timeToFirstToken ??= timeToLastToken;
|
|
18315
18362
|
raw += delta;
|
|
18316
18363
|
await dispatchSends(parser.push(delta));
|
|
18364
|
+
if (parser.done) break;
|
|
18365
|
+
if (parser.closed) closedAt ??= Date.now();
|
|
18366
|
+
}
|
|
18367
|
+
if (!responseMetadata && !streamCompleted) {
|
|
18368
|
+
const served = models.find((details) => details.id === servedModel) ?? await cognitive.getModelDetails(servedModel).catch(() => model);
|
|
18369
|
+
responseMetadata = estimateMetadata(served, messages, raw);
|
|
18317
18370
|
}
|
|
18318
18371
|
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
18319
18372
|
assertSuccessfulGeneration(responseMetadata);
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { StopReason } from '@botpress/cognitive';
|
|
2
2
|
import type { Diagnostic, MessageStreamEvent, ParsedItem } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Text a model may write before ■start. Some models stream junk for minutes
|
|
5
|
+
* without ever opening the envelope; past this many characters, give up.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MAX_PREAMBLE_LENGTH = 8000;
|
|
8
|
+
/** Text a model may write after ■end before the rest of its stream is ignored. */
|
|
9
|
+
export declare const MAX_TRAILER_LENGTH = 2000;
|
|
3
10
|
/** One wire format: a complete ■start … ■end envelope containing valid blocks. */
|
|
4
11
|
export declare class ResponseParser {
|
|
5
12
|
private _parser;
|
|
@@ -12,7 +19,12 @@ export declare class ResponseParser {
|
|
|
12
19
|
private _finished;
|
|
13
20
|
private _failure;
|
|
14
21
|
private _trailer;
|
|
22
|
+
private _preambleLength;
|
|
15
23
|
get framed(): boolean;
|
|
24
|
+
/** Whether ■end was received. Later text is only kept as a diagnostic. */
|
|
25
|
+
get closed(): boolean;
|
|
26
|
+
/** The model is writing junk past either boundary: stop reading the stream. */
|
|
27
|
+
get done(): boolean;
|
|
16
28
|
get valid(): boolean;
|
|
17
29
|
get items(): ParsedItem[];
|
|
18
30
|
get diagnostics(): Diagnostic[];
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "llmz",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "LLMz - An LLM-native Typescript VM built on top of Zui",
|
|
5
|
-
"version": "0.9.
|
|
5
|
+
"version": "0.9.13",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
8
|
"DOCS.md"
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@botpress/client": "2.11.0",
|
|
72
|
-
"@botpress/cognitive": "1.
|
|
72
|
+
"@botpress/cognitive": "1.3.0",
|
|
73
73
|
"@bpinternal/thicktoken": "^3.1.0",
|
|
74
74
|
"@bpinternal/zui": "^2.4.1"
|
|
75
75
|
},
|