185 lines
3.7 KiB
Markdown
185 lines
3.7 KiB
Markdown
# ToolLoopAgent Patterns
|
|
|
|
Deep dive on v6 agent workflows.
|
|
|
|
## When to Use ToolLoopAgent
|
|
|
|
| Use Case | Approach |
|
|
|----------|----------|
|
|
| Single tool call | `streamText` with tools |
|
|
| Multi-step reasoning | `ToolLoopAgent` |
|
|
| Autonomous workflows | `ToolLoopAgent` with `stopWhen` |
|
|
| Complex orchestration | `ToolLoopAgent` with custom stop conditions |
|
|
|
|
## Agent Configuration
|
|
|
|
```typescript
|
|
import { ToolLoopAgent, stepCountIs } from 'ai';
|
|
|
|
const agent = new ToolLoopAgent({
|
|
// Required
|
|
model: 'anthropic/claude-sonnet-4.5',
|
|
|
|
// Optional
|
|
instructions: 'You are a research assistant.',
|
|
tools: { search, calculate, summarize },
|
|
|
|
// Stop conditions
|
|
stopWhen: stepCountIs(10),
|
|
// Or custom: async ({ steps }) => steps.length >= 10
|
|
|
|
// Tool selection
|
|
toolChoice: 'auto', // 'auto' | 'required' | 'none'
|
|
|
|
// Token limits
|
|
maxOutputTokens: 4096,
|
|
});
|
|
```
|
|
|
|
## Execution Patterns
|
|
|
|
### Non-Streaming (Simple)
|
|
|
|
```typescript
|
|
const result = await agent.generate({
|
|
prompt: 'Research quantum computing breakthroughs.',
|
|
});
|
|
|
|
console.log(result.text);
|
|
console.log(result.steps); // Array of all steps
|
|
console.log(result.steps.length, 'steps executed');
|
|
```
|
|
|
|
### Streaming (Real-time)
|
|
|
|
```typescript
|
|
const stream = agent.stream({
|
|
prompt: 'Analyze this data and provide insights.',
|
|
});
|
|
|
|
for await (const chunk of stream.textStream) {
|
|
process.stdout.write(chunk);
|
|
}
|
|
```
|
|
|
|
### UI Streaming (React/Next.js)
|
|
|
|
```typescript
|
|
import { createAgentUIStream } from 'ai';
|
|
|
|
const stream = await createAgentUIStream({
|
|
agent,
|
|
messages: [{ role: 'user', content: 'What is the weather?' }],
|
|
abortSignal: controller.signal,
|
|
});
|
|
|
|
for await (const chunk of stream) {
|
|
// Yield to client
|
|
}
|
|
```
|
|
|
|
## Stop Conditions
|
|
|
|
### Built-in: Step Count
|
|
|
|
```typescript
|
|
import { stepCountIs } from 'ai';
|
|
|
|
stopWhen: stepCountIs(5) // Stop after 5 steps
|
|
```
|
|
|
|
### Custom: Finish Reason
|
|
|
|
```typescript
|
|
stopWhen: async ({ steps }) =>
|
|
steps.at(-1)?.finishReason === 'stop'
|
|
```
|
|
|
|
### Custom: Combined
|
|
|
|
```typescript
|
|
stopWhen: async ({ steps }) =>
|
|
steps.length >= 10 || steps.at(-1)?.finishReason === 'stop'
|
|
```
|
|
|
|
## Tool Choice Control
|
|
|
|
```typescript
|
|
const agent = new ToolLoopAgent({
|
|
model: 'anthropic/claude-sonnet-4.5',
|
|
tools: { search, calculate },
|
|
|
|
// Force tool use every step
|
|
toolChoice: 'required',
|
|
|
|
// Disable tools (text only)
|
|
toolChoice: 'none',
|
|
|
|
// Let model decide (default)
|
|
toolChoice: 'auto',
|
|
});
|
|
```
|
|
|
|
## Agent with Constraints
|
|
|
|
```typescript
|
|
const customerSupportAgent = new ToolLoopAgent({
|
|
model: 'anthropic/claude-sonnet-4.5',
|
|
instructions: `You are a customer support specialist.
|
|
|
|
Rules:
|
|
- Never promise refunds without checking policy
|
|
- Always be empathetic and professional
|
|
- If unsure, offer to escalate
|
|
- Keep responses concise
|
|
- Never share internal company information`,
|
|
tools: {
|
|
checkOrderStatus,
|
|
lookupPolicy,
|
|
createTicket,
|
|
},
|
|
});
|
|
```
|
|
|
|
## Accessing Step History
|
|
|
|
```typescript
|
|
const result = await agent.generate({ prompt: '...' });
|
|
|
|
for (const step of result.steps) {
|
|
if (step.type === 'tool-call') {
|
|
console.log(`Called ${step.tool} with`, step.input);
|
|
} else if (step.type === 'text-generation') {
|
|
console.log('Generated:', step.output);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```typescript
|
|
try {
|
|
const result = await agent.generate({ prompt: '...' });
|
|
} catch (error) {
|
|
if (error.name === 'AbortError') {
|
|
console.log('Agent execution aborted');
|
|
} else {
|
|
console.error('Agent error:', error);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
**DO:**
|
|
- Set reasonable `stopWhen` limits
|
|
- Use typed tool schemas with Zod
|
|
- Handle abort signals for long-running agents
|
|
- Log step history for debugging
|
|
|
|
**DON'T:**
|
|
- Leave agents unbounded (no stop condition)
|
|
- Use synchronous blocking operations in tools
|
|
- Ignore error states
|
|
- Skip tool validation
|