llmz 0.0.12 → 0.0.14

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/dist/chat.d.ts CHANGED
@@ -3,15 +3,340 @@ import { Context } from './context.js';
3
3
  import { ValueOrGetter } from './getter.js';
4
4
  import { ExecutionResult } from './result.js';
5
5
  import { TranscriptArray, Transcript } from './transcript.js';
6
+ /**
7
+ * Function type for handling messages sent from the agent to the user.
8
+ *
9
+ * The handler receives rendered components from the agent and is responsible for
10
+ * presenting them to the user through the appropriate interface (CLI, web UI, mobile app, etc.).
11
+ * This is how the agent communicates with the user.
12
+ *
13
+ * @param input - The rendered component to display to the user
14
+ * @returns Promise that resolves when the message has been handled
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const handler: MessageHandler = async (input) => {
19
+ * if (isComponent(input, DefaultComponents.Text)) {
20
+ * console.log('Agent:', input.children.join(''))
21
+ * } else if (isComponent(input, DefaultComponents.Button)) {
22
+ * console.log('Button:', input.props.label)
23
+ * }
24
+ * }
25
+ * ```
26
+ */
6
27
  export type MessageHandler = (input: RenderedComponent) => Promise<void> | void;
28
+ /**
29
+ * Base class for implementing chat interfaces in LLMz agents.
30
+ *
31
+ * The Chat class provides the foundation for interactive conversational agents by defining
32
+ * how agents communicate with users. It manages the conversation transcript, available UI
33
+ * components, and message handling. This is the bridge between the agent's generated code
34
+ * and your user interface.
35
+ *
36
+ * ## Key Concepts
37
+ *
38
+ * **Handler Function**: The core method that receives agent messages (rendered components)
39
+ * and displays them to the user. This is called every time the agent wants to communicate.
40
+ *
41
+ * **Transcript**: An up-to-date conversation history that is evaluated at each iteration.
42
+ * The transcript must reflect the complete conversation state as the agent uses it to
43
+ * understand context and generate appropriate responses.
44
+ *
45
+ * **Components**: The UI elements available to the agent for creating rich interactive
46
+ * experiences (text, buttons, images, cards, etc.).
47
+ *
48
+ * ## Implementation Requirements
49
+ *
50
+ * To create a functional chat interface, you must:
51
+ * 1. Implement the MessageHandler to display agent messages to users
52
+ * 2. Maintain an accurate transcript of the conversation
53
+ * 3. Provide the available UI components (typically includes DefaultComponents)
54
+ * 4. Optional: Override onExecutionDone() to handle execution completion
55
+ *
56
+ * ## Basic Implementation
57
+ *
58
+ * ```typescript
59
+ * import { Chat, DefaultComponents, isComponent } from 'llmz'
60
+ *
61
+ * class MyChat extends Chat {
62
+ * private messages: Array<{role: 'user' | 'assistant', content: string}> = []
63
+ *
64
+ * constructor() {
65
+ * super({
66
+ * // Handle agent messages - this is called for every agent output
67
+ * handler: async (input) => {
68
+ * if (isComponent(input, DefaultComponents.Text)) {
69
+ * const text = input.children.join('')
70
+ * console.log('Agent:', text)
71
+ * this.messages.push({ role: 'assistant', content: text })
72
+ * } else if (isComponent(input, DefaultComponents.Button)) {
73
+ * console.log('Button:', input.props.label)
74
+ * }
75
+ * },
76
+ *
77
+ * // Provide available components - agent can use these in generated code
78
+ * components: [DefaultComponents.Text, DefaultComponents.Button],
79
+ *
80
+ * // Return current transcript - evaluated at each iteration
81
+ * transcript: () => this.messages,
82
+ * })
83
+ * }
84
+ *
85
+ * // Add user message to transcript
86
+ * addUserMessage(content: string) {
87
+ * this.messages.push({ role: 'user', content })
88
+ * }
89
+ * }
90
+ *
91
+ * // Usage
92
+ * const chat = new MyChat()
93
+ * chat.addUserMessage('Hello!')
94
+ *
95
+ * const result = await execute({
96
+ * instructions: 'You are a helpful assistant',
97
+ * chat, // Enable chat mode
98
+ * client,
99
+ * })
100
+ * ```
101
+ *
102
+ * ## Advanced Implementation (CLIChat Example)
103
+ *
104
+ * ```typescript
105
+ * import { Chat, DefaultComponents, ListenExit } from 'llmz'
106
+ *
107
+ * class CLIChat extends Chat {
108
+ * public transcript: Array<{role: 'user' | 'assistant', content: string}> = []
109
+ * private buttons: string[] = []
110
+ * public result?: ExecutionResult
111
+ *
112
+ * constructor() {
113
+ * super({
114
+ * // Dynamic component list with custom renderers
115
+ * components: () => [
116
+ * DefaultComponents.Text,
117
+ * DefaultComponents.Button,
118
+ * ...this.customComponents
119
+ * ],
120
+ *
121
+ * // Dynamic transcript access
122
+ * transcript: () => this.transcript,
123
+ *
124
+ * // Sophisticated message handling
125
+ * handler: async (input) => {
126
+ * if (isComponent(input, DefaultComponents.Text)) {
127
+ * const text = input.children.join('')
128
+ * console.log('🤖 Agent:', text)
129
+ * this.transcript.push({ role: 'assistant', content: text })
130
+ * } else if (isComponent(input, DefaultComponents.Button)) {
131
+ * this.buttons.push(input.props.label)
132
+ * }
133
+ * },
134
+ * })
135
+ * }
136
+ *
137
+ * // Handle execution completion
138
+ * onExecutionDone(result: ExecutionResult) {
139
+ * this.result = result
140
+ * }
141
+ *
142
+ * // Check if agent is waiting for user input
143
+ * isWaitingForInput(): boolean {
144
+ * return this.result?.is(ListenExit) ?? false
145
+ * }
146
+ *
147
+ * // Conversation loop
148
+ * async iterate(): Promise<boolean> {
149
+ * if (this.isWaitingForInput()) {
150
+ * const userInput = await this.promptUser()
151
+ * this.transcript.push({ role: 'user', content: userInput })
152
+ * return true // Continue conversation
153
+ * }
154
+ * return false // End conversation
155
+ * }
156
+ * }
157
+ * ```
158
+ *
159
+ * ## Component System
160
+ *
161
+ * The agent generates JSX code using available components:
162
+ *
163
+ * ```typescript
164
+ * // Agent generates this TSX code:
165
+ * yield <Text>Welcome! Choose an option:</Text>
166
+ * yield <Button action="postback" label="Get Help" value="help" />
167
+ * yield <Button action="postback" label="Contact Sales" value="sales" />
168
+ *
169
+ * // Your handler receives these as RenderedComponent objects
170
+ * ```
171
+ *
172
+ * ## Transcript Management
173
+ *
174
+ * The transcript is critical for agent context and must be kept up-to-date:
175
+ *
176
+ * ```typescript
177
+ * // ❌ Bad - static transcript
178
+ * transcript: [{ role: 'user', content: 'Hello' }]
179
+ *
180
+ * // ✅ Good - dynamic transcript that reflects current state
181
+ * transcript: () => this.messages
182
+ *
183
+ * // The transcript is evaluated at each iteration, so the agent
184
+ * // always sees the current conversation state
185
+ * ```
186
+ *
187
+ * ## Custom Components
188
+ *
189
+ * Extend the UI with custom components for your specific use case:
190
+ *
191
+ * ```typescript
192
+ * import { Component } from 'llmz'
193
+ *
194
+ * const ProductCard = new Component({
195
+ * type: 'leaf',
196
+ * name: 'ProductCard',
197
+ * leaf: {
198
+ * props: z.object({
199
+ * name: z.string(),
200
+ * price: z.number(),
201
+ * imageUrl: z.string(),
202
+ * })
203
+ * }
204
+ * })
205
+ *
206
+ * class ShoppingChat extends Chat {
207
+ * constructor() {
208
+ * super({
209
+ * components: [
210
+ * ...DefaultComponents,
211
+ * ProductCard, // Add custom component
212
+ * ],
213
+ * handler: async (input) => {
214
+ * if (isComponent(input, ProductCard)) {
215
+ * // Handle custom component rendering
216
+ * this.renderProduct(input.props)
217
+ * }
218
+ * // ... handle other components
219
+ * },
220
+ * })
221
+ * }
222
+ * }
223
+ * ```
224
+ *
225
+ * @see {@link DefaultComponents} For standard UI components
226
+ * @see {@link https://github.com/botpress/botpress/blob/master/packages/llmz/examples/utils/cli-chat.ts} Complete CLIChat implementation
227
+ */
7
228
  export declare class Chat {
8
229
  readonly handler: MessageHandler;
9
230
  readonly transcript: ValueOrGetter<TranscriptArray, Context>;
10
231
  readonly components: ValueOrGetter<Component[], Context>;
232
+ /**
233
+ * Creates a new Chat instance.
234
+ *
235
+ * @param props - Chat configuration
236
+ * @param props.handler - Function to handle agent messages (called for every agent output)
237
+ * @param props.components - Available UI components (static array or dynamic function)
238
+ * @param props.transcript - Conversation history (static array or dynamic function, defaults to empty)
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * // Basic chat with static configuration
243
+ * const chat = new Chat({
244
+ * handler: async (input) => {
245
+ * if (isComponent(input, DefaultComponents.Text)) {
246
+ * console.log('Agent:', input.children.join(''))
247
+ * }
248
+ * },
249
+ * components: [DefaultComponents.Text, DefaultComponents.Button],
250
+ * transcript: [
251
+ * { role: 'user', content: 'Hello', timestamp: Date.now() }
252
+ * ],
253
+ * })
254
+ * ```
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * // Dynamic chat with functions for real-time updates
259
+ * class MyChat extends Chat {
260
+ * private messages: Transcript.Message[] = []
261
+ *
262
+ * constructor() {
263
+ * super({
264
+ * handler: (input) => this.handleMessage(input),
265
+ *
266
+ * // Dynamic components - can change during execution
267
+ * components: () => [
268
+ * DefaultComponents.Text,
269
+ * DefaultComponents.Button,
270
+ * ...this.getCustomComponents()
271
+ * ],
272
+ *
273
+ * // Dynamic transcript - always reflects current state
274
+ * transcript: () => this.messages,
275
+ * })
276
+ * }
277
+ * }
278
+ * ```
279
+ */
11
280
  constructor(props: {
12
281
  handler: MessageHandler;
13
282
  components: ValueOrGetter<Component[], Context>;
14
283
  transcript?: ValueOrGetter<Transcript.Message[], Context>;
15
284
  });
285
+ /**
286
+ * Called when an execution cycle completes, regardless of the outcome.
287
+ *
288
+ * Override this method to handle execution results, manage conversation flow,
289
+ * or perform cleanup tasks. This is called after each `execute()` call completes,
290
+ * whether it succeeds, fails, or is interrupted.
291
+ *
292
+ * @param result - The execution result containing status, iterations, and exit information
293
+ *
294
+ * @example
295
+ * ```typescript
296
+ * class MyChat extends Chat {
297
+ * public result?: ExecutionResult
298
+ *
299
+ * onExecutionDone(result: ExecutionResult) {
300
+ * // Store result for conversation flow control
301
+ * this.result = result
302
+ *
303
+ * // Handle different result types
304
+ * if (result.isSuccess()) {
305
+ * console.log('✅ Execution completed successfully')
306
+ * console.log('Exit:', result.output.exit_name)
307
+ * } else if (result.isError()) {
308
+ * console.error('❌ Execution failed:', result.output.error)
309
+ * } else if (result.isInterrupted()) {
310
+ * console.log('⏸️ Execution interrupted (partial result)')
311
+ * }
312
+ * }
313
+ *
314
+ * // Use stored result for conversation flow
315
+ * isWaitingForInput(): boolean {
316
+ * return this.result?.is(ListenExit) ?? false
317
+ * }
318
+ * }
319
+ * ```
320
+ *
321
+ * @example
322
+ * ```typescript
323
+ * // CLIChat implementation example
324
+ * class CLIChat extends Chat {
325
+ * public status?: IterationStatus
326
+ * public result?: ExecutionResult
327
+ *
328
+ * onExecutionDone(result: ExecutionResult) {
329
+ * this.result = result
330
+ * this.status = result.iterations.at(-1)?.status
331
+ * }
332
+ *
333
+ * // Check if agent exited with specific exit type
334
+ * hasExitedWith<R>(exit: Exit<R>): boolean {
335
+ * return this.status?.type === 'exit_success' &&
336
+ * this.status.exit_success.exit_name === exit.name
337
+ * }
338
+ * }
339
+ * ```
340
+ */
16
341
  onExecutionDone(_result: ExecutionResult): void;
17
342
  }