llmz 0.8.0 → 1.0.1

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.
Files changed (224) hide show
  1. package/DOCS.md +230 -1796
  2. package/ERRORS.md +98 -0
  3. package/README.md +96 -548
  4. package/dist/chat/chat.d.ts +63 -0
  5. package/dist/chat/component.d.ts +31 -0
  6. package/dist/chat/component.default.d.ts +58 -0
  7. package/dist/chat/response.d.ts +15 -0
  8. package/dist/compiler/compiler.d.ts +2 -7
  9. package/dist/compiler/plugins/dynamic-code.d.ts +7 -0
  10. package/dist/compiler/plugins/replace-comment.d.ts +2 -3
  11. package/dist/compiler/plugins/return-async.d.ts +5 -4
  12. package/dist/compiler/plugins/termination.d.ts +8 -0
  13. package/dist/compiler/plugins/tool-resolution.d.ts +4 -0
  14. package/dist/compiler/plugins/variable-extraction.d.ts +2 -8
  15. package/dist/component-BpMVZYOa.cjs +649 -0
  16. package/dist/component-C27qu6Zv.js +614 -0
  17. package/dist/context.d.ts +74 -385
  18. package/dist/custom-client-BDkgBR2w.js +1631 -0
  19. package/dist/custom-client-MytucGI-.cjs +1708 -0
  20. package/dist/custom-client.d.ts +12 -2
  21. package/dist/errors/catalog.d.ts +287 -0
  22. package/dist/errors/hooks.d.ts +2 -0
  23. package/dist/errors-H4JJFH3S.js +620 -0
  24. package/dist/errors-IhnTKUp7.cjs +871 -0
  25. package/dist/errors.d.ts +18 -36
  26. package/dist/execute-BYI_U5sR.js +1943 -0
  27. package/dist/execute-DLas4V2n.cjs +1944 -0
  28. package/dist/{exit-DUM96DN1.cjs → exit-BUgJ5qi5.cjs} +38 -28
  29. package/dist/{exit-CDdxDBRT.js → exit-CPNk3vbz.js} +37 -27
  30. package/dist/exit.d.ts +19 -16
  31. package/dist/index.cjs +181 -999
  32. package/dist/index.d.ts +25 -28
  33. package/dist/index.js +141 -974
  34. package/dist/index.workerd.js +7725 -9531
  35. package/dist/inspect.d.ts +19 -3
  36. package/dist/inspection.d.ts +38 -0
  37. package/dist/native-Bm6L9zOb.cjs +212 -0
  38. package/dist/native-DvTH9vFe.js +177 -0
  39. package/dist/objects.d.ts +2 -57
  40. package/dist/prompts/native.d.ts +2 -0
  41. package/dist/prompts/prompt.d.ts +10 -98
  42. package/dist/quickjs-variant-DJwYDSsb.cjs +1073 -0
  43. package/dist/quickjs-variant-DlPi9-Sx.js +984 -0
  44. package/dist/result.d.ts +30 -861
  45. package/dist/runtime/execute.d.ts +3 -2
  46. package/dist/runtime/execution-activity.d.ts +11 -0
  47. package/dist/runtime/execution-activity.test.d.ts +1 -0
  48. package/dist/runtime/execution-diagnostics.d.ts +11 -0
  49. package/dist/runtime/execution-diagnostics.test.d.ts +1 -0
  50. package/dist/runtime/execution-report.d.ts +48 -0
  51. package/dist/runtime/execution-report.test.d.ts +1 -0
  52. package/dist/runtime/execution-safety.test.d.ts +1 -0
  53. package/dist/runtime/exit-control-flow.test.d.ts +1 -0
  54. package/dist/runtime/fixtures/chat.d.ts +8 -0
  55. package/dist/runtime/fixtures/long-search.d.ts +19 -0
  56. package/dist/runtime/fixtures/long-search.test.d.ts +1 -0
  57. package/dist/runtime/fixtures/native-client.d.ts +33 -0
  58. package/dist/runtime/fixtures/protocol-languages.d.ts +74 -0
  59. package/dist/runtime/generate.d.ts +23 -27
  60. package/dist/runtime/generate.test.d.ts +1 -0
  61. package/dist/runtime/hook-provenance.test.d.ts +1 -0
  62. package/dist/runtime/inspection-hook.test.d.ts +1 -0
  63. package/dist/runtime/inspection-values.d.ts +14 -0
  64. package/dist/runtime/inspection-values.test.d.ts +1 -0
  65. package/dist/runtime/interruption-control-flow.test.d.ts +1 -0
  66. package/dist/runtime/interruption-settings.test.d.ts +1 -0
  67. package/dist/runtime/javascript-api.d.ts +59 -0
  68. package/dist/runtime/javascript-api.test.d.ts +1 -0
  69. package/dist/runtime/native-review.test.d.ts +1 -0
  70. package/dist/runtime/native-tools.d.ts +18 -0
  71. package/dist/runtime/native-tools.test.d.ts +1 -0
  72. package/dist/runtime/object-memory.test.d.ts +1 -0
  73. package/dist/runtime/protocol-adherence.test.d.ts +1 -0
  74. package/dist/runtime/single-tool.test.d.ts +1 -0
  75. package/dist/runtime/token-budget.d.ts +22 -0
  76. package/dist/runtime/token-budget.test.d.ts +1 -0
  77. package/dist/runtime/tool-wrapper.d.ts +4 -5
  78. package/dist/runtime/traces.test.d.ts +1 -0
  79. package/dist/runtime/truncation.test.d.ts +1 -0
  80. package/dist/runtime/types.d.ts +41 -36
  81. package/dist/runtime/variable-recovery.test.d.ts +1 -0
  82. package/dist/runtime/vm-context.d.ts +6 -1
  83. package/dist/runtime/worker-completion.test.d.ts +1 -0
  84. package/dist/runtime-names.d.ts +4 -0
  85. package/dist/schema-Aer_W7Al.js +45 -0
  86. package/dist/schema-DBkjo0b7.cjs +68 -0
  87. package/dist/schema.d.ts +10 -0
  88. package/dist/schema.test.d.ts +1 -0
  89. package/dist/session/compactor.d.ts +51 -0
  90. package/dist/session/compactor.test.d.ts +1 -0
  91. package/dist/session/history.d.ts +36 -0
  92. package/dist/session/history.test.d.ts +1 -0
  93. package/dist/session/json.d.ts +3 -0
  94. package/dist/session/json.test.d.ts +1 -0
  95. package/dist/session/memory-codec.d.ts +9 -0
  96. package/dist/session/memory-codec.test.d.ts +1 -0
  97. package/dist/session/memory-render.d.ts +15 -0
  98. package/dist/session/memory-render.test.d.ts +1 -0
  99. package/dist/session/memory.d.ts +112 -0
  100. package/dist/session/memory.test.d.ts +1 -0
  101. package/dist/session/messages.d.ts +17 -0
  102. package/dist/session/messages.test.d.ts +1 -0
  103. package/dist/session/serialization.d.ts +34 -0
  104. package/dist/session/serialization.test.d.ts +1 -0
  105. package/dist/session/session-memory.test.d.ts +1 -0
  106. package/dist/session/session.d.ts +117 -0
  107. package/dist/session/session.test.d.ts +1 -0
  108. package/dist/{transcript.d.ts → session/transcript.d.ts} +4 -8
  109. package/dist/session/transcript.test.d.ts +1 -0
  110. package/dist/{tool-Bv8N4IPj.js → tool--gK91eez.js} +144 -92
  111. package/dist/{tool-Dy6AJpJH.cjs → tool-Da_F-N-5.cjs} +146 -94
  112. package/dist/tool.d.ts +25 -17
  113. package/dist/truncate-BSoH2-nY.js +79 -0
  114. package/dist/truncate-nV3Mxr6-.cjs +102 -0
  115. package/dist/truncate.d.ts +24 -0
  116. package/dist/truncate.test.d.ts +1 -0
  117. package/dist/types.d.ts +27 -9
  118. package/dist/{typings-3lsqCbkn.cjs → typings-C1ihexWE.cjs} +38 -193
  119. package/dist/{typings-CrBa7Tyy.js → typings-D9_aC8aq.js} +38 -175
  120. package/dist/typings-formatter.d.ts +1 -1
  121. package/dist/typings.d.ts +3 -0
  122. package/dist/{uniq-BYQ7GWwb.js → uniq-DfUeSNaX.js} +2 -2
  123. package/dist/{uniq-G872RWmE.cjs → uniq-DiXgysNV.cjs} +6 -18
  124. package/dist/{_baseIteratee-P_firB7b.js → utils-BOFzb8Ok.js} +1134 -16
  125. package/dist/{_baseIteratee-CF4qP2a8.cjs → utils-CTlsXvdj.cjs} +1281 -84
  126. package/dist/vm/drivers/node.d.ts +1 -1
  127. package/dist/vm/drivers/quickjs.d.ts +1 -1
  128. package/dist/vm/errors.d.ts +4 -4
  129. package/dist/vm/index.d.ts +3 -4
  130. package/dist/vm/instrument.d.ts +14 -6
  131. package/dist/vm/member-proxy.d.ts +4 -0
  132. package/dist/vm/member-proxy.test.d.ts +1 -0
  133. package/dist/vm/memory.test.d.ts +1 -0
  134. package/dist/vm/return-semantics.test.d.ts +1 -0
  135. package/dist/vm/types.d.ts +18 -3
  136. package/dist/{vm-BLsHw1da.js → vm-8jxt8PTK.js} +1162 -180
  137. package/dist/{vm-D6s1zF6M.cjs → vm-XuVPuW3Y.cjs} +1195 -207
  138. package/package.json +13 -6
  139. package/dist/_baseForOwn-BfWDTL8L.cjs +0 -53
  140. package/dist/_baseForOwn-CFhWe_W6.js +0 -48
  141. package/dist/_getPrototype-CG7Dxrrz.js +0 -6
  142. package/dist/_getPrototype-DQDlNVVM.cjs +0 -10
  143. package/dist/_overArg-C5Hy7oCi.cjs +0 -196
  144. package/dist/_overArg-CRYbj1NH.js +0 -155
  145. package/dist/chat.d.ts +0 -401
  146. package/dist/common-DdArNQhl.cjs +0 -643
  147. package/dist/common-pgJjFu2Y.js +0 -596
  148. package/dist/compiler/plugins/track-tool-calls.d.ts +0 -33
  149. package/dist/compiler-C-OI9sim.cjs +0 -547
  150. package/dist/compiler-CW1VjQsn.js +0 -473
  151. package/dist/component-BXS8vAwO.cjs +0 -73
  152. package/dist/component-Dq7ZLdvy.js +0 -44
  153. package/dist/component.d.ts +0 -88
  154. package/dist/component.default.d.ts +0 -268
  155. package/dist/custom-client-2V9lmzUf.js +0 -2655
  156. package/dist/custom-client-HkM1Sdzv.cjs +0 -2726
  157. package/dist/dual-modes-Cb7ThvoV.cjs +0 -3020
  158. package/dist/dual-modes-Cy0_W4O2.js +0 -2930
  159. package/dist/errors-C962uJdS.cjs +0 -220
  160. package/dist/errors-Cg1G0Awu.js +0 -161
  161. package/dist/example.d.ts +0 -45
  162. package/dist/execute-Aw4cbIx-.js +0 -1080
  163. package/dist/execute-COIHOIKR.cjs +0 -1081
  164. package/dist/exit-parser.d.ts +0 -39
  165. package/dist/handlers.d.ts +0 -10
  166. package/dist/hoist.d.ts +0 -2
  167. package/dist/isEmpty-BhJRCqIF.js +0 -52
  168. package/dist/isEmpty-LY533Wmh.cjs +0 -57
  169. package/dist/jsx-B0iYyvfr.js +0 -100
  170. package/dist/jsx-D5Y2cPo-.cjs +0 -129
  171. package/dist/jsx.d.ts +0 -11
  172. package/dist/message-stream/index.d.ts +0 -9
  173. package/dist/message-stream/instructions.d.ts +0 -22
  174. package/dist/message-stream/normalizer.d.ts +0 -21
  175. package/dist/message-stream/parser.d.ts +0 -83
  176. package/dist/message-stream/registry.d.ts +0 -14
  177. package/dist/message-stream/replayable.d.ts +0 -27
  178. package/dist/message-stream/sanitize.d.ts +0 -10
  179. package/dist/message-stream/stream.d.ts +0 -54
  180. package/dist/message-stream/types.d.ts +0 -96
  181. package/dist/message-stream/validator.d.ts +0 -23
  182. package/dist/prompts/chat-mode/system.d.ts +0 -2
  183. package/dist/prompts/chat-mode/system.md.d.ts +0 -2
  184. package/dist/prompts/chat-mode/user.d.ts +0 -2
  185. package/dist/prompts/chat-mode/user.md.d.ts +0 -2
  186. package/dist/prompts/common.d.ts +0 -6
  187. package/dist/prompts/dual-modes.d.ts +0 -2
  188. package/dist/prompts/execution-history.d.ts +0 -6
  189. package/dist/prompts/execution-state.d.ts +0 -3
  190. package/dist/prompts/protocol.d.ts +0 -18
  191. package/dist/prompts/worker-mode/system.d.ts +0 -2
  192. package/dist/prompts/worker-mode/system.md.d.ts +0 -2
  193. package/dist/prompts/worker-mode/user.d.ts +0 -2
  194. package/dist/prompts/worker-mode/user.md.d.ts +0 -2
  195. package/dist/quickjs-variant-BYhMBpwU.js +0 -45
  196. package/dist/quickjs-variant-CsIwTVFC.cjs +0 -56
  197. package/dist/rolldown-runtime-EAsCxrDo.js +0 -14
  198. package/dist/runtime/interpret-result.d.ts +0 -22
  199. package/dist/snapshots.d.ts +0 -249
  200. package/dist/stack-traces-BIE_5Xwf.js +0 -21
  201. package/dist/stack-traces-ntw_qhoy.cjs +0 -26
  202. package/dist/truncator-CLkouTCO.cjs +0 -276
  203. package/dist/truncator-DZqEqnpD.js +0 -253
  204. package/dist/truncator.d.ts +0 -118
  205. package/dist/utils-3ESwP3yg.cjs +0 -1075
  206. package/dist/utils-UBeAFeEI.js +0 -950
  207. /package/dist/{citations.d.ts → chat/citations.d.ts} +0 -0
  208. /package/dist/{citations.test.d.ts → chat/citations.test.d.ts} +0 -0
  209. /package/dist/{component.default.test.d.ts → chat/component.default.test.d.ts} +0 -0
  210. /package/dist/{compiler/plugins/track-tool-calls.test.d.ts → chat/component.test.d.ts} +0 -0
  211. /package/dist/{example.test.d.ts → chat/response.test.d.ts} +0 -0
  212. /package/dist/{exit-parser.test.d.ts → compiler/plugins/dynamic-code.test.d.ts} +0 -0
  213. /package/dist/{handlers.test.d.ts → compiler/plugins/tool-resolution.test.d.ts} +0 -0
  214. /package/dist/{hoist.test.d.ts → errors/catalog.test.d.ts} +0 -0
  215. /package/dist/{message-stream/instructions.test.d.ts → exit.test.d.ts} +0 -0
  216. /package/dist/{message-stream/normalizer.test.d.ts → inspection.test.d.ts} +0 -0
  217. /package/dist/{message-stream/parser.test.d.ts → prompts/native.test.d.ts} +0 -0
  218. /package/dist/{message-stream/stream.test.d.ts → result.test.d.ts} +0 -0
  219. /package/dist/{message-stream/validator.test.d.ts → runtime/chat-delivery.test.d.ts} +0 -0
  220. /package/dist/{prompts/common.test.d.ts → runtime/citations.test.d.ts} +0 -0
  221. /package/dist/{prompts/protocol.test.d.ts → runtime/compatibility-regressions.test.d.ts} +0 -0
  222. /package/dist/runtime/{interpret-result.test.d.ts → context-registration.test.d.ts} +0 -0
  223. /package/dist/{transcript.test.d.ts → runtime/error-recovery.test.d.ts} +0 -0
  224. /package/dist/{truncator.test.d.ts → runtime/errors.test.d.ts} +0 -0
