llmz 0.9.0 → 1.0.2
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 +232 -1794
- package/ERRORS.md +101 -0
- package/README.md +96 -582
- package/dist/chat/chat.d.ts +63 -0
- package/dist/chat/component.d.ts +31 -0
- package/dist/chat/component.default.d.ts +58 -0
- package/dist/chat/response.d.ts +15 -0
- package/dist/compiler/compiler.d.ts +2 -7
- package/dist/compiler/plugins/dynamic-code.d.ts +7 -0
- package/dist/compiler/plugins/replace-comment.d.ts +2 -3
- package/dist/compiler/plugins/return-async.d.ts +5 -4
- package/dist/compiler/plugins/termination.d.ts +8 -0
- package/dist/compiler/plugins/tool-resolution.d.ts +4 -0
- package/dist/compiler/plugins/variable-extraction.d.ts +2 -8
- package/dist/component-CMFoCHyu.cjs +649 -0
- package/dist/component-DncqP4fB.js +614 -0
- package/dist/context.d.ts +71 -378
- package/dist/custom-client-C-WXvLD9.js +1655 -0
- package/dist/custom-client-Cgt9_0r1.cjs +1732 -0
- package/dist/custom-client.d.ts +12 -2
- package/dist/errors/catalog.d.ts +294 -0
- package/dist/errors/hooks.d.ts +2 -0
- package/dist/errors-C6ppQUZX.cjs +893 -0
- package/dist/errors-Crk5P8jo.js +636 -0
- package/dist/errors.d.ts +24 -36
- package/dist/execute-CiYvPs5Q.js +2061 -0
- package/dist/execute-DTTfacsi.cjs +2062 -0
- package/dist/{exit-DUM96DN1.cjs → exit-BOtKWPuT.cjs} +38 -28
- package/dist/{exit-CDdxDBRT.js → exit-DMPwCSba.js} +37 -27
- package/dist/exit.d.ts +19 -16
- package/dist/index.cjs +177 -1237
- package/dist/index.d.ts +25 -28
- package/dist/index.js +137 -1213
- package/dist/index.workerd.js +8974 -11145
- package/dist/inspect.d.ts +18 -4
- package/dist/inspection.d.ts +40 -0
- package/dist/native-0bq5ATZM.cjs +212 -0
- package/dist/native-n_718Z-T.js +177 -0
- package/dist/objects.d.ts +2 -57
- package/dist/prompts/native.d.ts +2 -0
- package/dist/prompts/prompt.d.ts +10 -101
- package/dist/quickjs-variant-21IO97PF.cjs +1080 -0
- package/dist/quickjs-variant-CtuGagsb.js +985 -0
- package/dist/result.d.ts +30 -861
- package/dist/runtime/execute.d.ts +3 -2
- package/dist/runtime/execution-activity.d.ts +11 -0
- package/dist/runtime/execution-diagnostics.d.ts +11 -0
- package/dist/runtime/execution-report.d.ts +51 -0
- package/dist/runtime/fixtures/chat.d.ts +8 -0
- package/dist/runtime/fixtures/long-search.d.ts +1 -1
- package/dist/runtime/fixtures/native-client.d.ts +33 -0
- package/dist/runtime/fixtures/protocol-languages.d.ts +1 -1
- package/dist/runtime/forced-inspection.d.ts +13 -0
- package/dist/runtime/forced-inspection.test.d.ts +1 -0
- package/dist/runtime/generate.d.ts +23 -20
- package/dist/runtime/generate.test.d.ts +1 -0
- package/dist/runtime/hook-provenance.test.d.ts +1 -0
- package/dist/runtime/inspection-hook.test.d.ts +1 -0
- package/dist/runtime/inspection-values.d.ts +14 -0
- package/dist/runtime/inspection-values.test.d.ts +1 -0
- package/dist/runtime/interruption-control-flow.test.d.ts +1 -0
- package/dist/runtime/interruption-settings.test.d.ts +1 -0
- package/dist/runtime/javascript-api.d.ts +62 -0
- package/dist/runtime/javascript-api.test.d.ts +1 -0
- package/dist/runtime/native-review.test.d.ts +1 -0
- package/dist/runtime/native-tools.d.ts +18 -0
- package/dist/runtime/native-tools.test.d.ts +1 -0
- package/dist/runtime/object-memory.test.d.ts +1 -0
- package/dist/runtime/single-tool.test.d.ts +1 -0
- package/dist/runtime/think-signal.test.d.ts +1 -0
- package/dist/runtime/token-budget.d.ts +22 -0
- package/dist/runtime/token-budget.test.d.ts +1 -0
- package/dist/runtime/tool-wrapper.d.ts +6 -5
- package/dist/runtime/traces.test.d.ts +1 -0
- package/dist/runtime/truncation.test.d.ts +1 -0
- package/dist/runtime/types.d.ts +47 -31
- package/dist/runtime/variable-recovery.test.d.ts +1 -0
- package/dist/runtime/vm-context.d.ts +6 -1
- package/dist/runtime/worker-completion.test.d.ts +1 -0
- package/dist/runtime-names.d.ts +4 -0
- package/dist/schema-CXlnbb3n.cjs +68 -0
- package/dist/schema-GE4ISPCR.js +45 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.test.d.ts +1 -0
- package/dist/session/compactor.d.ts +51 -0
- package/dist/session/compactor.test.d.ts +1 -0
- package/dist/session/history.d.ts +36 -0
- package/dist/session/history.test.d.ts +1 -0
- package/dist/session/json.d.ts +3 -0
- package/dist/session/json.test.d.ts +1 -0
- package/dist/session/memory-codec.d.ts +9 -0
- package/dist/session/memory-codec.test.d.ts +1 -0
- package/dist/session/memory-render.d.ts +15 -0
- package/dist/session/memory-render.test.d.ts +1 -0
- package/dist/session/memory.d.ts +112 -0
- package/dist/session/memory.test.d.ts +1 -0
- package/dist/session/messages.d.ts +19 -0
- package/dist/session/messages.test.d.ts +1 -0
- package/dist/session/serialization.d.ts +36 -0
- package/dist/session/serialization.test.d.ts +1 -0
- package/dist/session/session-memory.test.d.ts +1 -0
- package/dist/session/session.d.ts +121 -0
- package/dist/session/session.test.d.ts +1 -0
- package/dist/session/speaker.test.d.ts +1 -0
- package/dist/{transcript.d.ts → session/transcript.d.ts} +4 -8
- package/dist/session/transcript.test.d.ts +1 -0
- package/dist/{tool-Bv8N4IPj.js → tool-DstssiAs.js} +144 -92
- package/dist/{tool-Dy6AJpJH.cjs → tool-_wK9hQOb.cjs} +146 -94
- package/dist/tool.d.ts +25 -17
- package/dist/truncate-BEKbdo3t.js +79 -0
- package/dist/truncate-uomAMGPs.cjs +102 -0
- package/dist/truncate.d.ts +24 -0
- package/dist/truncate.test.d.ts +1 -0
- package/dist/types.d.ts +33 -9
- package/dist/{typings-3lsqCbkn.cjs → typings-BA_XxAcY.cjs} +38 -193
- package/dist/{typings-CrBa7Tyy.js → typings-BEVDvtuk.js} +38 -175
- package/dist/typings-formatter.d.ts +1 -1
- package/dist/typings.d.ts +3 -0
- package/dist/{uniq-BYQ7GWwb.js → uniq-DfUeSNaX.js} +2 -2
- package/dist/{uniq-G872RWmE.cjs → uniq-DiXgysNV.cjs} +6 -18
- package/dist/{_baseIteratee-P_firB7b.js → utils-BOFzb8Ok.js} +1134 -16
- package/dist/{_baseIteratee-CF4qP2a8.cjs → utils-CTlsXvdj.cjs} +1281 -84
- package/dist/vm/drivers/node.d.ts +1 -1
- package/dist/vm/drivers/quickjs.d.ts +1 -1
- package/dist/vm/errors.d.ts +4 -4
- package/dist/vm/index.d.ts +3 -4
- package/dist/vm/instrument.d.ts +14 -6
- package/dist/vm/member-proxy.d.ts +4 -0
- package/dist/vm/member-proxy.test.d.ts +1 -0
- package/dist/vm/memory.test.d.ts +1 -0
- package/dist/vm/return-semantics.test.d.ts +1 -0
- package/dist/vm/types.d.ts +20 -3
- package/dist/{vm-BLsHw1da.js → vm-C7SfutHn.js} +1187 -180
- package/dist/{vm-D6s1zF6M.cjs → vm-gmekHc0i.cjs} +1221 -207
- package/package.json +13 -6
- package/dist/_baseForOwn-BfWDTL8L.cjs +0 -53
- package/dist/_baseForOwn-CFhWe_W6.js +0 -48
- package/dist/_getPrototype-CG7Dxrrz.js +0 -6
- package/dist/_getPrototype-DQDlNVVM.cjs +0 -10
- package/dist/_overArg-C5Hy7oCi.cjs +0 -196
- package/dist/_overArg-CRYbj1NH.js +0 -155
- package/dist/chat.d.ts +0 -401
- package/dist/common-BlRFtdf2.js +0 -807
- package/dist/common-BnvrDnIT.cjs +0 -860
- package/dist/compiler/plugins/track-tool-calls.d.ts +0 -33
- package/dist/compiler-C-OI9sim.cjs +0 -547
- package/dist/compiler-CW1VjQsn.js +0 -473
- package/dist/component-C6Agl2ns.cjs +0 -73
- package/dist/component-DGG7d_Mz.js +0 -44
- package/dist/component.d.ts +0 -88
- package/dist/component.default.d.ts +0 -278
- package/dist/custom-client-ChuZ63zp.js +0 -2658
- package/dist/custom-client-DAsGRnYc.cjs +0 -2729
- package/dist/dual-modes-DDkoCp3R.js +0 -3006
- package/dist/dual-modes-DPXiuvNe.cjs +0 -3090
- package/dist/errors-C962uJdS.cjs +0 -220
- package/dist/errors-Cg1G0Awu.js +0 -161
- package/dist/example-format.d.ts +0 -8
- package/dist/example.d.ts +0 -45
- package/dist/execute-BWcdv9so.js +0 -1059
- package/dist/execute-DM2-7y86.cjs +0 -1060
- package/dist/exit-parser.d.ts +0 -39
- package/dist/handlers.d.ts +0 -10
- package/dist/hoist.d.ts +0 -2
- package/dist/isEmpty-BhJRCqIF.js +0 -52
- package/dist/isEmpty-LY533Wmh.cjs +0 -57
- package/dist/isPlainObject-CSxXVKCk.cjs +0 -56
- package/dist/isPlainObject-D39AzPO2.js +0 -51
- package/dist/jsx-CIgdGGVs.js +0 -52
- package/dist/jsx-owqxrquU.cjs +0 -75
- package/dist/jsx.d.ts +0 -11
- package/dist/message-stream/index.d.ts +0 -9
- package/dist/message-stream/instructions.d.ts +0 -30
- package/dist/message-stream/normalizer.d.ts +0 -21
- package/dist/message-stream/parser.d.ts +0 -89
- package/dist/message-stream/registry.d.ts +0 -14
- package/dist/message-stream/replayable.d.ts +0 -27
- package/dist/message-stream/response-parser.d.ts +0 -24
- package/dist/message-stream/sanitize.d.ts +0 -10
- package/dist/message-stream/stream.d.ts +0 -54
- package/dist/message-stream/types.d.ts +0 -97
- package/dist/message-stream/validator.d.ts +0 -23
- package/dist/prompts/chat-mode/protocol.d.ts +0 -2
- package/dist/prompts/chat-mode/system.d.ts +0 -2
- package/dist/prompts/chat-mode/system.md.d.ts +0 -2
- package/dist/prompts/chat-mode/user.d.ts +0 -2
- package/dist/prompts/chat-mode/user.md.d.ts +0 -2
- package/dist/prompts/code-examples.d.ts +0 -2
- package/dist/prompts/common.d.ts +0 -7
- package/dist/prompts/dual-modes.d.ts +0 -2
- package/dist/prompts/execution-history.d.ts +0 -6
- package/dist/prompts/execution-state.d.ts +0 -3
- package/dist/prompts/protocol-basics.d.ts +0 -5
- package/dist/prompts/protocol.d.ts +0 -31
- package/dist/prompts/worker-mode/protocol.d.ts +0 -2
- package/dist/prompts/worker-mode/system.d.ts +0 -2
- package/dist/prompts/worker-mode/system.md.d.ts +0 -2
- package/dist/prompts/worker-mode/user.d.ts +0 -2
- package/dist/prompts/worker-mode/user.md.d.ts +0 -2
- package/dist/quickjs-variant-BYhMBpwU.js +0 -45
- package/dist/quickjs-variant-CsIwTVFC.cjs +0 -56
- package/dist/rolldown-runtime-EAsCxrDo.js +0 -14
- package/dist/runtime/fixtures/qwen-protocol-failures.d.ts +0 -29
- package/dist/runtime/interpret-result.d.ts +0 -22
- package/dist/snapshots.d.ts +0 -249
- package/dist/stack-traces-BIE_5Xwf.js +0 -21
- package/dist/stack-traces-ntw_qhoy.cjs +0 -26
- package/dist/truncator-CLkouTCO.cjs +0 -276
- package/dist/truncator-DZqEqnpD.js +0 -253
- package/dist/truncator.d.ts +0 -118
- package/dist/utils-3ESwP3yg.cjs +0 -1075
- package/dist/utils-UBeAFeEI.js +0 -950
- /package/dist/{citations.d.ts → chat/citations.d.ts} +0 -0
- /package/dist/{citations.test.d.ts → chat/citations.test.d.ts} +0 -0
- /package/dist/{component.default.test.d.ts → chat/component.default.test.d.ts} +0 -0
- /package/dist/{compiler/plugins/track-tool-calls.test.d.ts → chat/component.test.d.ts} +0 -0
- /package/dist/{example.test.d.ts → chat/response.test.d.ts} +0 -0
- /package/dist/{exit-parser.test.d.ts → compiler/plugins/dynamic-code.test.d.ts} +0 -0
- /package/dist/{handlers.test.d.ts → compiler/plugins/tool-resolution.test.d.ts} +0 -0
- /package/dist/{hoist.test.d.ts → errors/catalog.test.d.ts} +0 -0
- /package/dist/{message-stream/instructions.test.d.ts → exit.test.d.ts} +0 -0
- /package/dist/{message-stream/normalizer.test.d.ts → inspection.test.d.ts} +0 -0
- /package/dist/{message-stream/parser.test.d.ts → prompts/native.test.d.ts} +0 -0
- /package/dist/{message-stream/response-parser.test.d.ts → result.test.d.ts} +0 -0
- /package/dist/{message-stream/stream.test.d.ts → runtime/chat-completion.test.d.ts} +0 -0
- /package/dist/{message-stream/validator.test.d.ts → runtime/chat-delivery.test.d.ts} +0 -0
- /package/dist/{prompts/adherence.test.d.ts → runtime/chat-last-speaker.test.d.ts} +0 -0
- /package/dist/{prompts/catalogue-examples.test.d.ts → runtime/compatibility-regressions.test.d.ts} +0 -0
- /package/dist/{prompts/code-examples.test.d.ts → runtime/context-registration.test.d.ts} +0 -0
- /package/dist/{prompts/common.test.d.ts → runtime/empty-completion.test.d.ts} +0 -0
- /package/dist/{prompts/concrete-patterns.test.d.ts → runtime/error-recovery.test.d.ts} +0 -0
- /package/dist/{prompts/long-search.test.d.ts → runtime/errors.test.d.ts} +0 -0
- /package/dist/{prompts/protocol-simple.test.d.ts → runtime/execution-activity.test.d.ts} +0 -0
- /package/dist/{prompts/protocol.test.d.ts → runtime/execution-diagnostics.test.d.ts} +0 -0
- /package/dist/{prompts/sections.test.d.ts → runtime/execution-report.test.d.ts} +0 -0
- /package/dist/runtime/{interpret-result.test.d.ts → execution-safety.test.d.ts} +0 -0
- /package/dist/{transcript.test.d.ts → runtime/exit-control-flow.test.d.ts} +0 -0
- /package/dist/{truncator.test.d.ts → runtime/fixtures/long-search.test.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,199 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as
|
|
3
|
-
import { a as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { t as configureQuickJS } from "./quickjs-variant-BYhMBpwU.js";
|
|
12
|
-
import { transforms, z } from "@bpinternal/zui";
|
|
1
|
+
import { c as isValidIdentifier, f as toValidFunctionName, i as getMultilineComment, p as toValidObjectName, t as configureTokenizer } from "./utils-BOFzb8Ok.js";
|
|
2
|
+
import { A as MemoryValueError, B as UnknownExitError, C as InvalidMessageError, D as LLMzError, E as InvalidToolError, F as SessionStateError, H as isCriticalError, I as TokenOverflowError, L as ToolExecutionError, M as NativeProtocolError, N as ObjectPropertyError, O as LoopExceededError, P as ReservedIdentifierError, R as ToolInputError, S as InvalidExitError, T as InvalidSessionError, U as isLLMzError, V as UnknownToolError, _ as InternalError, b as InvalidConfigurationError, c as CodeFormattingError, d as ComponentInputError, f as DeliveryError, g as HostOperationError, h as HookError, j as MissingChatResponseError, k as MemoryCapacityError, l as CognitiveError, m as ExitInputError, n as ThinkSignal, o as AssignmentError, p as ExecutionAbortedError, s as CodeExecutionError, u as CompactionError, v as InvalidCodeError, w as InvalidObjectError, x as InvalidEventError, y as InvalidComponentError, z as UnknownComponentError } from "./errors-Crk5P8jo.js";
|
|
3
|
+
import { a as isAnyComponent, n as assertValidComponent, o as isComponent, t as Component } from "./component-DncqP4fB.js";
|
|
4
|
+
import { t as Tool } from "./tool-DstssiAs.js";
|
|
5
|
+
import { t as Exit } from "./exit-DMPwCSba.js";
|
|
6
|
+
import { r as truncate } from "./truncate-BEKbdo3t.js";
|
|
7
|
+
import { f as createInspector, m as inspect, r as Memory, t as configureQuickJS } from "./quickjs-variant-CtuGagsb.js";
|
|
8
|
+
import { i as formatTypings } from "./typings-BEVDvtuk.js";
|
|
9
|
+
import { c as getValue, i as SuccessExecutionResult, l as Session, n as ErrorExecutionResult, o as DefaultExit, r as ExecutionResult, s as ListenExit, t as _CustomModelClient } from "./custom-client-C-WXvLD9.js";
|
|
10
|
+
import { z } from "@bpinternal/zui";
|
|
13
11
|
//#region package.json
|
|
14
|
-
var version = "0.
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/hoist.ts
|
|
17
|
-
/**
|
|
18
|
-
* Hoists object types (`{ ... }`) that appear more than once in a block of
|
|
19
|
-
* typings into named `type` aliases, replacing every occurrence with a
|
|
20
|
-
* reference. Runs repeatedly until a fixpoint so nested duplicates converge.
|
|
21
|
-
*/
|
|
22
|
-
/** Prints a node tree back to text, preserving line structure (formatTypings normalizes later) */
|
|
23
|
-
function printNodes(nodes) {
|
|
24
|
-
let out = "";
|
|
25
|
-
let afterLineComment = false;
|
|
26
|
-
const emit = (n) => {
|
|
27
|
-
const newlines = Math.min(n.nl ?? 0, 2);
|
|
28
|
-
if (newlines > 0) out += "\n".repeat(newlines);
|
|
29
|
-
else if (afterLineComment) out += "\n";
|
|
30
|
-
else if (out.length && !out.endsWith("\n")) out += " ";
|
|
31
|
-
afterLineComment = false;
|
|
32
|
-
if (isGroup(n)) {
|
|
33
|
-
out += n.open;
|
|
34
|
-
for (const child of n.children) emit(child);
|
|
35
|
-
if (afterLineComment) {
|
|
36
|
-
out += "\n";
|
|
37
|
-
afterLineComment = false;
|
|
38
|
-
}
|
|
39
|
-
out += n.close;
|
|
40
|
-
} else {
|
|
41
|
-
out += n.text;
|
|
42
|
-
afterLineComment = n.kind === "line-comment";
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
for (const n of nodes) emit(n);
|
|
46
|
-
return out;
|
|
47
|
-
}
|
|
48
|
-
/** Canonical structural key of a type literal: comments and separators ignored */
|
|
49
|
-
function keyOf(group) {
|
|
50
|
-
const parts = [];
|
|
51
|
-
const visit = (n) => {
|
|
52
|
-
if (isGroup(n)) {
|
|
53
|
-
parts.push(n.open);
|
|
54
|
-
n.children.forEach(visit);
|
|
55
|
-
parts.push(n.close);
|
|
56
|
-
} else if (n.kind === "word" || n.kind === "string" || n.kind === "punct" && n.text !== ";" && n.text !== ",") parts.push(n.text);
|
|
57
|
-
};
|
|
58
|
-
visit(group);
|
|
59
|
-
return parts.join(" ");
|
|
60
|
-
}
|
|
61
|
-
const prevMeaningful = (siblings, index) => {
|
|
62
|
-
for (let i = index - 1; i >= 0; i--) {
|
|
63
|
-
const n = siblings[i];
|
|
64
|
-
if (isGroup(n) || n.kind !== "block-comment" && n.kind !== "line-comment") return n;
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
const asName = (text) => upperFirst(text.replace(/['"]/g, "").replace(/[^A-Za-z0-9_$]/g, ""));
|
|
68
|
-
/** The naming segment for a `{`/`<` group from its surrounding tokens (`key:`, `fn(...)`, `): `, `=>`) */
|
|
69
|
-
function segmentsAt(siblings, index) {
|
|
70
|
-
const prev = prevMeaningful(siblings, index);
|
|
71
|
-
if (!prev || isGroup(prev)) return [];
|
|
72
|
-
if (isPunct(prev, "=>")) return ["Output"];
|
|
73
|
-
if (isPunct(prev, ":") || isPunct(prev, "<")) {
|
|
74
|
-
var _kind;
|
|
75
|
-
let i = siblings.indexOf(prev) - 1;
|
|
76
|
-
while (i >= 0 && !isGroup(siblings[i]) && ((_kind = siblings[i].kind) === null || _kind === void 0 ? void 0 : _kind.includes("comment"))) i--;
|
|
77
|
-
let q = siblings[i];
|
|
78
|
-
if (q && !isGroup(q) && q.kind === "punct" && q.text === "?") q = siblings[--i];
|
|
79
|
-
if (q && isGroup(q) && q.open === "(") {
|
|
80
|
-
const fnWord = prevMeaningful(siblings, i);
|
|
81
|
-
return fnWord && !isGroup(fnWord) && fnWord.kind === "word" ? [asName(fnWord.text), "Output"] : ["Output"];
|
|
82
|
-
}
|
|
83
|
-
if (q && !isGroup(q) && (q.kind === "word" || q.kind === "string")) return [asName(q.text)];
|
|
84
|
-
}
|
|
85
|
-
return [];
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Visits every hoistable `{ ... }` type literal with its naming path. Value
|
|
89
|
-
* objects (after `=`) are skipped — except `type X = { ... }` alias bodies,
|
|
90
|
-
* which are visited with their alias name so they can act as the canonical
|
|
91
|
-
* definition.
|
|
92
|
-
*/
|
|
93
|
-
function walkLiterals(siblings, path, visit) {
|
|
94
|
-
for (let i = 0; i < siblings.length; i++) {
|
|
95
|
-
var _prevMeaningful;
|
|
96
|
-
const node = siblings[i];
|
|
97
|
-
if (!isGroup(node)) continue;
|
|
98
|
-
if (node.open === "(") {
|
|
99
|
-
const fnWord = prevMeaningful(siblings, i);
|
|
100
|
-
const fnName = fnWord && !isGroup(fnWord) && fnWord.kind === "word" ? [asName(fnWord.text)] : [];
|
|
101
|
-
walkLiterals(node.children, [...path, ...fnName], visit);
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (node.open === "<" || node.open === "[") {
|
|
105
|
-
walkLiterals(node.children, [...path, ...segmentsAt(siblings, i)], visit);
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
const prev = prevMeaningful(siblings, i);
|
|
109
|
-
if (prev && isPunct(prev, "=")) {
|
|
110
|
-
const eqIdx = siblings.indexOf(prev);
|
|
111
|
-
const nameTok = siblings[eqIdx - 1];
|
|
112
|
-
const typeTok = siblings[eqIdx - 2];
|
|
113
|
-
if (!(nameTok && typeTok && !isGroup(nameTok) && !isGroup(typeTok) && nameTok.kind === "word" && typeTok.kind === "word" && typeTok.text === "type")) continue;
|
|
114
|
-
const aliasName = nameTok.text;
|
|
115
|
-
visit({
|
|
116
|
-
siblings,
|
|
117
|
-
index: i,
|
|
118
|
-
group: node,
|
|
119
|
-
path: [aliasName],
|
|
120
|
-
aliasName
|
|
121
|
-
});
|
|
122
|
-
if (siblings[i] === node) walkLiterals(node.children, [aliasName], visit);
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
const namespaceLike = prev && !isGroup(prev) && prev.kind === "word" && ((_prevMeaningful = prevMeaningful(siblings, siblings.indexOf(prev))) === null || _prevMeaningful === void 0 ? void 0 : _prevMeaningful.kind) === "word" && ["namespace", "module"].includes(prevMeaningful(siblings, siblings.indexOf(prev)).text);
|
|
126
|
-
const segments = segmentsAt(siblings, i);
|
|
127
|
-
const newPath = [...path, ...segments];
|
|
128
|
-
if (!namespaceLike) visit({
|
|
129
|
-
siblings,
|
|
130
|
-
index: i,
|
|
131
|
-
group: node,
|
|
132
|
-
path: newPath
|
|
133
|
-
});
|
|
134
|
-
if (siblings[i] === node) walkLiterals(node.children, namespaceLike ? [...path, asName(prev.text)] : newPath, visit);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
function extractAndHoistTypes(code) {
|
|
138
|
-
const top = parse(tokenize(code));
|
|
139
|
-
const counts = /* @__PURE__ */ new Map();
|
|
140
|
-
const aliasByKey = /* @__PURE__ */ new Map();
|
|
141
|
-
const usedNames = /* @__PURE__ */ new Set();
|
|
142
|
-
walkLiterals(top, [], ({ group, path, aliasName }) => {
|
|
143
|
-
const key = keyOf(group);
|
|
144
|
-
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
145
|
-
if (aliasName && !aliasByKey.has(key)) aliasByKey.set(key, aliasName);
|
|
146
|
-
for (const segment of path) usedNames.add(segment);
|
|
147
|
-
if (aliasName) usedNames.add(aliasName);
|
|
148
|
-
});
|
|
149
|
-
const uniqueName = (base) => {
|
|
150
|
-
let name = base;
|
|
151
|
-
let counter = 1;
|
|
152
|
-
while (usedNames.has(name)) name = `${base}${counter++}`;
|
|
153
|
-
usedNames.add(name);
|
|
154
|
-
return name;
|
|
155
|
-
};
|
|
156
|
-
const newAliases = [];
|
|
157
|
-
walkLiterals(top, [], ({ siblings, index, group, aliasName, path }) => {
|
|
158
|
-
const key = keyOf(group);
|
|
159
|
-
if ((counts.get(key) ?? 0) < 2 || aliasName) return;
|
|
160
|
-
let name = aliasByKey.get(key);
|
|
161
|
-
if (!name) {
|
|
162
|
-
const deduped = [...new Set(path)];
|
|
163
|
-
name = uniqueName(deduped.length ? deduped.join("") : "UnnamedType");
|
|
164
|
-
aliasByKey.set(key, name);
|
|
165
|
-
newAliases.push(`type ${name} = ${printNodes([{
|
|
166
|
-
...group,
|
|
167
|
-
nl: 0
|
|
168
|
-
}])}`);
|
|
169
|
-
}
|
|
170
|
-
siblings[index] = {
|
|
171
|
-
kind: "word",
|
|
172
|
-
text: name,
|
|
173
|
-
nl: group.nl
|
|
174
|
-
};
|
|
175
|
-
});
|
|
176
|
-
const body = printNodes(top);
|
|
177
|
-
return newAliases.length ? `${newAliases.join("\n")}\n${body}` : body;
|
|
178
|
-
}
|
|
179
|
-
async function hoistTypings(code, formatOptions) {
|
|
180
|
-
formatOptions ??= {};
|
|
181
|
-
formatOptions.throwOnError ??= true;
|
|
182
|
-
for (let i = 1; i <= 5; i++) try {
|
|
183
|
-
const initialCode = code;
|
|
184
|
-
code = extractAndHoistTypes(code);
|
|
185
|
-
if (initialCode === code) break;
|
|
186
|
-
} catch (err) {
|
|
187
|
-
console.error(err);
|
|
188
|
-
if (formatOptions.throwOnError) throw new CodeFormattingError(err instanceof Error ? err.message : String(err ?? "Unknown Error"), code);
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
return formatTypings(code, formatOptions);
|
|
192
|
-
}
|
|
12
|
+
var version = "1.0.2";
|
|
193
13
|
//#endregion
|
|
194
14
|
//#region src/objects.ts
|
|
195
|
-
/** How many lines of code an object needs to have before we insert a comment for end tag */
|
|
196
|
-
const LARGE_OBJECT_LINES_OF_CODE = 10;
|
|
197
15
|
/**
|
|
198
16
|
* ObjectInstance creates stateful, namespace-scoped objects for LLMz agents.
|
|
199
17
|
*
|
|
@@ -372,25 +190,6 @@ const LARGE_OBJECT_LINES_OF_CODE = 10;
|
|
|
372
190
|
* })
|
|
373
191
|
* ```
|
|
374
192
|
*
|
|
375
|
-
* ## TypeScript Integration
|
|
376
|
-
*
|
|
377
|
-
* Objects generate TypeScript namespace declarations:
|
|
378
|
-
*
|
|
379
|
-
* ```typescript
|
|
380
|
-
* // Generated types for the LLM context:
|
|
381
|
-
* export namespace user {
|
|
382
|
-
* const name: Writable<string | null> = null
|
|
383
|
-
* const age: Writable<number | null> = null
|
|
384
|
-
* const id: Readonly<string> = "user_123"
|
|
385
|
-
* }
|
|
386
|
-
*
|
|
387
|
-
* export namespace fs {
|
|
388
|
-
* function readFile(args: { path: string }): Promise<string>
|
|
389
|
-
* function writeFile(args: { path: string, content: string }): Promise<void>
|
|
390
|
-
* }
|
|
391
|
-
* ```
|
|
392
|
-
*
|
|
393
|
-
* @see {@link https://github.com/botpress/botpress/blob/master/packages/llmz/examples/09_chat_variables/index.ts} Example usage
|
|
394
193
|
*/
|
|
395
194
|
var ObjectInstance = class {
|
|
396
195
|
name;
|
|
@@ -456,18 +255,19 @@ var ObjectInstance = class {
|
|
|
456
255
|
*/
|
|
457
256
|
constructor(props) {
|
|
458
257
|
var _props$properties;
|
|
459
|
-
if (!
|
|
460
|
-
if (props.
|
|
461
|
-
if (props.
|
|
462
|
-
if (props.
|
|
463
|
-
if (props.
|
|
258
|
+
if (!props || typeof props !== "object" || Array.isArray(props)) throw new InvalidObjectError("Object definition must be an object.");
|
|
259
|
+
if (!isValidIdentifier(props.name)) throw new InvalidObjectError(`Invalid name for tool ${props.name}. A tool name must start with a letter and contain only letters, numbers, and underscores. It must be 1-50 characters long.`);
|
|
260
|
+
if (props.description !== void 0 && typeof props.description !== "string") throw new InvalidObjectError(`Invalid description for tool ${props.name}. Expected a string, but got type "${typeof props.description}"`);
|
|
261
|
+
if (props.metadata !== void 0 && typeof props.metadata !== "object") throw new InvalidObjectError(`Invalid metadata for tool ${props.name}. Expected an object, but got type "${typeof props.metadata}"`);
|
|
262
|
+
if (props.properties !== void 0 && !Array.isArray(props.properties)) throw new InvalidObjectError(`Invalid properties for tool ${props.name}. Expected an array, but got type "${typeof props.properties}"`);
|
|
263
|
+
if (props.tools !== void 0 && !Array.isArray(props.tools)) throw new InvalidObjectError(`Invalid tools for tool ${props.name}. Expected an array, but got type "${typeof props.tools}"`);
|
|
464
264
|
if ((_props$properties = props.properties) === null || _props$properties === void 0 ? void 0 : _props$properties.length) {
|
|
465
|
-
if (props.properties.length > 100) throw new
|
|
265
|
+
if (props.properties.length > 100) throw new InvalidObjectError(`Too many properties for tool ${props.name}. Expected at most 100 properties, but got ${props.properties.length}`);
|
|
466
266
|
for (const prop of props.properties) {
|
|
467
|
-
if (props.properties.filter((p) => p.name === prop.name).length > 1) throw new
|
|
468
|
-
if (!isValidIdentifier(prop.name)) throw new
|
|
469
|
-
if (prop.description !== void 0 && typeof prop.description !== "string") throw new
|
|
470
|
-
if (props.description && props.description.length >= 5e3) throw new
|
|
267
|
+
if (props.properties.filter((p) => p.name === prop.name).length > 1) throw new InvalidObjectError(`Duplicate property name "${prop.name}" in tool ${props.name}`);
|
|
268
|
+
if (!isValidIdentifier(prop.name)) throw new InvalidObjectError(`Invalid name for property ${prop.name}. A property name must start with a letter and contain only letters, numbers, and underscores. It must be 1-50 characters long.`);
|
|
269
|
+
if (prop.description !== void 0 && typeof prop.description !== "string") throw new InvalidObjectError(`Invalid description for property ${prop.name}. Expected a string, but got type "${typeof prop.description}"`);
|
|
270
|
+
if (props.description && props.description.length >= 5e3) throw new InvalidObjectError(`Description for property ${prop.name} is too long. Expected at most 5000 characters, but got ${props.description.length}`);
|
|
471
271
|
if (typeof prop.writable !== "boolean") prop.writable = false;
|
|
472
272
|
}
|
|
473
273
|
}
|
|
@@ -477,45 +277,17 @@ var ObjectInstance = class {
|
|
|
477
277
|
this.properties = props.properties;
|
|
478
278
|
this.tools = Tool.withUniqueNames(props.tools ?? []);
|
|
479
279
|
}
|
|
480
|
-
/**
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
* ```typescript
|
|
492
|
-
* const obj = new ObjectInstance({
|
|
493
|
-
* name: 'user',
|
|
494
|
-
* properties: [
|
|
495
|
-
* { name: 'name', value: 'John', writable: true },
|
|
496
|
-
* { name: 'id', value: 123, writable: false },
|
|
497
|
-
* ],
|
|
498
|
-
* tools: [
|
|
499
|
-
* new Tool({
|
|
500
|
-
* name: 'save',
|
|
501
|
-
* input: z.object({ data: z.string() }),
|
|
502
|
-
* handler: async ({ data }) => { /* ... *\/ },
|
|
503
|
-
* }),
|
|
504
|
-
* ],
|
|
505
|
-
* })
|
|
506
|
-
*
|
|
507
|
-
* const typings = await obj.getTypings()
|
|
508
|
-
* console.log(typings)
|
|
509
|
-
* // Output:
|
|
510
|
-
* // export namespace user {
|
|
511
|
-
* // const name: Writable<string> = "John"
|
|
512
|
-
* // const id: Readonly<number> = 123
|
|
513
|
-
* // function save(args: { data: string }): Promise<void>
|
|
514
|
-
* // }
|
|
515
|
-
* ```
|
|
516
|
-
*/
|
|
517
|
-
async getTypings() {
|
|
518
|
-
return getObjectTypings(this).withProperties().withTools().build();
|
|
280
|
+
/** Callable API only. Property values, schemas, and access rules belong in Memory. */
|
|
281
|
+
async getToolTypings() {
|
|
282
|
+
var _this$description;
|
|
283
|
+
const declarations = [];
|
|
284
|
+
for (const tool of this.tools ?? []) {
|
|
285
|
+
const declaration = await tool.getTypings();
|
|
286
|
+
declarations.push(declaration.replace("declare function ", "function "));
|
|
287
|
+
}
|
|
288
|
+
const description = ((_this$description = this.description) === null || _this$description === void 0 ? void 0 : _this$description.trim()) ? getMultilineComment(this.description) : "";
|
|
289
|
+
const body = declarations.join("\n\n");
|
|
290
|
+
return formatTypings(`${description}\nexport namespace ${this.name} {\n${body}\n}`, { throwOnError: false });
|
|
519
291
|
}
|
|
520
292
|
/**
|
|
521
293
|
* Converts this ObjectInstance to its JSON representation.
|
|
@@ -536,123 +308,36 @@ var ObjectInstance = class {
|
|
|
536
308
|
};
|
|
537
309
|
}
|
|
538
310
|
};
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/chat/chat.ts
|
|
539
313
|
/**
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* This function provides a fluent API for generating TypeScript declarations
|
|
543
|
-
* that include properties, tools, or both. It's used internally by ObjectInstance.getTypings().
|
|
544
|
-
*
|
|
545
|
-
* @param obj - The ObjectInstance to generate typings for
|
|
546
|
-
* @returns A builder object with methods to configure and build the namespace
|
|
547
|
-
* @internal
|
|
548
|
-
*/
|
|
549
|
-
function getObjectTypings(obj) {
|
|
550
|
-
let includeProperties = false;
|
|
551
|
-
let includeTools = false;
|
|
552
|
-
let hoisting = false;
|
|
553
|
-
const typings = [];
|
|
554
|
-
const addProperties = async () => {
|
|
555
|
-
var _obj$properties;
|
|
556
|
-
if (includeProperties && ((_obj$properties = obj.properties) === null || _obj$properties === void 0 ? void 0 : _obj$properties.length)) {
|
|
557
|
-
typings.push("");
|
|
558
|
-
typings.push("// ---------------- //");
|
|
559
|
-
typings.push("// Properties //");
|
|
560
|
-
typings.push("// ---------------- //");
|
|
561
|
-
typings.push("");
|
|
562
|
-
for (const prop of obj.properties ?? []) {
|
|
563
|
-
const description = prop.description ?? "";
|
|
564
|
-
if (description === null || description === void 0 ? void 0 : description.trim().length) typings.push(getMultilineComment(description));
|
|
565
|
-
let type = "unknown";
|
|
566
|
-
if (prop.type) type = await getTypings(prop.type, {});
|
|
567
|
-
else if (prop.value !== void 0) type = typeof prop.value;
|
|
568
|
-
type = prop.writable ? `Writable<${type}>` : `Readonly<${type}>`;
|
|
569
|
-
const value = embedPropertyValue(prop);
|
|
570
|
-
typings.push(`const ${prop.name}: ${type} = ${value}`);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
const addTools = async () => {
|
|
575
|
-
var _obj$tools;
|
|
576
|
-
if (includeTools && ((_obj$tools = obj.tools) === null || _obj$tools === void 0 ? void 0 : _obj$tools.length)) {
|
|
577
|
-
typings.push("");
|
|
578
|
-
typings.push("// ---------------- //");
|
|
579
|
-
typings.push("// Tools //");
|
|
580
|
-
typings.push("// ---------------- //");
|
|
581
|
-
typings.push("");
|
|
582
|
-
for (const tool of obj.tools) {
|
|
583
|
-
const fnType = z.function(tool.zInput, tool.zOutput).title(tool.name).describe(tool.description ?? "");
|
|
584
|
-
let temp = await getTypings(fnType, { declaration: true });
|
|
585
|
-
temp = temp.replace("declare function ", "function ");
|
|
586
|
-
typings.push(temp);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
const finalize = async () => {
|
|
591
|
-
var _obj$description;
|
|
592
|
-
let closingBracket = "";
|
|
593
|
-
if (typings.length >= LARGE_OBJECT_LINES_OF_CODE) closingBracket = ` // end namespace "${obj.name}"`;
|
|
594
|
-
let body = typings.join("\n");
|
|
595
|
-
if (hoisting) body = await hoistTypings(body, { throwOnError: false });
|
|
596
|
-
typings.push("}" + closingBracket);
|
|
597
|
-
let header = "";
|
|
598
|
-
if ((_obj$description = obj.description) === null || _obj$description === void 0 ? void 0 : _obj$description.trim().length) header = getMultilineComment(obj.description);
|
|
599
|
-
return formatTypings(`${header}
|
|
600
|
-
export namespace ${obj.name} {
|
|
601
|
-
${body}
|
|
602
|
-
} ${closingBracket}`.trim(), { throwOnError: false });
|
|
603
|
-
};
|
|
604
|
-
const api = {
|
|
605
|
-
withProperties: () => {
|
|
606
|
-
includeProperties = true;
|
|
607
|
-
return api;
|
|
608
|
-
},
|
|
609
|
-
withTools: () => {
|
|
610
|
-
includeTools = true;
|
|
611
|
-
return api;
|
|
612
|
-
},
|
|
613
|
-
withHoisting: () => {
|
|
614
|
-
hoisting = true;
|
|
615
|
-
return api;
|
|
616
|
-
},
|
|
617
|
-
async build() {
|
|
618
|
-
await addProperties();
|
|
619
|
-
await addTools();
|
|
620
|
-
return finalize();
|
|
621
|
-
}
|
|
622
|
-
};
|
|
623
|
-
return api;
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* Converts a property value to its TypeScript literal representation.
|
|
314
|
+
* Connects native assistant replies and rich components to the host application.
|
|
627
315
|
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
316
|
+
* `response` controls how all assistant text is written. It does not create a
|
|
317
|
+
* JavaScript method or synthesize audio. `components` registers only rich UI
|
|
318
|
+
* methods such as chat.buttons or chat.image.
|
|
631
319
|
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
320
|
+
* Streamed deltas are provisional. After successful generation, the response
|
|
321
|
+
* handler receives the complete text with the same message ID. Each component
|
|
322
|
+
* owns its delivery handler. Without response callbacks, text remains available
|
|
323
|
+
* in the native session history.
|
|
635
324
|
*/
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (property.value instanceof Map) return `new Map(${JSON.stringify(Array.from(property.value.entries()))})`;
|
|
651
|
-
if (property.value instanceof Set) return `new Set(${JSON.stringify(Array.from(property.value.values()))})`;
|
|
652
|
-
return "unknown";
|
|
653
|
-
}
|
|
325
|
+
var Chat = class {
|
|
326
|
+
components;
|
|
327
|
+
response;
|
|
328
|
+
constructor(props = {}) {
|
|
329
|
+
if (!props || typeof props !== "object" || Array.isArray(props)) throw new InvalidConfigurationError("Chat configuration must be an object.");
|
|
330
|
+
if ("handler" in props || "onMessageDelta" in props) throw new InvalidConfigurationError("Use response.handler and response.onDelta for text, and component handlers for rich messages.");
|
|
331
|
+
const unknown = Object.keys(props).find((key) => !["components", "response"].includes(key));
|
|
332
|
+
if (unknown) throw new InvalidConfigurationError(`Unknown Chat option: ${unknown}.`);
|
|
333
|
+
this.components = props.components ?? [];
|
|
334
|
+
this.response = props.response === void 0 ? "markdown" : props.response;
|
|
335
|
+
}
|
|
336
|
+
/** Called after an execution completes or fails. */
|
|
337
|
+
onExecutionDone(_result) {}
|
|
338
|
+
};
|
|
654
339
|
//#endregion
|
|
655
|
-
//#region src/citations.ts
|
|
340
|
+
//#region src/chat/citations.ts
|
|
656
341
|
/** These are all single-token symbols that are very rare in natural texts, making them suitable for usage within GPT Prompts. */
|
|
657
342
|
const RARE_SYMBOLS = {
|
|
658
343
|
ARROW_UP: "↑",
|
|
@@ -791,854 +476,95 @@ var CitationsManager = class {
|
|
|
791
476
|
}
|
|
792
477
|
};
|
|
793
478
|
//#endregion
|
|
794
|
-
//#region src/component.default.ts
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
} },
|
|
817
|
-
[
|
|
818
|
-
{ props: {
|
|
819
|
-
action: "say",
|
|
820
|
-
label: "Track my order"
|
|
821
|
-
} },
|
|
822
|
-
{ props: {
|
|
823
|
-
action: "say",
|
|
824
|
-
label: "Return an item"
|
|
825
|
-
} },
|
|
826
|
-
{ props: {
|
|
827
|
-
action: "say",
|
|
828
|
-
label: "Contact support"
|
|
829
|
-
} }
|
|
830
|
-
]
|
|
831
|
-
]
|
|
832
|
-
},
|
|
833
|
-
leaf: { props: z.object({
|
|
834
|
-
action: z.enum([
|
|
835
|
-
"say",
|
|
836
|
-
"url",
|
|
837
|
-
"postback"
|
|
838
|
-
]).default("say").describe("The action to perform when the button is clicked. Can be \"say\", \"url\", or \"postback\""),
|
|
839
|
-
label: z.string().describe("The text displayed on the button (min 1 character, max 250 characters)"),
|
|
840
|
-
value: z.string().optional().describe("The postback value to send when the button is clicked. Required if action is \"postback\""),
|
|
841
|
-
url: z.string().optional().describe("The URL to open when the button is clicked. Required if action is \"url\"")
|
|
842
|
-
}) }
|
|
843
|
-
});
|
|
844
|
-
const Image = new Component({
|
|
845
|
-
type: "leaf",
|
|
846
|
-
name: "Image",
|
|
847
|
-
description: "Displays an image from a URL.",
|
|
848
|
-
aliases: [],
|
|
849
|
-
generation: {
|
|
850
|
-
usage: "Use a known image URL from the user or tool results; never invent an image URL. No body.",
|
|
851
|
-
examples: [{ props: {
|
|
852
|
-
url: "https://example.com/trail.jpg",
|
|
853
|
-
alt: "Forest trail beside a lake"
|
|
854
|
-
} }]
|
|
855
|
-
},
|
|
856
|
-
leaf: { props: z.object({
|
|
857
|
-
url: z.string().describe("The URL of the image (must be valid)"),
|
|
858
|
-
alt: z.string().optional().describe("Alternative text describing the image")
|
|
859
|
-
}) }
|
|
860
|
-
});
|
|
861
|
-
const File = new Component({
|
|
862
|
-
type: "leaf",
|
|
863
|
-
name: "File",
|
|
864
|
-
description: "Sends a downloadable file to the user.",
|
|
865
|
-
aliases: [],
|
|
866
|
-
generation: { examples: [{ props: {
|
|
867
|
-
url: "https://example.com/report.pdf",
|
|
868
|
-
name: "Report.pdf"
|
|
869
|
-
} }] },
|
|
870
|
-
leaf: { props: z.object({
|
|
871
|
-
url: z.string().describe("The URL of the file (must be valid)"),
|
|
872
|
-
name: z.string().optional().describe("The display name of the file")
|
|
873
|
-
}) }
|
|
874
|
-
});
|
|
875
|
-
const Video = new Component({
|
|
876
|
-
type: "leaf",
|
|
877
|
-
name: "Video",
|
|
878
|
-
description: "Embeds a video from a URL.",
|
|
879
|
-
aliases: [],
|
|
880
|
-
generation: { examples: [{ props: {
|
|
881
|
-
url: "https://example.com/intro.mp4",
|
|
882
|
-
title: "Welcome"
|
|
883
|
-
} }] },
|
|
884
|
-
leaf: { props: z.object({
|
|
885
|
-
url: z.string().describe("The URL of the video (must be valid)"),
|
|
886
|
-
title: z.string().optional().describe("Title for the video")
|
|
887
|
-
}) }
|
|
888
|
-
});
|
|
889
|
-
const Audio = new Component({
|
|
890
|
-
type: "leaf",
|
|
891
|
-
name: "Audio",
|
|
892
|
-
description: "Plays an audio clip from a URL.",
|
|
893
|
-
aliases: [],
|
|
894
|
-
generation: { examples: [{ props: {
|
|
895
|
-
url: "https://example.com/audio.mp3",
|
|
896
|
-
title: "Sample"
|
|
897
|
-
} }] },
|
|
898
|
-
leaf: { props: z.object({
|
|
899
|
-
url: z.string().describe("The URL of the audio clip (must be valid)"),
|
|
900
|
-
title: z.string().optional().describe("Title for the audio clip")
|
|
901
|
-
}) }
|
|
902
|
-
});
|
|
903
|
-
const Card = new Component({
|
|
904
|
-
type: "container",
|
|
905
|
-
name: "Card",
|
|
906
|
-
description: "A card with a title, optional subtitle, and Markdown body.",
|
|
907
|
-
aliases: [],
|
|
908
|
-
generation: {
|
|
909
|
-
usage: "Present one item. The block body is Markdown, not nested component blocks or JSX.",
|
|
910
|
-
examples: [{
|
|
911
|
-
props: {
|
|
912
|
-
title: "Standard plan",
|
|
913
|
-
subtitle: "$20/month"
|
|
914
|
-
},
|
|
915
|
-
body: "Includes 5 projects and email support."
|
|
916
|
-
}]
|
|
917
|
-
},
|
|
918
|
-
container: {
|
|
919
|
-
props: z.object({
|
|
920
|
-
title: z.string().min(1).max(250).describe("Title text (1–250 characters)"),
|
|
921
|
-
subtitle: z.string().optional().describe("Optional subtitle for the card")
|
|
922
|
-
}),
|
|
923
|
-
children: [{
|
|
924
|
-
description: "Image (optional, max 1)",
|
|
925
|
-
component: Image.definition
|
|
926
|
-
}, {
|
|
927
|
-
description: "Button (optional, up to 5)",
|
|
928
|
-
component: Button.definition
|
|
929
|
-
}]
|
|
930
|
-
}
|
|
931
|
-
});
|
|
932
|
-
const carouselProps = z.object({ cards: z.array(Card.definition.container.props.extend({
|
|
933
|
-
body: z.string().optional().describe("Markdown text for this card"),
|
|
934
|
-
image: Image.definition.leaf.props.optional().describe("Optional image for this card; use a known URL"),
|
|
935
|
-
buttons: z.array(Button.definition.leaf.props).max(5).optional().describe("Up to 5 actions for this card")
|
|
936
|
-
})).min(1).max(10).describe("1–10 cards, in display order. Each card has its own title, optional subtitle, body, image, and buttons") });
|
|
937
|
-
var CarouselComponent = class extends Component {
|
|
938
|
-
render(props, children = []) {
|
|
939
|
-
if (!("cards" in props) && children.length && children.every((child) => isComponent(child, Card))) return super.render(props, children);
|
|
940
|
-
const { cards } = carouselProps.parse(props);
|
|
941
|
-
const renderedCards = cards.map(({ body, image, buttons, ...cardProps }) => Card.render(cardProps, [
|
|
942
|
-
...body ? [body] : [],
|
|
943
|
-
...image ? [Image.render(image)] : [],
|
|
944
|
-
...(buttons ?? []).map((button) => Button.render(button))
|
|
945
|
-
]));
|
|
946
|
-
return super.render({}, renderedCards);
|
|
947
|
-
}
|
|
948
|
-
};
|
|
479
|
+
//#region src/chat/component.default.ts
|
|
480
|
+
const buttonProps = z.object({
|
|
481
|
+
action: z.enum([
|
|
482
|
+
"say",
|
|
483
|
+
"url",
|
|
484
|
+
"postback"
|
|
485
|
+
]).default("say").describe("The action to perform when the button is clicked: say, url, or postback"),
|
|
486
|
+
label: z.string().min(1).max(250).describe("The text displayed on the button (1–250 characters)"),
|
|
487
|
+
value: z.string().optional().describe("The postback value. Required when action is postback"),
|
|
488
|
+
url: z.string().optional().describe("The URL to open. Required when action is url")
|
|
489
|
+
}).strict();
|
|
490
|
+
const imageProps = z.object({
|
|
491
|
+
url: z.string().describe("The URL of the image (must be valid)"),
|
|
492
|
+
alt: z.string().optional().describe("Alternative text describing the image")
|
|
493
|
+
}).strict();
|
|
494
|
+
const cardProps = z.object({
|
|
495
|
+
title: z.string().min(1).max(250).describe("Title text (1–250 characters)"),
|
|
496
|
+
subtitle: z.string().optional().describe("Optional subtitle for the card"),
|
|
497
|
+
text: z.string().optional().describe("Optional Markdown text for the card"),
|
|
498
|
+
image: imageProps.optional().describe("Optional image for the card; use a known URL"),
|
|
499
|
+
buttons: z.array(buttonProps).max(5).optional().describe("Up to 5 actions for the card")
|
|
500
|
+
}).strict();
|
|
949
501
|
const DefaultComponents = {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
Audio,
|
|
955
|
-
Card,
|
|
956
|
-
Carousel: new CarouselComponent({
|
|
957
|
-
type: "container",
|
|
958
|
-
name: "Carousel",
|
|
959
|
-
description: "Displays a horizontally scrollable collection of cards, each with its own content and actions.",
|
|
960
|
-
aliases: [],
|
|
961
|
-
body: false,
|
|
962
|
-
generation: {
|
|
963
|
-
usage: "Use for several comparable items. Put ALL cards in the cards array of ONE send block. Each card can include title, subtitle, body, image {url, alt?}, and buttons [{action, label, value?, url?}]. Do not write a Markdown list or separate Card blocks; those do not form a carousel.",
|
|
964
|
-
examples: [{ props: { cards: [{
|
|
965
|
-
title: "Standard plan",
|
|
966
|
-
subtitle: "$20/month",
|
|
967
|
-
body: "5 projects and email support.",
|
|
968
|
-
image: {
|
|
969
|
-
url: "https://example.com/standard.jpg",
|
|
970
|
-
alt: "Standard plan"
|
|
971
|
-
},
|
|
972
|
-
buttons: [{
|
|
973
|
-
action: "postback",
|
|
974
|
-
label: "Choose Standard",
|
|
975
|
-
value: "plan_standard"
|
|
976
|
-
}]
|
|
977
|
-
}, {
|
|
978
|
-
title: "Team plan",
|
|
979
|
-
subtitle: "$50/month",
|
|
980
|
-
body: "20 projects and priority support.",
|
|
981
|
-
image: {
|
|
982
|
-
url: "https://example.com/team.jpg",
|
|
983
|
-
alt: "Team plan"
|
|
984
|
-
},
|
|
985
|
-
buttons: [{
|
|
986
|
-
action: "postback",
|
|
987
|
-
label: "Choose Team",
|
|
988
|
-
value: "plan_team"
|
|
989
|
-
}]
|
|
990
|
-
}] } }]
|
|
991
|
-
},
|
|
992
|
-
container: {
|
|
993
|
-
props: carouselProps,
|
|
994
|
-
children: [{
|
|
995
|
-
description: "Card component (required, 1–10 allowed)",
|
|
996
|
-
component: Card.definition
|
|
997
|
-
}]
|
|
998
|
-
}
|
|
502
|
+
Buttons: new Component({
|
|
503
|
+
name: "buttons",
|
|
504
|
+
description: "Offer quick actions or choices after a message. Buttons appear together in array order.",
|
|
505
|
+
props: z.array(buttonProps).min(1)
|
|
999
506
|
}),
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
description: "A Markdown-formatted text message. Long answers are written the same way: plain Markdown prose.",
|
|
1005
|
-
generation: { examples: [{ body: `To reset your password:
|
|
1006
|
-
|
|
1007
|
-
1. Open the sign-in page and select **Forgot password?**
|
|
1008
|
-
2. Enter the email address you use for your account.
|
|
1009
|
-
3. Open the reset link in your email and choose a new password.
|
|
1010
|
-
|
|
1011
|
-
If the email does not arrive, check your spam folder. If you sign in through your organization, use its password reset process.` }, { body: "How do you currently manage board meetings?" }] },
|
|
1012
|
-
default: {
|
|
1013
|
-
props: z.object({}),
|
|
1014
|
-
children: []
|
|
1015
|
-
}
|
|
507
|
+
Image: new Component({
|
|
508
|
+
name: "image",
|
|
509
|
+
description: "Display an image using a known URL from the user or tool results; never invent an image URL.",
|
|
510
|
+
props: imageProps
|
|
1016
511
|
}),
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
512
|
+
File: new Component({
|
|
513
|
+
name: "file",
|
|
514
|
+
description: "Send a downloadable file to the user.",
|
|
515
|
+
props: z.object({
|
|
516
|
+
url: z.string().describe("The URL of the file (must be valid)"),
|
|
517
|
+
name: z.string().optional().describe("The display name of the file")
|
|
518
|
+
}).strict()
|
|
519
|
+
}),
|
|
520
|
+
Video: new Component({
|
|
521
|
+
name: "video",
|
|
522
|
+
description: "Embed a video from a URL.",
|
|
523
|
+
props: z.object({
|
|
524
|
+
url: z.string().describe("The URL of the video (must be valid)"),
|
|
525
|
+
title: z.string().optional().describe("Title for the video")
|
|
526
|
+
}).strict()
|
|
527
|
+
}),
|
|
528
|
+
Audio: new Component({
|
|
529
|
+
name: "audio",
|
|
530
|
+
description: "Play an audio clip from a URL.",
|
|
531
|
+
props: z.object({
|
|
532
|
+
url: z.string().describe("The URL of the audio clip (must be valid)"),
|
|
533
|
+
title: z.string().optional().describe("Title for the audio clip")
|
|
534
|
+
}).strict()
|
|
535
|
+
}),
|
|
536
|
+
Card: new Component({
|
|
537
|
+
name: "card",
|
|
538
|
+
description: "Present one item with a title, optional subtitle, Markdown text, image, and buttons.",
|
|
539
|
+
props: cardProps
|
|
540
|
+
}),
|
|
541
|
+
Carousel: new Component({
|
|
542
|
+
name: "carousel",
|
|
543
|
+
description: "Display several comparable items as a horizontally scrollable collection of cards.",
|
|
544
|
+
props: z.object({ cards: z.array(cardProps).min(1).max(10).describe("1–10 cards in display order, each with its own content and actions") }).strict()
|
|
1034
545
|
})
|
|
1035
546
|
};
|
|
1036
547
|
//#endregion
|
|
1037
|
-
//#region src/chat.ts
|
|
1038
|
-
/**
|
|
1039
|
-
* Base class for implementing chat interfaces in LLMz agents.
|
|
1040
|
-
*
|
|
1041
|
-
* The Chat class provides the foundation for interactive conversational agents by defining
|
|
1042
|
-
* how agents communicate with users. It manages the conversation transcript, available UI
|
|
1043
|
-
* components, and message handling. This is the bridge between the agent's generated code
|
|
1044
|
-
* and your user interface.
|
|
1045
|
-
*
|
|
1046
|
-
* ## Key Concepts
|
|
1047
|
-
*
|
|
1048
|
-
* **Handler Function**: The core method that receives agent messages (rendered components)
|
|
1049
|
-
* and displays them to the user. This is called every time the agent wants to communicate.
|
|
1050
|
-
*
|
|
1051
|
-
* **Transcript**: An up-to-date conversation history that is evaluated at each iteration.
|
|
1052
|
-
* The transcript must reflect the complete conversation state as the agent uses it to
|
|
1053
|
-
* understand context and generate appropriate responses.
|
|
1054
|
-
*
|
|
1055
|
-
* **Components**: The UI elements available to the agent for creating rich interactive
|
|
1056
|
-
* experiences (text, buttons, images, cards, etc.).
|
|
1057
|
-
*
|
|
1058
|
-
* ## Implementation Requirements
|
|
1059
|
-
*
|
|
1060
|
-
* To create a functional chat interface, you must:
|
|
1061
|
-
* 1. Implement the MessageHandler to display agent messages to users
|
|
1062
|
-
* 2. Maintain an accurate transcript of the conversation
|
|
1063
|
-
* 3. Provide the available UI components (typically includes DefaultComponents)
|
|
1064
|
-
* 4. Optional: Override onExecutionDone() to handle execution completion
|
|
1065
|
-
*
|
|
1066
|
-
* ## Basic Implementation
|
|
1067
|
-
*
|
|
1068
|
-
* ```typescript
|
|
1069
|
-
* import { Chat, DefaultComponents, isComponent } from 'llmz'
|
|
1070
|
-
*
|
|
1071
|
-
* class MyChat extends Chat {
|
|
1072
|
-
* private messages: Array<{role: 'user' | 'assistant', content: string}> = []
|
|
1073
|
-
*
|
|
1074
|
-
* constructor() {
|
|
1075
|
-
* super({
|
|
1076
|
-
* // Handle agent messages - this is called for every agent output
|
|
1077
|
-
* handler: async (input) => {
|
|
1078
|
-
* if (isComponent(input, DefaultComponents.Text)) {
|
|
1079
|
-
* const text = input.children.join('')
|
|
1080
|
-
* console.log('Agent:', text)
|
|
1081
|
-
* this.messages.push({ role: 'assistant', content: text })
|
|
1082
|
-
* } else if (isComponent(input, DefaultComponents.Button)) {
|
|
1083
|
-
* console.log('Button:', input.props.label)
|
|
1084
|
-
* }
|
|
1085
|
-
* },
|
|
1086
|
-
*
|
|
1087
|
-
* // Provide available components - agent can use these in generated code
|
|
1088
|
-
* components: [DefaultComponents.Text, DefaultComponents.Button],
|
|
1089
|
-
*
|
|
1090
|
-
* // Return current transcript - evaluated at each iteration
|
|
1091
|
-
* transcript: () => this.messages,
|
|
1092
|
-
* })
|
|
1093
|
-
* }
|
|
1094
|
-
*
|
|
1095
|
-
* // Add user message to transcript
|
|
1096
|
-
* addUserMessage(content: string) {
|
|
1097
|
-
* this.messages.push({ role: 'user', content })
|
|
1098
|
-
* }
|
|
1099
|
-
* }
|
|
1100
|
-
*
|
|
1101
|
-
* // Usage
|
|
1102
|
-
* const chat = new MyChat()
|
|
1103
|
-
* chat.addUserMessage('Hello!')
|
|
1104
|
-
*
|
|
1105
|
-
* const result = await execute({
|
|
1106
|
-
* instructions: 'You are a helpful assistant',
|
|
1107
|
-
* chat, // Enable chat mode
|
|
1108
|
-
* client,
|
|
1109
|
-
* })
|
|
1110
|
-
* ```
|
|
1111
|
-
*
|
|
1112
|
-
* ## Advanced Implementation (CLIChat Example)
|
|
1113
|
-
*
|
|
1114
|
-
* ```typescript
|
|
1115
|
-
* import { Chat, DefaultComponents, ListenExit } from 'llmz'
|
|
1116
|
-
*
|
|
1117
|
-
* class CLIChat extends Chat {
|
|
1118
|
-
* public transcript: Array<{role: 'user' | 'assistant', content: string}> = []
|
|
1119
|
-
* private buttons: string[] = []
|
|
1120
|
-
* public result?: ExecutionResult
|
|
1121
|
-
*
|
|
1122
|
-
* constructor() {
|
|
1123
|
-
* super({
|
|
1124
|
-
* // Dynamic component list with custom renderers
|
|
1125
|
-
* components: () => [
|
|
1126
|
-
* DefaultComponents.Text,
|
|
1127
|
-
* DefaultComponents.Button,
|
|
1128
|
-
* ...this.customComponents
|
|
1129
|
-
* ],
|
|
1130
|
-
*
|
|
1131
|
-
* // Dynamic transcript access
|
|
1132
|
-
* transcript: () => this.transcript,
|
|
1133
|
-
*
|
|
1134
|
-
* // Sophisticated message handling
|
|
1135
|
-
* handler: async (input) => {
|
|
1136
|
-
* if (isComponent(input, DefaultComponents.Text)) {
|
|
1137
|
-
* const text = input.children.join('')
|
|
1138
|
-
* console.log('🤖 Agent:', text)
|
|
1139
|
-
* this.transcript.push({ role: 'assistant', content: text })
|
|
1140
|
-
* } else if (isComponent(input, DefaultComponents.Button)) {
|
|
1141
|
-
* this.buttons.push(input.props.label)
|
|
1142
|
-
* }
|
|
1143
|
-
* },
|
|
1144
|
-
* })
|
|
1145
|
-
* }
|
|
1146
|
-
*
|
|
1147
|
-
* // Handle execution completion
|
|
1148
|
-
* onExecutionDone(result: ExecutionResult) {
|
|
1149
|
-
* this.result = result
|
|
1150
|
-
* }
|
|
1151
|
-
*
|
|
1152
|
-
* // Check if agent is waiting for user input
|
|
1153
|
-
* isWaitingForInput(): boolean {
|
|
1154
|
-
* return this.result?.is(ListenExit) ?? false
|
|
1155
|
-
* }
|
|
1156
|
-
*
|
|
1157
|
-
* // Conversation loop
|
|
1158
|
-
* async iterate(): Promise<boolean> {
|
|
1159
|
-
* if (this.isWaitingForInput()) {
|
|
1160
|
-
* const userInput = await this.promptUser()
|
|
1161
|
-
* this.transcript.push({ role: 'user', content: userInput })
|
|
1162
|
-
* return true // Continue conversation
|
|
1163
|
-
* }
|
|
1164
|
-
* return false // End conversation
|
|
1165
|
-
* }
|
|
1166
|
-
* }
|
|
1167
|
-
* ```
|
|
1168
|
-
*
|
|
1169
|
-
* ## Component System
|
|
1170
|
-
*
|
|
1171
|
-
* The agent generates JSX code using available components:
|
|
1172
|
-
*
|
|
1173
|
-
* ```typescript
|
|
1174
|
-
* // Agent generates this TSX code:
|
|
1175
|
-
* yield <Text>Welcome! Choose an option:</Text>
|
|
1176
|
-
* yield <Button action="postback" label="Get Help" value="help" />
|
|
1177
|
-
* yield <Button action="postback" label="Contact Sales" value="sales" />
|
|
1178
|
-
*
|
|
1179
|
-
* // Your handler receives these as RenderedComponent objects
|
|
1180
|
-
* ```
|
|
1181
|
-
*
|
|
1182
|
-
* ## Transcript Management
|
|
1183
|
-
*
|
|
1184
|
-
* The transcript is critical for agent context and must be kept up-to-date:
|
|
1185
|
-
*
|
|
1186
|
-
* ```typescript
|
|
1187
|
-
* // ❌ Bad - static transcript
|
|
1188
|
-
* transcript: [{ role: 'user', content: 'Hello' }]
|
|
1189
|
-
*
|
|
1190
|
-
* // ✅ Good - dynamic transcript that reflects current state
|
|
1191
|
-
* transcript: () => this.messages
|
|
1192
|
-
*
|
|
1193
|
-
* // The transcript is evaluated at each iteration, so the agent
|
|
1194
|
-
* // always sees the current conversation state
|
|
1195
|
-
* ```
|
|
1196
|
-
*
|
|
1197
|
-
* ## Custom Components
|
|
1198
|
-
*
|
|
1199
|
-
* Extend the UI with custom components for your specific use case:
|
|
1200
|
-
*
|
|
1201
|
-
* ```typescript
|
|
1202
|
-
* import { Component } from 'llmz'
|
|
1203
|
-
*
|
|
1204
|
-
* const ProductCard = new Component({
|
|
1205
|
-
* type: 'leaf',
|
|
1206
|
-
* name: 'ProductCard',
|
|
1207
|
-
* leaf: {
|
|
1208
|
-
* props: z.object({
|
|
1209
|
-
* name: z.string(),
|
|
1210
|
-
* price: z.number(),
|
|
1211
|
-
* imageUrl: z.string(),
|
|
1212
|
-
* })
|
|
1213
|
-
* }
|
|
1214
|
-
* })
|
|
1215
|
-
*
|
|
1216
|
-
* class ShoppingChat extends Chat {
|
|
1217
|
-
* constructor() {
|
|
1218
|
-
* super({
|
|
1219
|
-
* components: [
|
|
1220
|
-
* ...DefaultComponents,
|
|
1221
|
-
* ProductCard, // Add custom component
|
|
1222
|
-
* ],
|
|
1223
|
-
* handler: async (input) => {
|
|
1224
|
-
* if (isComponent(input, ProductCard)) {
|
|
1225
|
-
* // Handle custom component rendering
|
|
1226
|
-
* this.renderProduct(input.props)
|
|
1227
|
-
* }
|
|
1228
|
-
* // ... handle other components
|
|
1229
|
-
* },
|
|
1230
|
-
* })
|
|
1231
|
-
* }
|
|
1232
|
-
* }
|
|
1233
|
-
* ```
|
|
1234
|
-
*
|
|
1235
|
-
* @see {@link DefaultComponents} For standard UI components
|
|
1236
|
-
* @see {@link https://github.com/botpress/botpress/blob/master/packages/llmz/examples/utils/cli-chat.ts} Complete CLIChat implementation
|
|
1237
|
-
*/
|
|
1238
|
-
var Chat = class {
|
|
1239
|
-
handler;
|
|
1240
|
-
onMessageDelta;
|
|
1241
|
-
transcript;
|
|
1242
|
-
components;
|
|
1243
|
-
/**
|
|
1244
|
-
* Creates a new Chat instance.
|
|
1245
|
-
*
|
|
1246
|
-
* @param props - Chat configuration
|
|
1247
|
-
* @param props.handler - Function to handle agent messages (called for every agent output)
|
|
1248
|
-
* @param props.components - Available UI components (static array or dynamic function)
|
|
1249
|
-
* @param props.transcript - Conversation history (static array or dynamic function, defaults to empty)
|
|
1250
|
-
*
|
|
1251
|
-
* @example
|
|
1252
|
-
* ```typescript
|
|
1253
|
-
* // Basic chat with static configuration
|
|
1254
|
-
* const chat = new Chat({
|
|
1255
|
-
* handler: async (input) => {
|
|
1256
|
-
* if (isComponent(input, DefaultComponents.Text)) {
|
|
1257
|
-
* console.log('Agent:', input.children.join(''))
|
|
1258
|
-
* }
|
|
1259
|
-
* },
|
|
1260
|
-
* components: [DefaultComponents.Text, DefaultComponents.Button],
|
|
1261
|
-
* transcript: [
|
|
1262
|
-
* { role: 'user', content: 'Hello', timestamp: Date.now() }
|
|
1263
|
-
* ],
|
|
1264
|
-
* })
|
|
1265
|
-
* ```
|
|
1266
|
-
*
|
|
1267
|
-
* @example
|
|
1268
|
-
* ```typescript
|
|
1269
|
-
* // Dynamic chat with functions for real-time updates
|
|
1270
|
-
* class MyChat extends Chat {
|
|
1271
|
-
* private messages: Transcript.Message[] = []
|
|
1272
|
-
*
|
|
1273
|
-
* constructor() {
|
|
1274
|
-
* super({
|
|
1275
|
-
* handler: (input) => this.handleMessage(input),
|
|
1276
|
-
*
|
|
1277
|
-
* // Dynamic components - can change during execution
|
|
1278
|
-
* components: () => [
|
|
1279
|
-
* DefaultComponents.Text,
|
|
1280
|
-
* DefaultComponents.Button,
|
|
1281
|
-
* ...this.getCustomComponents()
|
|
1282
|
-
* ],
|
|
1283
|
-
*
|
|
1284
|
-
* // Dynamic transcript - always reflects current state
|
|
1285
|
-
* transcript: () => this.messages,
|
|
1286
|
-
* })
|
|
1287
|
-
* }
|
|
1288
|
-
* }
|
|
1289
|
-
* ```
|
|
1290
|
-
*/
|
|
1291
|
-
constructor(props) {
|
|
1292
|
-
this.handler = props.handler;
|
|
1293
|
-
this.onMessageDelta = props.onMessageDelta;
|
|
1294
|
-
this.components = props.components;
|
|
1295
|
-
this.transcript = props.transcript || [];
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* Called when an execution cycle completes, regardless of the outcome.
|
|
1299
|
-
*
|
|
1300
|
-
* Override this method to handle execution results, manage conversation flow,
|
|
1301
|
-
* or perform cleanup tasks. This is called after each `execute()` call completes,
|
|
1302
|
-
* whether it succeeds, fails, or is interrupted.
|
|
1303
|
-
*
|
|
1304
|
-
* @param result - The execution result containing status, iterations, and exit information
|
|
1305
|
-
*
|
|
1306
|
-
* @example
|
|
1307
|
-
* ```typescript
|
|
1308
|
-
* class MyChat extends Chat {
|
|
1309
|
-
* public result?: ExecutionResult
|
|
1310
|
-
*
|
|
1311
|
-
* onExecutionDone(result: ExecutionResult) {
|
|
1312
|
-
* // Store result for conversation flow control
|
|
1313
|
-
* this.result = result
|
|
1314
|
-
*
|
|
1315
|
-
* // Handle different result types
|
|
1316
|
-
* if (result.isSuccess()) {
|
|
1317
|
-
* console.log('✅ Execution completed successfully')
|
|
1318
|
-
* console.log('Exit:', result.output.exit_name)
|
|
1319
|
-
* } else if (result.isError()) {
|
|
1320
|
-
* console.error('❌ Execution failed:', result.output.error)
|
|
1321
|
-
* } else if (result.isInterrupted()) {
|
|
1322
|
-
* console.log('⏸️ Execution interrupted (partial result)')
|
|
1323
|
-
* }
|
|
1324
|
-
* }
|
|
1325
|
-
*
|
|
1326
|
-
* // Use stored result for conversation flow
|
|
1327
|
-
* isWaitingForInput(): boolean {
|
|
1328
|
-
* return this.result?.is(ListenExit) ?? false
|
|
1329
|
-
* }
|
|
1330
|
-
* }
|
|
1331
|
-
* ```
|
|
1332
|
-
*
|
|
1333
|
-
* @example
|
|
1334
|
-
* ```typescript
|
|
1335
|
-
* // CLIChat implementation example
|
|
1336
|
-
* class CLIChat extends Chat {
|
|
1337
|
-
* public status?: IterationStatus
|
|
1338
|
-
* public result?: ExecutionResult
|
|
1339
|
-
*
|
|
1340
|
-
* onExecutionDone(result: ExecutionResult) {
|
|
1341
|
-
* this.result = result
|
|
1342
|
-
* this.status = result.iterations.at(-1)?.status
|
|
1343
|
-
* }
|
|
1344
|
-
*
|
|
1345
|
-
* // Check if agent exited with specific exit type
|
|
1346
|
-
* hasExitedWith<R>(exit: Exit<R>): boolean {
|
|
1347
|
-
* return this.status?.type === 'exit_success' &&
|
|
1348
|
-
* this.status.exit_success.exit_name === exit.name
|
|
1349
|
-
* }
|
|
1350
|
-
* }
|
|
1351
|
-
* ```
|
|
1352
|
-
*/
|
|
1353
|
-
onExecutionDone(_result) {}
|
|
1354
|
-
};
|
|
1355
|
-
//#endregion
|
|
1356
|
-
//#region src/message-stream/replayable.ts
|
|
1357
|
-
/**
|
|
1358
|
-
* Wraps an async iterable so it can be iterated multiple times: chunks pulled
|
|
1359
|
-
* from the source are cached, and every iteration replays the cache before
|
|
1360
|
-
* pulling new chunks. Concurrent iterations are safe — pulls on the underlying
|
|
1361
|
-
* source are serialized. If the source fails, the failure is cached too:
|
|
1362
|
-
* every iteration replays the chunks received before the failure, then
|
|
1363
|
-
* rethrows the source error.
|
|
1364
|
-
*/
|
|
1365
|
-
var ReplayableAsyncIterable = class {
|
|
1366
|
-
_source;
|
|
1367
|
-
_chunks = [];
|
|
1368
|
-
_done = false;
|
|
1369
|
-
_failed = false;
|
|
1370
|
-
_error;
|
|
1371
|
-
_lock = Promise.resolve();
|
|
1372
|
-
constructor(source) {
|
|
1373
|
-
this._source = source[Symbol.asyncIterator]();
|
|
1374
|
-
}
|
|
1375
|
-
/** True once the underlying source has been fully consumed (or has failed). */
|
|
1376
|
-
get done() {
|
|
1377
|
-
return this._done;
|
|
1378
|
-
}
|
|
1379
|
-
/** The chunks pulled from the source so far. */
|
|
1380
|
-
get chunks() {
|
|
1381
|
-
return [...this._chunks];
|
|
1382
|
-
}
|
|
1383
|
-
async *[Symbol.asyncIterator]() {
|
|
1384
|
-
let index = 0;
|
|
1385
|
-
while (true) if (index < this._chunks.length) yield this._chunks[index++];
|
|
1386
|
-
else if (this._failed) throw this._error;
|
|
1387
|
-
else if (this._done) return;
|
|
1388
|
-
else await this._pull();
|
|
1389
|
-
}
|
|
1390
|
-
/** Consumes the entire source and returns all chunks. */
|
|
1391
|
-
async collect() {
|
|
1392
|
-
for await (const _ of this);
|
|
1393
|
-
return this.chunks;
|
|
1394
|
-
}
|
|
1395
|
-
_pull() {
|
|
1396
|
-
const next = this._lock.then(async () => {
|
|
1397
|
-
if (this._done) return;
|
|
1398
|
-
let result;
|
|
1399
|
-
try {
|
|
1400
|
-
result = await this._source.next();
|
|
1401
|
-
} catch (thrown) {
|
|
1402
|
-
this._done = true;
|
|
1403
|
-
this._failed = true;
|
|
1404
|
-
this._error = thrown;
|
|
1405
|
-
throw thrown;
|
|
1406
|
-
}
|
|
1407
|
-
if (result.done) this._done = true;
|
|
1408
|
-
else this._chunks.push(result.value);
|
|
1409
|
-
});
|
|
1410
|
-
this._lock = next.catch(() => {});
|
|
1411
|
-
return next;
|
|
1412
|
-
}
|
|
1413
|
-
};
|
|
1414
|
-
/** Drains a string iterable into a single string. */
|
|
1415
|
-
const collectText = async (iterable) => {
|
|
1416
|
-
let text = "";
|
|
1417
|
-
for await (const chunk of iterable) text += chunk;
|
|
1418
|
-
return text;
|
|
1419
|
-
};
|
|
1420
|
-
//#endregion
|
|
1421
|
-
//#region src/message-stream/stream.ts
|
|
1422
|
-
var BaseResponse = class {
|
|
1423
|
-
action;
|
|
1424
|
-
item;
|
|
1425
|
-
constructor(action, item) {
|
|
1426
|
-
this.action = action;
|
|
1427
|
-
this.item = item;
|
|
1428
|
-
}
|
|
1429
|
-
get diagnostics() {
|
|
1430
|
-
return this.item.diagnostics;
|
|
1431
|
-
}
|
|
1432
|
-
};
|
|
1433
|
-
/** `■send=<component> { props? }` followed by an optional streaming body. */
|
|
1434
|
-
var SendResponse = class extends BaseResponse {
|
|
1435
|
-
content;
|
|
1436
|
-
constructor(item, content) {
|
|
1437
|
-
super("send", item);
|
|
1438
|
-
this.content = content;
|
|
1439
|
-
}
|
|
1440
|
-
get component() {
|
|
1441
|
-
return this.item.name;
|
|
1442
|
-
}
|
|
1443
|
-
get props() {
|
|
1444
|
-
return this.item.props;
|
|
1445
|
-
}
|
|
1446
|
-
static formatToText(component, props, body) {
|
|
1447
|
-
const header = `■send=${component}${props && Object.keys(props).length ? ` ${JSON.stringify(props)}` : ""}`;
|
|
1448
|
-
return body ? `${header}\n${body}` : header;
|
|
1449
|
-
}
|
|
1450
|
-
};
|
|
1451
|
-
/** `■run` followed by streaming code. */
|
|
1452
|
-
var RunResponse = class extends BaseResponse {
|
|
1453
|
-
code;
|
|
1454
|
-
constructor(item, code) {
|
|
1455
|
-
super("run", item);
|
|
1456
|
-
this.code = code;
|
|
1457
|
-
}
|
|
1458
|
-
static formatToText(code) {
|
|
1459
|
-
return `■run\n${code}`;
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1462
|
-
/** `■next=<name> { props? }` — hands control to an exit (e.g. listen) with optional props. */
|
|
1463
|
-
var NextResponse = class extends BaseResponse {
|
|
1464
|
-
constructor(item) {
|
|
1465
|
-
super("next", item);
|
|
1466
|
-
}
|
|
1467
|
-
get name() {
|
|
1468
|
-
return this.item.name;
|
|
1469
|
-
}
|
|
1470
|
-
get props() {
|
|
1471
|
-
return this.item.props;
|
|
1472
|
-
}
|
|
1473
|
-
static formatToText(name, props) {
|
|
1474
|
-
return `■next=${name}${props && Object.keys(props).length ? ` ${JSON.stringify(props)}` : ""}`;
|
|
1475
|
-
}
|
|
1476
|
-
};
|
|
1477
|
-
/**
|
|
1478
|
-
* Pulls transport chunks through the parser on demand and hands out events one
|
|
1479
|
-
* at a time. Shared by the main response loop and by body streams; pulls are
|
|
1480
|
-
* serialized so interleaved consumers cannot race the source iterator.
|
|
1481
|
-
*/
|
|
1482
|
-
var EventPump = class {
|
|
1483
|
-
_iterator;
|
|
1484
|
-
_parser;
|
|
1485
|
-
_queue = [];
|
|
1486
|
-
_sourceDone = false;
|
|
1487
|
-
_lock = Promise.resolve();
|
|
1488
|
-
constructor(stream, parser) {
|
|
1489
|
-
this._iterator = stream[Symbol.asyncIterator]();
|
|
1490
|
-
this._parser = parser;
|
|
1491
|
-
}
|
|
1492
|
-
next() {
|
|
1493
|
-
const next = this._lock.then(() => this._next());
|
|
1494
|
-
this._lock = next.catch(() => {});
|
|
1495
|
-
return next;
|
|
1496
|
-
}
|
|
1497
|
-
unshift(event) {
|
|
1498
|
-
this._queue.unshift(event);
|
|
1499
|
-
}
|
|
1500
|
-
async _next() {
|
|
1501
|
-
while (this._queue.length === 0) {
|
|
1502
|
-
if (this._sourceDone) return;
|
|
1503
|
-
let result;
|
|
1504
|
-
try {
|
|
1505
|
-
result = await this._iterator.next();
|
|
1506
|
-
} catch {
|
|
1507
|
-
this._sourceDone = true;
|
|
1508
|
-
this._queue.push(...this._parser.finish("interrupted"));
|
|
1509
|
-
continue;
|
|
1510
|
-
}
|
|
1511
|
-
if (result.done) {
|
|
1512
|
-
this._sourceDone = true;
|
|
1513
|
-
this._queue.push(...this._parser.finish());
|
|
1514
|
-
} else this._queue.push(...this._parser.push(result.value));
|
|
1515
|
-
}
|
|
1516
|
-
return this._queue.shift();
|
|
1517
|
-
}
|
|
1518
|
-
};
|
|
1519
|
-
/**
|
|
1520
|
-
* Parses a raw LLM text stream into typed responses.
|
|
1521
|
-
*
|
|
1522
|
-
* `send` and `run` responses are yielded as soon as their header is parsed —
|
|
1523
|
-
* while their body is still streaming — with the body exposed as a replayable
|
|
1524
|
-
* async iterable. `next` responses are yielded once complete.
|
|
1525
|
-
*
|
|
1526
|
-
* The body streams are pull-based: consuming them drives the underlying
|
|
1527
|
-
* transport. Requesting the next response first drains the previous body into
|
|
1528
|
-
* its replay cache, so it can always be read later.
|
|
1529
|
-
*/
|
|
1530
|
-
function parseStream(stream, options) {
|
|
1531
|
-
return parseResponses(stream, options);
|
|
1532
|
-
}
|
|
1533
|
-
/** Parses a complete text (convenience wrapper over {@link parseStream}). */
|
|
1534
|
-
function parseText(text, options) {
|
|
1535
|
-
return parseResponses((async function* () {
|
|
1536
|
-
yield text;
|
|
1537
|
-
})(), options);
|
|
1538
|
-
}
|
|
1539
|
-
async function* parseResponses(stream, options) {
|
|
1540
|
-
const pump = new EventPump(stream, new StreamingMessageParser(options));
|
|
1541
|
-
let activeBody;
|
|
1542
|
-
while (true) {
|
|
1543
|
-
if (activeBody) {
|
|
1544
|
-
await activeBody.collect();
|
|
1545
|
-
activeBody = void 0;
|
|
1546
|
-
}
|
|
1547
|
-
const event = await pump.next();
|
|
1548
|
-
if (!event) return;
|
|
1549
|
-
if (event.type === "item-ready" && (event.item.kind === "send" || event.item.kind === "run")) {
|
|
1550
|
-
const body = new ReplayableAsyncIterable(bodyStream(pump, event.item.id));
|
|
1551
|
-
activeBody = body;
|
|
1552
|
-
yield event.item.kind === "send" ? new SendResponse(event.item, body) : new RunResponse(event.item, body);
|
|
1553
|
-
continue;
|
|
1554
|
-
}
|
|
1555
|
-
if (event.type === "item-complete" && event.item.kind === "next") {
|
|
1556
|
-
yield new NextResponse(event.item);
|
|
1557
|
-
continue;
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
async function* bodyStream(pump, itemId) {
|
|
1562
|
-
while (true) {
|
|
1563
|
-
const event = await pump.next();
|
|
1564
|
-
if (!event) return;
|
|
1565
|
-
if (event.type === "body-delta" && event.itemId === itemId) {
|
|
1566
|
-
yield event.delta;
|
|
1567
|
-
continue;
|
|
1568
|
-
}
|
|
1569
|
-
if (event.type === "body-start" && event.itemId === itemId) continue;
|
|
1570
|
-
if (event.type === "diagnostic") continue;
|
|
1571
|
-
if (event.type === "item-complete" && event.item.id === itemId) return;
|
|
1572
|
-
pump.unshift(event);
|
|
1573
|
-
return;
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
//#endregion
|
|
1577
|
-
//#region src/message-stream/normalizer.ts
|
|
1578
|
-
const EMPTY_PROPS_SCHEMA = {
|
|
1579
|
-
type: "object",
|
|
1580
|
-
properties: {},
|
|
1581
|
-
additionalProperties: false
|
|
1582
|
-
};
|
|
1583
|
-
const normalizeComponentName = (name) => name.trim().toLowerCase();
|
|
1584
|
-
function normalizeComponentDefinition(definition) {
|
|
1585
|
-
const name = normalizeComponentName(definition.name ?? "");
|
|
1586
|
-
if (!NAME_REGEX.test(name)) throw new Error(`Invalid component name "${definition.name}". Component names must be lowercase ([a-z][a-z0-9_-]*).`);
|
|
1587
|
-
return {
|
|
1588
|
-
name,
|
|
1589
|
-
description: definition.description,
|
|
1590
|
-
propsJsonSchema: normalizePropsSchema(definition.props, name),
|
|
1591
|
-
body: definition.body ? {
|
|
1592
|
-
format: definition.body.type,
|
|
1593
|
-
description: definition.body.description,
|
|
1594
|
-
required: definition.body.required ?? false
|
|
1595
|
-
} : void 0,
|
|
1596
|
-
generation: definition.generation
|
|
1597
|
-
};
|
|
1598
|
-
}
|
|
1599
|
-
function normalizePropsSchema(props, name) {
|
|
1600
|
-
if (props === void 0) return EMPTY_PROPS_SCHEMA;
|
|
1601
|
-
if (isZuiSchema(props)) try {
|
|
1602
|
-
return transforms.toJSONSchema(props);
|
|
1603
|
-
} catch {
|
|
1604
|
-
return transforms.toJSONSchemaLegacy(props);
|
|
1605
|
-
}
|
|
1606
|
-
if (isJsonSchema(props)) return props;
|
|
1607
|
-
throw new Error(`Invalid props schema for "${name}". Expected a ZUI/Zod object schema or a JSON schema, but got type "${typeof props}".`);
|
|
1608
|
-
}
|
|
1609
|
-
//#endregion
|
|
1610
|
-
//#region src/message-stream/sanitize.ts
|
|
1611
|
-
/**
|
|
1612
|
-
* The protocol has no escaping mechanism by design. Any untrusted text that is
|
|
1613
|
-
* inserted into model context (user messages, tool results, documents) must be
|
|
1614
|
-
* sanitized so it cannot inject protocol blocks.
|
|
1615
|
-
*/
|
|
1616
|
-
const sanitizeMessageText = (value, options = {}) => value.replaceAll("■", options.markerReplacement ?? "▪");
|
|
1617
|
-
//#endregion
|
|
1618
548
|
//#region src/index.ts
|
|
1619
549
|
const utils = {
|
|
1620
550
|
toValidObjectName,
|
|
1621
|
-
toValidFunctionName
|
|
1622
|
-
wrapContent,
|
|
1623
|
-
truncateWrappedContent,
|
|
1624
|
-
stripTruncationTags
|
|
551
|
+
toValidFunctionName
|
|
1625
552
|
};
|
|
1626
553
|
/**
|
|
1627
554
|
* Executes an LLMz agent in either Chat Mode or Worker Mode.
|
|
1628
555
|
*
|
|
1629
|
-
* LLMz
|
|
1630
|
-
*
|
|
1631
|
-
*
|
|
556
|
+
* LLMz generates and runs JavaScript in a sandbox through the native run_javascript
|
|
557
|
+
* tool. Assistant text streams normally; JavaScript returns decisions to present
|
|
558
|
+
* rich messages, inspect results, or complete through a typed exit.
|
|
1632
559
|
*
|
|
1633
560
|
* @param props - Configuration object for the execution
|
|
1634
561
|
* @param props.client - Botpress Client or Cognitive Client instance for LLM generation
|
|
1635
562
|
* @param props.instructions - System prompt/instructions for the LLM (static string or dynamic function)
|
|
1636
|
-
* @param props.examples - Optional labeled few-shot examples (static array or dynamic function)
|
|
1637
563
|
* @param props.chat - Optional Chat instance to enable Chat Mode with user interaction
|
|
1638
564
|
* @param props.tools - Array of Tool instances available to the agent (static or dynamic)
|
|
1639
565
|
* @param props.objects - Array of ObjectInstance for namespaced tools and variables (static or dynamic)
|
|
1640
566
|
* @param props.exits - Array of Exit definitions for structured completion (static or dynamic)
|
|
1641
|
-
* @param props.
|
|
567
|
+
* @param props.session - Conversation state; append input before execution and persist it between executions
|
|
1642
568
|
* @param props.signal - Optional AbortSignal to cancel execution
|
|
1643
569
|
* @param props.model - Optional model name (or array or models to use as fallback) (static or dynamic function)
|
|
1644
570
|
* @param props.temperature - Optional temperature value (static or dynamic function)
|
|
@@ -1682,7 +608,7 @@ const utils = {
|
|
|
1682
608
|
* // With dynamic instructions and hooks
|
|
1683
609
|
* const result = await execute({
|
|
1684
610
|
* client: cognitiveClient,
|
|
1685
|
-
* instructions: (ctx) => `Process ${ctx.variables.dataCount} records`,
|
|
611
|
+
* instructions: (ctx) => `Process ${ctx.session.memory.variables.dataCount} records`,
|
|
1686
612
|
* tools: async (ctx) => await getContextualTools(ctx),
|
|
1687
613
|
* model: 'best',
|
|
1688
614
|
* temperature: 0.1,
|
|
@@ -1692,7 +618,7 @@ const utils = {
|
|
|
1692
618
|
* })
|
|
1693
619
|
*/
|
|
1694
620
|
const execute = async (props) => {
|
|
1695
|
-
const { executeContext } = await import("./execute-
|
|
621
|
+
const { executeContext } = await import("./execute-CiYvPs5Q.js");
|
|
1696
622
|
return executeContext(props);
|
|
1697
623
|
};
|
|
1698
624
|
/**
|
|
@@ -1701,16 +627,14 @@ const execute = async (props) => {
|
|
|
1701
627
|
* It's recommended to call this function at the beginning of your application without awaiting it (void init())
|
|
1702
628
|
*/
|
|
1703
629
|
const init = async () => {
|
|
1704
|
-
await import("./execute-
|
|
1705
|
-
await import("./component-
|
|
1706
|
-
await import("./tool-
|
|
1707
|
-
await import("./exit-
|
|
1708
|
-
await import("./
|
|
1709
|
-
await import("./
|
|
1710
|
-
await import("./
|
|
1711
|
-
await import("./
|
|
1712
|
-
await import("./typings-CrBa7Tyy.js").then((n) => n.n);
|
|
1713
|
-
await import("./dual-modes-DDkoCp3R.js").then((n) => n.n);
|
|
630
|
+
await import("./execute-CiYvPs5Q.js");
|
|
631
|
+
await import("./component-DncqP4fB.js").then((n) => n.r);
|
|
632
|
+
await import("./tool-DstssiAs.js").then((n) => n.n);
|
|
633
|
+
await import("./exit-DMPwCSba.js").then((n) => n.n);
|
|
634
|
+
await import("./vm-C7SfutHn.js");
|
|
635
|
+
await import("./utils-BOFzb8Ok.js").then((n) => n.m);
|
|
636
|
+
await import("./typings-BEVDvtuk.js").then((n) => n.r);
|
|
637
|
+
await import("./native-n_718Z-T.js").then((n) => n.n);
|
|
1714
638
|
};
|
|
1715
639
|
//#endregion
|
|
1716
|
-
export {
|
|
640
|
+
export { AssignmentError, Chat, CitationsManager, CodeExecutionError, CodeFormattingError, CognitiveError, CompactionError, Component, ComponentInputError, DefaultComponents, DefaultExit, DeliveryError, ErrorExecutionResult, ExecutionAbortedError, ExecutionResult, Exit, ExitInputError, HookError, HostOperationError, InternalError, InvalidCodeError, InvalidComponentError, InvalidConfigurationError, InvalidEventError, InvalidExitError, InvalidMessageError, InvalidObjectError, InvalidSessionError, InvalidToolError, LLMzError, ListenExit, LoopExceededError, Memory, MemoryCapacityError, MemoryValueError, MissingChatResponseError, NativeProtocolError, ObjectInstance, ObjectPropertyError, ReservedIdentifierError, Session, SessionStateError, SuccessExecutionResult, ThinkSignal, TokenOverflowError, Tool, ToolExecutionError, ToolInputError, UnknownComponentError, UnknownExitError, UnknownToolError, _CustomModelClient, assertValidComponent, configureQuickJS, configureTokenizer, createInspector, execute, getValue, init, inspect, isAnyComponent, isComponent, isCriticalError, isLLMzError, truncate, utils, version };
|