llmz 0.6.7 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/context.d.ts +8 -0
- package/dist/{custom-client-Cr33K60k.cjs → custom-client-Bp1TgTKk.cjs} +1 -1
- package/dist/{custom-client-CJIThG2H.js → custom-client-CMuy7fXU.js} +1 -1
- package/dist/{dual-modes-wAOAlaBS.cjs → dual-modes-CfqTk9M8.cjs} +17 -43
- package/dist/{dual-modes-D_p-jedw.js → dual-modes-mNyMThtf.js} +17 -43
- package/dist/{execute-sn9RT_IN.js → execute-DP_17lYZ.js} +14 -5
- package/dist/{execute-BmEjJjka.cjs → execute-msui51b2.cjs} +14 -5
- package/dist/index.cjs +6 -6
- package/dist/index.js +6 -6
- package/dist/index.workerd.js +26 -46
- package/dist/message-stream/parser.d.ts +7 -8
- package/dist/prompts/common.d.ts +2 -2
- package/dist/prompts/prompt.d.ts +3 -1
- package/dist/result.d.ts +3 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -79,6 +79,10 @@ return { ...payment, date: dates[0] }
|
|
|
79
79
|
|
|
80
80
|
Because the protocol is parsed incrementally, messages stream to your UI token-by-token, tool calls surface live, and code execution can start before the response has even finished streaming.
|
|
81
81
|
|
|
82
|
+
Only explicit `■send` blocks produce messages or message deltas. Unexpected text outside protocol blocks is discarded in streaming, fallback restarts, and nonstreaming execution. Explicit Markdown (`■send=md`) is supported. A response with only unexpected text follows the normal invalid-response retry/error path. For debugging, `iteration.llm.output` retains the raw response and `iteration.llm.diagnostics` records parser diagnostics, including `unexpected-text`.
|
|
83
|
+
|
|
84
|
+
As of 0.7.0, the parser options `strict` and `recoveryComponent` have been removed. All parsing requires explicit send blocks; callers relying on implicit messages must emit `■send=<component>` instead.
|
|
85
|
+
|
|
82
86
|
---
|
|
83
87
|
|
|
84
88
|
## Quick Start
|
|
@@ -323,15 +327,22 @@ With a streaming client (`CognitiveBeta` / Cognitive v2), everything an executio
|
|
|
323
327
|
const chat = new Chat({
|
|
324
328
|
components: [DefaultComponents.Text],
|
|
325
329
|
transcript: () => transcript,
|
|
326
|
-
handler: async (component) => finalizeBubble(component),
|
|
330
|
+
handler: async (component, metadata) => finalizeBubble(component, metadata),
|
|
327
331
|
// Fires per token-chunk while the LLM is still generating
|
|
328
|
-
onMessageDelta: (delta) =>
|
|
332
|
+
onMessageDelta: (delta) => {
|
|
333
|
+
if (delta.restart) {
|
|
334
|
+
// Remove ALL this iteration's messages, including completed handler sends.
|
|
335
|
+
return clearIterationMessages(delta.iterationId)
|
|
336
|
+
}
|
|
337
|
+
return updateBubble(delta.iterationId, delta.id, delta.content)
|
|
338
|
+
},
|
|
329
339
|
})
|
|
330
340
|
|
|
331
341
|
const result = await execute({
|
|
332
342
|
client, // CognitiveBeta
|
|
333
343
|
chat,
|
|
334
344
|
tools,
|
|
345
|
+
options: { midStreamFallback: true },
|
|
335
346
|
onTrace: ({ trace }) => {
|
|
336
347
|
if (trace.type === 'llm_call_started') showSpinner()
|
|
337
348
|
if (trace.type === 'code_generation_started') showStatus('writing code…')
|
|
@@ -343,7 +354,14 @@ const result = await execute({
|
|
|
343
354
|
|
|
344
355
|
- **Message deltas** stream to your UI token-by-token (`handler` remains the authoritative delivery)
|
|
345
356
|
- **Live traces** cover the full turn lifecycle: `llm_call_started` → message deltas → `code_generation_started` → `llm_call_success` (with the code) → `tool_call`s → exit
|
|
346
|
-
- **
|
|
357
|
+
- **Fallback**: a `restart: true` delta invalidates the current iteration's messages before replacement output arrives. Replacement messages have fresh IDs under the same `iterationId`. Code executes only after the replacement stream succeeds; abandoned code never runs.
|
|
358
|
+
- **Early execution**: without `midStreamFallback`, a closed `■run` block can start executing while the response tail is still streaming. A later generation failure returns an error without retrying the code. The VM pre-warms when code generation begins in either mode.
|
|
359
|
+
|
|
360
|
+
Terminal failures return an `ErrorExecutionResult`; they do not emit a restart delta because there is no replacement attempt. Handle that result to clear or mark unfinished messages as failed. Already delivered messages remain delivered unless your consumer retracts them. Nonstreaming Cognitive fallback exposes only the successful response, so no message reset is needed.
|
|
361
|
+
|
|
362
|
+
LLMz rejects explicit Cognitive errors, error metadata (`provider: "unknown"`), and responses stopped by a token limit or content filter before finalizing unfinished blocks. Such failures cannot turn a partial code prefix into executable code. With fallback disabled, this cannot undo code that already ran after a block boundary.
|
|
363
|
+
|
|
364
|
+
`■run` followed by `■send` is currently accepted, but that message was generated without seeing the code's result. Prefer sending an acknowledgement before `■run`, returning the needed data, then answering in the next iteration. A top-level `return` always requests another iteration; side-effect-only code can finish immediately with `■next`.
|
|
347
365
|
|
|
348
366
|
Forward these events over a websocket or SSE stream and your frontend renders the agent live — see [example 22](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/22_chat_streaming).
|
|
349
367
|
|
package/dist/context.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { SnapshotSignal } from './errors.js';
|
|
|
6
6
|
import { Exit } from './exit.js';
|
|
7
7
|
import { ValueOrGetter } from './getter.js';
|
|
8
8
|
import { HookedArray } from './handlers.js';
|
|
9
|
+
import type { Diagnostic } from './message-stream/types.js';
|
|
9
10
|
import { ObjectInstance } from './objects.js';
|
|
10
11
|
import { LLMzPrompts, ParsedNext, ParsedSend, Prompt } from './prompts/prompt.js';
|
|
11
12
|
import { Snapshot } from './snapshots.js';
|
|
@@ -365,6 +366,7 @@ export declare namespace Iteration {
|
|
|
365
366
|
tokens: number;
|
|
366
367
|
spend: number;
|
|
367
368
|
output: string;
|
|
369
|
+
diagnostics?: Diagnostic[];
|
|
368
370
|
model: string;
|
|
369
371
|
time_to_first_token?: number;
|
|
370
372
|
time_to_last_token?: number;
|
|
@@ -420,6 +422,8 @@ export declare class Iteration implements Serializable<Iteration.JSON> {
|
|
|
420
422
|
tokens: number;
|
|
421
423
|
spend: number;
|
|
422
424
|
output: string;
|
|
425
|
+
/** Syntax diagnostics from the response parser; raw output remains available above. */
|
|
426
|
+
diagnostics?: Diagnostic[];
|
|
423
427
|
model: string;
|
|
424
428
|
/** Milliseconds between the LLM call start and the first streamed token. Only set on streaming clients. */
|
|
425
429
|
time_to_first_token?: number;
|
|
@@ -475,6 +479,8 @@ export declare class Iteration implements Serializable<Iteration.JSON> {
|
|
|
475
479
|
tokens: number;
|
|
476
480
|
spend: number;
|
|
477
481
|
output: string;
|
|
482
|
+
/** Syntax diagnostics from the response parser; raw output remains available above. */
|
|
483
|
+
diagnostics?: Diagnostic[];
|
|
478
484
|
model: string;
|
|
479
485
|
/** Milliseconds between the LLM call start and the first streamed token. Only set on streaming clients. */
|
|
480
486
|
time_to_first_token?: number;
|
|
@@ -637,6 +643,8 @@ export declare class Context implements Serializable<Context.JSON> {
|
|
|
637
643
|
tokens: number;
|
|
638
644
|
spend: number;
|
|
639
645
|
output: string;
|
|
646
|
+
/** Syntax diagnostics from the response parser; raw output remains available above. */
|
|
647
|
+
diagnostics?: Diagnostic[];
|
|
640
648
|
model: string;
|
|
641
649
|
/** Milliseconds between the LLM call start and the first streamed token. Only set on streaming clients. */
|
|
642
650
|
time_to_first_token?: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require__overArg = require("./_overArg-C5Hy7oCi.cjs");
|
|
2
2
|
const require__baseIteratee = require("./_baseIteratee-CF4qP2a8.cjs");
|
|
3
|
-
const require_dual_modes = require("./dual-modes-
|
|
3
|
+
const require_dual_modes = require("./dual-modes-CfqTk9M8.cjs");
|
|
4
4
|
const require_utils = require("./utils-ZpJm00ed.cjs");
|
|
5
5
|
const require__getPrototype = require("./_getPrototype-DQDlNVVM.cjs");
|
|
6
6
|
const require_isPlainObject = require("./isPlainObject-CSxXVKCk.cjs");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as Symbol, n as isArray, o as root, r as isObjectLike } from "./_overArg-CRYbj1NH.js";
|
|
2
2
|
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";
|
|
3
|
-
import { f as flatRest, l as extractType, m as baseCreate, p as copyArray, t as DualModePrompt, u as inspect } from "./dual-modes-
|
|
3
|
+
import { f as flatRest, l as extractType, m as baseCreate, p as copyArray, t as DualModePrompt, u as inspect } from "./dual-modes-mNyMThtf.js";
|
|
4
4
|
import { _ as getSymbolsIn, b as keysIn, g as getAllKeysIn, o as getTokenizer, x as assignValue, y as baseSlice } from "./utils-UBeAFeEI.js";
|
|
5
5
|
import { t as getPrototype } from "./_getPrototype-CG7Dxrrz.js";
|
|
6
6
|
import { t as isPlainObject } from "./isPlainObject-D39AzPO2.js";
|
|
@@ -1615,6 +1615,8 @@ const tryParseJson = (text) => {
|
|
|
1615
1615
|
* The parser is purely syntactic: it knows the reserved `■` symbol and the
|
|
1616
1616
|
* directive grammar, but nothing about registered components, exits or their
|
|
1617
1617
|
* schemas. Semantic validation is a separate step (see `validator.ts`).
|
|
1618
|
+
* Text outside protocol blocks is always discarded with a diagnostic; only
|
|
1619
|
+
* explicit `■send` blocks can produce messages.
|
|
1618
1620
|
*
|
|
1619
1621
|
* Pushing the same text split across arbitrary chunk boundaries always produces
|
|
1620
1622
|
* the same items and the same concatenated body deltas. For a higher-level
|
|
@@ -1622,10 +1624,9 @@ const tryParseJson = (text) => {
|
|
|
1622
1624
|
*/
|
|
1623
1625
|
var StreamingMessageParser = class {
|
|
1624
1626
|
_maxPropsLength;
|
|
1625
|
-
_strict;
|
|
1626
|
-
_recoveryComponent;
|
|
1627
1627
|
_state = "idle";
|
|
1628
1628
|
_items = [];
|
|
1629
|
+
_diagnostics = [];
|
|
1629
1630
|
_current;
|
|
1630
1631
|
_currentReady = false;
|
|
1631
1632
|
_counter = 0;
|
|
@@ -1641,13 +1642,15 @@ var StreamingMessageParser = class {
|
|
|
1641
1642
|
_pendingWhitespace = "";
|
|
1642
1643
|
constructor(options = {}) {
|
|
1643
1644
|
this._maxPropsLength = options.maxPropsLength ?? 1e5;
|
|
1644
|
-
this._strict = options.strict ?? false;
|
|
1645
|
-
this._recoveryComponent = options.recoveryComponent ?? "md";
|
|
1646
1645
|
}
|
|
1647
1646
|
/** All items parsed so far, in order of appearance. */
|
|
1648
1647
|
get items() {
|
|
1649
1648
|
return [...this._items];
|
|
1650
1649
|
}
|
|
1650
|
+
/** All syntax diagnostics, including discarded text that has no protocol item. */
|
|
1651
|
+
get diagnostics() {
|
|
1652
|
+
return [...this._diagnostics];
|
|
1653
|
+
}
|
|
1651
1654
|
push(chunk) {
|
|
1652
1655
|
if (this._finished) throw new Error("Parser has already finished. Call reset() before parsing a new stream.");
|
|
1653
1656
|
const events = [];
|
|
@@ -1693,6 +1696,7 @@ var StreamingMessageParser = class {
|
|
|
1693
1696
|
reset() {
|
|
1694
1697
|
this._state = "idle";
|
|
1695
1698
|
this._items = [];
|
|
1699
|
+
this._diagnostics = [];
|
|
1696
1700
|
this._current = void 0;
|
|
1697
1701
|
this._currentReady = false;
|
|
1698
1702
|
this._counter = 0;
|
|
@@ -1711,7 +1715,7 @@ var StreamingMessageParser = class {
|
|
|
1711
1715
|
switch (this._state) {
|
|
1712
1716
|
case "idle":
|
|
1713
1717
|
if (char === "■") this._beginItem();
|
|
1714
|
-
else if (!isWhitespace(char)) this.
|
|
1718
|
+
else if (!isWhitespace(char)) this._skipUnexpectedText(events);
|
|
1715
1719
|
return;
|
|
1716
1720
|
case "directive":
|
|
1717
1721
|
if (char === "=") this._endDirective(events, "=");
|
|
@@ -1790,7 +1794,7 @@ var StreamingMessageParser = class {
|
|
|
1790
1794
|
if (isWhitespace(char)) return;
|
|
1791
1795
|
if (item.kind === "next") {
|
|
1792
1796
|
this._completeCurrent(events);
|
|
1793
|
-
this.
|
|
1797
|
+
this._skipUnexpectedText(events);
|
|
1794
1798
|
return;
|
|
1795
1799
|
}
|
|
1796
1800
|
this._startBody(events);
|
|
@@ -2036,46 +2040,15 @@ var StreamingMessageParser = class {
|
|
|
2036
2040
|
this._current = void 0;
|
|
2037
2041
|
this._currentReady = false;
|
|
2038
2042
|
}
|
|
2039
|
-
|
|
2040
|
-
if (this._strict) {
|
|
2041
|
-
this._diagnostic(events, {
|
|
2042
|
-
code: "unexpected-text",
|
|
2043
|
-
message: "Encountered text outside of a ■ block"
|
|
2044
|
-
});
|
|
2045
|
-
this._state = "skip";
|
|
2046
|
-
return;
|
|
2047
|
-
}
|
|
2048
|
-
const item = {
|
|
2049
|
-
id: `item-${this._counter++}`,
|
|
2050
|
-
kind: "send",
|
|
2051
|
-
name: this._recoveryComponent,
|
|
2052
|
-
props: {},
|
|
2053
|
-
body: "",
|
|
2054
|
-
status: "pending",
|
|
2055
|
-
diagnostics: []
|
|
2056
|
-
};
|
|
2057
|
-
this._items.push(item);
|
|
2058
|
-
this._current = item;
|
|
2059
|
-
this._currentReady = false;
|
|
2060
|
-
this._pendingWhitespace = "";
|
|
2043
|
+
_skipUnexpectedText(events) {
|
|
2061
2044
|
this._diagnostic(events, {
|
|
2062
2045
|
code: "unexpected-text",
|
|
2063
|
-
message:
|
|
2064
|
-
itemId: item.id
|
|
2065
|
-
});
|
|
2066
|
-
events.push({
|
|
2067
|
-
type: "item-start",
|
|
2068
|
-
item
|
|
2046
|
+
message: "Encountered text outside of a ■ block"
|
|
2069
2047
|
});
|
|
2070
|
-
this.
|
|
2071
|
-
events.push({
|
|
2072
|
-
type: "body-start",
|
|
2073
|
-
itemId: item.id
|
|
2074
|
-
});
|
|
2075
|
-
this._state = "body";
|
|
2076
|
-
this._appendBody(char);
|
|
2048
|
+
this._state = "skip";
|
|
2077
2049
|
}
|
|
2078
2050
|
_diagnostic(events, diagnostic) {
|
|
2051
|
+
this._diagnostics.push(diagnostic);
|
|
2079
2052
|
if (diagnostic.itemId) {
|
|
2080
2053
|
const item = this._items.find((i) => i.id === diagnostic.itemId);
|
|
2081
2054
|
item === null || item === void 0 || item.diagnostics.push(diagnostic);
|
|
@@ -2094,7 +2067,7 @@ const stripWrappingFences = (text) => text.trim().split("\n").filter((line, inde
|
|
|
2094
2067
|
return true;
|
|
2095
2068
|
}).join("\n");
|
|
2096
2069
|
/** Builds a {@link ParsedAssistantResponse} from parsed protocol items. */
|
|
2097
|
-
const toParsedAssistantResponse = (items, raw) => {
|
|
2070
|
+
const toParsedAssistantResponse = (items, raw, diagnostics = []) => {
|
|
2098
2071
|
var _run$body;
|
|
2099
2072
|
const sends = items.filter((item) => item.kind === "send").map((item) => ({
|
|
2100
2073
|
name: item.name,
|
|
@@ -2106,6 +2079,7 @@ const toParsedAssistantResponse = (items, raw) => {
|
|
|
2106
2079
|
return {
|
|
2107
2080
|
raw,
|
|
2108
2081
|
items,
|
|
2082
|
+
diagnostics,
|
|
2109
2083
|
sends,
|
|
2110
2084
|
code: (run === null || run === void 0 || (_run$body = run.body) === null || _run$body === void 0 ? void 0 : _run$body.trim()) || void 0,
|
|
2111
2085
|
next: next ? {
|
|
@@ -2118,7 +2092,7 @@ const parseAssistantResponse = (response) => {
|
|
|
2118
2092
|
const parser = new StreamingMessageParser();
|
|
2119
2093
|
parser.push(stripWrappingFences(response));
|
|
2120
2094
|
parser.finish();
|
|
2121
|
-
return toParsedAssistantResponse(parser.items, response);
|
|
2095
|
+
return toParsedAssistantResponse(parser.items, response, parser.diagnostics);
|
|
2122
2096
|
};
|
|
2123
2097
|
const replacePlaceholders = (prompt, values) => {
|
|
2124
2098
|
const regex = /* @__PURE__ */ new RegExp("■■■([A-Z0-9_\\.-]+)■■■", "gi");
|
|
@@ -1614,6 +1614,8 @@ const tryParseJson = (text) => {
|
|
|
1614
1614
|
* The parser is purely syntactic: it knows the reserved `■` symbol and the
|
|
1615
1615
|
* directive grammar, but nothing about registered components, exits or their
|
|
1616
1616
|
* schemas. Semantic validation is a separate step (see `validator.ts`).
|
|
1617
|
+
* Text outside protocol blocks is always discarded with a diagnostic; only
|
|
1618
|
+
* explicit `■send` blocks can produce messages.
|
|
1617
1619
|
*
|
|
1618
1620
|
* Pushing the same text split across arbitrary chunk boundaries always produces
|
|
1619
1621
|
* the same items and the same concatenated body deltas. For a higher-level
|
|
@@ -1621,10 +1623,9 @@ const tryParseJson = (text) => {
|
|
|
1621
1623
|
*/
|
|
1622
1624
|
var StreamingMessageParser = class {
|
|
1623
1625
|
_maxPropsLength;
|
|
1624
|
-
_strict;
|
|
1625
|
-
_recoveryComponent;
|
|
1626
1626
|
_state = "idle";
|
|
1627
1627
|
_items = [];
|
|
1628
|
+
_diagnostics = [];
|
|
1628
1629
|
_current;
|
|
1629
1630
|
_currentReady = false;
|
|
1630
1631
|
_counter = 0;
|
|
@@ -1640,13 +1641,15 @@ var StreamingMessageParser = class {
|
|
|
1640
1641
|
_pendingWhitespace = "";
|
|
1641
1642
|
constructor(options = {}) {
|
|
1642
1643
|
this._maxPropsLength = options.maxPropsLength ?? 1e5;
|
|
1643
|
-
this._strict = options.strict ?? false;
|
|
1644
|
-
this._recoveryComponent = options.recoveryComponent ?? "md";
|
|
1645
1644
|
}
|
|
1646
1645
|
/** All items parsed so far, in order of appearance. */
|
|
1647
1646
|
get items() {
|
|
1648
1647
|
return [...this._items];
|
|
1649
1648
|
}
|
|
1649
|
+
/** All syntax diagnostics, including discarded text that has no protocol item. */
|
|
1650
|
+
get diagnostics() {
|
|
1651
|
+
return [...this._diagnostics];
|
|
1652
|
+
}
|
|
1650
1653
|
push(chunk) {
|
|
1651
1654
|
if (this._finished) throw new Error("Parser has already finished. Call reset() before parsing a new stream.");
|
|
1652
1655
|
const events = [];
|
|
@@ -1692,6 +1695,7 @@ var StreamingMessageParser = class {
|
|
|
1692
1695
|
reset() {
|
|
1693
1696
|
this._state = "idle";
|
|
1694
1697
|
this._items = [];
|
|
1698
|
+
this._diagnostics = [];
|
|
1695
1699
|
this._current = void 0;
|
|
1696
1700
|
this._currentReady = false;
|
|
1697
1701
|
this._counter = 0;
|
|
@@ -1710,7 +1714,7 @@ var StreamingMessageParser = class {
|
|
|
1710
1714
|
switch (this._state) {
|
|
1711
1715
|
case "idle":
|
|
1712
1716
|
if (char === "■") this._beginItem();
|
|
1713
|
-
else if (!isWhitespace(char)) this.
|
|
1717
|
+
else if (!isWhitespace(char)) this._skipUnexpectedText(events);
|
|
1714
1718
|
return;
|
|
1715
1719
|
case "directive":
|
|
1716
1720
|
if (char === "=") this._endDirective(events, "=");
|
|
@@ -1789,7 +1793,7 @@ var StreamingMessageParser = class {
|
|
|
1789
1793
|
if (isWhitespace(char)) return;
|
|
1790
1794
|
if (item.kind === "next") {
|
|
1791
1795
|
this._completeCurrent(events);
|
|
1792
|
-
this.
|
|
1796
|
+
this._skipUnexpectedText(events);
|
|
1793
1797
|
return;
|
|
1794
1798
|
}
|
|
1795
1799
|
this._startBody(events);
|
|
@@ -2035,46 +2039,15 @@ var StreamingMessageParser = class {
|
|
|
2035
2039
|
this._current = void 0;
|
|
2036
2040
|
this._currentReady = false;
|
|
2037
2041
|
}
|
|
2038
|
-
|
|
2039
|
-
if (this._strict) {
|
|
2040
|
-
this._diagnostic(events, {
|
|
2041
|
-
code: "unexpected-text",
|
|
2042
|
-
message: "Encountered text outside of a ■ block"
|
|
2043
|
-
});
|
|
2044
|
-
this._state = "skip";
|
|
2045
|
-
return;
|
|
2046
|
-
}
|
|
2047
|
-
const item = {
|
|
2048
|
-
id: `item-${this._counter++}`,
|
|
2049
|
-
kind: "send",
|
|
2050
|
-
name: this._recoveryComponent,
|
|
2051
|
-
props: {},
|
|
2052
|
-
body: "",
|
|
2053
|
-
status: "pending",
|
|
2054
|
-
diagnostics: []
|
|
2055
|
-
};
|
|
2056
|
-
this._items.push(item);
|
|
2057
|
-
this._current = item;
|
|
2058
|
-
this._currentReady = false;
|
|
2059
|
-
this._pendingWhitespace = "";
|
|
2042
|
+
_skipUnexpectedText(events) {
|
|
2060
2043
|
this._diagnostic(events, {
|
|
2061
2044
|
code: "unexpected-text",
|
|
2062
|
-
message:
|
|
2063
|
-
itemId: item.id
|
|
2064
|
-
});
|
|
2065
|
-
events.push({
|
|
2066
|
-
type: "item-start",
|
|
2067
|
-
item
|
|
2045
|
+
message: "Encountered text outside of a ■ block"
|
|
2068
2046
|
});
|
|
2069
|
-
this.
|
|
2070
|
-
events.push({
|
|
2071
|
-
type: "body-start",
|
|
2072
|
-
itemId: item.id
|
|
2073
|
-
});
|
|
2074
|
-
this._state = "body";
|
|
2075
|
-
this._appendBody(char);
|
|
2047
|
+
this._state = "skip";
|
|
2076
2048
|
}
|
|
2077
2049
|
_diagnostic(events, diagnostic) {
|
|
2050
|
+
this._diagnostics.push(diagnostic);
|
|
2078
2051
|
if (diagnostic.itemId) {
|
|
2079
2052
|
const item = this._items.find((i) => i.id === diagnostic.itemId);
|
|
2080
2053
|
item === null || item === void 0 || item.diagnostics.push(diagnostic);
|
|
@@ -2093,7 +2066,7 @@ const stripWrappingFences = (text) => text.trim().split("\n").filter((line, inde
|
|
|
2093
2066
|
return true;
|
|
2094
2067
|
}).join("\n");
|
|
2095
2068
|
/** Builds a {@link ParsedAssistantResponse} from parsed protocol items. */
|
|
2096
|
-
const toParsedAssistantResponse = (items, raw) => {
|
|
2069
|
+
const toParsedAssistantResponse = (items, raw, diagnostics = []) => {
|
|
2097
2070
|
var _run$body;
|
|
2098
2071
|
const sends = items.filter((item) => item.kind === "send").map((item) => ({
|
|
2099
2072
|
name: item.name,
|
|
@@ -2105,6 +2078,7 @@ const toParsedAssistantResponse = (items, raw) => {
|
|
|
2105
2078
|
return {
|
|
2106
2079
|
raw,
|
|
2107
2080
|
items,
|
|
2081
|
+
diagnostics,
|
|
2108
2082
|
sends,
|
|
2109
2083
|
code: (run === null || run === void 0 || (_run$body = run.body) === null || _run$body === void 0 ? void 0 : _run$body.trim()) || void 0,
|
|
2110
2084
|
next: next ? {
|
|
@@ -2117,7 +2091,7 @@ const parseAssistantResponse = (response) => {
|
|
|
2117
2091
|
const parser = new StreamingMessageParser();
|
|
2118
2092
|
parser.push(stripWrappingFences(response));
|
|
2119
2093
|
parser.finish();
|
|
2120
|
-
return toParsedAssistantResponse(parser.items, response);
|
|
2094
|
+
return toParsedAssistantResponse(parser.items, response, parser.diagnostics);
|
|
2121
2095
|
};
|
|
2122
2096
|
const replacePlaceholders = (prompt, values) => {
|
|
2123
2097
|
const regex = /* @__PURE__ */ new RegExp("■■■([A-Z0-9_\\.-]+)■■■", "gi");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as StreamingMessageParser, d as isEqual, h as toNumber, i as toParsedAssistantResponse } from "./dual-modes-
|
|
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-
|
|
1
|
+
import { a as StreamingMessageParser, d as isEqual, h as toNumber, i as toParsedAssistantResponse } from "./dual-modes-mNyMThtf.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-CMuy7fXU.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";
|
|
@@ -120,11 +120,16 @@ const RESPONSE_LENGTH_BUFFER = {
|
|
|
120
120
|
};
|
|
121
121
|
/** Maximum time to wait between two stream chunks before considering the stream stalled. */
|
|
122
122
|
const STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
123
|
+
/** A syntactically valid prefix must not execute when generation did not finish successfully. */
|
|
124
|
+
const assertSuccessfulGeneration = (metadata) => {
|
|
125
|
+
if (metadata.provider === "unknown") throw new CognitiveError("LLM generation failed: received error metadata with unknown provider");
|
|
126
|
+
if (metadata.stopReason === "max_tokens" || metadata.stopReason === "content_filter") throw new CognitiveError(`LLM generation did not complete: stopReason=${metadata.stopReason}`);
|
|
127
|
+
};
|
|
123
128
|
const getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
124
129
|
/**
|
|
125
130
|
* Models sometimes wrap their whole response in a code fence. The fence has to
|
|
126
|
-
* be removed before it reaches the incremental parser
|
|
127
|
-
*
|
|
131
|
+
* be removed before it reaches the incremental parser to avoid a spurious
|
|
132
|
+
* unexpected-text diagnostic. Works on arbitrary chunk boundaries
|
|
128
133
|
* by holding content back until the first newline.
|
|
129
134
|
*/
|
|
130
135
|
var LeadingFenceFilter = class {
|
|
@@ -330,10 +335,11 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
330
335
|
await dispatchSends(parser.push(fence.push(delta)));
|
|
331
336
|
}
|
|
332
337
|
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
338
|
+
assertSuccessfulGeneration(responseMetadata);
|
|
333
339
|
const remaining = fence.flush();
|
|
334
340
|
if (remaining) await dispatchSends(parser.push(remaining));
|
|
335
341
|
await dispatchSends(parser.finish());
|
|
336
|
-
assistantResponse = toParsedAssistantResponse(parser.items, raw);
|
|
342
|
+
assistantResponse = toParsedAssistantResponse(parser.items, raw, parser.diagnostics);
|
|
337
343
|
} finally {
|
|
338
344
|
streamController.abort("LLM stream closed");
|
|
339
345
|
if (!streamCompleted) stream.return(void 0).catch((err) => {});
|
|
@@ -343,8 +349,10 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
343
349
|
const response = await cognitive.generateText(input, { signal: controller.signal }).catch((thrown) => {
|
|
344
350
|
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
345
351
|
});
|
|
352
|
+
if (response.error) throw new CognitiveError(`LLM generation failed: ${response.error}`);
|
|
346
353
|
if (!response.output) throw new CognitiveError("LLM did not return any text output");
|
|
347
354
|
responseMetadata = response.metadata;
|
|
355
|
+
assertSuccessfulGeneration(responseMetadata);
|
|
348
356
|
raw = response.output;
|
|
349
357
|
assistantResponse = ctx.version.parseAssistantResponse(raw);
|
|
350
358
|
for (const [index, send] of assistantResponse.sends.entries()) await (onSend === null || onSend === void 0 ? void 0 : onSend(send, messageMetadata(`send-${index}`)));
|
|
@@ -361,6 +369,7 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
361
369
|
tokens: usage.inputTokens + usage.outputTokens,
|
|
362
370
|
spend: responseMetadata.cost ?? usage.inputCost + usage.outputCost,
|
|
363
371
|
output: assistantResponse.raw,
|
|
372
|
+
diagnostics: assistantResponse.diagnostics,
|
|
364
373
|
model: `${responseMetadata.provider}:${responseMetadata.model}`,
|
|
365
374
|
time_to_first_token: timeToFirstToken,
|
|
366
375
|
time_to_last_token: timeToLastToken,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require__baseForOwn = require("./_baseForOwn-buOZDFbK.cjs");
|
|
2
|
-
const require_dual_modes = require("./dual-modes-
|
|
3
|
-
const require_custom_client = require("./custom-client-
|
|
2
|
+
const require_dual_modes = require("./dual-modes-CfqTk9M8.cjs");
|
|
3
|
+
const require_custom_client = require("./custom-client-Bp1TgTKk.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");
|
|
@@ -122,11 +122,16 @@ const RESPONSE_LENGTH_BUFFER = {
|
|
|
122
122
|
};
|
|
123
123
|
/** Maximum time to wait between two stream chunks before considering the stream stalled. */
|
|
124
124
|
const STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
125
|
+
/** A syntactically valid prefix must not execute when generation did not finish successfully. */
|
|
126
|
+
const assertSuccessfulGeneration = (metadata) => {
|
|
127
|
+
if (metadata.provider === "unknown") throw new require_errors.CognitiveError("LLM generation failed: received error metadata with unknown provider");
|
|
128
|
+
if (metadata.stopReason === "max_tokens" || metadata.stopReason === "content_filter") throw new require_errors.CognitiveError(`LLM generation did not complete: stopReason=${metadata.stopReason}`);
|
|
129
|
+
};
|
|
125
130
|
const getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
126
131
|
/**
|
|
127
132
|
* Models sometimes wrap their whole response in a code fence. The fence has to
|
|
128
|
-
* be removed before it reaches the incremental parser
|
|
129
|
-
*
|
|
133
|
+
* be removed before it reaches the incremental parser to avoid a spurious
|
|
134
|
+
* unexpected-text diagnostic. Works on arbitrary chunk boundaries
|
|
130
135
|
* by holding content back until the first newline.
|
|
131
136
|
*/
|
|
132
137
|
var LeadingFenceFilter = class {
|
|
@@ -332,10 +337,11 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
332
337
|
await dispatchSends(parser.push(fence.push(delta)));
|
|
333
338
|
}
|
|
334
339
|
if (!responseMetadata) throw new require_errors.CognitiveError("LLM streaming completed without metadata");
|
|
340
|
+
assertSuccessfulGeneration(responseMetadata);
|
|
335
341
|
const remaining = fence.flush();
|
|
336
342
|
if (remaining) await dispatchSends(parser.push(remaining));
|
|
337
343
|
await dispatchSends(parser.finish());
|
|
338
|
-
assistantResponse = require_dual_modes.toParsedAssistantResponse(parser.items, raw);
|
|
344
|
+
assistantResponse = require_dual_modes.toParsedAssistantResponse(parser.items, raw, parser.diagnostics);
|
|
339
345
|
} finally {
|
|
340
346
|
streamController.abort("LLM stream closed");
|
|
341
347
|
if (!streamCompleted) stream.return(void 0).catch((err) => {});
|
|
@@ -345,8 +351,10 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
345
351
|
const response = await cognitive.generateText(input, { signal: controller.signal }).catch((thrown) => {
|
|
346
352
|
throw new require_errors.CognitiveError(`LLM generation failed: ${require_utils.getErrorMessage(thrown)}`);
|
|
347
353
|
});
|
|
354
|
+
if (response.error) throw new require_errors.CognitiveError(`LLM generation failed: ${response.error}`);
|
|
348
355
|
if (!response.output) throw new require_errors.CognitiveError("LLM did not return any text output");
|
|
349
356
|
responseMetadata = response.metadata;
|
|
357
|
+
assertSuccessfulGeneration(responseMetadata);
|
|
350
358
|
raw = response.output;
|
|
351
359
|
assistantResponse = ctx.version.parseAssistantResponse(raw);
|
|
352
360
|
for (const [index, send] of assistantResponse.sends.entries()) await (onSend === null || onSend === void 0 ? void 0 : onSend(send, messageMetadata(`send-${index}`)));
|
|
@@ -363,6 +371,7 @@ const generateCode = async ({ iteration, ctx, cognitive, controller, metadata, o
|
|
|
363
371
|
tokens: usage.inputTokens + usage.outputTokens,
|
|
364
372
|
spend: responseMetadata.cost ?? usage.inputCost + usage.outputCost,
|
|
365
373
|
output: assistantResponse.raw,
|
|
374
|
+
diagnostics: assistantResponse.diagnostics,
|
|
366
375
|
model: `${responseMetadata.provider}:${responseMetadata.model}`,
|
|
367
376
|
time_to_first_token: timeToFirstToken,
|
|
368
377
|
time_to_last_token: timeToLastToken,
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dual_modes = require("./dual-modes-
|
|
3
|
-
const require_custom_client = require("./custom-client-
|
|
2
|
+
const require_dual_modes = require("./dual-modes-CfqTk9M8.cjs");
|
|
3
|
+
const require_custom_client = require("./custom-client-Bp1TgTKk.cjs");
|
|
4
4
|
const require_utils = require("./utils-ZpJm00ed.cjs");
|
|
5
5
|
const require_tool = require("./tool-ReA9gxMp.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.
|
|
14
|
+
var version = "0.7.0";
|
|
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-msui51b2.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-msui51b2.cjs"));
|
|
1787
1787
|
await Promise.resolve().then(() => require("./component-BwixNVH8.cjs")).then((n) => n.component_exports);
|
|
1788
1788
|
await Promise.resolve().then(() => require("./tool-ReA9gxMp.cjs")).then((n) => n.tool_exports);
|
|
1789
1789
|
await Promise.resolve().then(() => require("./exit-BGi0Kk0y.cjs")).then((n) => n.exit_exports);
|
|
@@ -1792,7 +1792,7 @@ const init = async () => {
|
|
|
1792
1792
|
await Promise.resolve().then(() => require("./utils-ZpJm00ed.cjs")).then((n) => n.utils_exports);
|
|
1793
1793
|
await Promise.resolve().then(() => require("./truncator-B6aaJaN1.cjs")).then((n) => n.truncator_exports);
|
|
1794
1794
|
await Promise.resolve().then(() => require("./typings-BwAz_TM9.cjs")).then((n) => n.typings_exports);
|
|
1795
|
-
await Promise.resolve().then(() => require("./dual-modes-
|
|
1795
|
+
await Promise.resolve().then(() => require("./dual-modes-CfqTk9M8.cjs")).then((n) => n.dual_modes_exports);
|
|
1796
1796
|
};
|
|
1797
1797
|
//#endregion
|
|
1798
1798
|
exports.BaseResponse = BaseResponse;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as StreamingMessageParser, c as NAME_REGEX, o as tryParseJson, r as generateInstructions, s as MARKER } from "./dual-modes-
|
|
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-
|
|
1
|
+
import { a as StreamingMessageParser, c as NAME_REGEX, o as tryParseJson, r as generateInstructions, s as MARKER } from "./dual-modes-mNyMThtf.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-CMuy7fXU.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-Bv8N4IPj.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.
|
|
13
|
+
var version = "0.7.0";
|
|
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-DP_17lYZ.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-DP_17lYZ.js");
|
|
1786
1786
|
await import("./component-DGG7d_Mz.js").then((n) => n.r);
|
|
1787
1787
|
await import("./tool-Bv8N4IPj.js").then((n) => n.n);
|
|
1788
1788
|
await import("./exit-CDdxDBRT.js").then((n) => n.n);
|
|
@@ -1791,7 +1791,7 @@ const init = async () => {
|
|
|
1791
1791
|
await import("./utils-UBeAFeEI.js").then((n) => n.h);
|
|
1792
1792
|
await import("./truncator-DZqEqnpD.js").then((n) => n.r);
|
|
1793
1793
|
await import("./typings-CrBa7Tyy.js").then((n) => n.n);
|
|
1794
|
-
await import("./dual-modes-
|
|
1794
|
+
await import("./dual-modes-mNyMThtf.js").then((n) => n.n);
|
|
1795
1795
|
};
|
|
1796
1796
|
//#endregion
|
|
1797
1797
|
export { BaseResponse, Chat, CitationsManager, Component, ComponentRegistry, DefaultComponents, DefaultExit, ErrorExecutionResult, 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.
|
|
55
|
+
var version = "0.7.0";
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region ../../node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_freeGlobal.js
|
|
58
58
|
var freeGlobal;
|
|
@@ -10830,10 +10830,9 @@ var init_parser = __esmMin((() => {
|
|
|
10830
10830
|
};
|
|
10831
10831
|
StreamingMessageParser = class {
|
|
10832
10832
|
_maxPropsLength;
|
|
10833
|
-
_strict;
|
|
10834
|
-
_recoveryComponent;
|
|
10835
10833
|
_state = "idle";
|
|
10836
10834
|
_items = [];
|
|
10835
|
+
_diagnostics = [];
|
|
10837
10836
|
_current;
|
|
10838
10837
|
_currentReady = false;
|
|
10839
10838
|
_counter = 0;
|
|
@@ -10849,13 +10848,15 @@ var init_parser = __esmMin((() => {
|
|
|
10849
10848
|
_pendingWhitespace = "";
|
|
10850
10849
|
constructor(options = {}) {
|
|
10851
10850
|
this._maxPropsLength = options.maxPropsLength ?? 1e5;
|
|
10852
|
-
this._strict = options.strict ?? false;
|
|
10853
|
-
this._recoveryComponent = options.recoveryComponent ?? "md";
|
|
10854
10851
|
}
|
|
10855
10852
|
/** All items parsed so far, in order of appearance. */
|
|
10856
10853
|
get items() {
|
|
10857
10854
|
return [...this._items];
|
|
10858
10855
|
}
|
|
10856
|
+
/** All syntax diagnostics, including discarded text that has no protocol item. */
|
|
10857
|
+
get diagnostics() {
|
|
10858
|
+
return [...this._diagnostics];
|
|
10859
|
+
}
|
|
10859
10860
|
push(chunk) {
|
|
10860
10861
|
if (this._finished) throw new Error("Parser has already finished. Call reset() before parsing a new stream.");
|
|
10861
10862
|
const events = [];
|
|
@@ -10901,6 +10902,7 @@ var init_parser = __esmMin((() => {
|
|
|
10901
10902
|
reset() {
|
|
10902
10903
|
this._state = "idle";
|
|
10903
10904
|
this._items = [];
|
|
10905
|
+
this._diagnostics = [];
|
|
10904
10906
|
this._current = void 0;
|
|
10905
10907
|
this._currentReady = false;
|
|
10906
10908
|
this._counter = 0;
|
|
@@ -10919,7 +10921,7 @@ var init_parser = __esmMin((() => {
|
|
|
10919
10921
|
switch (this._state) {
|
|
10920
10922
|
case "idle":
|
|
10921
10923
|
if (char === "■") this._beginItem();
|
|
10922
|
-
else if (!isWhitespace(char)) this.
|
|
10924
|
+
else if (!isWhitespace(char)) this._skipUnexpectedText(events);
|
|
10923
10925
|
return;
|
|
10924
10926
|
case "directive":
|
|
10925
10927
|
if (char === "=") this._endDirective(events, "=");
|
|
@@ -10998,7 +11000,7 @@ var init_parser = __esmMin((() => {
|
|
|
10998
11000
|
if (isWhitespace(char)) return;
|
|
10999
11001
|
if (item.kind === "next") {
|
|
11000
11002
|
this._completeCurrent(events);
|
|
11001
|
-
this.
|
|
11003
|
+
this._skipUnexpectedText(events);
|
|
11002
11004
|
return;
|
|
11003
11005
|
}
|
|
11004
11006
|
this._startBody(events);
|
|
@@ -11244,46 +11246,15 @@ var init_parser = __esmMin((() => {
|
|
|
11244
11246
|
this._current = void 0;
|
|
11245
11247
|
this._currentReady = false;
|
|
11246
11248
|
}
|
|
11247
|
-
|
|
11248
|
-
if (this._strict) {
|
|
11249
|
-
this._diagnostic(events, {
|
|
11250
|
-
code: "unexpected-text",
|
|
11251
|
-
message: "Encountered text outside of a ■ block"
|
|
11252
|
-
});
|
|
11253
|
-
this._state = "skip";
|
|
11254
|
-
return;
|
|
11255
|
-
}
|
|
11256
|
-
const item = {
|
|
11257
|
-
id: `item-${this._counter++}`,
|
|
11258
|
-
kind: "send",
|
|
11259
|
-
name: this._recoveryComponent,
|
|
11260
|
-
props: {},
|
|
11261
|
-
body: "",
|
|
11262
|
-
status: "pending",
|
|
11263
|
-
diagnostics: []
|
|
11264
|
-
};
|
|
11265
|
-
this._items.push(item);
|
|
11266
|
-
this._current = item;
|
|
11267
|
-
this._currentReady = false;
|
|
11268
|
-
this._pendingWhitespace = "";
|
|
11249
|
+
_skipUnexpectedText(events) {
|
|
11269
11250
|
this._diagnostic(events, {
|
|
11270
11251
|
code: "unexpected-text",
|
|
11271
|
-
message:
|
|
11272
|
-
itemId: item.id
|
|
11273
|
-
});
|
|
11274
|
-
events.push({
|
|
11275
|
-
type: "item-start",
|
|
11276
|
-
item
|
|
11277
|
-
});
|
|
11278
|
-
this._ready(events);
|
|
11279
|
-
events.push({
|
|
11280
|
-
type: "body-start",
|
|
11281
|
-
itemId: item.id
|
|
11252
|
+
message: "Encountered text outside of a ■ block"
|
|
11282
11253
|
});
|
|
11283
|
-
this._state = "
|
|
11284
|
-
this._appendBody(char);
|
|
11254
|
+
this._state = "skip";
|
|
11285
11255
|
}
|
|
11286
11256
|
_diagnostic(events, diagnostic) {
|
|
11257
|
+
this._diagnostics.push(diagnostic);
|
|
11287
11258
|
if (diagnostic.itemId) this._items.find((i) => i.id === diagnostic.itemId)?.diagnostics.push(diagnostic);
|
|
11288
11259
|
events.push({
|
|
11289
11260
|
type: "diagnostic",
|
|
@@ -11301,7 +11272,7 @@ var init_common = __esmMin((() => {
|
|
|
11301
11272
|
if ((index === 0 || index === arr.length - 1) && line.trim().startsWith("```")) return false;
|
|
11302
11273
|
return true;
|
|
11303
11274
|
}).join("\n");
|
|
11304
|
-
toParsedAssistantResponse = (items, raw) => {
|
|
11275
|
+
toParsedAssistantResponse = (items, raw, diagnostics = []) => {
|
|
11305
11276
|
const sends = items.filter((item) => item.kind === "send").map((item) => ({
|
|
11306
11277
|
name: item.name,
|
|
11307
11278
|
props: item.props,
|
|
@@ -11312,6 +11283,7 @@ var init_common = __esmMin((() => {
|
|
|
11312
11283
|
return {
|
|
11313
11284
|
raw,
|
|
11314
11285
|
items,
|
|
11286
|
+
diagnostics,
|
|
11315
11287
|
sends,
|
|
11316
11288
|
code: run?.body?.trim() || void 0,
|
|
11317
11289
|
next: next ? {
|
|
@@ -11324,7 +11296,7 @@ var init_common = __esmMin((() => {
|
|
|
11324
11296
|
const parser = new StreamingMessageParser();
|
|
11325
11297
|
parser.push(stripWrappingFences(response));
|
|
11326
11298
|
parser.finish();
|
|
11327
|
-
return toParsedAssistantResponse(parser.items, response);
|
|
11299
|
+
return toParsedAssistantResponse(parser.items, response, parser.diagnostics);
|
|
11328
11300
|
};
|
|
11329
11301
|
replacePlaceholders = (prompt, values) => {
|
|
11330
11302
|
const regex = /* @__PURE__ */ new RegExp("■■■([A-Z0-9_\\.-]+)■■■", "gi");
|
|
@@ -17025,7 +16997,7 @@ var init_vm = __esmMin((() => {
|
|
|
17025
16997
|
}));
|
|
17026
16998
|
//#endregion
|
|
17027
16999
|
//#region src/runtime/generate.ts
|
|
17028
|
-
var RESPONSE_LENGTH_BUFFER, STREAM_INACTIVITY_TIMEOUT, getModelOutputLimit, LeadingFenceFilter, generateCode;
|
|
17000
|
+
var RESPONSE_LENGTH_BUFFER, STREAM_INACTIVITY_TIMEOUT, assertSuccessfulGeneration, getModelOutputLimit, LeadingFenceFilter, generateCode;
|
|
17029
17001
|
var init_generate = __esmMin((() => {
|
|
17030
17002
|
init_lodash();
|
|
17031
17003
|
init_abort_signal();
|
|
@@ -17040,6 +17012,10 @@ var init_generate = __esmMin((() => {
|
|
|
17040
17012
|
PERCENTAGE: .1
|
|
17041
17013
|
};
|
|
17042
17014
|
STREAM_INACTIVITY_TIMEOUT = 18e4;
|
|
17015
|
+
assertSuccessfulGeneration = (metadata) => {
|
|
17016
|
+
if (metadata.provider === "unknown") throw new CognitiveError("LLM generation failed: received error metadata with unknown provider");
|
|
17017
|
+
if (metadata.stopReason === "max_tokens" || metadata.stopReason === "content_filter") throw new CognitiveError(`LLM generation did not complete: stopReason=${metadata.stopReason}`);
|
|
17018
|
+
};
|
|
17043
17019
|
getModelOutputLimit = (inputLength) => clamp(RESPONSE_LENGTH_BUFFER.PERCENTAGE * inputLength, RESPONSE_LENGTH_BUFFER.MIN_TOKENS, RESPONSE_LENGTH_BUFFER.MAX_TOKENS);
|
|
17044
17020
|
LeadingFenceFilter = class {
|
|
17045
17021
|
_buffer = "";
|
|
@@ -17243,10 +17219,11 @@ var init_generate = __esmMin((() => {
|
|
|
17243
17219
|
await dispatchSends(parser.push(fence.push(delta)));
|
|
17244
17220
|
}
|
|
17245
17221
|
if (!responseMetadata) throw new CognitiveError("LLM streaming completed without metadata");
|
|
17222
|
+
assertSuccessfulGeneration(responseMetadata);
|
|
17246
17223
|
const remaining = fence.flush();
|
|
17247
17224
|
if (remaining) await dispatchSends(parser.push(remaining));
|
|
17248
17225
|
await dispatchSends(parser.finish());
|
|
17249
|
-
assistantResponse = toParsedAssistantResponse(parser.items, raw);
|
|
17226
|
+
assistantResponse = toParsedAssistantResponse(parser.items, raw, parser.diagnostics);
|
|
17250
17227
|
} finally {
|
|
17251
17228
|
streamController.abort("LLM stream closed");
|
|
17252
17229
|
if (!streamCompleted) stream.return(void 0).catch((err) => {});
|
|
@@ -17256,8 +17233,10 @@ var init_generate = __esmMin((() => {
|
|
|
17256
17233
|
const response = await cognitive.generateText(input, { signal: controller.signal }).catch((thrown) => {
|
|
17257
17234
|
throw new CognitiveError(`LLM generation failed: ${getErrorMessage(thrown)}`);
|
|
17258
17235
|
});
|
|
17236
|
+
if (response.error) throw new CognitiveError(`LLM generation failed: ${response.error}`);
|
|
17259
17237
|
if (!response.output) throw new CognitiveError("LLM did not return any text output");
|
|
17260
17238
|
responseMetadata = response.metadata;
|
|
17239
|
+
assertSuccessfulGeneration(responseMetadata);
|
|
17261
17240
|
raw = response.output;
|
|
17262
17241
|
assistantResponse = ctx.version.parseAssistantResponse(raw);
|
|
17263
17242
|
for (const [index, send] of assistantResponse.sends.entries()) await onSend?.(send, messageMetadata(`send-${index}`));
|
|
@@ -17274,6 +17253,7 @@ var init_generate = __esmMin((() => {
|
|
|
17274
17253
|
tokens: usage.inputTokens + usage.outputTokens,
|
|
17275
17254
|
spend: responseMetadata.cost ?? usage.inputCost + usage.outputCost,
|
|
17276
17255
|
output: assistantResponse.raw,
|
|
17256
|
+
diagnostics: assistantResponse.diagnostics,
|
|
17277
17257
|
model: `${responseMetadata.provider}:${responseMetadata.model}`,
|
|
17278
17258
|
time_to_first_token: timeToFirstToken,
|
|
17279
17259
|
time_to_last_token: timeToLastToken,
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { type MessageStreamEvent, type ParsedItem } from './types.js';
|
|
1
|
+
import { type Diagnostic, type MessageStreamEvent, type ParsedItem } from './types.js';
|
|
2
2
|
export type StreamingParserOptions = {
|
|
3
3
|
/** Maximum number of characters buffered for a props object before the item is marked invalid. Default: 100 000. */
|
|
4
4
|
maxPropsLength?: number;
|
|
5
|
-
/** When true, unexpected free text is dropped (with a diagnostic) instead of being recovered into an implicit `send`. Default: false. */
|
|
6
|
-
strict?: boolean;
|
|
7
|
-
/** Component used to recover unexpected free text into an implicit `■send`. Default: 'md'. */
|
|
8
|
-
recoveryComponent?: string;
|
|
9
5
|
};
|
|
10
6
|
/**
|
|
11
7
|
* Lenient JSON parsing: JSON5 first (unquoted keys, single quotes, trailing
|
|
@@ -18,6 +14,8 @@ export declare const tryParseJson: (text: string) => unknown;
|
|
|
18
14
|
* The parser is purely syntactic: it knows the reserved `■` symbol and the
|
|
19
15
|
* directive grammar, but nothing about registered components, exits or their
|
|
20
16
|
* schemas. Semantic validation is a separate step (see `validator.ts`).
|
|
17
|
+
* Text outside protocol blocks is always discarded with a diagnostic; only
|
|
18
|
+
* explicit `■send` blocks can produce messages.
|
|
21
19
|
*
|
|
22
20
|
* Pushing the same text split across arbitrary chunk boundaries always produces
|
|
23
21
|
* the same items and the same concatenated body deltas. For a higher-level
|
|
@@ -25,10 +23,9 @@ export declare const tryParseJson: (text: string) => unknown;
|
|
|
25
23
|
*/
|
|
26
24
|
export declare class StreamingMessageParser {
|
|
27
25
|
private _maxPropsLength;
|
|
28
|
-
private _strict;
|
|
29
|
-
private _recoveryComponent;
|
|
30
26
|
private _state;
|
|
31
27
|
private _items;
|
|
28
|
+
private _diagnostics;
|
|
32
29
|
private _current;
|
|
33
30
|
private _currentReady;
|
|
34
31
|
private _counter;
|
|
@@ -45,6 +42,8 @@ export declare class StreamingMessageParser {
|
|
|
45
42
|
constructor(options?: StreamingParserOptions);
|
|
46
43
|
/** All items parsed so far, in order of appearance. */
|
|
47
44
|
get items(): ParsedItem[];
|
|
45
|
+
/** All syntax diagnostics, including discarded text that has no protocol item. */
|
|
46
|
+
get diagnostics(): Diagnostic[];
|
|
48
47
|
push(chunk: string): MessageStreamEvent[];
|
|
49
48
|
/**
|
|
50
49
|
* Signals the end of the transport stream.
|
|
@@ -76,6 +75,6 @@ export declare class StreamingMessageParser {
|
|
|
76
75
|
private _flushBodyDelta;
|
|
77
76
|
private _ready;
|
|
78
77
|
private _completeCurrent;
|
|
79
|
-
private
|
|
78
|
+
private _skipUnexpectedText;
|
|
80
79
|
private _diagnostic;
|
|
81
80
|
}
|
package/dist/prompts/common.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ParsedItem } from '../message-stream/types.js';
|
|
1
|
+
import type { Diagnostic, ParsedItem } from '../message-stream/types.js';
|
|
2
2
|
import { ParsedAssistantResponse } from './prompt.js';
|
|
3
3
|
/** Builds a {@link ParsedAssistantResponse} from parsed protocol items. */
|
|
4
|
-
export declare const toParsedAssistantResponse: (items: ParsedItem[], raw: string) => ParsedAssistantResponse;
|
|
4
|
+
export declare const toParsedAssistantResponse: (items: ParsedItem[], raw: string, diagnostics?: Diagnostic[]) => ParsedAssistantResponse;
|
|
5
5
|
export declare const parseAssistantResponse: (response: string) => ParsedAssistantResponse;
|
|
6
6
|
export declare const replacePlaceholders: (prompt: string, values: Record<string, unknown>) => string;
|
package/dist/prompts/prompt.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CognitiveMessage } from '@botpress/cognitive';
|
|
2
2
|
import { Component } from '../component.js';
|
|
3
3
|
import { Exit } from '../exit.js';
|
|
4
|
-
import type { ParsedItem } from '../message-stream/types.js';
|
|
4
|
+
import type { Diagnostic, ParsedItem } from '../message-stream/types.js';
|
|
5
5
|
import type { ObjectInstance } from '../objects.js';
|
|
6
6
|
import { Snapshot } from '../snapshots.js';
|
|
7
7
|
import { type Tool } from '../tool.js';
|
|
@@ -21,6 +21,8 @@ export type ParsedAssistantResponse = {
|
|
|
21
21
|
raw: string;
|
|
22
22
|
/** All protocol items, in order of appearance. */
|
|
23
23
|
items: ParsedItem[];
|
|
24
|
+
/** Syntax diagnostics, including unexpected text discarded outside protocol blocks. */
|
|
25
|
+
diagnostics?: Diagnostic[];
|
|
24
26
|
/** Messages to send to the user, in order. */
|
|
25
27
|
sends: ParsedSend[];
|
|
26
28
|
/** The body of the `■run` block, if any. */
|
package/dist/result.d.ts
CHANGED
|
@@ -427,6 +427,7 @@ export declare class SuccessExecutionResult<TOutput = unknown> extends Execution
|
|
|
427
427
|
tokens: number;
|
|
428
428
|
spend: number;
|
|
429
429
|
output: string;
|
|
430
|
+
diagnostics?: import("./index.js").Diagnostic[];
|
|
430
431
|
model: string;
|
|
431
432
|
time_to_first_token?: number;
|
|
432
433
|
time_to_last_token?: number;
|
|
@@ -592,6 +593,7 @@ export declare class ErrorExecutionResult extends ExecutionResult implements Ser
|
|
|
592
593
|
tokens: number;
|
|
593
594
|
spend: number;
|
|
594
595
|
output: string;
|
|
596
|
+
diagnostics?: import("./index.js").Diagnostic[];
|
|
595
597
|
model: string;
|
|
596
598
|
time_to_first_token?: number;
|
|
597
599
|
time_to_last_token?: number;
|
|
@@ -777,6 +779,7 @@ export declare class PartialExecutionResult extends ExecutionResult implements S
|
|
|
777
779
|
tokens: number;
|
|
778
780
|
spend: number;
|
|
779
781
|
output: string;
|
|
782
|
+
diagnostics?: import("./index.js").Diagnostic[];
|
|
780
783
|
model: string;
|
|
781
784
|
time_to_first_token?: number;
|
|
782
785
|
time_to_last_token?: number;
|
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.
|
|
5
|
+
"version": "0.7.0",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
8
|
"DOCS.md"
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@botpress/client": "2.5.0",
|
|
72
|
-
"@botpress/cognitive": "1.2.
|
|
72
|
+
"@botpress/cognitive": "1.2.1",
|
|
73
73
|
"@bpinternal/thicktoken": "^3.1.0",
|
|
74
74
|
"@bpinternal/zui": "^2.4.1"
|
|
75
75
|
},
|