package/README.md CHANGED
@@ -1,605 +1,153 @@
1
- # LLMz
1
+ # LLMZ
2
2
 
3
- **Stop chaining tools. Start generating code.**
3
+ LLMZ runs agents that use JavaScript to call tools, work with data, and return typed outcomes. The model receives one native `run_javascript` tool. Programs run in a sandbox; the host supplies the business tools they can call.
4
4
 
5
- LLMz is a TypeScript AI agent framework that replaces traditional JSON tool calling with executable code generation. Instead of orchestrating tools through multiple LLM roundtrips, agents write and execute TypeScript directly—enabling complex logic, loops, and multi-tool coordination in a single pass.
5
+ Use `Session` for conversation history and retained values, `Chat` for text and component delivery, and `Exit` for structured completion.
6
6
 
7
- Powers millions of production agents at [Botpress](https://botpress.com).
7
+ [API guide](./DOCS.md) · [Examples](./examples) · [Migration](./DOCS.md#migrating-from-the-previous-api)
8
8
 
9
- | | |
10
- | --- | ----------------------------------------------------------------------------------------- |
11
- | 📚 | [**Examples →**](https://github.com/botpress/botpress/tree/master/packages/llmz/examples) |
9
+ ## Installation
12
10
 
13
- ---
14
-
15
- ## The Problem with Tool Calling
16
-
17
- Traditional agentic frameworks (LangChain, CrewAI, MCP servers) rely on JSON tool calling:
18
-
19
- ```json
20
- {
21
- "tool": "getTicketPrice",
22
- "parameters": { "from": "quebec", "to": "new york" }
23
- }
11
+ ```sh
12
+ pnpm add llmz @botpress/cognitive @bpinternal/zui @bpinternal/thicktoken
24
13
  ```
25
14
 
26
- This breaks down quickly:
27
-
28
- - **Verbose schemas**: LLMs struggle with complex JSON structures
29
- - **No logic**: Can't express conditionals, loops, or error handling
30
- - **Multiple roundtrips**: Each tool call requires another LLM inference ($$$)
31
- - **Fragile composition**: Chaining tools is error-prone and expensive
32
-
33
- You end up with brittle agents that cost 10-100x more than they should.
34
-
35
- ---
36
-
37
- ## The LLMz Solution
38
-
39
- LLMz generates and executes **real TypeScript code** in a secure sandbox:
40
-
41
- ```typescript
42
- const price = await getTicketPrice({ from: 'quebec', to: 'new york' })
43
-
44
- if (price > 500) {
45
- throw new Error('Price too high')
46
- }
47
-
48
- const ticketId = await buyTicket({ from: 'quebec', to: 'new york' })
49
- ```
50
-
51
- **Why this works:**
52
-
53
- - LLMs have seen billions of lines of TypeScript—they're exceptionally good at it
54
- - Complex logic (loops, conditionals, error handling) happens in one inference
55
- - Multiple tool calls execute synchronously without LLM roundtrips
56
- - Full type safety via Zui schemas and TypeScript inference
57
-
58
- **Real-world impact**: Anthropic reduced agent costs by 98.7% using code execution patterns ([source](https://www.anthropic.com/engineering/code-execution-with-mcp)).
59
-
60
- ---
61
-
62
- ## The ■ Protocol
63
-
64
- Every model response is a sequence of streaming-native `■` blocks:
65
-
66
- ```
67
- ■send=message
68
- Let me check the next launch dates for the Moon...
69
- ■run
70
- const dates = await checkAvailability({ destination: 'moon' })
71
- const reservation = await bookTrip({ destination: 'moon', date: dates[0], travelerName: 'Ada' })
72
- const payment = await processPayment({ reservationId: reservation.reservationId })
73
- return { ...payment, date: dates[0] }
74
- ```
15
+ The following examples assume `BOTPRESS_BOT_ID` and `BOTPRESS_TOKEN` are configured for Cognitive. Examples are type-checked with `pnpm check:docs`.
75
16
 
76
- - **`■send=<component> {props?}`** — sends a message to the user, delivered (and streamable) the moment it is parsed
77
- - **`■run`** — executes the TypeScript body in the sandbox; the returned value is fed back to the model
78
- - **`■next=<exit> {props?}`** — ends the turn through a typed exit (the built-in `listen` hands the turn back to the user)
17
+ ## Start a conversation
79
18
 
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.
19
+ ```ts
20
+ import { Cognitive } from '@botpress/cognitive'
21
+ import { Chat, Session, execute } from 'llmz'
81
22
 
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
-
86
- ---
87
-
88
- ## Quick Start
89
-
90
- **Requirements:** Node.js 20+
91
-
92
- ```bash
93
- npm install @botpress/client llmz
94
- ```
95
-
96
- ### Platform Support
97
-
98
- | Platform | Support |
99
- | ------------------ | ------- |
100
- | Node.js 20+ | ✅ Full |
101
- | Browser | ✅ Full |
102
- | AWS Lambda | ✅ Full |
103
- | Cloudflare Workers | ✅ Full |
104
- | Bun | ✅ Full |
105
- | Deno | ✅ Full |
106
-
107
- #### Sandbox Execution
108
-
109
- LLMz uses **QuickJS** (a lightweight JavaScript engine compiled to WebAssembly) to execute generated code in a secure, isolated sandbox. This provides:
110
-
111
- - **Complete isolation**: No access to filesystem, network, or host environment
112
- - **Memory limits**: Configurable heap size to prevent resource exhaustion
113
- - **Execution timeouts**: Automatic termination of runaway code
114
- - **Abort signals**: Support for programmatic execution cancellation
115
- - **Universal compatibility**: Works everywhere WebAssembly is supported
116
-
117
- The QuickJS sandbox is bundled as a singlefile variant with WASM inlined as base64, so it works out-of-the-box with any bundler (esbuild, webpack, vite, rollup) without configuration.
118
-
119
- ### Worker Mode: Autonomous Execution
120
-
121
- ```typescript
122
- import { Client } from '@botpress/client'
123
- import { execute } from 'llmz'
124
-
125
- const client = new Client({ botId: '...', token: '...' })
126
-
127
- const result = await execute({
128
- instructions: 'Calculate sum of integers 14-1078 divisible by 3, 9, or 5',
129
- client,
23
+ const client = new Cognitive({
24
+ botId: process.env.BOTPRESS_BOT_ID!,
25
+ token: process.env.BOTPRESS_TOKEN!,
130
26
  })
131
-
132
- console.log(result.output) // 271575
133
- ```
134
-
135
- **Generated response:**
136
-
137
- ```
138
- ■run
139
- let sum = 0
140
- for (let i = 14; i <= 1078; i++) {
141
- if (i % 3 === 0 || i % 9 === 0 || i % 5 === 0) {
142
- sum += i
143
- }
144
- }
145
- return sum
146
- ```
147
-
148
- ### Chat Mode: Interactive Agents
149
-
150
- ```typescript
151
- import { execute, Chat, DefaultComponents, ListenExit } from 'llmz'
152
-
153
- const transcript = []
154
-
27
+ const session = new Session()
155
28
  const chat = new Chat({
156
- components: [DefaultComponents.Text, DefaultComponents.Button],
157
- transcript: () => transcript,
158
-
159
- // Complete messages, delivered as soon as they are parsed
160
- handler: async (component) => {
161
- render(component)
162
- },
163
-
164
- // Optional: message body chunks, streamed while the LLM is still generating
165
- onMessageDelta: (delta) => {
166
- appendToBubble(delta.id, delta.delta)
29
+ response: {
30
+ preset: 'markdown',
31
+ handler: (text) => {
32
+ console.log(text)
33
+ },
167
34
  },
168
35
  })
169
36
 
170
- while (true) {
171
- const result = await execute({ client, chat, tools: [searchFlights, bookTicket] })
37
+ session.append({ role: 'user', content: 'Help me plan a weekend in Montreal.' })
38
+ const result = await execute({ client, session, chat, instructions: 'Be concise and helpful.' })
172
39
 
173
- if (result.is(ListenExit)) {
174
- // Agent handed the turn back — wait for user input
175
- transcript.push({ role: 'user', content: await getUserInput() })
176
- } else {
177
- break // Agent completed (custom exit) or errored
178
- }
40
+ if (result.isError()) {
41
+ console.error(result.error)
179
42
  }
180
43
  ```
181
44
 
182
- **Generated response:**
45
+ Append the next message and call `execute` again with the same session. Inputs appended during execution wait for the next turn. Await one execution before starting another on that session.
183
46
 
184
- ```
185
- ■send=message
186
- Found 12 flights. The cheapest is **$249**. Want me to book it?
187
- ■send=button {"label": "Book flight", "action": "postback", "value": "book"}
188
- ■send=button {"label": "Cancel", "action": "postback", "value": "cancel"}
189
- ■next=listen
190
- ```
191
-
192
- ---
193
-
194
- ## Core Concepts
47
+ ## Return a typed result
195
48
 
196
- ### Execution Modes
49
+ Workers complete through a named exit. Tool input and exit output use Zui schemas.
197
50
 
198
- **Worker Mode**: Autonomous agents that execute to completion
199
-
200
- ```typescript
201
- const result = await execute({
202
- instructions: 'Analyze Q4 sales data and generate report',
203
- client,
204
- tools: [fetchSales, calculateMetrics, generatePDF],
205
- })
206
- ```
207
-
208
- **Chat Mode**: Interactive conversations with user input
209
-
210
- ```typescript
211
- const result = await execute({
212
- client,
213
- tools,
214
- chat, // a Chat instance: components + transcript + message handler
215
- })
216
- ```
217
-
218
- ### Tools: Type-Safe Functions
219
-
220
- ```typescript
221
- import { Tool } from 'llmz'
51
+ ```ts
52
+ import { Cognitive } from '@botpress/cognitive'
222
53
  import { z } from '@bpinternal/zui'
54
+ import { Exit, Tool, execute } from 'llmz'
223
55
 
224
- const searchFlights = new Tool({
225
- name: 'searchFlights',
226
- description: 'Search for available flights',
227
- input: z.object({
228
- from: z.string(),
229
- to: z.string(),
230
- date: z.string(),
231
- }),
232
- output: z.array(
233
- z.object({
234
- id: z.string(),
235
- price: z.number(),
236
- departure: z.string(),
237
- })
238
- ),
239
- handler: async ({ from, to, date }) => {
240
- // Your implementation
241
- return flights
242
- },
56
+ const client = new Cognitive({
57
+ botId: process.env.BOTPRESS_BOT_ID!,
58
+ token: process.env.BOTPRESS_TOKEN!,
243
59
  })
244
- ```
245
-
246
- Tools are exposed to agents with full TypeScript signatures. Agents call them like regular async functions — and chain them freely inside a single `■run` block.
247
-
248
- Tool handlers can also be **async generators** that push UI components to the chat mid-execution (progress bars, previews) before returning their result — see [example 21](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/21_chat_tool_components).
249
-
250
- ### Objects: Namespaced State
251
-
252
- Group related tools and variables:
253
-
254
- ```typescript
255
- import { ObjectInstance } from 'llmz'
256
- import { z } from '@bpinternal/zui'
257
-
258
- const database = new ObjectInstance({
259
- name: 'db',
260
- description: 'Database operations',
261
- tools: [queryUsers, updateRecord, deleteRecord],
262
- properties: [
263
- {
264
- name: 'connectionString',
265
- value: process.env.DB_URL,
266
- writable: false,
267
- },
268
- {
269
- name: 'lastQueryTime',
270
- value: null,
271
- type: z.string().nullable(),
272
- writable: true,
273
- },
274
- ],
60
+ const getPrice = new Tool({
61
+ name: 'getPrice',
62
+ description: 'Look up the unit price of an item.',
63
+ input: z.object({ sku: z.string() }),
64
+ output: z.number(),
65
+ handler: async ({ sku }) => (sku === 'coffee' ? 12 : 0),
275
66
  })
276
- ```
277
-
278
- Agents access via namespaces:
279
-
280
- ```typescript
281
- const users = await db.queryUsers({ active: true })
282
- db.lastQueryTime = new Date().toISOString()
283
- ```
284
-
285
- ### Exits: Structured Termination
286
-
287
- Define how agents can complete:
288
-
289
- ```typescript
290
- import { Exit } from 'llmz'
291
- import { z } from '@bpinternal/zui'
292
-
293
- const TicketBooked = new Exit({
294
- name: 'ticket_booked',
295
- description: 'Successfully booked a ticket',
296
- schema: z.object({
297
- ticketId: z.string(),
298
- price: z.number(),
299
- confirmation: z.string(),
300
- }),
67
+ const done = new Exit({
68
+ name: 'done',
69
+ description: 'Return the calculated total.',
70
+ schema: z.object({ total: z.number() }),
301
71
  })
302
72
 
303
73
  const result = await execute({
304
74
  client,
305
- tools,
306
- exits: [TicketBooked],
75
+ instructions: 'Calculate the price of three units of coffee and finish with done.',
76
+ tools: [getPrice],
77
+ exits: [done],
307
78
  })
308
79
 
309
- if (result.is(TicketBooked)) {
310
- console.log('Booked:', result.output.ticketId) // Fully typed
80
+ if (result.is(done)) {
81
+ console.log(result.output.total)
82
+ } else if (result.isError()) {
83
+ console.error(result.error)
311
84
  }
312
85
  ```
313
86
 
314
- Agents invoke exits with a `■next` block:
87
+ The model can compose tool calls in a program. It uses `return inspect(value)` to examine evidence in another iteration, and `return exit('done', payload)` to finish. [Execution and memory](./DOCS.md#execution-and-memory) explains their lifetimes.
315
88
 
316
- ```
317
- ■next=ticket_booked {"ticketId": "TKT-12345", "price": 299, "confirmation": "ABC123"}
318
- ```
89
+ ## Save a conversation
319
90
 
320
- ---
91
+ Persist the session after execution settles. The execution result contains the outcome and diagnostics for one run.
321
92
 
322
- ## Streaming
93
+ ```ts
94
+ import { Session } from 'llmz'
323
95
 
324
- With a streaming client (`CognitiveBeta` / Cognitive v2), everything an execution produces surfaces in real time:
96
+ const session = new Session({ variables: { accountId: 'customer-42' } })
97
+ session.append({ role: 'user', content: 'Check my account.' })
325
98
 
326
- ```typescript
327
- const chat = new Chat({
328
- components: [DefaultComponents.Text],
329
- transcript: () => transcript,
330
- handler: async (component, metadata) => finalizeBubble(component, metadata),
331
- // Fires per token-chunk while the LLM is still generating
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
- },
339
- })
99
+ const saved = JSON.stringify(session.toJSON())
100
+ const restored = Session.fromJSON(JSON.parse(saved))
340
101
 
341
- const result = await execute({
342
- client, // CognitiveBeta
343
- chat,
344
- tools,
345
- options: { midStreamFallback: true },
346
- onTrace: ({ trace }) => {
347
- if (trace.type === 'llm_call_started') showSpinner()
348
- if (trace.type === 'code_generation_started') showStatus('writing code…')
349
- if (trace.type === 'llm_call_success') showCode(trace.code)
350
- if (trace.type === 'tool_call') showToolCall(trace)
351
- },
352
- })
102
+ console.log(restored.pendingMessages)
103
+ console.log(restored.memory.variables.accountId)
353
104
  ```
354
105
 
355
- - **Message deltas** stream to your UI token-by-token (`handler` remains the authoritative delivery)
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
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.
106
+ A failed execution retains its active turn. Calling `execute` again continues that turn; newly queued input remains separate. Completed tool effects are not rolled back. [Persistence and recovery](./DOCS.md#persistence-and-recovery) documents this contract.
361
107
 
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.
108
+ ## Stream text
363
109
 
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`.
110
+ `onDelta` receives provisional text. `handler` receives the complete accepted response. A restart retracts the preview for that iteration.
365
111
 
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).
112
+ ```ts
113
+ import { Chat } from 'llmz'
367
114
 
368
- ### Token Usage & Timings
369
-
370
- Every iteration reports what it consumed:
371
-
372
- ```typescript
373
- const { input, output, total, limit, context } = result.iteration.tokens
374
- // context measures the prompt size by part (pre-truncation):
375
- // { framework, instructions, tools, transcript, protocol, iterations, total }
376
- console.log(`context used: ${Math.round((context.total / limit) * 100)}%`)
377
-
378
- const { time_to_first_token, time_to_last_token } = result.iteration.llm
379
-
380
- // Aggregated across all iterations:
381
- console.log(result.tokens) // { input, output, total }
382
- ```
383
-
384
- ### Execution Options
385
-
386
- ```typescript
387
- const result = await execute({
388
- client,
389
- model: ['cerebras:gpt-oss-120b', 'anthropic:claude-haiku-4-5'], // fallback chain
390
- reasoningEffort: 'low', // 'low' | 'medium' | 'high' | 'dynamic' | 'none'
391
- options: {
392
- loop: 5, // max iterations
393
- timeout: 60_000, // VM execution timeout (ms)
394
- maxTokens: 32_000, // context window cap: min(maxTokens, model max)
395
- maxTimeToFirstToken: 5_000, // fall back to the next model if the first token is late (ms)
396
- },
397
- })
398
- ```
399
-
400
- ---
401
-
402
- ## Advanced Features
403
-
404
- ### Thinking: Forced Reflection
405
-
406
- Tools can force the agent to look at data before acting on it:
407
-
408
- ```typescript
409
- import { ThinkSignal } from 'llmz'
410
-
411
- const complexAnalysis = new Tool({
412
- name: 'analyze',
413
- handler: async (data) => {
414
- const result = performComplexCalculation(data)
415
- // Force agent to reflect on results before proceeding
416
- throw new ThinkSignal('Analysis complete. Review data before next step.')
417
- },
418
- })
419
- ```
420
-
421
- Agents self-initiate reflection by returning values from their code — the returned value is shown to them and they respond again:
422
-
423
- ```
424
- ■run
425
- const data = await fetchLargeDataset()
426
- return data.summary
427
- ```
428
-
429
- ### Snapshots: Pause and Resume
430
-
431
- Save execution state for long-running workflows:
432
-
433
- ```typescript
434
- import { SnapshotSignal } from 'llmz'
435
-
436
- const approvalRequired = new Tool({
437
- name: 'submitForApproval',
438
- handler: async (request) => {
439
- await saveToDatabase(request)
440
- // Halt execution until manual approval
441
- throw new SnapshotSignal('Awaiting manager approval')
442
- },
443
- })
444
-
445
- // Later, resume from snapshot
446
- const result = await execute({
447
- client,
448
- snapshot: savedSnapshot,
449
- })
450
- ```
451
-
452
- ### Hooks: Custom Logic Injection
453
-
454
- ```typescript
455
- const result = await execute({
456
- client,
457
- tools,
458
-
459
- // Non-blocking: observe everything (and abort when needed)
460
- onTrace: ({ trace, controller }) => {
461
- logger.info(trace)
462
- if (trace.type === 'tool_call' && trace.tool_name === 'forbidden') {
463
- controller.abort('Forbidden tool call')
464
- }
465
- },
466
-
467
- // Validate before allowing an exit — throw to retry, abort to stop
468
- onExit: (result, controller) => {
469
- if (result.exit.name === 'transfer_money' && result.result.amount > 10_000) {
470
- throw new Error('Amount exceeds limit')
471
- }
472
- },
473
-
474
- // Inspect/modify generated code before execution
475
- onBeforeExecution: (iteration) => {
476
- if (iteration.code?.includes('dangerousOperation')) {
477
- return { code: '// blocked' }
478
- }
115
+ const previews = new Map<string, string>()
116
+ const chat = new Chat({
117
+ response: {
118
+ preset: 'text',
119
+ onDelta: (event) => {
120
+ if (event.restart) {
121
+ previews.delete(event.iterationId)
122
+ } else {
123
+ previews.set(event.iterationId, event.content)
124
+ }
125
+ },
126
+ handler: (text, metadata) => {
127
+ previews.delete(metadata.iterationId)
128
+ console.log(metadata.id, text)
129
+ },
479
130
  },
480
-
481
- // Also available: onIterationStart, onIterationEnd, onBeforeTool, onAfterTool
482
131
  })
483
132
  ```
484
133
 
485
- ---
486
-
487
- ## Coming from MCP?
488
-
489
- LLMz is **not** a replacement for MCP—it's complementary.
490
-
491
- **MCP** (Model Context Protocol): Standardizes how AI applications connect to data sources and tools across processes/machines.
492
-
493
- **LLMz**: Replaces the execution pattern _after_ tools are exposed. Instead of making multiple LLM calls to orchestrate MCP tools via JSON, LLMz generates TypeScript code that calls those same tools in a single inference—reducing costs by up to 98%.
494
-
495
- ---
496
-
497
- ## Production Ready
498
-
499
- LLMz has been running in production for over a year:
134
+ Streaming requires a client with `generateTextStream`. See [streaming semantics](./DOCS.md#streaming-and-delivery) before enabling model fallback.
500
135
 
501
- - **Millions** of active users across enterprise and consumer applications
502
- - **Hundreds of thousands** of deployed agents handling real-world workloads
503
- - **Secure sandbox**: Uses QuickJS WASM for isolated code execution
504
- - **Type-safe**: Full TypeScript inference and Zui validation
505
- - **Observable**: Comprehensive tracing, token accounting and error handling
136
+ ## Examples and development
506
137
 
507
- ---
138
+ - [Basic chat](./examples/01_chat_basic/index.ts)
139
+ - [Typed chat exits](./examples/02_chat_exits/index.ts)
140
+ - [Rich components](./examples/10_chat_components/index.ts)
141
+ - [Worker tool chaining](./examples/16_worker_tool_chaining/index.ts)
142
+ - [Streaming chat](./examples/22_chat_streaming/index.ts)
508
143
 
509
- ## Architecture
510
-
511
- **Execution Pipeline:**
512
-
513
- 1. **Prompt Generation**: Injects tools, schemas, and context into dual-mode prompts
514
- 2. **Streaming Generation**: The LLM streams ■ blocks — messages dispatch to the chat as they are parsed
515
- 3. **Compilation**: Babel AST transformation with instrumentation plugins (line tracking, tool call tracking, variable extraction)
516
- 4. **Execution**: Runs in QuickJS WASM sandbox with full isolation — starting while the response tail is still streaming
517
- 5. **Result Processing**: Type-safe exit handling, thinking loops and error recovery
518
-
519
- **Security:**
520
-
521
- - QuickJS WASM sandbox with complete isolation (no filesystem/network access)
522
- - Stack trace sanitization (removes internal framework details)
523
- - Configurable memory limits and execution timeouts
524
- - Tool-level permissions and rate limiting
525
- - Automatic token limit handling
526
-
527
- ---
528
-
529
- ## Comparison
530
-
531
- | Feature | LangChain / CrewAI | MCP Servers | LLMz |
532
- | ------------------------ | ---------------------- | ---------------------- | ------------------------- |
533
- | Tool calling | JSON | JSON | TypeScript code |
534
- | Multi-tool orchestration | Multiple LLM calls | Multiple LLM calls | Single LLM call |
535
- | Complex logic | Limited | Limited | Full language support |
536
- | Type safety | Partial | Schema-based | Full TypeScript + Zui |
537
- | Streaming | Text only | Text only | Messages, code, tools |
538
- | Execution environment | Python/JS runtime | Cross-process | QuickJS WASM sandbox |
539
- | Cost (complex workflows) | High (many roundtrips) | High (many roundtrips) | Low (one-shot generation) |
540
- | Production scale | Varies | Emerging | Battle-tested (1M+ users) |
541
-
542
- ---
543
-
544
- ## Examples
545
-
546
- Check out the [examples folder](https://github.com/botpress/botpress/tree/master/packages/llmz/examples) for complete working examples:
547
-
548
- | Title | Mode | Description |
549
- | --------------------------------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------- |
550
- | [Basic Chat](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/01_chat_basic) | Chat | Simple interactive chat with button-based navigation |
551
- | [Chat with Exits](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/02_chat_exits) | Chat | Custom exit conditions with type-safe validation |
552
- | [Conditional Tools](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/03_chat_conditional_tool) | Chat | Dynamic tool availability based on context |
553
- | [Small Models](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/04_chat_small_models) | Chat | Optimized prompts for smaller language models |
554
- | [Web Search](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/05_chat_web_search) | Chat | Integrate web search and content browsing |
555
- | [Tool Confirmation](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/06_chat_confirm_tool) | Chat | User confirmation before executing tools |
556
- | [Guardrails](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/07_chat_guardrails) | Chat | Safety constraints and content filtering |
557
- | [Multi-Agent](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/08_chat_multi_agent) | Chat | Coordinating multiple agents in one system |
558
- | [Variables](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/09_chat_variables) | Chat | Stateful properties that persist across iterations |
559
- | [Components](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/10_chat_components) | Chat | Rich UI components for interactive experiences |
560
- | [Minimal Worker](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/11_worker_minimal) | Worker | One-shot computational task execution |
561
- | [File System](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/12_worker_fs) | Worker | Automated file operations with conditional logic |
562
- | [Sandbox](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/13_worker_sandbox) | Worker | Secure isolated code execution environment |
563
- | [Snapshots](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/14_worker_snapshot) | Worker | Pause and resume long-running workflows |
564
- | [Stack Traces](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/15_worker_stacktraces) | Worker | Error handling and debugging patterns |
565
- | [Tool Chaining](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/16_worker_tool_chaining) | Worker | Sequential multi-tool orchestration |
566
- | [Error Recovery](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/17_worker_error_recovery) | Worker | Graceful failure handling and retries |
567
- | [Security](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/18_worker_security) | Worker | Code inspection and security validation |
568
- | [Wrap Tools](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/19_worker_wrap_tool) | Worker | Creating higher-order tool abstractions |
569
- | [RAG](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/20_chat_rag) | Chat | Retrieval-augmented generation with knowledge bases |
570
- | [Tool Components](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/21_chat_tool_components) | Chat | Tool handlers pushing UI components mid-execution |
571
- | [Streaming](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/22_chat_streaming) | Chat | Guided simulation: streamed messages, live code + tool calls, typed exits, per-turn stats |
572
-
573
- ---
574
-
575
- ## Contributing
576
-
577
- ```bash
578
- git clone https://github.com/botpress/botpress
579
- cd packages/llmz
580
-
581
- pnpm install
144
+ ```sh
582
145
  pnpm test
583
- pnpm build
146
+ pnpm check:type
147
+ pnpm check:e2e:type
148
+ pnpm check:docs
149
+ pnpm check:lint
150
+ pnpm check:format
584
151
  ```
585
152
 
586
- **Commands:**
587
-
588
- - `pnpm test`: Run test suite (Vitest with LLM retries)
589
- - `pnpm test:watch`: Watch mode for development
590
- - `pnpm build`: Compile TypeScript and bundle (ESM + CJS)
591
- - `pnpm generate`: Regenerate prompt templates from markdown
592
-
593
- ---
594
-
595
- ## License
596
-
597
- MIT
598
-
599
- ---
600
-
601
- ## Learn More
602
-
603
- - [Anthropic: Code Execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp)
604
- - [How Code Execution Reduces Agent Costs by 98%](https://medium.com/@meshuggah22/weve-been-using-mcp-wrong-how-anthropic-reduced-ai-agent-costs-by-98-7-7c102fc22589)
605
- - [Botpress Documentation](https://botpress.com/docs)
153
+ Unit tests use scripted clients. Model evaluations run separately through `pnpm test:e2e` and require the configured provider credentials.