llmz 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +185 -98
  2. package/dist/chat.d.ts +34 -0
  3. package/dist/{chunk-TIZWOIDF.js → chunk-33AB6SVX.js} +134 -76
  4. package/dist/{chunk-EFEF2AL7.js → chunk-DH35WO5G.js} +93 -556
  5. package/dist/chunk-E5NHK3FS.js +1637 -0
  6. package/dist/{chunk-L74UZONX.js → chunk-HM5H556L.js} +3 -1
  7. package/dist/chunk-I56MPOVG.cjs +62 -0
  8. package/dist/{chunk-C7T6OJB4.cjs → chunk-IKLFMVSW.cjs} +144 -86
  9. package/dist/chunk-KWQTYXAT.js +62 -0
  10. package/dist/{chunk-JXD2KJVB.cjs → chunk-WWZ2W4WR.cjs} +103 -566
  11. package/dist/chunk-YGKQEVQQ.cjs +1637 -0
  12. package/dist/{chunk-ZPHRTTQX.cjs → chunk-YQT5G77W.cjs} +3 -1
  13. package/dist/compiler/compiler.d.ts +7 -2
  14. package/dist/compiler/index.d.ts +1 -1
  15. package/dist/compiler/plugins/async-wrapper.d.ts +11 -0
  16. package/dist/component-2NYFY6CW.cjs +14 -0
  17. package/dist/{component-2Z3KLWLX.js → component-ASNZHQUR.js} +3 -7
  18. package/dist/component.d.ts +3 -10
  19. package/dist/context.d.ts +88 -2
  20. package/dist/{dual-modes-HEXPFVUE.js → dual-modes-RMF7V7ZQ.js} +2 -4
  21. package/dist/dual-modes-ZZY6QPYT.cjs +10 -0
  22. package/dist/{execute-22PSGL7P.cjs → execute-BXPFSEVX.cjs} +331 -87
  23. package/dist/{execute-ZENBZBWL.js → execute-HIRXXR6X.js} +321 -77
  24. package/dist/index.cjs +502 -27
  25. package/dist/index.d.ts +8 -5
  26. package/dist/index.js +491 -16
  27. package/dist/message-stream/index.d.ts +9 -0
  28. package/dist/message-stream/instructions.d.ts +22 -0
  29. package/dist/message-stream/normalizer.d.ts +21 -0
  30. package/dist/message-stream/parser.d.ts +81 -0
  31. package/dist/message-stream/registry.d.ts +14 -0
  32. package/dist/message-stream/replayable.d.ts +27 -0
  33. package/dist/message-stream/sanitize.d.ts +10 -0
  34. package/dist/message-stream/stream.d.ts +54 -0
  35. package/dist/message-stream/types.d.ts +96 -0
  36. package/dist/message-stream/validator.d.ts +23 -0
  37. package/dist/message-stream/validator.test.d.ts +1 -0
  38. package/dist/prompts/chat-mode/system.md.d.ts +1 -1
  39. package/dist/prompts/chat-mode/user.md.d.ts +1 -1
  40. package/dist/prompts/common.d.ts +5 -5
  41. package/dist/prompts/prompt.d.ts +43 -6
  42. package/dist/prompts/protocol.d.ts +18 -0
  43. package/dist/prompts/worker-mode/system.md.d.ts +1 -1
  44. package/dist/prompts/worker-mode/user.md.d.ts +1 -1
  45. package/dist/result.d.ts +31 -0
  46. package/dist/runtime/execute.test.d.ts +1 -0
  47. package/dist/runtime/generate.d.ts +24 -1
  48. package/dist/runtime/interpret-result.d.ts +10 -0
  49. package/dist/runtime/types.d.ts +29 -4
  50. package/dist/truncator-7PGEGCHV.cjs +12 -0
  51. package/dist/{truncator-3U2QUUJJ.js → truncator-OZOBNYON.js} +3 -1
  52. package/dist/truncator.d.ts +2 -0
  53. package/dist/types.d.ts +8 -1
  54. package/dist/vm/drivers/quickjs.d.ts +2 -0
  55. package/dist/vm/index.d.ts +7 -0
  56. package/dist/vm/instrument.d.ts +1 -1
  57. package/dist/{vm-PYCKS77H.js → vm-44H4UKI2.js} +5 -4
  58. package/dist/{vm-VHB67FVH.cjs → vm-A3OTQVIR.cjs} +4 -3
  59. package/package.json +5 -5
  60. package/dist/chunk-2O3UTPVH.js +0 -813
  61. package/dist/chunk-3T5IU7OU.js +0 -186
  62. package/dist/chunk-BBX2LDZE.cjs +0 -813
  63. package/dist/chunk-CQ3UJW76.cjs +0 -186
  64. package/dist/compiler/plugins/async-iterator.d.ts +0 -6
  65. package/dist/compiler/plugins/braces-tsx.d.ts +0 -3
  66. package/dist/compiler/plugins/html-to-markdown.d.ts +0 -21
  67. package/dist/compiler/plugins/jsx-preserve-newlines.d.ts +0 -5
  68. package/dist/compiler/plugins/jsx-undefined-vars.d.ts +0 -14
  69. package/dist/component-NNHBHD72.cjs +0 -18
  70. package/dist/dual-modes-LLIWZCHC.cjs +0 -12
  71. package/dist/truncator-3ZN7W6NB.cjs +0 -10
  72. /package/dist/{compiler/plugins/html-to-markdown.test.d.ts → message-stream/instructions.test.d.ts} +0 -0
  73. /package/dist/{compiler/plugins/jsx-undefined-vars.test.d.ts → message-stream/normalizer.test.d.ts} +0 -0
  74. /package/dist/{component.test.d.ts → message-stream/parser.test.d.ts} +0 -0
  75. /package/dist/{vm/vm-jsx.test.d.ts → message-stream/stream.test.d.ts} +0 -0
