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.
@@ -0,0 +1,231 @@
1
+ import {
2
+ isJsonSchema,
3
+ isValidIdentifier,
4
+ isZuiSchema
5
+ } from "./chunk-4MNIJGK6.js";
6
+ import {
7
+ uniq_default
8
+ } from "./chunk-7WRN4E42.js";
9
+
10
+ // src/exit.ts
11
+ import { transforms } from "@bpinternal/zui";
12
+ var Exit = class _Exit {
13
+ /** The primary name of the exit (used in return statements) */
14
+ name;
15
+ /** Alternative names that can be used to reference this exit */
16
+ aliases = [];
17
+ /** Human-readable description of when this exit should be used */
18
+ description;
19
+ /** Additional metadata for orchestration and custom logic */
20
+ metadata;
21
+ /** JSON Schema for validating exit result data */
22
+ schema;
23
+ /**
24
+ * Returns the Zod schema equivalent of the JSON schema (if available).
25
+ * Used internally for validation and type inference.
26
+ */
27
+ get zSchema() {
28
+ return this.schema ? transforms.fromJSONSchemaLegacy(this.schema) : void 0;
29
+ }
30
+ /**
31
+ * Renames the exit and updates aliases accordingly.
32
+ *
33
+ * @param name - The new name for the exit (must be a valid identifier)
34
+ * @returns This exit instance for chaining
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const exit = new Exit({ name: 'old_name', description: 'Test exit' })
39
+ * exit.rename('new_name')
40
+ * console.log(exit.name) // 'new_name'
41
+ * ```
42
+ */
43
+ rename(name) {
44
+ const before = this.name;
45
+ if (!isValidIdentifier(name)) {
46
+ throw new Error(
47
+ `Invalid name for exit ${name}. An exit name must start with a letter and contain only letters, numbers, and underscores. It must be 1-50 characters long.`
48
+ );
49
+ }
50
+ this.name = name;
51
+ this.aliases = uniq_default([name, ...this.aliases.map((alias) => alias === before ? name : alias)]);
52
+ return this;
53
+ }
54
+ /**
55
+ * Creates a deep copy of this exit.
56
+ *
57
+ * The clone is completely independent and can be modified without affecting
58
+ * the original exit. This is useful for creating variations of existing exits.
59
+ *
60
+ * @returns A new Exit instance with the same configuration
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const originalExit = new Exit({
65
+ * name: 'base',
66
+ * description: 'Base exit',
67
+ * schema: z.object({ status: z.string() }),
68
+ * })
69
+ *
70
+ * const customExit = originalExit.clone().rename('custom')
71
+ * // customExit is independent of originalExit
72
+ * ```
73
+ */
74
+ clone() {
75
+ return new _Exit({
76
+ name: this.name,
77
+ aliases: [...this.aliases],
78
+ description: this.description,
79
+ metadata: JSON.parse(JSON.stringify(this.metadata)),
80
+ schema: this.zSchema
81
+ });
82
+ }
83
+ /**
84
+ * Type guard to check if this exit matches another exit by name.
85
+ *
86
+ * Used internally for type narrowing and exit comparison.
87
+ *
88
+ * @param exit - The exit to compare against
89
+ * @returns True if the exits have the same name
90
+ */
91
+ is(exit) {
92
+ return this.name === exit.name;
93
+ }
94
+ /**
95
+ * Type guard to check if an ExitResult matches this exit.
96
+ *
97
+ * @param result - The exit result to check
98
+ * @returns True if the result was created by this exit
99
+ */
100
+ match(result) {
101
+ return result.exit instanceof _Exit && this.name === result.exit.name;
102
+ }
103
+ /**
104
+ * Creates a new Exit instance.
105
+ *
106
+ * @param props - Exit configuration
107
+ * @param props.name - Primary name for the exit (must be valid identifier)
108
+ * @param props.description - Human-readable description of the exit's purpose
109
+ * @param props.aliases - Alternative names that can be used to reference this exit
110
+ * @param props.metadata - Additional data for orchestration and custom logic
111
+ * @param props.schema - Zod schema for validating exit result data
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * // Simple exit without data validation
116
+ * const exit = new Exit({
117
+ * name: 'complete',
118
+ * description: 'Task completed successfully',
119
+ * })
120
+ * ```
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * // Exit with typed result data
125
+ * const approval = new Exit({
126
+ * name: 'approved',
127
+ * description: 'Request approved by system',
128
+ * schema: z.object({
129
+ * amount: z.number().positive(),
130
+ * reference: z.string().min(1),
131
+ * timestamp: z.date().default(() => new Date()),
132
+ * }),
133
+ * })
134
+ * ```
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * // Exit with aliases and metadata
139
+ * const handoff = new Exit({
140
+ * name: 'handoff_support',
141
+ * aliases: ['escalate', 'transfer'],
142
+ * description: 'Transfer to human support agent',
143
+ * metadata: {
144
+ * department: 'customer_service',
145
+ * priority: 'high',
146
+ * },
147
+ * schema: z.object({
148
+ * reason: z.string(),
149
+ * customerData: z.record(z.any()),
150
+ * }),
151
+ * })
152
+ * ```
153
+ */
154
+ constructor(props) {
155
+ if (!isValidIdentifier(props.name)) {
156
+ throw new Error(
157
+ `Invalid name for exit ${props.name}. A exit name must start with a letter and contain only letters, numbers, and underscores. It must be 1-50 characters long.`
158
+ );
159
+ }
160
+ if (typeof props.description !== "string" || props.description.trim().length === 0) {
161
+ throw new Error(
162
+ `Invalid description for exit ${props.name}. Expected a non-empty string, but got type "${typeof props.description}"`
163
+ );
164
+ }
165
+ if (props.metadata !== void 0 && typeof props.metadata !== "object") {
166
+ throw new Error(
167
+ `Invalid metadata for exit ${props.name}. Expected an object, but got type "${typeof props.metadata}"`
168
+ );
169
+ }
170
+ if (props.aliases !== void 0 && !Array.isArray(props.aliases)) {
171
+ throw new Error(
172
+ `Invalid aliases for exit ${props.name}. Expected an array, but got type "${typeof props.aliases}"`
173
+ );
174
+ }
175
+ if (props.aliases && props.aliases.some((alias) => !isValidIdentifier(alias))) {
176
+ throw new Error(`Invalid aliases for exit ${props.name}. Expected an array of valid identifiers.`);
177
+ }
178
+ if (typeof props.schema !== "undefined") {
179
+ if (isZuiSchema(props.schema)) {
180
+ this.schema = transforms.toJSONSchemaLegacy(props.schema);
181
+ } else if (isJsonSchema(props.schema)) {
182
+ this.schema = props.schema;
183
+ } else {
184
+ throw new Error(
185
+ `Invalid input schema for exit ${props.name}. Expected a ZodType or JSONSchema, but got type "${typeof props.schema}"`
186
+ );
187
+ }
188
+ }
189
+ this.name = props.name;
190
+ this.aliases = uniq_default([props.name, ...props.aliases ?? []]);
191
+ this.description = props.description;
192
+ this.metadata = props.metadata ?? {};
193
+ }
194
+ /**
195
+ * Ensures all exits in an array have unique names by renaming duplicates.
196
+ *
197
+ * When multiple exits have the same name, this method appends numbers to
198
+ * create unique names (e.g., 'exit1', 'exit2'). This prevents naming conflicts
199
+ * in execution contexts with multiple exits.
200
+ *
201
+ * @param exits - Array of exits that may have duplicate names
202
+ * @returns Array of exits with guaranteed unique names
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * const exit1 = new Exit({ name: 'done', description: 'First done' })
207
+ * const exit2 = new Exit({ name: 'done', description: 'Second done' })
208
+ *
209
+ * const uniqueExits = Exit.withUniqueNames([exit1, exit2])
210
+ * // Result: [{ name: 'done' }, { name: 'done1' }]
211
+ * ```
212
+ */
213
+ static withUniqueNames = (exits) => {
214
+ const names = /* @__PURE__ */ new Set();
215
+ return exits.map((exit) => {
216
+ if (exits.filter((t) => t.name === exit.name).length === 1) {
217
+ return exit;
218
+ }
219
+ let counter = 1;
220
+ let exitName = exit.name + counter;
221
+ while (names.has(exitName)) {
222
+ exitName = `${exit.name}${++counter}`;
223
+ }
224
+ return exit.rename(exitName);
225
+ });
226
+ };
227
+ };
228
+
229
+ export {
230
+ Exit
231
+ };
package/dist/context.d.ts CHANGED
@@ -79,8 +79,220 @@ export declare namespace IterationStatuses {
79
79
  };
