llmz 0.6.3 → 0.6.5
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/DOCS.md +25 -0
- package/dist/context.d.ts +6 -0
- package/dist/{custom-client-BPmEoWKu.cjs → custom-client-BX8gx0tI.cjs} +7 -0
- package/dist/{custom-client-NUoxrFQh.js → custom-client-BnlDpjdI.js} +7 -0
- package/dist/{execute-BEaq3jkV.cjs → execute-BJF4Txh2.cjs} +107 -50
- package/dist/{execute-DYvFRs54.js → execute-BjBBTshA.js} +107 -50
- package/dist/index.cjs +4 -4
- package/dist/index.js +4 -4
- package/dist/index.workerd.js +111 -47
- package/dist/runtime/types.d.ts +7 -0
- package/dist/types.d.ts +8 -1
- package/package.json +2 -2
package/DOCS.md
CHANGED
|
@@ -1582,6 +1582,31 @@ await execute({
|
|
|
1582
1582
|
|
|
1583
1583
|
---
|
|
1584
1584
|
|
|
1585
|
+
### Buffered Delivery (midStreamFallback)
|
|
1586
|
+
|
|
1587
|
+
By default, LLMz streams responses: send blocks are dispatched as soon as they are parsed, and the ■run block starts executing while the model is still generating the rest of the response. This gives the lowest time-to-first-token but runs code before the response is complete.
|
|
1588
|
+
|
|
1589
|
+
Set `options.midStreamFallback: true` to allow Cognitive to restart a failed stream on another model safely. LLMz buffers delivery and discards all content from abandoned attempts:
|
|
1590
|
+
|
|
1591
|
+
```typescript
|
|
1592
|
+
await execute({
|
|
1593
|
+
// ...
|
|
1594
|
+
options: { midStreamFallback: true },
|
|
1595
|
+
})
|
|
1596
|
+
```
|
|
1597
|
+
|
|
1598
|
+
When enabled, the runtime buffers the full generated response and only dispatches it (sends and code execution) once the stream has finished. Trade-offs:
|
|
1599
|
+
|
|
1600
|
+
- **Latency**: higher time-to-first-send/token, since nothing is delivered until the response completes.
|
|
1601
|
+
- **No early code**: the VM is not run mid-stream; code executes only after the full response is parsed.
|
|
1602
|
+
- **Cancellation**: cancellation still aborts the original generation request as usual.
|
|
1603
|
+
- **No extra retry loop**: Cognitive owns fallback, bounded by the model chain. LLMz does not retry abandoned attempts itself.
|
|
1604
|
+
- **Not exactly-once**: abandoned attempts deliver nothing, but successful-attempt callbacks cannot be rolled back if delivery fails or cancellation arrives during delivery. Caller retries can duplicate effects.
|
|
1605
|
+
|
|
1606
|
+
This option defaults to false and applies only to streaming clients. Non-streaming Cognitive requests already fall back transparently. It can be combined with `maxTimeToFirstToken` and `transcriptionModel`; do not enable it globally underneath LLMz without also enabling LLMz's buffering option.
|
|
1607
|
+
|
|
1608
|
+
Restarts emit `llm_call_restarted` traces with the attempt, source/destination models, and reason. Token timings remain relative to the original request and describe the surviving attempt (including time spent on prior attempts). Usage and cost retain Cognitive's final reported metadata; LLMz does not infer or sum abandoned-attempt billing. Cancellation deadlines are not reset, and the existing stream inactivity guard remains active during handoffs.
|
|
1609
|
+
|
|
1585
1610
|
## API Reference
|
|
1586
1611
|
|
|
1587
1612
|
### Core Functions
|
package/dist/context.d.ts
CHANGED
|
@@ -564,6 +564,11 @@ export declare class Context implements Serializable<Context.JSON> {
|
|
|
564
564
|
* before the cognitive service falls back to the next model/provider.
|
|
565
565
|
*/
|
|
566
566
|
maxTimeToFirstToken?: number;
|
|
567
|
+
/**
|
|
568
|
+
* Allow Cognitive mid-stream fallback, buffering delivery until generation
|
|
569
|
+
* succeeds and discarding abandoned attempts. Streaming-only; defaults to false.
|
|
570
|
+
*/
|
|
571
|
+
midStreamFallback?: boolean;
|
|
567
572
|
/**
|
|
568
573
|
* STT model used by the cognitive service to transcribe audio attachments
|
|
569
574
|
* when the target LLM does not support audio natively. Defaults to 'fast'.
|
|
@@ -600,6 +605,7 @@ export declare class Context implements Serializable<Context.JSON> {
|
|
|
600
605
|
timeout?: number;
|
|
601
606
|
maxTokens?: number;
|
|
602
607
|
maxTimeToFirstToken?: number;
|
|
608
|
+
midStreamFallback?: boolean;
|
|
603
609
|
transcriptionModel?: SttModels;
|
|
604
610
|
});
|
|
605
611
|
toJSON(): {
|
|
@@ -2254,6 +2254,11 @@ var Context = class {
|
|
|
2254
2254
|
*/
|
|
2255
2255
|
maxTimeToFirstToken;
|
|
2256
2256
|
/**
|
|
2257
|
+
* Allow Cognitive mid-stream fallback, buffering delivery until generation
|
|
2258
|
+
* succeeds and discarding abandoned attempts. Streaming-only; defaults to false.
|
|
2259
|
+
*/
|
|
2260
|
+
midStreamFallback;
|
|
2261
|
+
/**
|
|
2257
2262
|
* STT model used by the cognitive service to transcribe audio attachments
|
|
2258
2263
|
* when the target LLM does not support audio natively. Defaults to 'fast'.
|
|
2259
2264
|
*/
|
|
@@ -2509,10 +2514,12 @@ var Context = class {
|
|
|
2509
2514
|
this.snapshot = props.snapshot;
|
|
2510
2515
|
this.maxTokens = props.maxTokens;
|
|
2511
2516
|
this.maxTimeToFirstToken = props.maxTimeToFirstToken;
|
|
2517
|
+
this.midStreamFallback = props.midStreamFallback;
|
|
2512
2518
|
this.transcriptionModel = props.transcriptionModel;
|
|
2513
2519
|
if (this.loop < 1 || this.loop > 100) throw new Error("Invalid loop. Expected a number between 1 and 100.");
|
|
2514
2520
|
if (this.maxTokens !== void 0 && (!Number.isFinite(this.maxTokens) || this.maxTokens < 1)) throw new Error("Invalid maxTokens. Expected a positive number.");
|
|
2515
2521
|
if (this.maxTimeToFirstToken !== void 0 && (!Number.isFinite(this.maxTimeToFirstToken) || this.maxTimeToFirstToken < 1)) throw new Error("Invalid maxTimeToFirstToken. Expected a positive number of milliseconds.");
|
|
2522
|
+
if (this.midStreamFallback !== void 0 && typeof this.midStreamFallback !== "boolean") throw new Error("Invalid midStreamFallback. Expected a boolean.");
|
|
2516
2523
|
}
|
|
2517
2524
|
toJSON() {
|
|
2518
2525
|
var _this$snapshot4;
|
|
@@ -2254,6 +2254,11 @@ var Context = class {
|
|
|
2254
2254
|
*/
|
|
2255
2255
|
maxTimeToFirstToken;
|
|
2256
2256
|
/**
|
|
2257
|
+
* Allow Cognitive mid-stream fallback, buffering delivery until generation
|
|
2258
|
+
* succeeds and discarding abandoned attempts. Streaming-only; defaults to false.
|
|
2259
|
+
*/
|
|
2260
|
+
midStreamFallback;
|
|
2261
|
+
/**
|
|
2257
2262
|
* STT model used by the cognitive service to transcribe audio attachments
|
|
2258
2263
|
* when the target LLM does not support audio natively. Defaults to 'fast'.
|
|
2259
2264
|
*/
|
|
@@ -2509,10 +2514,12 @@ var Context = class {
|
|
|
2509
2514
|
this.snapshot = props.snapshot;
|
|
2510
2515
|
this.maxTokens = props.maxTokens;
|
|
2511
2516
|
this.maxTimeToFirstToken = props.maxTimeToFirstToken;
|
|
2517
|
+
this.midStreamFallback = props.midStreamFallback;
|
|
2512
2518
|
this.transcriptionModel = props.transcriptionModel;
|
|
2513
2519
|
if (this.loop < 1 || this.loop > 100) throw new Error("Invalid loop. Expected a number between 1 and 100.");
|
|
2514
2520
|
if (this.maxTokens !== void 0 && (!Number.isFinite(this.maxTokens) || this.maxTokens < 1)) throw new Error("Invalid maxTokens. Expected a positive number.");
|
|
2515
2521
|
if (this.maxTimeToFirstToken !== void 0 && (!Number.isFinite(this.maxTimeToFirstToken) || this.maxTimeToFirstToken < 1)) throw new Error("Invalid maxTimeToFirstToken. Expected a positive number of milliseconds.");
|
|
2522
|
+
if (this.midStreamFallback !== void 0 && typeof this.midStreamFallback !== "boolean") throw new Error("Invalid midStreamFallback. Expected a boolean.");
|
|
2516
2523
|
}
|
|
2517
2524
|
toJSON() {
|
|
2518
2525
|
var _this$snapshot4;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require__baseForOwn = require("./_baseForOwn-buOZDFbK.cjs");
|
|
2
2
|
const require_dual_modes = require("./dual-modes-wAOAlaBS.cjs");
|
|
3
|
-
const require_custom_client = require("./custom-client-
|
|
3
|
+
const require_custom_client = require("./custom-client-BX8gx0tI.cjs");
|
|
4
4
|
const require_utils = require("./utils-ZpJm00ed.cjs");
|
|
5
5
|
const require_jsx = require("./jsx-BWvT6ukg.cjs");
|
|
6
6
|
const require_stack_traces = require("./stack-traces-ntw_qhoy.cjs");
|
|
@@ -121,7 +121,7 @@ const RESPONSE_LENGTH_BUFFER = {
|
|
|
121
121
|
PERCENTAGE: .1
|
|
122
122
|
};
|
|
123
123
|
/** Maximum time to wait between two stream chunks before considering the stream stalled. */
|
|
124
|
-
const STREAM_INACTIVITY_TIMEOUT =
|
|
124
|
+
const STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
125
125
|
const getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
126
126
|
/**
|
|
127
127
|
* Models sometimes wrap their whole response in a code fence. The fence has to
|
|
@@ -197,6 +197,12 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
197
197
|
/** Milliseconds between the stream request and the first/last streamed tokens. */
|
|
198
198
|
let timeToFirstToken;
|
|
199
199
|
let timeToLastToken;
|
|
200
|
+
const bufferedDelivery = ctx.midStreamFallback === true;
|
|
201
|
+
let pendingDeliveries = [];
|
|
202
|
+
const deliver = async (callback) => {
|
|
203
|
+
if (bufferedDelivery) pendingDeliveries.push(callback);
|
|
204
|
+
else await callback();
|
|
205
|
+
};
|
|
200
206
|
const liveItems = /* @__PURE__ */ new Map();
|
|
201
207
|
const liveContent = /* @__PURE__ */ new Map();
|
|
202
208
|
let codeGenerationTraced = false;
|
|
@@ -206,48 +212,58 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
206
212
|
liveItems.set(event.item.id, event.item);
|
|
207
213
|
if (event.item.kind === "run" && !codeGenerationTraced) {
|
|
208
214
|
codeGenerationTraced = true;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
const started_at = Date.now();
|
|
216
|
+
await deliver(() => {
|
|
217
|
+
traces.push({
|
|
218
|
+
type: "code_generation_started",
|
|
219
|
+
started_at
|
|
220
|
+
});
|
|
221
|
+
onRunStart === null || onRunStart === void 0 || onRunStart();
|
|
212
222
|
});
|
|
213
|
-
onRunStart === null || onRunStart === void 0 || onRunStart();
|
|
214
223
|
}
|
|
215
224
|
} else if (event.type === "body-delta" && onSendDelta) {
|
|
216
225
|
const item = liveItems.get(event.itemId);
|
|
217
226
|
if ((item === null || item === void 0 ? void 0 : item.kind) !== "send") continue;
|
|
218
227
|
const content = (liveContent.get(item.id) ?? "") + event.delta;
|
|
219
228
|
liveContent.set(item.id, content);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
name: event.item.name,
|
|
232
|
-
props: event.item.props,
|
|
233
|
-
body: event.item.body
|
|
229
|
+
const delta = {
|
|
230
|
+
id: `${iteration.id}:${item.id}`,
|
|
231
|
+
component: item.name,
|
|
232
|
+
props: bufferedDelivery ? structuredClone(item.props) : item.props,
|
|
233
|
+
delta: event.delta,
|
|
234
|
+
content
|
|
235
|
+
};
|
|
236
|
+
await deliver(async () => {
|
|
237
|
+
try {
|
|
238
|
+
await onSendDelta(delta);
|
|
239
|
+
} catch (err) {}
|
|
234
240
|
});
|
|
235
|
-
|
|
241
|
+
} else if (event.type === "item-complete") {
|
|
242
|
+
if (event.item.kind === "send" && onSend) {
|
|
243
|
+
const send = {
|
|
244
|
+
name: event.item.name,
|
|
245
|
+
props: bufferedDelivery ? structuredClone(event.item.props) : event.item.props,
|
|
246
|
+
body: event.item.body
|
|
247
|
+
};
|
|
248
|
+
await deliver(() => onSend(send));
|
|
249
|
+
} else if (event.item.kind === "run" && event.item.status === "complete" && !runCompleted) {
|
|
236
250
|
runCompleted = true;
|
|
237
|
-
|
|
251
|
+
const code = (event.item.body ?? "").trim();
|
|
252
|
+
await deliver(() => onRunComplete === null || onRunComplete === void 0 ? void 0 : onRunComplete(code));
|
|
238
253
|
}
|
|
239
254
|
}
|
|
240
255
|
};
|
|
241
256
|
if (typeof cognitive.generateTextStream === "function") {
|
|
242
|
-
|
|
243
|
-
|
|
257
|
+
let parser = new require_dual_modes.StreamingMessageParser();
|
|
258
|
+
let fence = new LeadingFenceFilter();
|
|
244
259
|
const streamController = createJoinedAbortController([controller.signal]);
|
|
245
260
|
const requestedAt = Date.now();
|
|
246
261
|
const stream = cognitive.generateTextStream({
|
|
247
262
|
...input,
|
|
248
|
-
...ctx.maxTimeToFirstToken ? { options: {
|
|
263
|
+
...ctx.maxTimeToFirstToken || bufferedDelivery ? { options: {
|
|
249
264
|
...input.options,
|
|
250
|
-
maxTimeToFirstToken: ctx.maxTimeToFirstToken
|
|
265
|
+
...ctx.maxTimeToFirstToken ? { maxTimeToFirstToken: ctx.maxTimeToFirstToken } : {},
|
|
266
|
+
...bufferedDelivery ? { midStreamFallback: true } : {}
|
|
251
267
|
} } : {}
|
|
252
268
|
}, { signal: streamController.signal });
|
|
253
269
|
const inactivityTimeout = Math.max(STREAM_INACTIVITY_TIMEOUT, ctx.maxTimeToFirstToken ?? 0);
|
|
@@ -266,28 +282,68 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
266
282
|
}
|
|
267
283
|
};
|
|
268
284
|
raw = "";
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
chunk
|
|
274
|
-
|
|
275
|
-
|
|
285
|
+
let streamCompleted = false;
|
|
286
|
+
try {
|
|
287
|
+
while (true) {
|
|
288
|
+
var _chunk$value, _chunk$value2, _chunk$value3, _chunk$value4;
|
|
289
|
+
let chunk;
|
|
290
|
+
try {
|
|
291
|
+
chunk = await nextChunk();
|
|
292
|
+
} catch (thrown) {
|
|
293
|
+
throw new require_errors.CognitiveError(`LLM generation failed: ${require_utils.getErrorMessage(thrown)}`);
|
|
294
|
+
}
|
|
295
|
+
if (chunk.done) {
|
|
296
|
+
streamCompleted = true;
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
if (((_chunk$value = chunk.value) === null || _chunk$value === void 0 ? void 0 : _chunk$value.restart) && !bufferedDelivery) {
|
|
300
|
+
streamController.abort("Unexpected LLM stream restart");
|
|
301
|
+
throw new require_errors.CognitiveError("LLM stream restarted without options.midStreamFallback enabled");
|
|
302
|
+
}
|
|
303
|
+
if ((_chunk$value2 = chunk.value) === null || _chunk$value2 === void 0 ? void 0 : _chunk$value2.restart) {
|
|
304
|
+
traces.push({
|
|
305
|
+
type: "llm_call_restarted",
|
|
306
|
+
started_at: Date.now(),
|
|
307
|
+
...chunk.value.restart
|
|
308
|
+
});
|
|
309
|
+
raw = "";
|
|
310
|
+
parser = new require_dual_modes.StreamingMessageParser();
|
|
311
|
+
fence = new LeadingFenceFilter();
|
|
312
|
+
liveItems.clear();
|
|
313
|
+
liveContent.clear();
|
|
314
|
+
pendingDeliveries = [];
|
|
315
|
+
codeGenerationTraced = false;
|
|
316
|
+
runCompleted = false;
|
|
317
|
+
responseMetadata = void 0;
|
|
318
|
+
timeToFirstToken = void 0;
|
|
319
|
+
timeToLastToken = void 0;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if ((_chunk$value3 = chunk.value) === null || _chunk$value3 === void 0 ? void 0 : _chunk$value3.metadata) responseMetadata = chunk.value.metadata;
|
|
323
|
+
const delta = (_chunk$value4 = chunk.value) === null || _chunk$value4 === void 0 ? void 0 : _chunk$value4.output;
|
|
324
|
+
if (!delta) continue;
|
|
325
|
+
timeToLastToken = Date.now() - requestedAt;
|
|
326
|
+
timeToFirstToken ??= timeToLastToken;
|
|
327
|
+
raw += delta;
|
|
328
|
+
await dispatchSends(parser.push(fence.push(delta)));
|
|
329
|
+
}
|
|
330
|
+
if (!responseMetadata) throw new require_errors.CognitiveError("LLM streaming completed without metadata");
|
|
331
|
+
const remaining = fence.flush();
|
|
332
|
+
if (remaining) await dispatchSends(parser.push(remaining));
|
|
333
|
+
await dispatchSends(parser.finish());
|
|
334
|
+
assistantResponse = require_dual_modes.toParsedAssistantResponse(parser.items, raw);
|
|
335
|
+
} finally {
|
|
336
|
+
streamController.abort("LLM stream closed");
|
|
337
|
+
if (!streamCompleted) stream.return(void 0).catch(() => {});
|
|
338
|
+
}
|
|
339
|
+
if (bufferedDelivery) {
|
|
340
|
+
controller.signal.throwIfAborted();
|
|
341
|
+
for (const callback of pendingDeliveries) {
|
|
342
|
+
controller.signal.throwIfAborted();
|
|
343
|
+
await callback();
|
|
276
344
|
}
|
|
277
|
-
|
|
278
|
-
if ((_chunk$value = chunk.value) === null || _chunk$value === void 0 ? void 0 : _chunk$value.metadata) responseMetadata = chunk.value.metadata;
|
|
279
|
-
const delta = (_chunk$value2 = chunk.value) === null || _chunk$value2 === void 0 ? void 0 : _chunk$value2.output;
|
|
280
|
-
if (!delta) continue;
|
|
281
|
-
timeToLastToken = Date.now() - requestedAt;
|
|
282
|
-
timeToFirstToken ??= timeToLastToken;
|
|
283
|
-
raw += delta;
|
|
284
|
-
await dispatchSends(parser.push(fence.push(delta)));
|
|
345
|
+
pendingDeliveries = [];
|
|
285
346
|
}
|
|
286
|
-
if (!responseMetadata) throw new require_errors.CognitiveError("LLM streaming completed without metadata");
|
|
287
|
-
const remaining = fence.flush();
|
|
288
|
-
if (remaining) await dispatchSends(parser.push(remaining));
|
|
289
|
-
await dispatchSends(parser.finish());
|
|
290
|
-
assistantResponse = require_dual_modes.toParsedAssistantResponse(parser.items, raw);
|
|
291
347
|
} else {
|
|
292
348
|
const response = await cognitive.generateText(input, { signal: controller.signal }).catch((thrown) => {
|
|
293
349
|
throw new require_errors.CognitiveError(`LLM generation failed: ${require_utils.getErrorMessage(thrown)}`);
|
|
@@ -329,7 +385,7 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
329
385
|
type: "llm_call_success",
|
|
330
386
|
started_at: startedAt,
|
|
331
387
|
ended_at: iteration.llm.ended_at,
|
|
332
|
-
model: model
|
|
388
|
+
model: iteration.llm.model,
|
|
333
389
|
code: iteration.code ?? ""
|
|
334
390
|
});
|
|
335
391
|
};
|
|
@@ -677,7 +733,7 @@ const executeContext = async (props) => {
|
|
|
677
733
|
return result;
|
|
678
734
|
};
|
|
679
735
|
const executeContextInternal = async (props) => {
|
|
680
|
-
var _props$options, _props$options2, _props$options3, _props$options4, _props$options5;
|
|
736
|
+
var _props$options, _props$options2, _props$options3, _props$options4, _props$options5, _props$options6;
|
|
681
737
|
const controller = createJoinedAbortController([props.signal]);
|
|
682
738
|
const { onIterationStart, onIterationEnd, onTrace, onExit, onBeforeExecution, onAfterTool, onBeforeTool } = props;
|
|
683
739
|
const client = props.client ?? new _botpress_client.Client();
|
|
@@ -691,7 +747,8 @@ const executeContextInternal = async (props) => {
|
|
|
691
747
|
timeout: (_props$options2 = props.options) === null || _props$options2 === void 0 ? void 0 : _props$options2.timeout,
|
|
692
748
|
maxTokens: (_props$options3 = props.options) === null || _props$options3 === void 0 ? void 0 : _props$options3.maxTokens,
|
|
693
749
|
maxTimeToFirstToken: (_props$options4 = props.options) === null || _props$options4 === void 0 ? void 0 : _props$options4.maxTimeToFirstToken,
|
|
694
|
-
|
|
750
|
+
midStreamFallback: (_props$options5 = props.options) === null || _props$options5 === void 0 ? void 0 : _props$options5.midStreamFallback,
|
|
751
|
+
transcriptionModel: (_props$options6 = props.options) === null || _props$options6 === void 0 ? void 0 : _props$options6.transcriptionModel,
|
|
695
752
|
exits: props.exits,
|
|
696
753
|
snapshot: props.snapshot,
|
|
697
754
|
model: props.model,
|
|
@@ -884,7 +941,7 @@ const executeIteration = async ({ iteration, ctx, cognitive, controller, onExit,
|
|
|
884
941
|
};
|
|
885
942
|
});
|
|
886
943
|
};
|
|
887
|
-
const canExecuteEarly = typeof onBeforeExecution !== "function";
|
|
944
|
+
const canExecuteEarly = typeof onBeforeExecution !== "function" && !ctx.midStreamFallback;
|
|
888
945
|
let earlyExecution;
|
|
889
946
|
await generateCode({
|
|
890
947
|
iteration,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as StreamingMessageParser, d as isEqual, h as toNumber, i as toParsedAssistantResponse } from "./dual-modes-D_p-jedw.js";
|
|
2
|
-
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-
|
|
2
|
+
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-BnlDpjdI.js";
|
|
3
3
|
import { d as stripInvalidIdentifiers, i as getErrorMessage, s as init } from "./utils-UBeAFeEI.js";
|
|
4
4
|
import { t as createJsxComponent } from "./jsx-CIgdGGVs.js";
|
|
5
5
|
import { t as cleanStackTrace } from "./stack-traces-BIE_5Xwf.js";
|
|
@@ -119,7 +119,7 @@ const RESPONSE_LENGTH_BUFFER = {
|
|
|
119
119
|
PERCENTAGE: .1
|
|
120
120
|
};
|
|
121
121
|
/** Maximum time to wait between two stream chunks before considering the stream stalled. */
|
|
122
|
-
const STREAM_INACTIVITY_TIMEOUT =
|
|
122
|
+
const STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
123
123
|
const getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
124
124
|
/**
|
|
125
125
|
* Models sometimes wrap their whole response in a code fence. The fence has to
|
|
@@ -195,6 +195,12 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
195
195
|
/** Milliseconds between the stream request and the first/last streamed tokens. */
|
|
196
196
|
let timeToFirstToken;
|
|
197
197
|
let timeToLastToken;
|
|
198
|
+
const bufferedDelivery = ctx.midStreamFallback === true;
|
|
199
|
+
let pendingDeliveries = [];
|
|
200
|
+
const deliver = async (callback) => {
|
|
201
|
+
if (bufferedDelivery) pendingDeliveries.push(callback);
|
|
202
|
+
else await callback();
|
|
203
|
+
};
|
|
198
204
|
const liveItems = /* @__PURE__ */ new Map();
|
|
199
205
|
const liveContent = /* @__PURE__ */ new Map();
|
|
200
206
|
let codeGenerationTraced = false;
|
|
@@ -204,48 +210,58 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
204
210
|
liveItems.set(event.item.id, event.item);
|
|
205
211
|
if (event.item.kind === "run" && !codeGenerationTraced) {
|
|
206
212
|
codeGenerationTraced = true;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
const started_at = Date.now();
|
|
214
|
+
await deliver(() => {
|
|
215
|
+
traces.push({
|
|
216
|
+
type: "code_generation_started",
|
|
217
|
+
started_at
|
|
218
|
+
});
|
|
219
|
+
onRunStart === null || onRunStart === void 0 || onRunStart();
|
|
210
220
|
});
|
|
211
|
-
onRunStart === null || onRunStart === void 0 || onRunStart();
|
|
212
221
|
}
|
|
213
222
|
} else if (event.type === "body-delta" && onSendDelta) {
|
|
214
223
|
const item = liveItems.get(event.itemId);
|
|
215
224
|
if ((item === null || item === void 0 ? void 0 : item.kind) !== "send") continue;
|
|
216
225
|
const content = (liveContent.get(item.id) ?? "") + event.delta;
|
|
217
226
|
liveContent.set(item.id, content);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
name: event.item.name,
|
|
230
|
-
props: event.item.props,
|
|
231
|
-
body: event.item.body
|
|
227
|
+
const delta = {
|
|
228
|
+
id: `${iteration.id}:${item.id}`,
|
|
229
|
+
component: item.name,
|
|
230
|
+
props: bufferedDelivery ? structuredClone(item.props) : item.props,
|
|
231
|
+
delta: event.delta,
|
|
232
|
+
content
|
|
233
|
+
};
|
|
234
|
+
await deliver(async () => {
|
|
235
|
+
try {
|
|
236
|
+
await onSendDelta(delta);
|
|
237
|
+
} catch (err) {}
|
|
232
238
|
});
|
|
233
|
-
|
|
239
|
+
} else if (event.type === "item-complete") {
|
|
240
|
+
if (event.item.kind === "send" && onSend) {
|
|
241
|
+
const send = {
|
|
242
|
+
name: event.item.name,
|
|
243
|
+
props: bufferedDelivery ? structuredClone(event.item.props) : event.item.props,
|
|
244
|
+
body: event.item.body
|
|
245
|
+
};
|
|
246
|
+
await deliver(() => onSend(send));
|
|
247
|
+
} else if (event.item.kind === "run" && event.item.status === "complete" && !runCompleted) {
|
|
234
248
|
runCompleted = true;
|
|
235
|
-
|
|
249
|
+
const code = (event.item.body ?? "").trim();
|
|
250
|
+
await deliver(() => onRunComplete === null || onRunComplete === void 0 ? void 0 : onRunComplete(code));
|
|
236
251
|
}
|
|
237
252
|
}
|
|
238
253
|
};
|
|
239
254
|
if (typeof cognitive.generateTextStream === "function") {
|
|
240
|
-
|
|
241
|
-
|
|
255
|
+
let parser = new StreamingMessageParser();
|
|
256
|
+
let fence = new LeadingFenceFilter();
|
|
242
257
|
const streamController = createJoinedAbortController([controller.signal]);
|
|
243
258
|
const requestedAt = Date.now();
|
|
244
259
|
const stream = cognitive.generateTextStream({
|
|
245
260
|
...input,
|
|
246
|
-
...ctx.maxTimeToFirstToken ? { options: {
|
|
261
|
+
...ctx.maxTimeToFirstToken || bufferedDelivery ? { options: {
|
|
247
262
|
...input.options,
|
|
248
|
-
maxTimeToFirstToken: ctx.maxTimeToFirstToken
|
|
263
|
+
...ctx.maxTimeToFirstToken ? { maxTimeToFirstToken: ctx.maxTimeToFirstToken } : {},
|
|
264
|
+
...bufferedDelivery ? { midStreamFallback: true } : {}
|
|
249
265
|
} } : {}
|
|
250
266
|
}, { signal: streamController.signal });
|
|
251
267
|
const inactivityTimeout = Math.max(STREAM_INACTIVITY_TIMEOUT, ctx.maxTimeToFirstToken ?? 0);
|
|
@@ -264,28 +280,68 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
264
280
|
}
|
|
265
281
|
};
|
|
266
282
|
raw = "";
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
chunk
|
|
272
|
-
|
|
273
|
-
|
|
283
|
+
let streamCompleted = false;
|
|
284
|
+
try {
|
|
285
|
+
while (true) {
|
|
286
|
+
var _chunk$value, _chunk$value2, _chunk$value3, _chunk$value4;
|
|
287
|
+
let chunk;
|
|
288
|
+
try {
|
|
289
|
+
chunk = await nextChunk();
|
|
290
|
+
} catch (thrown) {
|
|
291
|
+
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
292
|
+
}
|
|
293
|
+
if (chunk.done) {
|
|
294
|
+
streamCompleted = true;
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
if (((_chunk$value = chunk.value) === null || _chunk$value === void 0 ? void 0 : _chunk$value.restart) && !bufferedDelivery) {
|
|
298
|
+
streamController.abort("Unexpected LLM stream restart");
|
|
299
|
+
throw new CognitiveError("LLM stream restarted without options.midStreamFallback enabled");
|
|
300
|
+
}
|
|
301
|
+
if ((_chunk$value2 = chunk.value) === null || _chunk$value2 === void 0 ? void 0 : _chunk$value2.restart) {
|
|
302
|
+
traces.push({
|
|
303
|
+
type: "llm_call_restarted",
|
|
304
|
+
started_at: Date.now(),
|
|
305
|
+
...chunk.value.restart
|
|
306
|
+
});
|
|
307
|
+
raw = "";
|
|
308
|
+
parser = new StreamingMessageParser();
|
|
309
|
+
fence = new LeadingFenceFilter();
|
|
310
|
+
liveItems.clear();
|
|
311
|
+
liveContent.clear();
|
|
312
|
+
pendingDeliveries = [];
|
|
313
|
+
codeGenerationTraced = false;
|
|
314
|
+
runCompleted = false;
|
|
315
|
+
responseMetadata = void 0;
|
|
316
|
+
timeToFirstToken = void 0;
|
|
317
|
+
timeToLastToken = void 0;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if ((_chunk$value3 = chunk.value) === null || _chunk$value3 === void 0 ? void 0 : _chunk$value3.metadata) responseMetadata = chunk.value.metadata;
|
|
321
|
+
const delta = (_chunk$value4 = chunk.value) === null || _chunk$value4 === void 0 ? void 0 : _chunk$value4.output;
|
|
322
|
+
if (!delta) continue;
|
|
323
|
+
timeToLastToken = Date.now() - requestedAt;
|
|
324
|
+
timeToFirstToken ??= timeToLastToken;
|
|
325
|
+
raw += delta;
|
|
326
|
+
await dispatchSends(parser.push(fence.push(delta)));
|
|
327
|
+
}
|
|
328
|
+
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
329
|
+
const remaining = fence.flush();
|
|
330
|
+
if (remaining) await dispatchSends(parser.push(remaining));
|
|
331
|
+
await dispatchSends(parser.finish());
|
|
332
|
+
assistantResponse = toParsedAssistantResponse(parser.items, raw);
|
|
333
|
+
} finally {
|
|
334
|
+
streamController.abort("LLM stream closed");
|
|
335
|
+
if (!streamCompleted) stream.return(void 0).catch(() => {});
|
|
336
|
+
}
|
|
337
|
+
if (bufferedDelivery) {
|
|
338
|
+
controller.signal.throwIfAborted();
|
|
339
|
+
for (const callback of pendingDeliveries) {
|
|
340
|
+
controller.signal.throwIfAborted();
|
|
341
|
+
await callback();
|
|
274
342
|
}
|
|
275
|
-
|
|
276
|
-
if ((_chunk$value = chunk.value) === null || _chunk$value === void 0 ? void 0 : _chunk$value.metadata) responseMetadata = chunk.value.metadata;
|
|
277
|
-
const delta = (_chunk$value2 = chunk.value) === null || _chunk$value2 === void 0 ? void 0 : _chunk$value2.output;
|
|
278
|
-
if (!delta) continue;
|
|
279
|
-
timeToLastToken = Date.now() - requestedAt;
|
|
280
|
-
timeToFirstToken ??= timeToLastToken;
|
|
281
|
-
raw += delta;
|
|
282
|
-
await dispatchSends(parser.push(fence.push(delta)));
|
|
343
|
+
pendingDeliveries = [];
|
|
283
344
|
}
|
|
284
|
-
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
285
|
-
const remaining = fence.flush();
|
|
286
|
-
if (remaining) await dispatchSends(parser.push(remaining));
|
|
287
|
-
await dispatchSends(parser.finish());
|
|
288
|
-
assistantResponse = toParsedAssistantResponse(parser.items, raw);
|
|
289
345
|
} else {
|
|
290
346
|
const response = await cognitive.generateText(input, { signal: controller.signal }).catch((thrown) => {
|
|
291
347
|
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
@@ -327,7 +383,7 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
327
383
|
type: "llm_call_success",
|
|
328
384
|
started_at: startedAt,
|
|
329
385
|
ended_at: iteration.llm.ended_at,
|
|
330
|
-
model: model
|
|
386
|
+
model: iteration.llm.model,
|
|
331
387
|
code: iteration.code ?? ""
|
|
332
388
|
});
|
|
333
389
|
};
|
|
@@ -675,7 +731,7 @@ const executeContext = async (props) => {
|
|
|
675
731
|
return result;
|
|
676
732
|
};
|
|
677
733
|
const executeContextInternal = async (props) => {
|
|
678
|
-
var _props$options, _props$options2, _props$options3, _props$options4, _props$options5;
|
|
734
|
+
var _props$options, _props$options2, _props$options3, _props$options4, _props$options5, _props$options6;
|
|
679
735
|
const controller = createJoinedAbortController([props.signal]);
|
|
680
736
|
const { onIterationStart, onIterationEnd, onTrace, onExit, onBeforeExecution, onAfterTool, onBeforeTool } = props;
|
|
681
737
|
const client = props.client ?? new Client();
|
|
@@ -689,7 +745,8 @@ const executeContextInternal = async (props) => {
|
|
|
689
745
|
timeout: (_props$options2 = props.options) === null || _props$options2 === void 0 ? void 0 : _props$options2.timeout,
|
|
690
746
|
maxTokens: (_props$options3 = props.options) === null || _props$options3 === void 0 ? void 0 : _props$options3.maxTokens,
|
|
691
747
|
maxTimeToFirstToken: (_props$options4 = props.options) === null || _props$options4 === void 0 ? void 0 : _props$options4.maxTimeToFirstToken,
|
|
692
|
-
|
|
748
|
+
midStreamFallback: (_props$options5 = props.options) === null || _props$options5 === void 0 ? void 0 : _props$options5.midStreamFallback,
|
|
749
|
+
transcriptionModel: (_props$options6 = props.options) === null || _props$options6 === void 0 ? void 0 : _props$options6.transcriptionModel,
|
|
693
750
|
exits: props.exits,
|
|
694
751
|
snapshot: props.snapshot,
|
|
695
752
|
model: props.model,
|
|
@@ -882,7 +939,7 @@ const executeIteration = async ({ iteration, ctx, cognitive, controller, onExit,
|
|
|
882
939
|
};
|
|
883
940
|
});
|
|
884
941
|
};
|
|
885
|
-
const canExecuteEarly = typeof onBeforeExecution !== "function";
|
|
942
|
+
const canExecuteEarly = typeof onBeforeExecution !== "function" && !ctx.midStreamFallback;
|
|
886
943
|
let earlyExecution;
|
|
887
944
|
await generateCode({
|
|
888
945
|
iteration,
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_dual_modes = require("./dual-modes-wAOAlaBS.cjs");
|
|
3
|
-
const require_custom_client = require("./custom-client-
|
|
3
|
+
const require_custom_client = require("./custom-client-BX8gx0tI.cjs");
|
|
4
4
|
const require_utils = require("./utils-ZpJm00ed.cjs");
|
|
5
5
|
const require_tool = require("./tool-DdPZb0JW.cjs");
|
|
6
6
|
const require_errors = require("./errors-C962uJdS.cjs");
|
|
@@ -11,7 +11,7 @@ const require_truncator = require("./truncator-B6aaJaN1.cjs");
|
|
|
11
11
|
const require_quickjs_variant = require("./quickjs-variant-CsIwTVFC.cjs");
|
|
12
12
|
let _bpinternal_zui = require("@bpinternal/zui");
|
|
13
13
|
//#region package.json
|
|
14
|
-
var version = "0.6.
|
|
14
|
+
var version = "0.6.5";
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/hoist.ts
|
|
17
17
|
/**
|
|
@@ -1774,7 +1774,7 @@ const utils = {
|
|
|
1774
1774
|
* })
|
|
1775
1775
|
*/
|
|
1776
1776
|
const execute = async (props) => {
|
|
1777
|
-
const { executeContext } = await Promise.resolve().then(() => require("./execute-
|
|
1777
|
+
const { executeContext } = await Promise.resolve().then(() => require("./execute-BJF4Txh2.cjs"));
|
|
1778
1778
|
return executeContext(props);
|
|
1779
1779
|
};
|
|
1780
1780
|
/**
|
|
@@ -1783,7 +1783,7 @@ const execute = async (props) => {
|
|
|
1783
1783
|
* It's recommended to call this function at the beginning of your application without awaiting it (void init())
|
|
1784
1784
|
*/
|
|
1785
1785
|
const init = async () => {
|
|
1786
|
-
await Promise.resolve().then(() => require("./execute-
|
|
1786
|
+
await Promise.resolve().then(() => require("./execute-BJF4Txh2.cjs"));
|
|
1787
1787
|
await Promise.resolve().then(() => require("./component-BwixNVH8.cjs")).then((n) => n.component_exports);
|
|
1788
1788
|
await Promise.resolve().then(() => require("./tool-DdPZb0JW.cjs")).then((n) => n.tool_exports);
|
|
1789
1789
|
await Promise.resolve().then(() => require("./exit-BGi0Kk0y.cjs")).then((n) => n.exit_exports);
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as StreamingMessageParser, c as NAME_REGEX, o as tryParseJson, r as generateInstructions, s as MARKER } from "./dual-modes-D_p-jedw.js";
|
|
2
|
-
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-
|
|
2
|
+
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-BnlDpjdI.js";
|
|
3
3
|
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";
|
|
4
4
|
import { t as Tool } from "./tool-CAo-BQHs.js";
|
|
5
5
|
import { c as SnapshotSignal, l as ThinkSignal, o as LoopExceededError, r as CodeFormattingError } from "./errors-Cg1G0Awu.js";
|
|
@@ -10,7 +10,7 @@ import { i as wrapContent, n as truncateWrappedContent, t as stripTruncationTags
|
|
|
10
10
|
import { t as configureQuickJS } from "./quickjs-variant-BYhMBpwU.js";
|
|
11
11
|
import { transforms, z } from "@bpinternal/zui";
|
|
12
12
|
//#region package.json
|
|
13
|
-
var version = "0.6.
|
|
13
|
+
var version = "0.6.5";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/hoist.ts
|
|
16
16
|
/**
|
|
@@ -1773,7 +1773,7 @@ const utils = {
|
|
|
1773
1773
|
* })
|
|
1774
1774
|
*/
|
|
1775
1775
|
const execute = async (props) => {
|
|
1776
|
-
const { executeContext } = await import("./execute-
|
|
1776
|
+
const { executeContext } = await import("./execute-BjBBTshA.js");
|
|
1777
1777
|
return executeContext(props);
|
|
1778
1778
|
};
|
|
1779
1779
|
/**
|
|
@@ -1782,7 +1782,7 @@ const execute = async (props) => {
|
|
|
1782
1782
|
* It's recommended to call this function at the beginning of your application without awaiting it (void init())
|
|
1783
1783
|
*/
|
|
1784
1784
|
const init = async () => {
|
|
1785
|
-
await import("./execute-
|
|
1785
|
+
await import("./execute-BjBBTshA.js");
|
|
1786
1786
|
await import("./component-DGG7d_Mz.js").then((n) => n.r);
|
|
1787
1787
|
await import("./tool-CAo-BQHs.js").then((n) => n.n);
|
|
1788
1788
|
await import("./exit-CDdxDBRT.js").then((n) => n.n);
|
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.6.
|
|
55
|
+
var version = "0.6.5";
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region ../../node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_freeGlobal.js
|
|
58
58
|
var freeGlobal;
|
|
@@ -12215,6 +12215,11 @@ var init_context = __esmMin((() => {
|
|
|
12215
12215
|
*/
|
|
12216
12216
|
maxTimeToFirstToken;
|
|
12217
12217
|
/**
|
|
12218
|
+
* Allow Cognitive mid-stream fallback, buffering delivery until generation
|
|
12219
|
+
* succeeds and discarding abandoned attempts. Streaming-only; defaults to false.
|
|
12220
|
+
*/
|
|
12221
|
+
midStreamFallback;
|
|
12222
|
+
/**
|
|
12218
12223
|
* STT model used by the cognitive service to transcribe audio attachments
|
|
12219
12224
|
* when the target LLM does not support audio natively. Defaults to 'fast'.
|
|
12220
12225
|
*/
|
|
@@ -12449,10 +12454,12 @@ var init_context = __esmMin((() => {
|
|
|
12449
12454
|
this.snapshot = props.snapshot;
|
|
12450
12455
|
this.maxTokens = props.maxTokens;
|
|
12451
12456
|
this.maxTimeToFirstToken = props.maxTimeToFirstToken;
|
|
12457
|
+
this.midStreamFallback = props.midStreamFallback;
|
|
12452
12458
|
this.transcriptionModel = props.transcriptionModel;
|
|
12453
12459
|
if (this.loop < 1 || this.loop > 100) throw new Error("Invalid loop. Expected a number between 1 and 100.");
|
|
12454
12460
|
if (this.maxTokens !== void 0 && (!Number.isFinite(this.maxTokens) || this.maxTokens < 1)) throw new Error("Invalid maxTokens. Expected a positive number.");
|
|
12455
12461
|
if (this.maxTimeToFirstToken !== void 0 && (!Number.isFinite(this.maxTimeToFirstToken) || this.maxTimeToFirstToken < 1)) throw new Error("Invalid maxTimeToFirstToken. Expected a positive number of milliseconds.");
|
|
12462
|
+
if (this.midStreamFallback !== void 0 && typeof this.midStreamFallback !== "boolean") throw new Error("Invalid midStreamFallback. Expected a boolean.");
|
|
12456
12463
|
}
|
|
12457
12464
|
toJSON() {
|
|
12458
12465
|
return {
|
|
@@ -17023,7 +17030,7 @@ var init_generate = __esmMin((() => {
|
|
|
17023
17030
|
MAX_TOKENS: 16e3,
|
|
17024
17031
|
PERCENTAGE: .1
|
|
17025
17032
|
};
|
|
17026
|
-
STREAM_INACTIVITY_TIMEOUT =
|
|
17033
|
+
STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
17027
17034
|
getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
17028
17035
|
LeadingFenceFilter = class {
|
|
17029
17036
|
_buffer = "";
|
|
@@ -17093,6 +17100,12 @@ var init_generate = __esmMin((() => {
|
|
|
17093
17100
|
/** Milliseconds between the stream request and the first/last streamed tokens. */
|
|
17094
17101
|
let timeToFirstToken;
|
|
17095
17102
|
let timeToLastToken;
|
|
17103
|
+
const bufferedDelivery = ctx.midStreamFallback === true;
|
|
17104
|
+
let pendingDeliveries = [];
|
|
17105
|
+
const deliver = async (callback) => {
|
|
17106
|
+
if (bufferedDelivery) pendingDeliveries.push(callback);
|
|
17107
|
+
else await callback();
|
|
17108
|
+
};
|
|
17096
17109
|
const liveItems = /* @__PURE__ */ new Map();
|
|
17097
17110
|
const liveContent = /* @__PURE__ */ new Map();
|
|
17098
17111
|
let codeGenerationTraced = false;
|
|
@@ -17102,48 +17115,58 @@ var init_generate = __esmMin((() => {
|
|
|
17102
17115
|
liveItems.set(event.item.id, event.item);
|
|
17103
17116
|
if (event.item.kind === "run" && !codeGenerationTraced) {
|
|
17104
17117
|
codeGenerationTraced = true;
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
17118
|
+
const started_at = Date.now();
|
|
17119
|
+
await deliver(() => {
|
|
17120
|
+
traces.push({
|
|
17121
|
+
type: "code_generation_started",
|
|
17122
|
+
started_at
|
|
17123
|
+
});
|
|
17124
|
+
onRunStart?.();
|
|
17108
17125
|
});
|
|
17109
|
-
onRunStart?.();
|
|
17110
17126
|
}
|
|
17111
17127
|
} else if (event.type === "body-delta" && onSendDelta) {
|
|
17112
17128
|
const item = liveItems.get(event.itemId);
|
|
17113
17129
|
if (item?.kind !== "send") continue;
|
|
17114
17130
|
const content = (liveContent.get(item.id) ?? "") + event.delta;
|
|
17115
17131
|
liveContent.set(item.id, content);
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
name: event.item.name,
|
|
17128
|
-
props: event.item.props,
|
|
17129
|
-
body: event.item.body
|
|
17132
|
+
const delta = {
|
|
17133
|
+
id: `${iteration.id}:${item.id}`,
|
|
17134
|
+
component: item.name,
|
|
17135
|
+
props: bufferedDelivery ? structuredClone(item.props) : item.props,
|
|
17136
|
+
delta: event.delta,
|
|
17137
|
+
content
|
|
17138
|
+
};
|
|
17139
|
+
await deliver(async () => {
|
|
17140
|
+
try {
|
|
17141
|
+
await onSendDelta(delta);
|
|
17142
|
+
} catch (err) {}
|
|
17130
17143
|
});
|
|
17131
|
-
|
|
17144
|
+
} else if (event.type === "item-complete") {
|
|
17145
|
+
if (event.item.kind === "send" && onSend) {
|
|
17146
|
+
const send = {
|
|
17147
|
+
name: event.item.name,
|
|
17148
|
+
props: bufferedDelivery ? structuredClone(event.item.props) : event.item.props,
|
|
17149
|
+
body: event.item.body
|
|
17150
|
+
};
|
|
17151
|
+
await deliver(() => onSend(send));
|
|
17152
|
+
} else if (event.item.kind === "run" && event.item.status === "complete" && !runCompleted) {
|
|
17132
17153
|
runCompleted = true;
|
|
17133
|
-
|
|
17154
|
+
const code = (event.item.body ?? "").trim();
|
|
17155
|
+
await deliver(() => onRunComplete?.(code));
|
|
17134
17156
|
}
|
|
17135
17157
|
}
|
|
17136
17158
|
};
|
|
17137
17159
|
if (typeof cognitive.generateTextStream === "function") {
|
|
17138
|
-
|
|
17139
|
-
|
|
17160
|
+
let parser = new StreamingMessageParser();
|
|
17161
|
+
let fence = new LeadingFenceFilter();
|
|
17140
17162
|
const streamController = createJoinedAbortController([controller.signal]);
|
|
17141
17163
|
const requestedAt = Date.now();
|
|
17142
17164
|
const stream = cognitive.generateTextStream({
|
|
17143
17165
|
...input,
|
|
17144
|
-
...ctx.maxTimeToFirstToken ? { options: {
|
|
17166
|
+
...ctx.maxTimeToFirstToken || bufferedDelivery ? { options: {
|
|
17145
17167
|
...input.options,
|
|
17146
|
-
maxTimeToFirstToken: ctx.maxTimeToFirstToken
|
|
17168
|
+
...ctx.maxTimeToFirstToken ? { maxTimeToFirstToken: ctx.maxTimeToFirstToken } : {},
|
|
17169
|
+
...bufferedDelivery ? { midStreamFallback: true } : {}
|
|
17147
17170
|
} } : {}
|
|
17148
17171
|
}, { signal: streamController.signal });
|
|
17149
17172
|
const inactivityTimeout = Math.max(STREAM_INACTIVITY_TIMEOUT, ctx.maxTimeToFirstToken ?? 0);
|
|
@@ -17162,27 +17185,67 @@ var init_generate = __esmMin((() => {
|
|
|
17162
17185
|
}
|
|
17163
17186
|
};
|
|
17164
17187
|
raw = "";
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
chunk
|
|
17169
|
-
|
|
17170
|
-
|
|
17188
|
+
let streamCompleted = false;
|
|
17189
|
+
try {
|
|
17190
|
+
while (true) {
|
|
17191
|
+
let chunk;
|
|
17192
|
+
try {
|
|
17193
|
+
chunk = await nextChunk();
|
|
17194
|
+
} catch (thrown) {
|
|
17195
|
+
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
17196
|
+
}
|
|
17197
|
+
if (chunk.done) {
|
|
17198
|
+
streamCompleted = true;
|
|
17199
|
+
break;
|
|
17200
|
+
}
|
|
17201
|
+
if (chunk.value?.restart && !bufferedDelivery) {
|
|
17202
|
+
streamController.abort("Unexpected LLM stream restart");
|
|
17203
|
+
throw new CognitiveError("LLM stream restarted without options.midStreamFallback enabled");
|
|
17204
|
+
}
|
|
17205
|
+
if (chunk.value?.restart) {
|
|
17206
|
+
traces.push({
|
|
17207
|
+
type: "llm_call_restarted",
|
|
17208
|
+
started_at: Date.now(),
|
|
17209
|
+
...chunk.value.restart
|
|
17210
|
+
});
|
|
17211
|
+
raw = "";
|
|
17212
|
+
parser = new StreamingMessageParser();
|
|
17213
|
+
fence = new LeadingFenceFilter();
|
|
17214
|
+
liveItems.clear();
|
|
17215
|
+
liveContent.clear();
|
|
17216
|
+
pendingDeliveries = [];
|
|
17217
|
+
codeGenerationTraced = false;
|
|
17218
|
+
runCompleted = false;
|
|
17219
|
+
responseMetadata = void 0;
|
|
17220
|
+
timeToFirstToken = void 0;
|
|
17221
|
+
timeToLastToken = void 0;
|
|
17222
|
+
continue;
|
|
17223
|
+
}
|
|
17224
|
+
if (chunk.value?.metadata) responseMetadata = chunk.value.metadata;
|
|
17225
|
+
const delta = chunk.value?.output;
|
|
17226
|
+
if (!delta) continue;
|
|
17227
|
+
timeToLastToken = Date.now() - requestedAt;
|
|
17228
|
+
timeToFirstToken ??= timeToLastToken;
|
|
17229
|
+
raw += delta;
|
|
17230
|
+
await dispatchSends(parser.push(fence.push(delta)));
|
|
17231
|
+
}
|
|
17232
|
+
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
17233
|
+
const remaining = fence.flush();
|
|
17234
|
+
if (remaining) await dispatchSends(parser.push(remaining));
|
|
17235
|
+
await dispatchSends(parser.finish());
|
|
17236
|
+
assistantResponse = toParsedAssistantResponse(parser.items, raw);
|
|
17237
|
+
} finally {
|
|
17238
|
+
streamController.abort("LLM stream closed");
|
|
17239
|
+
if (!streamCompleted) stream.return(void 0).catch(() => {});
|
|
17240
|
+
}
|
|
17241
|
+
if (bufferedDelivery) {
|
|
17242
|
+
controller.signal.throwIfAborted();
|
|
17243
|
+
for (const callback of pendingDeliveries) {
|
|
17244
|
+
controller.signal.throwIfAborted();
|
|
17245
|
+
await callback();
|
|
17171
17246
|
}
|
|
17172
|
-
|
|
17173
|
-
if (chunk.value?.metadata) responseMetadata = chunk.value.metadata;
|
|
17174
|
-
const delta = chunk.value?.output;
|
|
17175
|
-
if (!delta) continue;
|
|
17176
|
-
timeToLastToken = Date.now() - requestedAt;
|
|
17177
|
-
timeToFirstToken ??= timeToLastToken;
|
|
17178
|
-
raw += delta;
|
|
17179
|
-
await dispatchSends(parser.push(fence.push(delta)));
|
|
17247
|
+
pendingDeliveries = [];
|
|
17180
17248
|
}
|
|
17181
|
-
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
17182
|
-
const remaining = fence.flush();
|
|
17183
|
-
if (remaining) await dispatchSends(parser.push(remaining));
|
|
17184
|
-
await dispatchSends(parser.finish());
|
|
17185
|
-
assistantResponse = toParsedAssistantResponse(parser.items, raw);
|
|
17186
17249
|
} else {
|
|
17187
17250
|
const response = await cognitive.generateText(input, { signal: controller.signal }).catch((thrown) => {
|
|
17188
17251
|
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
@@ -17224,7 +17287,7 @@ var init_generate = __esmMin((() => {
|
|
|
17224
17287
|
type: "llm_call_success",
|
|
17225
17288
|
started_at: startedAt,
|
|
17226
17289
|
ended_at: iteration.llm.ended_at,
|
|
17227
|
-
model: model
|
|
17290
|
+
model: iteration.llm.model,
|
|
17228
17291
|
code: iteration.code ?? ""
|
|
17229
17292
|
});
|
|
17230
17293
|
};
|
|
@@ -17614,6 +17677,7 @@ var init_execute = __esmMin((() => {
|
|
|
17614
17677
|
timeout: props.options?.timeout,
|
|
17615
17678
|
maxTokens: props.options?.maxTokens,
|
|
17616
17679
|
maxTimeToFirstToken: props.options?.maxTimeToFirstToken,
|
|
17680
|
+
midStreamFallback: props.options?.midStreamFallback,
|
|
17617
17681
|
transcriptionModel: props.options?.transcriptionModel,
|
|
17618
17682
|
exits: props.exits,
|
|
17619
17683
|
snapshot: props.snapshot,
|
|
@@ -17805,7 +17869,7 @@ var init_execute = __esmMin((() => {
|
|
|
17805
17869
|
};
|
|
17806
17870
|
});
|
|
17807
17871
|
};
|
|
17808
|
-
const canExecuteEarly = typeof onBeforeExecution !== "function";
|
|
17872
|
+
const canExecuteEarly = typeof onBeforeExecution !== "function" && !ctx.midStreamFallback;
|
|
17809
17873
|
let earlyExecution;
|
|
17810
17874
|
await generateCode({
|
|
17811
17875
|
iteration,
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -122,6 +122,13 @@ type Options = Partial<Pick<Context, 'loop' | 'timeout'>> & {
|
|
|
122
122
|
* `model` is an array of fallback models.
|
|
123
123
|
*/
|
|
124
124
|
maxTimeToFirstToken?: number;
|
|
125
|
+
/**
|
|
126
|
+
* Allow Cognitive to restart failed streams on another model. Buffers message
|
|
127
|
+
* previews, sends, and code execution until generation succeeds; abandoned
|
|
128
|
+
* attempts deliver nothing. Streaming-only; defaults to false, preserving
|
|
129
|
+
* progressive sends and early code execution.
|
|
130
|
+
*/
|
|
131
|
+
midStreamFallback?: boolean;
|
|
125
132
|
/**
|
|
126
133
|
* STT model used to transcribe audio attachments (voice messages) when the
|
|
127
134
|
* target LLM does not support audio natively. Audio-capable models receive
|
package/dist/types.d.ts
CHANGED
|
@@ -55,6 +55,13 @@ export declare namespace Traces {
|
|
|
55
55
|
model: string;
|
|
56
56
|
code: string;
|
|
57
57
|
}>;
|
|
58
|
+
/** Diagnostic only: content and effects from the preceding attempt are discarded. */
|
|
59
|
+
type LLMCallRestart = TraceTemplate<'llm_call_restarted', {
|
|
60
|
+
attempt: number;
|
|
61
|
+
fromModel: string;
|
|
62
|
+
toModel: string;
|
|
63
|
+
reason: string;
|
|
64
|
+
}>;
|
|
58
65
|
/**
|
|
59
66
|
* Emitted on streaming clients the moment the model starts writing a `■run`
|
|
60
67
|
* block — before the code is fully generated. Useful to show a
|
|
@@ -77,7 +84,7 @@ export declare namespace Traces {
|
|
|
77
84
|
started_at: number;
|
|
78
85
|
ended_at?: number;
|
|
79
86
|
} & Content;
|
|
80
|
-
type Trace = Comment | Log | ToolCall | ToolSlow | PropertyMutation | YieldTrace | LLMCallStart | LLMCallSuccess | CodeGenerationStart | ThinkSignal | CodeExecution | CodeExecutionException | InvalidCodeExceptionTrace | AbortTrace;
|
|
87
|
+
type Trace = Comment | Log | ToolCall | ToolSlow | PropertyMutation | YieldTrace | LLMCallStart | LLMCallSuccess | LLMCallRestart | CodeGenerationStart | ThinkSignal | CodeExecution | CodeExecutionException | InvalidCodeExceptionTrace | AbortTrace;
|
|
81
88
|
}
|
|
82
89
|
export type Trace = Traces.Trace;
|
|
83
90
|
export type VMExecutionResult = {
|
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.6.
|
|
5
|
+
"version": "0.6.5",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
8
|
"DOCS.md"
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@botpress/client": "2.4.0",
|
|
72
|
-
"@botpress/cognitive": "1.
|
|
72
|
+
"@botpress/cognitive": "1.2.0",
|
|
73
73
|
"@bpinternal/thicktoken": "^3.1.0",
|
|
74
74
|
"@bpinternal/zui": "^2.4.1"
|
|
75
75
|
},
|