package/README.md CHANGED
@@ -46,7 +46,6 @@ if (price > 500) {
46
46
  }
47
47
 
48
48
  const ticketId = await buyTicket({ from: 'quebec', to: 'new york' })
49
- return { action: 'done', result: ticketId }
50
49
  ```
51
50
 
52
51
  **Why this works:**
@@ -60,6 +59,28 @@ return { action: 'done', result: ticketId }
60
59
 
61
60
  ---
62
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
+ ```
75
+
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)
79
+
80
+ Because the protocol is parsed incrementally, messages stream to your UI token-by-token, tool calls surface live, and code execution can start before the response has even finished streaming.
81
+
82
+ ---
83
+
63
84
  ## Quick Start
64
85
 
65
86
  **Requirements:** Node.js 20+
@@ -107,64 +128,61 @@ const result = await execute({
107
128
  console.log(result.output) // 271575
108
129
  ```
109
130
 
110
- **Generated code:**
131
+ **Generated response:**
111
132
 
112
- ```typescript
133
+ ```
134
+ ■run
113
135
  let sum = 0
114
136
  for (let i = 14; i <= 1078; i++) {
115
137
  if (i % 3 === 0 || i % 9 === 0 || i % 5 === 0) {
116
138
  sum += i
117
139
  }
118
140
  }
119
- return { action: 'done', value: { success: true, result: sum } }
141
+ return sum
120
142
  ```
121
143
 
122
144
  ### Chat Mode: Interactive Agents
123
145
 
124
146
  ```typescript
125
- import { execute } from 'llmz'
126
- import { Text, Button } from './components'
147
+ import { execute, Chat, DefaultComponents, ListenExit } from 'llmz'
148
+
149
+ const transcript = []
127
150
 
128
- const tools = [searchFlights, bookTicket, cancelBooking]
151
+ const chat = new Chat({
152
+ components: [DefaultComponents.Text, DefaultComponents.Button],
153
+ transcript: () => transcript,
129
154
 
130
- let state = { transcript: [] }
155
+ // Complete messages, delivered as soon as they are parsed
156
+ handler: async (component) => {
157
+ render(component)
158
+ },
159
+
160
+ // Optional: message body chunks, streamed while the LLM is still generating
161
+ onMessageDelta: (delta) => {
162
+ appendToBubble(delta.id, delta.delta)
163
+ },
164
+ })
131
165
 
132
166
  while (true) {
133
- const result = await execute({
134
- client,
135
- tools,
136
- chat: {
137
- transcript: state.transcript,
138
- components: { Text, Button },
139
- },
140
- })
167
+ const result = await execute({ client, chat, tools: [searchFlights, bookTicket] })
141
168
 
142
- if (result.is('listen')) {
143
- // Agent yielded UI and is waiting for user input
144
- console.log('Agent:', result.value.components)
145
- const userInput = await getUserInput()
146
- state.transcript.push({ role: 'user', content: userInput })
169
+ if (result.is(ListenExit)) {
170
+ // Agent handed the turn back — wait for user input
171
+ transcript.push({ role: 'user', content: await getUserInput() })
147
172
  } else {
148
- // Agent completed the task
149
- break
173
+ break // Agent completed (custom exit) or errored
150
174
  }
151
175
  }
152
176
  ```
153
177
 
154
- **Generated code:**
155
-
156
- ```typescript
157
- const flights = await searchFlights({ from: 'SFO', to: 'NYC' })
158
-
159
- yield (
160
- <Text>
161
- Found {flights.length} flights. Cheapest is ${flights[0].price}. Book it?
162
- </Text>
163
- )
164
- yield <Button>Book Flight</Button>
165
- yield <Button>Cancel</Button>
178
+ **Generated response:**
166
179
 
167
- return { action: 'listen' }
180
+ ```
181
+ ■send=message
182
+ Found 12 flights. The cheapest is **$249**. Want me to book it?
183
+ ■send=button {"label": "Book flight", "action": "postback", "value": "book"}
184
+ ■send=button {"label": "Cancel", "action": "postback", "value": "cancel"}
185
+ ■next=listen
168
186
  ```
169
187
 
170
188
  ---
@@ -189,10 +207,7 @@ const result = await execute({
189
207
  const result = await execute({
190
208
  client,
191
209
  tools,
192
- chat: {
193
- transcript: conversationHistory,
194
- components: { Text, Button, Form },
195
- },
210
+ chat, // a Chat instance: components + transcript + message handler
196
211
  })
197
212
  ```
198
213
 
@@ -224,7 +239,9 @@ const searchFlights = new Tool({
224
239
  })
225
240
  ```
226
241
 
227
- Tools are exposed to agents with full TypeScript signatures. Agents call them like regular async functions.
242
+ 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.
243
+
244
+ 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).
228
245
 
229
246
  ### Objects: Namespaced State
230
247
 
@@ -286,19 +303,80 @@ const result = await execute({
286
303
  })
287
304
 
288
305
  if (result.is(TicketBooked)) {
289
- console.log('Booked:', result.value.ticketId) // Fully typed
306
+ console.log('Booked:', result.output.ticketId) // Fully typed
290
307
  }
291
308
  ```
292
309
 
293
- Agents use exits via return statements:
310
+ Agents invoke exits with a `■next` block:
311
+
312
+ ```
313
+ ■next=ticket_booked {"ticketId": "TKT-12345", "price": 299, "confirmation": "ABC123"}
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Streaming
319
+
320
+ With a streaming client (`CognitiveBeta` / Cognitive v2), everything an execution produces surfaces in real time:
294
321
 
295
322
  ```typescript
296
- return {
297
- action: 'ticket_booked',
298
- ticketId: 'TKT-12345',
299
- price: 299,
300
- confirmation: 'ABC123',
301
- }
323
+ const chat = new Chat({
324
+ components: [DefaultComponents.Text],
325
+ transcript: () => transcript,
326
+ handler: async (component) => finalizeBubble(component),
327
+ // Fires per token-chunk while the LLM is still generating
328
+ onMessageDelta: (delta) => appendToBubble(delta.id, delta.delta),
329
+ })
330
+
331
+ const result = await execute({
332
+ client, // CognitiveBeta
333
+ chat,
334
+ tools,
335
+ onTrace: ({ trace }) => {
336
+ if (trace.type === 'llm_call_started') showSpinner()
337
+ if (trace.type === 'code_generation_started') showStatus('writing code…')
338
+ if (trace.type === 'llm_call_success') showCode(trace.code)
339
+ if (trace.type === 'tool_call') showToolCall(trace)
340
+ },
341
+ })
342
+ ```
343
+
344
+ - **Message deltas** stream to your UI token-by-token (`handler` remains the authoritative delivery)
345
+ - **Live traces** cover the full turn lifecycle: `llm_call_started` → message deltas → `code_generation_started` → `llm_call_success` (with the code) → `tool_call`s → exit
346
+ - **Early execution**: the `■run` block starts executing while the tail of the response is still streaming, and the VM pre-warms the moment the model starts writing code
347
+
348
+ Forward these events over a websocket or SSE stream and your frontend renders the agent live — see [example 22](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/22_chat_streaming).
349
+
350
+ ### Token Usage & Timings
351
+
352
+ Every iteration reports what it consumed:
353
+
354
+ ```typescript
355
+ const { input, output, total, limit, context } = result.iteration.tokens
356
+ // context measures the prompt size by part (pre-truncation):
357
+ // { framework, instructions, tools, transcript, protocol, iterations, total }
358
+ console.log(`context used: ${Math.round((context.total / limit) * 100)}%`)
359
+
360
+ const { time_to_first_token, time_to_last_token } = result.iteration.llm
361
+
362
+ // Aggregated across all iterations:
363
+ console.log(result.tokens) // { input, output, total }
364
+ ```
365
+
366
+ ### Execution Options
367
+
368
+ ```typescript
369
+ const result = await execute({
370
+ client,
371
+ model: ['cerebras:gpt-oss-120b', 'anthropic:claude-haiku-4-5'], // fallback chain
372
+ reasoningEffort: 'low', // 'low' | 'medium' | 'high' | 'dynamic' | 'none'
373
+ options: {
374
+ loop: 5, // max iterations
375
+ timeout: 60_000, // VM execution timeout (ms)
376
+ maxTokens: 32_000, // context window cap: min(maxTokens, model max)
377
+ maxTimeToFirstToken: 5_000, // fall back to the next model if the first token is late (ms)
378
+ },
379
+ })
302
380
  ```
303
381
 
304
382
  ---
@@ -307,7 +385,7 @@ return {
307
385
 
308
386
  ### Thinking: Forced Reflection
309
387
 
310
- Prevent agents from rushing to conclusions:
388
+ Tools can force the agent to look at data before acting on it:
311
389
 
312
390
  ```typescript
313
391
  import { ThinkSignal } from 'llmz'
@@ -322,12 +400,12 @@ const complexAnalysis = new Tool({
322
400
  })
323
401
  ```
324
402
 
325
- Agents can also self-initiate thinking:
403
+ Agents self-initiate reflection by returning values from their code — the returned value is shown to them and they respond again:
326
404
 
327
- ```typescript
328
- // Agent-generated code
405
+ ```
406
+ ■run
329
407
  const data = await fetchLargeDataset()
330
- return { action: 'think' } // Pause to process information
408
+ return data.summary
331
409
  ```
332
410
 
333
411
  ### Snapshots: Pause and Resume
@@ -359,24 +437,30 @@ const result = await execute({
359
437
  const result = await execute({
360
438
  client,
361
439
  tools,
362
- hooks: {
363
- onTrace: (trace) => {
364
- // Non-blocking: log tool calls, errors, outputs
365
- logger.info(trace)
366
- },
367
- onExit: (exit) => {
368
- // Validate before allowing exit
369
- if (exit.action === 'transfer_money' && exit.amount > 10000) {
370
- throw new Error('Amount exceeds limit')
371
- }
372
- },
373
- onBeforeExecution: (code) => {
374
- // Inspect/modify generated code before execution
375
- if (code.includes('dangerousOperation')) {
376
- throw new Error('Blocked unsafe operation')
377
- }
378
- },
440
+
441
+ // Non-blocking: observe everything (and abort when needed)
442
+ onTrace: ({ trace, controller }) => {
443
+ logger.info(trace)
444
+ if (trace.type === 'tool_call' && trace.tool_name === 'forbidden') {
445
+ controller.abort('Forbidden tool call')
446
+ }
447
+ },
448
+
449
+ // Validate before allowing an exit — throw to retry, abort to stop
450
+ onExit: (result, controller) => {
451
+ if (result.exit.name === 'transfer_money' && result.result.amount > 10_000) {
452
+ throw new Error('Amount exceeds limit')
453
+ }
454
+ },
455
+
456
+ // Inspect/modify generated code before execution
457
+ onBeforeExecution: (iteration) => {
458
+ if (iteration.code?.includes('dangerousOperation')) {
459
+ return { code: '// blocked' }
460
+ }
379
461
  },
462
+
463
+ // Also available: onIterationStart, onIterationEnd, onBeforeTool, onAfterTool
380
464
  })
381
465
  ```
382
466
 
@@ -400,7 +484,7 @@ LLMz has been running in production for over a year:
400
484
  - **Hundreds of thousands** of deployed agents handling real-world workloads
401
485
  - **Secure sandbox**: Uses QuickJS WASM for isolated code execution
402
486
  - **Type-safe**: Full TypeScript inference and Zui validation
403
- - **Observable**: Comprehensive tracing and error handling
487
+ - **Observable**: Comprehensive tracing, token accounting and error handling
404
488
 
405
489
  ---
406
490
 
@@ -409,10 +493,10 @@ LLMz has been running in production for over a year:
409
493
  **Execution Pipeline:**
410
494
 
411
495
  1. **Prompt Generation**: Injects tools, schemas, and context into dual-mode prompts
412
- 2. **Code Generation**: LLM generates TypeScript with tool calls and logic
413
- 3. **Compilation**: Babel AST transformation with custom plugins (tracking, JSX, source maps)
414
- 4. **Execution**: Runs in QuickJS WASM sandbox with full isolation
415
- 5. **Result Processing**: Type-safe exit handling and error recovery
496
+ 2. **Streaming Generation**: The LLM streams ■ blocks — messages dispatch to the chat as they are parsed
497
+ 3. **Compilation**: Babel AST transformation with instrumentation plugins (line tracking, tool call tracking, variable extraction)
498
+ 4. **Execution**: Runs in QuickJS WASM sandbox with full isolation — starting while the response tail is still streaming
499
+ 5. **Result Processing**: Type-safe exit handling, thinking loops and error recovery
416
500
 
417
501
  **Security:**
418
502
 
@@ -432,6 +516,7 @@ LLMz has been running in production for over a year:
432
516
  | Multi-tool orchestration | Multiple LLM calls | Multiple LLM calls | Single LLM call |
433
517
  | Complex logic | Limited | Limited | Full language support |
434
518
  | Type safety | Partial | Schema-based | Full TypeScript + Zui |
519
+ | Streaming | Text only | Text only | Messages, code, tools |
435
520
  | Execution environment | Python/JS runtime | Cross-process | QuickJS WASM sandbox |
436
521
  | Cost (complex workflows) | High (many roundtrips) | High (many roundtrips) | Low (one-shot generation) |
437
522
  | Production scale | Varies | Emerging | Battle-tested (1M+ users) |
@@ -442,28 +527,30 @@ LLMz has been running in production for over a year:
442
527
 
443
528
  Check out the [examples folder](https://github.com/botpress/botpress/tree/master/packages/llmz/examples) for complete working examples:
444
529
 
445
- | Title | Mode | Description |
446
- | --------------------------------------------------------------------------------------------------------------------- | ------ | ---------------------------------------------------- |
447
- | [Basic Chat](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/01_chat_basic) | Chat | Simple interactive chat with button-based navigation |
448
- | [Chat with Exits](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/02_chat_exits) | Chat | Custom exit conditions with type-safe validation |
449
- | [Conditional Tools](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/03_chat_conditional_tool) | Chat | Dynamic tool availability based on context |
450
- | [Small Models](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/04_chat_small_models) | Chat | Optimized prompts for smaller language models |
451
- | [Web Search](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/05_chat_web_search) | Chat | Integrate web search and content browsing |
452
- | [Tool Confirmation](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/06_chat_confirm_tool) | Chat | User confirmation before executing tools |
453
- | [Guardrails](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/07_chat_guardrails) | Chat | Safety constraints and content filtering |
454
- | [Multi-Agent](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/08_chat_multi_agent) | Chat | Coordinating multiple agents in one system |
455
- | [Variables](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/09_chat_variables) | Chat | Stateful properties that persist across iterations |
456
- | [Components](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/10_chat_components) | Chat | Rich UI components for interactive experiences |
457
- | [Minimal Worker](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/11_worker_minimal) | Worker | One-shot computational task execution |
458
- | [File System](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/12_worker_fs) | Worker | Automated file operations with conditional logic |
459
- | [Sandbox](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/13_worker_sandbox) | Worker | Secure isolated code execution environment |
460
- | [Snapshots](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/14_worker_snapshot) | Worker | Pause and resume long-running workflows |
461
- | [Stack Traces](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/15_worker_stacktraces) | Worker | Error handling and debugging patterns |
462
- | [Tool Chaining](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/16_worker_tool_chaining) | Worker | Sequential multi-tool orchestration |
463
- | [Error Recovery](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/17_worker_error_recovery) | Worker | Graceful failure handling and retries |
464
- | [Security](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/18_worker_security) | Worker | Code inspection and security validation |
465
- | [Wrap Tools](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/19_worker_wrap_tool) | Worker | Creating higher-order tool abstractions |
466
- | [RAG](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/20_chat_rag) | Chat | Retrieval-augmented generation with knowledge bases |
530
+ | Title | Mode | Description |
531
+ | --------------------------------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------- |
532
+ | [Basic Chat](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/01_chat_basic) | Chat | Simple interactive chat with button-based navigation |
533
+ | [Chat with Exits](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/02_chat_exits) | Chat | Custom exit conditions with type-safe validation |
534
+ | [Conditional Tools](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/03_chat_conditional_tool) | Chat | Dynamic tool availability based on context |
535
+ | [Small Models](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/04_chat_small_models) | Chat | Optimized prompts for smaller language models |
536
+ | [Web Search](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/05_chat_web_search) | Chat | Integrate web search and content browsing |
537
+ | [Tool Confirmation](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/06_chat_confirm_tool) | Chat | User confirmation before executing tools |
538
+ | [Guardrails](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/07_chat_guardrails) | Chat | Safety constraints and content filtering |
539
+ | [Multi-Agent](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/08_chat_multi_agent) | Chat | Coordinating multiple agents in one system |
540
+ | [Variables](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/09_chat_variables) | Chat | Stateful properties that persist across iterations |
541
+ | [Components](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/10_chat_components) | Chat | Rich UI components for interactive experiences |
542
+ | [Minimal Worker](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/11_worker_minimal) | Worker | One-shot computational task execution |
543
+ | [File System](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/12_worker_fs) | Worker | Automated file operations with conditional logic |
544
+ | [Sandbox](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/13_worker_sandbox) | Worker | Secure isolated code execution environment |
545
+ | [Snapshots](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/14_worker_snapshot) | Worker | Pause and resume long-running workflows |
546
+ | [Stack Traces](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/15_worker_stacktraces) | Worker | Error handling and debugging patterns |
547
+ | [Tool Chaining](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/16_worker_tool_chaining) | Worker | Sequential multi-tool orchestration |
548
+ | [Error Recovery](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/17_worker_error_recovery) | Worker | Graceful failure handling and retries |
549
+ | [Security](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/18_worker_security) | Worker | Code inspection and security validation |
550
+ | [Wrap Tools](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/19_worker_wrap_tool) | Worker | Creating higher-order tool abstractions |
551
+ | [RAG](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/20_chat_rag) | Chat | Retrieval-augmented generation with knowledge bases |
552
+ | [Tool Components](https://github.com/botpress/botpress/tree/master/packages/llmz/examples/21_chat_tool_components) | Chat | Tool handlers pushing UI components mid-execution |
553
+ | [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 |
467
554
 
468
555
  ---
469
556
 
package/dist/chat.d.ts CHANGED
@@ -25,6 +25,33 @@ import { TranscriptArray, Transcript } from './transcript.js';
25
25
  * ```
26
26
  */
27
27
  export type MessageHandler = (input: RenderedComponent) => Promise<void> | void;
28
+ /**
29
+ * A chunk of a message body streamed live from the LLM, before the message is complete.
30
+ *
31
+ * On streaming cognitive clients, message bodies (`■send` blocks) arrive token by token.
32
+ * Each chunk is forwarded to {@link Chat} `onMessageDelta` as soon as it is parsed, so the
33
+ * client can render the message progressively (e.g. typewriter effect in a chat UI).
34
+ *
35
+ * The complete message is always delivered to the regular `handler` afterwards — deltas
36
+ * are a progressive preview, the `handler` call remains the authoritative delivery.
37
+ */
38
+ export type MessageDelta = {
39
+ /** Identifies the message being streamed. Unique within an `execute()` call. */
40
+ id: string;
41
+ /** Component name of the message being streamed (e.g. 'message', 'button'). */
42
+ component: string;
43
+ /** Props of the message being streamed. Final by the time the body starts streaming. */
44
+ props: Record<string, unknown>;
45
+ /** The new chunk of body text. */
46
+ delta: string;
47
+ /** The full body text accumulated so far, including this chunk. */
48
+ content: string;
49
+ };
50
+ /**
51
+ * Function type for handling message chunks as they are streamed from the LLM.
52
+ * Errors thrown by this handler are ignored — streaming previews are best-effort.
53
+ */
54
+ export type MessageDeltaHandler = (delta: MessageDelta) => Promise<void> | void;
28
55
  /**
29
56
  * Base class for implementing chat interfaces in LLMz agents.
30
57
  *
@@ -227,6 +254,7 @@ export type MessageHandler = (input: RenderedComponent) => Promise<void> | void;
227
254
  */
228
255
  export declare class Chat {
229
256
  readonly handler: MessageHandler;
257
+ readonly onMessageDelta?: MessageDeltaHandler;
230
258
  readonly transcript: ValueOrGetter<TranscriptArray, Context>;
231
259
  readonly components: ValueOrGetter<Component[], Context>;
232
260
  /**
@@ -279,6 +307,12 @@ export declare class Chat {
279
307
  */
280
308
  constructor(props: {
281
309
  handler: MessageHandler;
310
+ /**
311
+ * Called with each message body chunk as it is streamed from the LLM (streaming
312
+ * clients only). Enables progressive rendering; the complete message is still
313
+ * delivered to `handler` once fully parsed.
314
+ */
315
+ onMessageDelta?: MessageDeltaHandler;
282
316
  components: ValueOrGetter<Component[], Context>;
283
317
  transcript?: ValueOrGetter<Transcript.Message[], Context>;
284
318
  });