80
80
  };
81
81
  }
82
+ /**
83
+ * Built-in exit for requesting thinking time during agent execution.
84
+ *
85
+ * The ThinkExit allows agents to pause execution and reflect on the current situation,
86
+ * variables, and context before continuing. There are two ways to trigger thinking:
87
+ *
88
+ * 1. **Agent-initiated**: Agent calls `return { action: 'think' }` to pause and reflect
89
+ * 2. **Tool/Hook-initiated**: Tools or hooks throw `ThinkSignal` to force agent reflection
90
+ *
91
+ * This exit is automatically available in all LLMz executions and is commonly used for:
92
+ * - Complex decision making that requires analysis
93
+ * - Debugging and understanding current variable state
94
+ * - Planning multi-step operations
95
+ * - Tool feedback and result processing
96
+ * - Reflecting on previous iterations and results
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * // Agent retrieves web search results and decides to think about them
101
+ * const results = await searchWeb(query)
102
+ *
103
+ * // Agent decides it needs to think (look at the search results) before responding
104
+ * return { action: 'think', results }
105
+ * ```
106
+ *
107
+ * Sometimes, as the author of the tool, you may want to always force the agent to think about the results.
108
+ * In this case, you can throw a `ThinkSignal` from the tool handler to trigger thinking.
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * // Tool-initiated thinking using ThinkSignal
113
+ * import { ThinkSignal } from 'llmz'
114
+ *
115
+ * const searchTool = new Tool({
116
+ * name: 'search',
117
+ * handler: async ({ query }) => {
118
+ * const results = await performSearch(query)
119
+ *
120
+ * if (!results.length) {
121
+ * // Force agent to think about alternative approaches
122
+ * throw new ThinkSignal(
123
+ * 'No search results found',
124
+ * 'No results were found. Consider rephrasing the query or using a different approach.'
125
+ * )
126
+ * }
127
+ *
128
+ * // Provide context for agent to process results
129
+ * throw new ThinkSignal(
130
+ * 'Search completed with results',
131
+ * `Found ${results.length} results. Process them carefully and provide citations.`
132
+ * )
133
+ * }
134
+ * })
135
+ * ```
136
+ * When an iteration ends with ThinkExit, the agent will automatically loop and start a new iteration to continue processing, unless iteration limit is reached.
137
+ *
138
+ * The thinking process helps agents:
139
+ * - Avoid rushing into incorrect solutions
140
+ * - Better understand complex problems and tool results
141
+ * - Maintain variable state across iterations
142
+ * - Process feedback from tools and hooks
143
+ * - Provide more thoughtful and accurate responses
144
+ */
82
145
  export declare const ThinkExit: Exit<unknown>;
