@botpress/adk-cli 1.19.0-beta.4 → 1.19.0-beta.5
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/{README-wjb7z7f0.md → README-824wa4jj.md} +1 -1
- package/dist/SKILL-75ym6tcj.md +257 -0
- package/dist/SKILL-chnwzmt1.md +548 -0
- package/dist/SKILL-d4bs53y3.md +244 -0
- package/dist/SKILL-h4b2f1n9.md +114 -0
- package/dist/SKILL-hbw5nt95.md +111 -0
- package/dist/actions-h7hxxvxr.md +823 -0
- package/dist/adk-build-emhwd0tg.md +39 -0
- package/dist/adk-debug-yrrdtpmb.md +23 -0
- package/dist/adk-dev-console-7z9rtjpy.md +17 -0
- package/dist/adk-document-ras6zzzh.md +68 -0
- package/dist/adk-eval-vx76dwq0.md +17 -0
- package/dist/adk-explain-fcsaw852.md +22 -0
- package/dist/adk-init-9kmxmbbe.md +30 -0
- package/dist/adk-ship-dybzn884.md +29 -0
- package/dist/adk-test-xq67savs.md +27 -0
- package/dist/adk-validate-1p4skv4m.md +31 -0
- package/dist/advanced-patterns-z86m9h1a.md +669 -0
- package/dist/agent-config-1aqvkrgf.md +450 -0
- package/dist/agent-steps-zj4c1n9t.md +115 -0
- package/dist/assets-q7jt8r2q.md +237 -0
- package/dist/autonomous-execution-fymc12e5.md +747 -0
- package/dist/cli-c31e06yr.md +1334 -0
- package/dist/cli.js +970 -566
- package/dist/commands.json +24 -3
- package/dist/common-failures-ht29w2db.md +231 -0
- package/dist/component-registry-bbpw0see.md +43 -0
- package/dist/context-api-760cvh0h.md +461 -0
- package/dist/conversation-analysis-8ka4nrm4.md +420 -0
- package/dist/conversation-lifecycle-4seqqjc1.md +311 -0
- package/dist/conversations-gwfvxaee.md +1111 -0
- package/dist/custom-components-y5wdgpey.md +167 -0
- package/dist/debug-workflow-vz84q80v.md +239 -0
- package/dist/desk-k54ktvsd.md +852 -0
- package/dist/doc-standards-ck6ax2jd.md +124 -0
- package/dist/eval-format-7n9brja4.md +354 -0
- package/dist/evals-y1zcr1mc.md +11 -0
- package/dist/explain-config-1yaq3zzd.md +424 -0
- package/dist/files-dzt0wxn3.md +918 -0
- package/dist/integration-actions-xang7tma.md +659 -0
- package/dist/integrations-k5ss07f4.md +266 -0
- package/dist/interfaces-6t0bpxs4.md +97 -0
- package/dist/knowledge-bases-20rg8p5c.md +456 -0
- package/dist/llm-debugging-76ng8rzm.md +209 -0
- package/dist/mcp-server-n1asyzhv.md +112 -0
- package/dist/messages-gkkg0b54.md +769 -0
- package/dist/model-configuration-f273kgd0.md +201 -0
- package/dist/multi-agent-dashboard-1mdfjdts.md +70 -0
- package/dist/pages-xn18xn73.md +273 -0
- package/dist/patterns-mistakes-5vb99dhf.md +469 -0
- package/dist/plugins-ttnx8f49.md +280 -0
- package/dist/tables-x45t36dd.md +1136 -0
- package/dist/tags-46td3qrg.md +516 -0
- package/dist/test-patterns-hj47w4nc.md +355 -0
- package/dist/testing-workflow-2vkp932f.md +225 -0
- package/dist/tools-wk7bq24z.md +581 -0
- package/dist/trace-summarization-hdyx1c2e.md +313 -0
- package/dist/traces-and-logs-f2kjfh19.md +203 -0
- package/dist/triggers-4j2cc86x.md +719 -0
- package/dist/ui-server-entry.js +952 -137
- package/dist/workflow-steps-mrdrf1c5.md +851 -0
- package/dist/workflows-gadx3s69.md +1408 -0
- package/dist/zai-agent-reference-e6644aad.md +454 -0
- package/dist/zai-complete-guide-mnna5d6f.md +1408 -0
- package/package.json +4 -4
|
@@ -0,0 +1,747 @@
|
|
|
1
|
+
# Autonomous Execution
|
|
2
|
+
|
|
3
|
+
The `execute()` function is the core of AI-powered behavior in ADK bots. It runs a code-generating LLM in a sandboxed loop: the model writes TypeScript, the runtime executes it, and the loop continues until an exit is reached or iterations are exhausted.
|
|
4
|
+
|
|
5
|
+
This reference covers **Objects, Exits, execution hooks, and configuration options**. For basic tool definition and handler patterns, see [tools.md](./tools.md).
|
|
6
|
+
|
|
7
|
+
## execute() Full API
|
|
8
|
+
|
|
9
|
+
`execute()` is provided as a parameter in conversation handlers and is also available in workflows. It accepts these properties:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
type Props = {
|
|
13
|
+
/** System prompt guiding the LLM. Can be static or dynamic per iteration. */
|
|
14
|
+
instructions: string | ((ctx: Context) => string | Promise<string>)
|
|
15
|
+
|
|
16
|
+
/** AI-callable tools. See tools.md for creation patterns. */
|
|
17
|
+
tools?: Tool[] | ((ctx: Context) => Tool[] | Promise<Tool[]>)
|
|
18
|
+
|
|
19
|
+
/** Namespaced objects with properties and scoped tools. */
|
|
20
|
+
objects?: Object[] | ((ctx: Context) => Object[] | Promise<Object[]>)
|
|
21
|
+
|
|
22
|
+
/** Structured termination points. Controls how execution ends. */
|
|
23
|
+
exits?: Exit[] | ((ctx: Context) => Exit[] | Promise<Exit[]>)
|
|
24
|
+
|
|
25
|
+
/** Execution lifecycle hooks. */
|
|
26
|
+
hooks?: Hooks
|
|
27
|
+
|
|
28
|
+
/** LLM temperature (0-2). Default: 0.7 */
|
|
29
|
+
temperature?: number | ((ctx: Context) => number | Promise<number>)
|
|
30
|
+
|
|
31
|
+
/** Model or fallback chain. Uses agent config default if omitted. */
|
|
32
|
+
model?: Model | Model[] | ((ctx: Context) => Model | Model[] | Promise<Model | Model[]>)
|
|
33
|
+
|
|
34
|
+
/** Reasoning effort for models that support it. */
|
|
35
|
+
reasoningEffort?: 'low' | 'medium' | 'high' | 'dynamic' | 'none'
|
|
36
|
+
|
|
37
|
+
/** Knowledge bases for RAG. Adds a search_knowledge tool automatically. */
|
|
38
|
+
knowledge?: BaseKnowledge[]
|
|
39
|
+
|
|
40
|
+
/** Maximum iteration loops. Default: 10. Clamped to 1-100. */
|
|
41
|
+
iterations?: number
|
|
42
|
+
|
|
43
|
+
/** AbortSignal to cancel execution externally. */
|
|
44
|
+
signal?: AbortSignal
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Every property except `instructions` is optional. Most properties accept a **ValueOrGetter** — either a static value or a function receiving the current execution context that returns the value (optionally async). This lets you change tools, objects, or instructions between iterations based on what happened previously.
|
|
49
|
+
|
|
50
|
+
## Exits
|
|
51
|
+
|
|
52
|
+
Exits define the structured ways an execution can terminate. The LLM ends execution by writing `return { action: 'exit_name', ...data }` in its generated code.
|
|
53
|
+
|
|
54
|
+
### Creating Exits
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Autonomous, z } from '@botpress/runtime'
|
|
58
|
+
|
|
59
|
+
// Simple exit (no data)
|
|
60
|
+
const Done = new Autonomous.Exit({
|
|
61
|
+
name: 'done',
|
|
62
|
+
description: 'Task is complete',
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Exit with typed data
|
|
66
|
+
const TriageComplete = new Autonomous.Exit({
|
|
67
|
+
name: 'triage_complete',
|
|
68
|
+
description: 'Classification is done and the user has been notified.',
|
|
69
|
+
schema: z.object({
|
|
70
|
+
category: z.string().describe('The category the request was classified as'),
|
|
71
|
+
}),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Exit with aliases
|
|
75
|
+
const Escalate = new Autonomous.Exit({
|
|
76
|
+
name: 'escalate',
|
|
77
|
+
aliases: ['transfer', 'handoff'],
|
|
78
|
+
description: 'Escalate to a human agent',
|
|
79
|
+
schema: z.object({
|
|
80
|
+
reason: z.enum(['frustrated', 'technical', 'sensitive', 'other']),
|
|
81
|
+
priority: z.enum(['low', 'medium', 'high']).default('medium'),
|
|
82
|
+
}),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Exit with metadata for orchestration
|
|
86
|
+
const Handoff = new Autonomous.Exit({
|
|
87
|
+
name: 'handoff_sales',
|
|
88
|
+
description: 'Transfer to sales team',
|
|
89
|
+
metadata: { department: 'sales', type: 'handoff' },
|
|
90
|
+
schema: z.object({ reason: z.string() }),
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Exit Constructor
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
new Autonomous.Exit<T>({
|
|
98
|
+
name: string // Required. Valid TypeScript identifier.
|
|
99
|
+
description: string // Required. Tells the LLM when to use this exit.
|
|
100
|
+
schema?: ZuiType<T> // Optional. Zod schema for validated return data.
|
|
101
|
+
aliases?: string[] // Optional. Alternative names the LLM can use.
|
|
102
|
+
metadata?: Record<string, unknown> // Optional. Custom data for orchestration.
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Using Exits in execute()
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
export const SlackDM = new Conversation({
|
|
110
|
+
channel: 'slack.dm',
|
|
111
|
+
|
|
112
|
+
async handler({ execute }) {
|
|
113
|
+
const result = await execute({
|
|
114
|
+
instructions: `Classify the user's request, tell them the result, then exit.`,
|
|
115
|
+
tools: [classifyRequest.asTool()],
|
|
116
|
+
exits: [TriageComplete],
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Type-safe result checking
|
|
120
|
+
if (result.is(TriageComplete)) {
|
|
121
|
+
console.log(`Triaged as: ${result.output.category}`)
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Multiple Exits for Branching
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const Approved = new Autonomous.Exit({
|
|
131
|
+
name: 'approved',
|
|
132
|
+
description: 'Loan application approved',
|
|
133
|
+
schema: z.object({ amount: z.number(), reference: z.string() }),
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const Rejected = new Autonomous.Exit({
|
|
137
|
+
name: 'rejected',
|
|
138
|
+
description: 'Loan application rejected',
|
|
139
|
+
schema: z.object({ reason: z.string() }),
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const result = await execute({
|
|
143
|
+
instructions: 'Review and decide on the loan application.',
|
|
144
|
+
tools: [creditCheckTool, reviewTool],
|
|
145
|
+
exits: [Approved, Rejected],
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
if (result.is(Approved)) {
|
|
149
|
+
console.log(`Approved: $${result.output.amount} (ref: ${result.output.reference})`)
|
|
150
|
+
} else if (result.is(Rejected)) {
|
|
151
|
+
console.log(`Rejected: ${result.output.reason}`)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Built-in Exits
|
|
156
|
+
|
|
157
|
+
Three exits are built into the runtime. Do not redefine them.
|
|
158
|
+
|
|
159
|
+
| Exit | When Available | Action Name | Purpose |
|
|
160
|
+
|------|----------------|-------------|---------|
|
|
161
|
+
| **ListenExit** | Chat mode (conversation handlers) | `listen` | Pauses execution, returns control to the user. Auto-added when `execute()` runs in a conversation. |
|
|
162
|
+
| **ThinkExit** | Always | `think` | LLM pauses to reflect. Triggers another iteration (does not end execution). |
|
|
163
|
+
| **DefaultExit** | Worker mode, when no custom exits provided | `done` | Returns `{ success: true, result? }` or `{ success: false, error }`. |
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { Autonomous } from '@botpress/runtime'
|
|
167
|
+
|
|
168
|
+
// Check for built-in exits
|
|
169
|
+
if (result.is(Autonomous.ListenExit)) {
|
|
170
|
+
// Agent is waiting for user input
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (result.is(Autonomous.DefaultExit)) {
|
|
174
|
+
if (result.output.success) {
|
|
175
|
+
console.log('Result:', result.output.result)
|
|
176
|
+
} else {
|
|
177
|
+
console.error('Error:', result.output.error)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Chat mode behavior**: In conversation handlers, `ListenExit` is added automatically. When no custom exits are provided the LLM will use `ListenExit` to hand control back after responding. When you provide custom exits, both your exits and `ListenExit` are available.
|
|
183
|
+
|
|
184
|
+
**Worker mode behavior**: When `execute()` runs without a chat context (e.g. in a workflow or standalone), `ListenExit` is not available. If no custom exits are provided, `DefaultExit` is added automatically.
|
|
185
|
+
|
|
186
|
+
### Exit Utilities
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// Clone and rename an exit
|
|
190
|
+
const customExit = baseExit.clone().rename('custom')
|
|
191
|
+
|
|
192
|
+
// Deduplicate exit names
|
|
193
|
+
const uniqueExits = Autonomous.Exit.withUniqueNames([exit1, exit2])
|
|
194
|
+
|
|
195
|
+
// Match an exit result
|
|
196
|
+
if (someExit.match(exitResult)) {
|
|
197
|
+
// exitResult is typed as ExitResult<T>
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Objects
|
|
202
|
+
|
|
203
|
+
Objects group related properties and tools into a namespace. The LLM sees them as TypeScript namespaces with typed constants and methods.
|
|
204
|
+
|
|
205
|
+
### Creating Objects
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { Autonomous, z } from '@botpress/runtime'
|
|
209
|
+
|
|
210
|
+
const userProfile = new Autonomous.Object({
|
|
211
|
+
name: 'user',
|
|
212
|
+
description: 'Current user profile data',
|
|
213
|
+
properties: [
|
|
214
|
+
{
|
|
215
|
+
name: 'name',
|
|
216
|
+
value: 'John Doe',
|
|
217
|
+
type: z.string().min(1),
|
|
218
|
+
description: 'User full name',
|
|
219
|
+
writable: true,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: 'email',
|
|
223
|
+
value: null,
|
|
224
|
+
type: z.string().email().nullable(),
|
|
225
|
+
description: 'User email address',
|
|
226
|
+
writable: true,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'id',
|
|
230
|
+
value: 'user_123',
|
|
231
|
+
writable: false, // Read-only — LLM cannot modify
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The LLM sees this as:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
export namespace user {
|
|
241
|
+
const name: Writable<string> = "John Doe"
|
|
242
|
+
const email: Writable<string | null> = null
|
|
243
|
+
const id: Readonly<string> = "user_123"
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Object Constructor
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
new Autonomous.Object({
|
|
251
|
+
name: string // Required. Valid TypeScript identifier.
|
|
252
|
+
description?: string // What this object represents.
|
|
253
|
+
properties?: ObjectProperty[] // Stateful variables (max 100).
|
|
254
|
+
tools?: Tool[] // Scoped tools (called as obj.toolName()).
|
|
255
|
+
metadata?: Record<string, unknown>
|
|
256
|
+
})
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### ObjectProperty
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
type ObjectProperty = {
|
|
263
|
+
name: string // Valid TypeScript identifier.
|
|
264
|
+
value: any // Current value.
|
|
265
|
+
type?: ZuiType // Zod schema for validation on write.
|
|
266
|
+
description?: string // Helps the LLM understand the property.
|
|
267
|
+
writable?: boolean // Default: false. If true, LLM can assign new values.
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Objects with Scoped Tools
|
|
272
|
+
|
|
273
|
+
Tools on an object are called as `objectName.toolName()` by the LLM:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const fileSystem = new Autonomous.Object({
|
|
277
|
+
name: 'fs',
|
|
278
|
+
description: 'File system operations',
|
|
279
|
+
tools: [
|
|
280
|
+
new Autonomous.Tool({
|
|
281
|
+
name: 'readFile',
|
|
282
|
+
input: z.object({ path: z.string() }),
|
|
283
|
+
output: z.string(),
|
|
284
|
+
handler: async ({ path }) => readFileSync(path, 'utf8'),
|
|
285
|
+
}),
|
|
286
|
+
new Autonomous.Tool({
|
|
287
|
+
name: 'writeFile',
|
|
288
|
+
input: z.object({ path: z.string(), content: z.string() }),
|
|
289
|
+
handler: async ({ path, content }) => writeFileSync(path, content),
|
|
290
|
+
}),
|
|
291
|
+
],
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
// LLM can call: fs.readFile({ path: '/tmp/data.txt' })
|
|
295
|
+
// LLM can call: fs.writeFile({ path: '/tmp/out.txt', content: '...' })
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Dynamic Objects
|
|
299
|
+
|
|
300
|
+
Pass a function instead of an array to rebuild objects each iteration, reflecting current state:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const memory: Record<string, any> = {}
|
|
304
|
+
|
|
305
|
+
await execute({
|
|
306
|
+
instructions: 'Collect user information.',
|
|
307
|
+
objects: () => [
|
|
308
|
+
new Autonomous.Object({
|
|
309
|
+
name: 'form',
|
|
310
|
+
properties: [
|
|
311
|
+
{
|
|
312
|
+
name: 'name',
|
|
313
|
+
value: memory.name ?? null,
|
|
314
|
+
type: z.string().nullable(),
|
|
315
|
+
writable: true,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: 'age',
|
|
319
|
+
value: memory.age ?? null,
|
|
320
|
+
type: z.number().min(0).max(150).nullable(),
|
|
321
|
+
writable: true,
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
}),
|
|
325
|
+
],
|
|
326
|
+
hooks: {
|
|
327
|
+
onTrace: ({ trace }) => {
|
|
328
|
+
if (trace.type === 'property') {
|
|
329
|
+
memory[trace.property] = trace.value
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
})
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Using Objects in execute()
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
await execute({
|
|
340
|
+
instructions: 'You have access to the user profile. Update fields as needed.',
|
|
341
|
+
objects: [userProfile],
|
|
342
|
+
tools: [saveProfileTool],
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Execution Hooks
|
|
347
|
+
|
|
348
|
+
Hooks let you observe and modify the execution loop. They are passed in the `hooks` property of `execute()`.
|
|
349
|
+
|
|
350
|
+
### Hook Reference
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
type Hooks = {
|
|
354
|
+
/** NON-BLOCKING. Called for each trace (log, tool call, LLM call, etc). */
|
|
355
|
+
onTrace?: (props: { trace: Trace; iteration: number }) => void
|
|
356
|
+
|
|
357
|
+
/** BLOCKING. Called before each iteration. Can modify iteration parameters. */
|
|
358
|
+
onIterationStart?: (
|
|
359
|
+
iteration: Iteration,
|
|
360
|
+
controller: AbortController,
|
|
361
|
+
context: Context
|
|
362
|
+
) => Promise<void | Partial<Iteration>> | void | Partial<Iteration>
|
|
363
|
+
|
|
364
|
+
/** BLOCKING. Called after each iteration. Good for logging and cleanup. */
|
|
365
|
+
onIterationEnd?: (
|
|
366
|
+
iteration: Iteration,
|
|
367
|
+
controller: IterationController
|
|
368
|
+
) => void | Promise<void>
|
|
369
|
+
|
|
370
|
+
/** BLOCKING. Called when an exit is reached. Throw to reject the exit. */
|
|
371
|
+
onExit?: <T = unknown>(result: ExitResult<T>) => Promise<void> | void
|
|
372
|
+
|
|
373
|
+
/** BLOCKING, MUTATION. Called after LLM generates code, before execution. */
|
|
374
|
+
onBeforeExecution?: (
|
|
375
|
+
iteration: Iteration,
|
|
376
|
+
controller: AbortController
|
|
377
|
+
) => Promise<{ code?: string } | void>
|
|
378
|
+
|
|
379
|
+
/** BLOCKING, MUTATION. Called before any tool executes. Can modify input. */
|
|
380
|
+
onBeforeTool?: (event: {
|
|
381
|
+
iteration: Iteration
|
|
382
|
+
tool: Tool
|
|
383
|
+
input: unknown
|
|
384
|
+
controller: AbortController
|
|
385
|
+
}) => Promise<{ input?: unknown } | void>
|
|
386
|
+
|
|
387
|
+
/** BLOCKING, MUTATION. Called after a tool executes. Can modify output. */
|
|
388
|
+
onAfterTool?: (event: {
|
|
389
|
+
iteration: Iteration
|
|
390
|
+
tool: Tool
|
|
391
|
+
input: unknown
|
|
392
|
+
output: unknown
|
|
393
|
+
controller: AbortController
|
|
394
|
+
}) => Promise<{ output?: unknown } | void>
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Hook Categories
|
|
399
|
+
|
|
400
|
+
| Category | Hooks | Behavior |
|
|
401
|
+
|----------|-------|----------|
|
|
402
|
+
| **Non-blocking** | `onTrace` | Fire-and-forget. Cannot delay execution. |
|
|
403
|
+
| **Blocking, mutation** | `onIterationStart`, `onBeforeTool`, `onAfterTool`, `onBeforeExecution` | Block until resolved. Can return modified values. |
|
|
404
|
+
| **Blocking, non-mutation** | `onIterationEnd`, `onExit` | Block until resolved. Cannot change tool I/O or code. |
|
|
405
|
+
|
|
406
|
+
### Common Hook Patterns
|
|
407
|
+
|
|
408
|
+
**Logging tool calls:**
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
await execute({
|
|
412
|
+
instructions: 'Help the user',
|
|
413
|
+
tools: [searchTool, ticketTool],
|
|
414
|
+
hooks: {
|
|
415
|
+
onBeforeTool: async ({ tool, input }) => {
|
|
416
|
+
console.log(`[tool:start] ${tool.name}`, JSON.stringify(input))
|
|
417
|
+
},
|
|
418
|
+
onAfterTool: async ({ tool, input, output }) => {
|
|
419
|
+
console.log(`[tool:end] ${tool.name}`, JSON.stringify(output))
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
})
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Modifying tool input (e.g. appending search scope):**
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
hooks: {
|
|
429
|
+
onBeforeTool: async ({ tool, input }) => {
|
|
430
|
+
if (tool.name === 'search') {
|
|
431
|
+
return { input: { ...input, query: `${input.query} site:docs.example.com` } }
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Rejecting an exit (forces the LLM to keep iterating):**
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
hooks: {
|
|
441
|
+
onExit: async (result) => {
|
|
442
|
+
if (result.exit.name === 'done' && !result.result?.confirmed) {
|
|
443
|
+
throw new Error('Must confirm before exiting')
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Aborting execution from a hook:**
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
hooks: {
|
|
453
|
+
onBeforeTool: async ({ controller }) => {
|
|
454
|
+
if (shouldStop()) {
|
|
455
|
+
controller.abort()
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Modifying generated code before execution:**
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
hooks: {
|
|
465
|
+
onBeforeExecution: async (iteration) => {
|
|
466
|
+
// Inject a safety wrapper or strip dangerous patterns
|
|
467
|
+
const modified = iteration.code?.replace(/dangerousCall\(\)/g, '/* blocked */')
|
|
468
|
+
return { code: modified }
|
|
469
|
+
},
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Tracking property mutations via onTrace:**
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
hooks: {
|
|
477
|
+
onTrace: ({ trace }) => {
|
|
478
|
+
if (trace.type === 'property') {
|
|
479
|
+
console.log(`${trace.object}.${trace.property} = ${trace.value}`)
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## Execution Result
|
|
486
|
+
|
|
487
|
+
`execute()` returns an `ExecutionResult` with three possible statuses:
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
const result = await execute({ instructions: '...' })
|
|
491
|
+
|
|
492
|
+
// Status checks
|
|
493
|
+
result.isSuccess() // Completed with an exit
|
|
494
|
+
result.isError() // Failed (aborted, iterations exhausted)
|
|
495
|
+
result.isInterrupted() // Paused with a snapshot (SnapshotSignal)
|
|
496
|
+
|
|
497
|
+
// Exit type-narrowing
|
|
498
|
+
result.is(MyExit) // true if exited via MyExit, narrows result.output type
|
|
499
|
+
|
|
500
|
+
// Access execution data
|
|
501
|
+
result.iteration // Last iteration (or null)
|
|
502
|
+
result.iterations // All iterations
|
|
503
|
+
result.output // Exit data (if success), null otherwise
|
|
504
|
+
result.context // Full execution context
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Success Result
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
if (result.isSuccess()) {
|
|
511
|
+
console.log('Exit:', result.result.exit.name)
|
|
512
|
+
console.log('Output:', result.output)
|
|
513
|
+
console.log('Code:', result.iteration.code)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Typed exit checking (preferred)
|
|
517
|
+
if (result.is(TriageComplete)) {
|
|
518
|
+
// result.output is typed as { category: string }
|
|
519
|
+
console.log(result.output.category)
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Error Result
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
if (result.isError()) {
|
|
527
|
+
console.error('Failed:', result.error)
|
|
528
|
+
// Inspect the last iteration for details
|
|
529
|
+
const last = result.iteration
|
|
530
|
+
if (last?.status.type === 'execution_error') {
|
|
531
|
+
console.error(last.status.execution_error.message)
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Interrupted Result (Snapshots)
|
|
537
|
+
|
|
538
|
+
When a tool throws `SnapshotSignal`, execution pauses and can be resumed later:
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
if (result.isInterrupted()) {
|
|
542
|
+
const snapshot = result.snapshot.toJSON()
|
|
543
|
+
// Persist snapshot, resume later with: execute({ snapshot, ... })
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
## Configuration Options
|
|
548
|
+
|
|
549
|
+
### Model Selection
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
await execute({
|
|
553
|
+
instructions: '...',
|
|
554
|
+
model: 'openai:gpt-4o', // Single model
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
await execute({
|
|
558
|
+
instructions: '...',
|
|
559
|
+
model: ['openai:gpt-4o', 'anthropic:claude-3-5-sonnet'], // Fallback chain
|
|
560
|
+
})
|
|
561
|
+
|
|
562
|
+
// Dynamic model per iteration
|
|
563
|
+
await execute({
|
|
564
|
+
instructions: '...',
|
|
565
|
+
model: (ctx) => ctx.iteration > 2 ? 'openai:gpt-4o' : 'openai:gpt-4o-mini',
|
|
566
|
+
})
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
If `model` is omitted, the `defaultModels.autonomous` value from `agent.config.ts` is used.
|
|
570
|
+
|
|
571
|
+
### Temperature
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
await execute({
|
|
575
|
+
instructions: '...',
|
|
576
|
+
temperature: 0.1, // Low = deterministic. Default: 0.7. Range: 0-2.
|
|
577
|
+
})
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Reasoning Effort
|
|
581
|
+
|
|
582
|
+
```typescript
|
|
583
|
+
await execute({
|
|
584
|
+
instructions: '...',
|
|
585
|
+
reasoningEffort: 'high', // 'none' | 'low' | 'medium' | 'high' | 'dynamic'
|
|
586
|
+
})
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
- `'none'` disables reasoning for models with optional reasoning.
|
|
590
|
+
- `'dynamic'` lets the provider decide.
|
|
591
|
+
- Omitting this field disables reasoning for optional-reasoning models.
|
|
592
|
+
|
|
593
|
+
### Iteration Limit
|
|
594
|
+
|
|
595
|
+
```typescript
|
|
596
|
+
await execute({
|
|
597
|
+
instructions: '...',
|
|
598
|
+
iterations: 20, // Default: 10. Clamped to 1-100.
|
|
599
|
+
})
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
Each "iteration" is one LLM generation + code execution cycle. The LLM can call multiple tools in a single iteration. `ThinkExit` consumes one iteration. If iterations are exhausted without an exit, the result is an error.
|
|
603
|
+
|
|
604
|
+
### AbortSignal
|
|
605
|
+
|
|
606
|
+
```typescript
|
|
607
|
+
const controller = new AbortController()
|
|
608
|
+
setTimeout(() => controller.abort(), 30_000)
|
|
609
|
+
|
|
610
|
+
await execute({
|
|
611
|
+
instructions: '...',
|
|
612
|
+
signal: controller.signal,
|
|
613
|
+
})
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
When aborted, the current LLM generation and sandbox execution are killed immediately. The result status will be `error` with an aborted iteration.
|
|
617
|
+
|
|
618
|
+
## Dynamic Properties (ValueOrGetter)
|
|
619
|
+
|
|
620
|
+
Most `execute()` properties accept either a static value or a function that receives the execution context:
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
// Static
|
|
624
|
+
tools: [searchTool, ticketTool]
|
|
625
|
+
|
|
626
|
+
// Dynamic — re-evaluated each iteration
|
|
627
|
+
tools: (ctx) => {
|
|
628
|
+
if (ctx.iteration > 0) {
|
|
629
|
+
return [searchTool, ticketTool, escalateTool]
|
|
630
|
+
}
|
|
631
|
+
return [searchTool]
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Async dynamic
|
|
635
|
+
instructions: async (ctx) => {
|
|
636
|
+
const rules = await fetchRules()
|
|
637
|
+
return `Follow these rules: ${rules}`
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
This pattern applies to `instructions`, `tools`, `objects`, `exits`, `temperature`, and `model`.
|
|
642
|
+
|
|
643
|
+
## Chat Mode vs Worker Mode
|
|
644
|
+
|
|
645
|
+
`execute()` behaves differently depending on where it runs:
|
|
646
|
+
|
|
647
|
+
| Aspect | Chat Mode (Conversations) | Worker Mode (Workflows, Actions) |
|
|
648
|
+
|--------|--------------------------|----------------------------------|
|
|
649
|
+
| Transcript | LLM sees conversation history | No transcript |
|
|
650
|
+
| ListenExit | Auto-added | Not available |
|
|
651
|
+
| DefaultExit | Not auto-added when exits provided | Auto-added when no exits provided |
|
|
652
|
+
| Components | Can yield UI components | No component rendering |
|
|
653
|
+
| Typical pattern | Open-ended conversation | Task completion with structured exit |
|
|
654
|
+
|
|
655
|
+
In conversation handlers, `execute()` is provided as a parameter and runs in chat mode by default:
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
export const Chat = new Conversation({
|
|
659
|
+
channel: 'chat.channel',
|
|
660
|
+
async handler({ execute }) {
|
|
661
|
+
await execute({
|
|
662
|
+
instructions: 'You are a helpful assistant.',
|
|
663
|
+
tools: [searchTool],
|
|
664
|
+
})
|
|
665
|
+
// After execute(), the LLM used ListenExit to return control
|
|
666
|
+
},
|
|
667
|
+
})
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
For lifecycle event handling (nudge/expire) in conversations, see [conversation-lifecycle.md](./conversation-lifecycle.md).
|
|
671
|
+
|
|
672
|
+
## Common Patterns
|
|
673
|
+
|
|
674
|
+
### Classify-and-exit (single-shot)
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
const Category = new Autonomous.Exit({
|
|
678
|
+
name: 'categorized',
|
|
679
|
+
description: 'Message has been categorized',
|
|
680
|
+
schema: z.object({
|
|
681
|
+
category: z.enum(['billing', 'technical', 'general']),
|
|
682
|
+
confidence: z.number().min(0).max(1),
|
|
683
|
+
}),
|
|
684
|
+
})
|
|
685
|
+
|
|
686
|
+
const result = await execute({
|
|
687
|
+
instructions: 'Classify the user message into a category.',
|
|
688
|
+
exits: [Category],
|
|
689
|
+
iterations: 3,
|
|
690
|
+
})
|
|
691
|
+
|
|
692
|
+
if (result.is(Category)) {
|
|
693
|
+
await routeToTeam(result.output.category)
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Chaining execute() calls
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
async handler({ execute }) {
|
|
701
|
+
// First pass: classify
|
|
702
|
+
const result = await execute({
|
|
703
|
+
instructions: 'Classify the request and respond.',
|
|
704
|
+
tools: [classifyTool],
|
|
705
|
+
exits: [TriageComplete],
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
// Second pass: follow-up
|
|
709
|
+
if (result.is(TriageComplete) && result.output.category === 'technical') {
|
|
710
|
+
await execute({
|
|
711
|
+
instructions: 'Ask for technical details and create a ticket.',
|
|
712
|
+
tools: [createTicketTool],
|
|
713
|
+
})
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Open-ended conversation (no custom exits)
|
|
719
|
+
|
|
720
|
+
```typescript
|
|
721
|
+
await execute({
|
|
722
|
+
instructions: 'You are an IT help desk assistant.',
|
|
723
|
+
tools: [createTicket, lookupTicket, updateTicket, deleteTicket],
|
|
724
|
+
knowledge: [DocsKB],
|
|
725
|
+
})
|
|
726
|
+
// LLM uses ListenExit to return control after each response
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
## Pitfalls
|
|
730
|
+
|
|
731
|
+
- **Do not redefine built-in exits.** Creating an exit named `listen`, `think`, or `done` will conflict with the built-in ListenExit, ThinkExit, and DefaultExit.
|
|
732
|
+
- **Exits require good descriptions.** The LLM decides which exit to use based on the `description`. Vague descriptions lead to wrong exit selection.
|
|
733
|
+
- **Writable properties need a schema.** If `writable: true` without `type`, the sandbox cannot validate writes and they will be unchecked.
|
|
734
|
+
- **Object property limit is 100.** More than 100 properties on a single object will throw.
|
|
735
|
+
- **ThinkExit consumes an iteration.** If your iteration limit is low and the LLM thinks frequently, it may exhaust iterations before finishing. Increase `iterations` for complex tasks.
|
|
736
|
+
- **Blocking hooks delay execution.** All hooks except `onTrace` are async and block the loop. Keep hook logic fast.
|
|
737
|
+
- **onExit throw = retry.** Throwing in `onExit` rejects the exit and the LLM gets the error as context for the next iteration. Use this deliberately.
|
|
738
|
+
|
|
739
|
+
## See Also
|
|
740
|
+
|
|
741
|
+
- [Tools](./tools.md) — Tool creation, handler syntax, ThinkSignal, advanced properties
|
|
742
|
+
- [Conversations](./conversations.md) — Conversation handlers, message routing, channel IDs
|
|
743
|
+
- [Workflows](./workflows.md) — Long-running processes, step-based execution
|
|
744
|
+
- [Context API](./context-api.md) — Accessing runtime services and state
|
|
745
|
+
- [Model Configuration](./model-configuration.md) — Model selection and defaults
|
|
746
|
+
- [Workflow Steps](./workflow-steps.md) — Step API reference for using execute() within workflow handlers
|
|
747
|
+
- [Conversation Lifecycle](./conversation-lifecycle.md) — Lifecycle events (nudge/expire) that also receive execute as a handler prop
|