146
+ /**
147
+ * Built-in exit for waiting for user input in chat mode.
148
+ *
149
+ * The ListenExit is automatically available when chat mode is enabled (when a Chat
150
+ * instance is provided to execute()). When an agent calls `return { action: 'listen' }`,
151
+ * the execution pauses and waits for user input before continuing the conversation.
152
+ *
153
+ * This exit is essential for interactive conversational agents and is used to:
154
+ * - Wait for user responses in chat interfaces
155
+ * - Pause execution until user provides input
156
+ * - Enable back-and-forth conversation flow
157
+ * - Allow users to guide the conversation direction
158
+ *
159
+ * The ListenExit is only available in chat mode - it will not be present in
160
+ * worker mode executions where no chat interface is provided.
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * // Agent generated code using ListenExit in chat mode
165
+ * yield <Message>What would you like me to help you with today?</Message>
166
+ * yield <Button action="postback" label="Get Weather" value="weather" />
167
+ * yield <Button action="postback" label="Set Reminder" value="reminder" />
168
+ *
169
+ * // Wait for user to respond
170
+ * return { action: 'listen' }
171
+ * ```
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * // Standard chat interaction pattern
176
+ * const calculation = 2 + 8
177
+ * yield <Message>The result of `2 + 8` is **{calculation}**.</Message>
178
+ * return { action: 'listen' }
179
+ * ```
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * // CLI chat example with ListenExit handling
184
+ * const chat = new CLIChat()
185
+ *
186
+ * while (chat.iterate()) {
187
+ * const result = await execute({
188
+ * instructions: 'Help the user with their questions',
189
+ * chat,
190
+ * client,
191
+ * })
192
+ *
193
+ * if (result.is(ListenExit)) {
194
+ * // CLIChat handles prompting user automatically
195
+ * continue
196
+ * } else {
197
+ * console.log('Conversation ended')
198
+ * break
199
+ * }
200
+ * }
201
+ * ```
202
+ *
203
+ * The ListenExit enables natural conversation flow where:
204
+ * - Agent sends messages and waits for responses
205
+ * - User provides input to guide the conversation
206
+ * - Conversation continues iteratively until completion
207
+ * - Chat interface manages the input/output cycle
208
+ */
83
209
  export declare const ListenExit: Exit<unknown>;
210
+ /**
211
+ * Default exit used when no custom exits are provided.
212
+ *
213
+ * The DefaultExit is automatically used in worker mode when no custom exits are defined.
214
+ * It provides a standard way to complete execution with either success or failure outcomes.
215
+ * The exit uses a discriminated union schema to ensure type-safe handling of both success
216
+ * and error cases.
217
+ *
218
+ * This exit is commonly used for:
219
+ * - Simple worker mode executions without custom completion logic
220
+ * - Standardized success/failure reporting
221
+ * - Basic task completion with result or error information
222
+ * - Default fallback when no specific exit behavior is needed
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * // Agent generated code using DefaultExit for successful completion
227
+ * const data = await fetchUserData(userId)
228
+ * const processedResult = processData(data)
229
+ *
230
+ * return {
231
+ * action: 'done',
232
+ * success: true,
233
+ * result: processedResult
234
+ * }
235
+ * ```
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * // Agent generated code using DefaultExit for error cases
240
+ * try {
241
+ * const result = await riskyOperation()
242
+ * return { action: 'done', success: true, result }
243
+ * } catch (error) {
244
+ * return {
245
+ * action: 'done',
246
+ * success: false,
247
+ * error: `Operation failed: ${error.message}`
248
+ * }
249
+ * }
250
+ * ```
251
+ *
252
+ * @example
253
+ * ```typescript
254
+ * import { execute, DefaultExit } from 'llmz'
255
+ *
256
+ * // Handling DefaultExit in execution results
257
+ * const result = await execute({
258
+ * instructions: 'Process the user data and return results',
259
+ * // No custom exits provided - DefaultExit will be used
260
+ * client,
261
+ * })
262
+ *
263
+ * if (result.is(DefaultExit)) {
264
+ * if (result.output.success) {
265
+ * console.log('Success:', result.output.result)
266
+ * } else {
267
+ * console.error('Error:', result.output.error)
268
+ * }
269
+ * }
270
+ * ```
271
+ *
272
+ * @example
273
+ * ```typescript
274
+ * // Worker mode execution with automatic DefaultExit
275
+ * const result = await execute({
276
+ * instructions: 'Calculate fibonacci numbers up to 100',
277
+ * tools: [mathTools],
278
+ * client,
279
+ * // No chat provided = worker mode
280
+ * // No exits provided = DefaultExit automatically added
281
+ * })
282
+ *
283
+ * // Result will use DefaultExit for completion
284
+ * if (result.isSuccess() && result.is(DefaultExit)) {
285
+ * const { success, result: data, error } = result.output
286
+ * // Handle success/failure cases
287
+ * }
288
+ * ```
289
+ *
290
+ * The DefaultExit provides a consistent interface for:
291
+ * - Type-safe success/failure handling
292
+ * - Standardized result reporting across different executions
293
+ * - Automatic fallback behavior when no custom exits are defined
294
+ * - Clear separation between successful results and error conditions
295
+ */
84
296
  export declare const DefaultExit: Exit<{
85
297
  success: true;
86
298
  result?: any;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Exit
3
- } from "./chunk-JMSZKB4T.js";
3
+ } from "./chunk-XAN7HQP5.js";
4
4
  import "./chunk-4MNIJGK6.js";
5
5
  import "./chunk-7WRN4E42.js";
6
6
  export {
@@ -1,8 +1,8 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkGWFYZDURcjs = require('./chunk-GWFYZDUR.cjs');
3
+ var _chunkWL7ZIMYDcjs = require('./chunk-WL7ZIMYD.cjs');
4
4
  require('./chunk-276Q6EWP.cjs');
5
5
  require('./chunk-UQOBUJIQ.cjs');
6
6
 
7
7
 
8
- exports.Exit = _chunkGWFYZDURcjs.Exit;
8
+ exports.Exit = _chunkWL7ZIMYDcjs.Exit;