ai 7.0.0-beta.111 → 7.0.0-beta.113
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/CHANGELOG.md +60 -0
- package/dist/index.d.ts +2640 -2457
- package/dist/index.js +1136 -640
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +324 -262
- package/dist/internal/index.js +23 -20
- package/dist/internal/index.js.map +1 -1
- package/docs/02-foundations/03-prompts.mdx +13 -10
- package/docs/03-agents/01-overview.mdx +16 -0
- package/docs/03-agents/02-building-agents.mdx +78 -14
- package/docs/03-agents/06-subagents.mdx +3 -1
- package/docs/03-agents/07-workflow-agent.mdx +130 -3
- package/docs/03-agents/index.mdx +4 -2
- package/docs/03-ai-sdk-core/05-generating-text.mdx +53 -23
- package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +154 -115
- package/docs/03-ai-sdk-core/17-runtime-and-tool-context.mdx +215 -0
- package/docs/03-ai-sdk-core/60-telemetry.mdx +115 -27
- package/docs/03-ai-sdk-core/65-event-listeners.mdx +176 -153
- package/docs/03-ai-sdk-core/index.mdx +6 -0
- package/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +46 -4
- package/docs/04-ai-sdk-ui/50-stream-protocol.mdx +43 -0
- package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +172 -128
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +172 -110
- package/docs/07-reference/01-ai-sdk-core/05-embed.mdx +4 -16
- package/docs/07-reference/01-ai-sdk-core/06-embed-many.mdx +4 -16
- package/docs/07-reference/01-ai-sdk-core/06-rerank.mdx +2 -2
- package/docs/07-reference/01-ai-sdk-core/15-agent.mdx +4 -4
- package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +92 -126
- package/docs/07-reference/01-ai-sdk-core/17-create-agent-ui-stream.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/18-create-agent-ui-stream-response.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/18-pipe-agent-ui-stream-to-response.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/20-tool.mdx +12 -1
- package/docs/07-reference/01-ai-sdk-core/22-dynamic-tool.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +14 -1
- package/docs/07-reference/01-ai-sdk-core/29-filter-active-tools.mdx +14 -2
- package/docs/07-reference/01-ai-sdk-core/30-model-message.mdx +5 -2
- package/docs/07-reference/02-ai-sdk-ui/31-convert-to-model-messages.mdx +9 -0
- package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +7 -0
- package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +48 -29
- package/docs/08-migration-guides/23-migration-guide-7-0.mdx +99 -0
- package/package.json +9 -7
- package/src/agent/agent.ts +10 -10
- package/src/agent/create-agent-ui-stream-response.ts +5 -4
- package/src/agent/create-agent-ui-stream.ts +5 -4
- package/src/agent/index.ts +0 -4
- package/src/agent/pipe-agent-ui-stream-to-response.ts +5 -4
- package/src/agent/tool-loop-agent-settings.ts +28 -41
- package/src/agent/tool-loop-agent.ts +23 -10
- package/src/embed/embed-events.ts +8 -44
- package/src/embed/embed-many.ts +14 -34
- package/src/embed/embed.ts +11 -23
- package/src/generate-object/generate-object.ts +20 -24
- package/src/generate-object/index.ts +4 -4
- package/src/generate-object/stream-object.ts +26 -27
- package/src/generate-object/structured-output-events.ts +4 -25
- package/src/generate-text/active-tools.ts +12 -0
- package/src/generate-text/content-part.ts +5 -3
- package/src/generate-text/create-execute-tools-transformation.ts +80 -38
- package/src/generate-text/execute-tool-call.ts +31 -37
- package/src/generate-text/filter-active-tools.ts +38 -0
- package/src/generate-text/{core-events.ts → generate-text-events.ts} +108 -113
- package/src/generate-text/generate-text.ts +214 -167
- package/src/generate-text/index.ts +29 -14
- package/src/generate-text/language-model-events.ts +79 -0
- package/src/generate-text/prepare-step.ts +2 -1
- package/src/generate-text/resolve-tool-approval.ts +134 -0
- package/src/generate-text/restricted-telemetry-dispatcher.ts +247 -0
- package/src/generate-text/step-result.ts +0 -9
- package/src/generate-text/stream-language-model-call.ts +245 -35
- package/src/generate-text/stream-text-result.ts +5 -0
- package/src/generate-text/stream-text.ts +168 -215
- package/src/generate-text/to-response-messages.ts +34 -2
- package/src/generate-text/tool-approval-configuration.ts +128 -0
- package/src/generate-text/tool-approval-request-output.ts +7 -0
- package/src/generate-text/tool-approval-response-output.ts +35 -0
- package/src/generate-text/tool-execution-events.ts +120 -65
- package/src/index.ts +1 -0
- package/src/prompt/convert-to-language-model-prompt.ts +1 -1
- package/src/prompt/prompt.ts +9 -0
- package/src/prompt/standardize-prompt.ts +38 -27
- package/src/rerank/index.ts +3 -3
- package/src/rerank/rerank-events.ts +8 -44
- package/src/rerank/rerank.ts +13 -33
- package/src/telemetry/{create-unified-telemetry.ts → create-telemetry-dispatcher.ts} +71 -24
- package/src/telemetry/index.ts +1 -1
- package/src/telemetry/telemetry.ts +92 -36
- package/src/ui/convert-to-model-messages.ts +21 -1
- package/src/ui/process-ui-message-stream.ts +48 -1
- package/src/ui/ui-messages.ts +10 -0
- package/src/ui/validate-ui-messages.ts +10 -0
- package/src/ui-message-stream/ui-message-chunks.ts +18 -0
- package/src/util/merge-objects.ts +5 -0
- package/src/generate-text/filter-active-tool.ts +0 -41
- package/src/generate-text/is-tool-approval-needed.ts +0 -66
- package/src/generate-text/tool-needs-approval-configuration.ts +0 -21
|
@@ -45,6 +45,14 @@ const result = await generateText({
|
|
|
45
45
|
System prompts are the initial set of instructions given to models that help guide and constrain the models' behaviors and responses.
|
|
46
46
|
You can set system prompts using the `system` property.
|
|
47
47
|
System prompts work with both the `prompt` and the `messages` properties.
|
|
48
|
+
System messages in `prompt` or `messages` are rejected by default; use the `system` property for system instructions, or set `allowSystemInMessages: true` when you need to send existing message histories that contain system messages.
|
|
49
|
+
|
|
50
|
+
<Note type="warning">
|
|
51
|
+
Opting in with `allowSystemInMessages` can create a prompt injection risk
|
|
52
|
+
where users can override or set the system prompt by injecting system
|
|
53
|
+
messages. In most cases, only trusted server-side code should set system
|
|
54
|
+
instructions via the `system` or `instructions` property.
|
|
55
|
+
</Note>
|
|
48
56
|
|
|
49
57
|
```ts highlight="3-6"
|
|
50
58
|
const result = await generateText({
|
|
@@ -59,11 +67,6 @@ const result = await generateText({
|
|
|
59
67
|
});
|
|
60
68
|
```
|
|
61
69
|
|
|
62
|
-
<Note>
|
|
63
|
-
When you use a message prompt, you can also use system messages instead of a
|
|
64
|
-
system prompt.
|
|
65
|
-
</Note>
|
|
66
|
-
|
|
67
70
|
## Message Prompts
|
|
68
71
|
|
|
69
72
|
A message prompt is an array of user, assistant, and tool messages.
|
|
@@ -118,10 +121,9 @@ const { text } = await generateText({
|
|
|
118
121
|
For granular control over applying provider options at the message level, you can pass `providerOptions` to the message object:
|
|
119
122
|
|
|
120
123
|
```ts
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
{
|
|
124
|
+
const result = await generateText({
|
|
125
|
+
model: __MODEL__,
|
|
126
|
+
system: {
|
|
125
127
|
role: 'system',
|
|
126
128
|
content: 'Cached system message',
|
|
127
129
|
providerOptions: {
|
|
@@ -129,7 +131,8 @@ const messages: ModelMessage[] = [
|
|
|
129
131
|
anthropic: { cacheControl: { type: 'ephemeral' } },
|
|
130
132
|
},
|
|
131
133
|
},
|
|
132
|
-
|
|
134
|
+
prompt: 'Invent a new holiday and describe its traditions.',
|
|
135
|
+
});
|
|
133
136
|
```
|
|
134
137
|
|
|
135
138
|
#### Message Part Level
|
|
@@ -15,6 +15,21 @@ These components work together:
|
|
|
15
15
|
- **Context management** - Maintaining conversation history and deciding what the model sees (input) at each step
|
|
16
16
|
- **Stopping conditions** - Determining when the loop (task) is complete
|
|
17
17
|
|
|
18
|
+
## Agent State and Context
|
|
19
|
+
|
|
20
|
+
Agents often need server-side state that should not be placed directly in the
|
|
21
|
+
prompt, such as tenant settings, request IDs, feature flags, credentials, or
|
|
22
|
+
progress through a task.
|
|
23
|
+
|
|
24
|
+
Use `runtimeContext` as the agent's shared runtime state. It flows through the
|
|
25
|
+
agent loop, is available in `prepareStep` and lifecycle callbacks, and can be
|
|
26
|
+
updated between steps. Use `toolsContext` for per-tool values such as API keys
|
|
27
|
+
or scoped permissions; each tool receives only its own typed `context` based on
|
|
28
|
+
its `contextSchema`.
|
|
29
|
+
|
|
30
|
+
Learn more in [Runtime and Tool
|
|
31
|
+
Context](/docs/ai-sdk-core/runtime-and-tool-context).
|
|
32
|
+
|
|
18
33
|
## ToolLoopAgent Class
|
|
19
34
|
|
|
20
35
|
The ToolLoopAgent class handles these three components. Here's an agent that uses multiple tools in a loop to accomplish a task:
|
|
@@ -90,5 +105,6 @@ Agents are flexible and powerful, but non-deterministic. When you need reliable,
|
|
|
90
105
|
## Next Steps
|
|
91
106
|
|
|
92
107
|
- **[Building Agents](/docs/agents/building-agents)** - Guide to creating agents with the ToolLoopAgent
|
|
108
|
+
- **[Runtime and Tool Context](/docs/ai-sdk-core/runtime-and-tool-context)** - How to pass shared agent state and per-tool context
|
|
93
109
|
- **[Workflow Patterns](/docs/agents/workflows)** - Structured patterns using core functions for complex workflows
|
|
94
110
|
- **[Loop Control](/docs/agents/loop-control)** - Execution control with stopWhen and prepareStep
|
|
@@ -77,9 +77,73 @@ const codeAgent = new ToolLoopAgent({
|
|
|
77
77
|
});
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`
|
|
80
|
+
### Context and Agent State
|
|
81
|
+
|
|
82
|
+
Use `runtimeContext` as the agent's shared runtime state. It flows through the
|
|
83
|
+
agent loop and is available in `prepareStep`, lifecycle callbacks, and final
|
|
84
|
+
results. If a tool needs server-side values such as credentials, scoped
|
|
85
|
+
permissions, or default settings, pass them through `toolsContext` and declare
|
|
86
|
+
them with the tool's `contextSchema`.
|
|
87
|
+
|
|
88
|
+
```ts highlight="8-15,21-31,37-49"
|
|
89
|
+
import { ToolLoopAgent, tool } from 'ai';
|
|
90
|
+
import { z } from 'zod';
|
|
91
|
+
|
|
92
|
+
const agent = new ToolLoopAgent({
|
|
93
|
+
model: __MODEL__,
|
|
94
|
+
tools: {
|
|
95
|
+
searchTickets: tool({
|
|
96
|
+
description: 'Search support tickets',
|
|
97
|
+
inputSchema: z.object({
|
|
98
|
+
query: z.string(),
|
|
99
|
+
}),
|
|
100
|
+
contextSchema: z.object({
|
|
101
|
+
apiKey: z.string(),
|
|
102
|
+
accountId: z.string(),
|
|
103
|
+
}),
|
|
104
|
+
execute: async ({ query }, { context }) =>
|
|
105
|
+
searchTickets(query, context.accountId, context.apiKey),
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
prepareStep: async ({ runtimeContext }) => {
|
|
109
|
+
if (runtimeContext.escalated) {
|
|
110
|
+
return { temperature: 0.1 };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {};
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const result = await agent.generate({
|
|
118
|
+
prompt: 'Find open billing tickets for this account.',
|
|
119
|
+
runtimeContext: {
|
|
120
|
+
requestId: 'req_abc',
|
|
121
|
+
escalated: false,
|
|
122
|
+
},
|
|
123
|
+
toolsContext: {
|
|
124
|
+
searchTickets: {
|
|
125
|
+
apiKey: process.env.SUPPORT_API_KEY!,
|
|
126
|
+
accountId: 'acct_123',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
For the full model, including sensitive context filtering and where each context
|
|
133
|
+
value is available, see [Runtime and Tool
|
|
134
|
+
Context](/docs/ai-sdk-core/runtime-and-tool-context).
|
|
135
|
+
|
|
136
|
+
You can also require approval before a tool executes. Configure approval on the
|
|
137
|
+
`ToolLoopAgent` with `toolApproval`. The older `needsApproval` property on
|
|
138
|
+
tools is deprecated for `ToolLoopAgent`. `toolApproval` can be a
|
|
139
|
+
`GenericToolApprovalFunction` (one callback for every tool call) or a per-tool
|
|
140
|
+
object of statuses and/or `SingleToolApprovalFunction` handlers. For the
|
|
141
|
+
default execution path, use `'not-applicable'` or return `undefined` from an
|
|
142
|
+
approval function. Use `'user-approval'` for manual review, or `'approved'` /
|
|
143
|
+
`'denied'` when you want explicit automatic approval records in the output. For
|
|
144
|
+
automatic approvals and denials, you can also return an object such as
|
|
145
|
+
`{ type: 'denied', reason: 'blocked by policy' }` to attach a reason to the
|
|
146
|
+
approval response:
|
|
83
147
|
|
|
84
148
|
```ts
|
|
85
149
|
const agent = new ToolLoopAgent({
|
|
@@ -93,8 +157,8 @@ const agent = new ToolLoopAgent({
|
|
|
93
157
|
execute: async ({ code }) => ({ output: code }),
|
|
94
158
|
}),
|
|
95
159
|
},
|
|
96
|
-
|
|
97
|
-
runCode:
|
|
160
|
+
toolApproval: {
|
|
161
|
+
runCode: 'user-approval',
|
|
98
162
|
},
|
|
99
163
|
});
|
|
100
164
|
```
|
|
@@ -364,21 +428,21 @@ These are useful for logging, observability, debugging, and custom telemetry.
|
|
|
364
428
|
const result = await myAgent.generate({
|
|
365
429
|
prompt: 'Research and summarize the latest AI trends',
|
|
366
430
|
|
|
367
|
-
experimental_onStart({
|
|
368
|
-
console.log('Agent started', {
|
|
431
|
+
experimental_onStart({ modelId }) {
|
|
432
|
+
console.log('Agent started', { modelId });
|
|
369
433
|
},
|
|
370
434
|
|
|
371
|
-
experimental_onStepStart({ stepNumber,
|
|
372
|
-
console.log(`Step ${stepNumber} starting`, {
|
|
435
|
+
experimental_onStepStart({ stepNumber, modelId }) {
|
|
436
|
+
console.log(`Step ${stepNumber} starting`, { modelId });
|
|
373
437
|
},
|
|
374
438
|
|
|
375
439
|
experimental_onToolExecutionStart({ toolCall }) {
|
|
376
440
|
console.log(`Tool call starting: ${toolCall.toolName}`);
|
|
377
441
|
},
|
|
378
442
|
|
|
379
|
-
experimental_onToolExecutionEnd({ toolCall, durationMs,
|
|
443
|
+
experimental_onToolExecutionEnd({ toolCall, durationMs, toolOutput }) {
|
|
380
444
|
console.log(`Tool call finished: ${toolCall.toolName} (${durationMs}ms)`, {
|
|
381
|
-
success,
|
|
445
|
+
success: toolOutput.type === 'tool-result',
|
|
382
446
|
});
|
|
383
447
|
},
|
|
384
448
|
|
|
@@ -402,10 +466,10 @@ const result = await myAgent.generate({
|
|
|
402
466
|
|
|
403
467
|
The available lifecycle callbacks are:
|
|
404
468
|
|
|
405
|
-
- **`experimental_onStart`**: Called once when the agent operation begins, before any LLM calls. Receives model info,
|
|
469
|
+
- **`experimental_onStart`**: Called once when the agent operation begins, before any LLM calls. Receives model info, messages, settings, and `runtimeContext`.
|
|
406
470
|
- **`experimental_onStepStart`**: Called before each step (LLM call). Receives the step number, model, messages being sent, tools, and prior steps.
|
|
407
|
-
- **`experimental_onToolExecutionStart`**: Called right before a tool's `execute` function runs. Receives the tool call object
|
|
408
|
-
- **`experimental_onToolExecutionEnd`**: Called right after a tool's `execute` function completes or errors. Receives the tool call, `durationMs`, and a `
|
|
471
|
+
- **`experimental_onToolExecutionStart`**: Called right before a tool's `execute` function runs. Receives the tool call object, messages, and `toolContext`.
|
|
472
|
+
- **`experimental_onToolExecutionEnd`**: Called right after a tool's `execute` function completes or errors. Receives the tool call, `durationMs`, and a `toolOutput` discriminated union (`type: 'tool-result'` with `output`, or `type: 'tool-error'` with `error`).
|
|
409
473
|
- **`onStepFinish`**: Called after each step finishes. Receives step results including usage, finish reason, and tool calls.
|
|
410
474
|
- **`onFinish`**: Called when all steps are finished and the response is complete. Receives all step results, total usage, and `runtimeContext`.
|
|
411
475
|
|
|
@@ -334,7 +334,9 @@ export function Chat() {
|
|
|
334
334
|
|
|
335
335
|
### No Tool Approvals in Subagents
|
|
336
336
|
|
|
337
|
-
Subagent tools cannot use
|
|
337
|
+
Subagent tools cannot use approval flows such as `toolApproval` (or the
|
|
338
|
+
deprecated `needsApproval`). All tools must execute automatically without user
|
|
339
|
+
confirmation.
|
|
338
340
|
|
|
339
341
|
### Subagent Context is Isolated
|
|
340
342
|
|
|
@@ -302,7 +302,11 @@ Tools without `'use step'` still work but run as regular in-memory functions wit
|
|
|
302
302
|
|
|
303
303
|
## Tool Approval
|
|
304
304
|
|
|
305
|
-
|
|
305
|
+
For `WorkflowAgent`, human approval is configured on the tool definition with
|
|
306
|
+
`needsApproval`. This is specific to `WorkflowAgent`; for `generateText`,
|
|
307
|
+
`streamText`, and `ToolLoopAgent`, use `toolApproval` instead. When a workflow
|
|
308
|
+
tool has `needsApproval` set, the agent pauses and emits an approval request to
|
|
309
|
+
the writable stream. The workflow suspends until the user approves or denies:
|
|
306
310
|
|
|
307
311
|
```ts
|
|
308
312
|
const agent = new WorkflowAgent({
|
|
@@ -426,7 +430,7 @@ Agents provide lifecycle callbacks for logging, observability, and custom teleme
|
|
|
426
430
|
const agent = new WorkflowAgent({
|
|
427
431
|
model: "anthropic/claude-sonnet-4-6",
|
|
428
432
|
|
|
429
|
-
experimental_onStart({
|
|
433
|
+
experimental_onStart({ modelId, messages }) {
|
|
430
434
|
console.log("Agent started");
|
|
431
435
|
},
|
|
432
436
|
|
|
@@ -438,7 +442,7 @@ const agent = new WorkflowAgent({
|
|
|
438
442
|
console.log(`Calling tool: ${toolCall.toolName}`);
|
|
439
443
|
},
|
|
440
444
|
|
|
441
|
-
experimental_onToolExecutionEnd({ toolCall,
|
|
445
|
+
experimental_onToolExecutionEnd({ toolCall, toolOutput }) {
|
|
442
446
|
console.log(`Tool finished: ${toolCall.toolName}`);
|
|
443
447
|
},
|
|
444
448
|
|
|
@@ -466,6 +470,129 @@ const myAgent = new WorkflowAgent({
|
|
|
466
470
|
export type MyAgentUIMessage = InferWorkflowAgentUIMessage<typeof myAgent>;
|
|
467
471
|
```
|
|
468
472
|
|
|
473
|
+
## Migrating from `DurableAgent`
|
|
474
|
+
|
|
475
|
+
`WorkflowAgent` replaces the Workflow DevKit's [`DurableAgent`](https://workflow-sdk.dev/docs/api-reference/workflow-ai/durable-agent). The two share the same core idea — a durable agent loop that runs inside a workflow — but `WorkflowAgent` moves the class into the AI SDK, tightens typing, and introduces first-class tool approval. If you are using `DurableAgent` today, follow the steps below to switch.
|
|
476
|
+
|
|
477
|
+
### Change the import and class name
|
|
478
|
+
|
|
479
|
+
`DurableAgent` was exported from `workflow/ai`. `WorkflowAgent` is exported from `@ai-sdk/workflow`, alongside its helpers.
|
|
480
|
+
|
|
481
|
+
```diff
|
|
482
|
+
- import { DurableAgent } from 'workflow/ai';
|
|
483
|
+
+ import { WorkflowAgent, type ModelCallStreamPart } from '@ai-sdk/workflow';
|
|
484
|
+
|
|
485
|
+
- const agent = new DurableAgent({
|
|
486
|
+
+ const agent = new WorkflowAgent({
|
|
487
|
+
model: 'anthropic/claude-sonnet-4-6',
|
|
488
|
+
instructions: 'You are a helpful assistant.',
|
|
489
|
+
tools: { /* ... */ },
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Install the new package alongside `workflow`:
|
|
494
|
+
|
|
495
|
+
```bash
|
|
496
|
+
npm install @ai-sdk/workflow
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Write `ModelCallStreamPart`, not `UIMessageChunk`
|
|
500
|
+
|
|
501
|
+
`DurableAgent` wrote `UIMessageChunk` objects directly to the writable returned by `getWritable()`. `WorkflowAgent` writes the lower-level `ModelCallStreamPart` shape and leaves the conversion to a transform at the response boundary. This keeps the durable stream provider-shaped and avoids baking a UI protocol into the workflow payload.
|
|
502
|
+
|
|
503
|
+
```diff
|
|
504
|
+
// Inside the workflow
|
|
505
|
+
await agent.stream({
|
|
506
|
+
messages,
|
|
507
|
+
- writable: getWritable<UIMessageChunk>(),
|
|
508
|
+
+ writable: getWritable<ModelCallStreamPart>(),
|
|
509
|
+
});
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
```diff
|
|
513
|
+
// Inside the route handler
|
|
514
|
+
+ import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
|
|
515
|
+
|
|
516
|
+
return createUIMessageStreamResponse({
|
|
517
|
+
- stream: run.readable,
|
|
518
|
+
+ stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Replace `maxSteps` with `stopWhen`
|
|
523
|
+
|
|
524
|
+
`DurableAgent` accepted `maxSteps` directly. `WorkflowAgent` uses the AI SDK's shared `stopWhen` conditions so the same stop logic works across `ToolLoopAgent`, `generateText`, and `streamText`.
|
|
525
|
+
|
|
526
|
+
```diff
|
|
527
|
+
+ import { isStepCount } from 'ai';
|
|
528
|
+
|
|
529
|
+
await agent.stream({
|
|
530
|
+
messages,
|
|
531
|
+
- maxSteps: 10,
|
|
532
|
+
+ stopWhen: isStepCount(10),
|
|
533
|
+
});
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
See [Loop Control](/docs/agents/loop-control) for the full list of stop conditions.
|
|
537
|
+
|
|
538
|
+
### Replace `experimental_output` with `output`
|
|
539
|
+
|
|
540
|
+
```diff
|
|
541
|
+
+ import { Output } from '@ai-sdk/workflow';
|
|
542
|
+
|
|
543
|
+
await agent.stream({
|
|
544
|
+
messages,
|
|
545
|
+
- experimental_output: Output.object({ schema }),
|
|
546
|
+
+ output: Output.object({ schema }),
|
|
547
|
+
});
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
The returned value is now on `result.output` (previously `result.experimental_output`).
|
|
551
|
+
|
|
552
|
+
### WorkflowAgent: Use `needsApproval` for human-in-the-loop tools
|
|
553
|
+
|
|
554
|
+
With `DurableAgent`, tool approval was implemented by calling a Hook from inside the tool's `execute` function. `WorkflowAgent` makes approval a first-class tool property — the agent emits the approval request, suspends the workflow, and resumes automatically when the user responds.
|
|
555
|
+
|
|
556
|
+
```diff
|
|
557
|
+
bookFlight: tool({
|
|
558
|
+
description: 'Book a flight',
|
|
559
|
+
inputSchema: z.object({ flightId: z.string() }),
|
|
560
|
+
+ needsApproval: true,
|
|
561
|
+
- execute: async (input) => {
|
|
562
|
+
- const approved = await waitForApprovalHook(input);
|
|
563
|
+
- if (!approved) throw new Error('Denied');
|
|
564
|
+
- return bookFlightStep(input);
|
|
565
|
+
- },
|
|
566
|
+
+ execute: bookFlightStep,
|
|
567
|
+
}),
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
`needsApproval` also accepts an async function so you can decide per-input
|
|
571
|
+
whether approval is required (see [Tool Approval](#tool-approval) above).
|
|
572
|
+
|
|
573
|
+
### `uiMessages` / `collectUIMessages` is gone
|
|
574
|
+
|
|
575
|
+
`DurableAgent.stream()` returned accumulated `uiMessages` when `collectUIMessages: true` was set. `WorkflowAgent.stream()` returns `ModelMessage[]` on `result.messages` instead — persist those and convert them at the edge with `convertToModelMessages` / `convertToUIMessages` as needed.
|
|
576
|
+
|
|
577
|
+
```diff
|
|
578
|
+
const result = await agent.stream({
|
|
579
|
+
messages,
|
|
580
|
+
writable: getWritable<ModelCallStreamPart>(),
|
|
581
|
+
- collectUIMessages: true,
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
- return { uiMessages: result.uiMessages };
|
|
585
|
+
+ return { messages: result.messages };
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### No `generate()` method
|
|
589
|
+
|
|
590
|
+
`WorkflowAgent` only exposes `stream()`. If you were calling `agent.generate()`, switch to `stream()` and read `result.messages` / `result.output` once the promise resolves.
|
|
591
|
+
|
|
592
|
+
### Everything else
|
|
593
|
+
|
|
594
|
+
Other options carry over with the same names: `prepareStep`, `onStepFinish`, `onFinish`, `onError`, `toolChoice`, `activeTools`, `timeout`, `experimental_context`, `experimental_repairToolCall`, and the usual generation settings (`temperature`, `maxOutputTokens`, `topP`, …). `WorkflowAgent` additionally adds `prepareCall` (runs once before the loop) and the `experimental_onStart` / `experimental_onStepStart` / `experimental_onToolExecutionStart` / `experimental_onToolExecutionEnd` lifecycle callbacks documented above.
|
|
595
|
+
|
|
469
596
|
## Next Steps
|
|
470
597
|
|
|
471
598
|
- [WorkflowAgent API Reference](/docs/reference/ai-sdk-workflow/workflow-agent) for detailed parameter documentation
|
package/docs/03-agents/index.mdx
CHANGED
|
@@ -11,12 +11,14 @@ The following section shows you how to build agents with the AI SDK - systems wh
|
|
|
11
11
|
cards={[
|
|
12
12
|
{
|
|
13
13
|
title: 'Overview',
|
|
14
|
-
description:
|
|
14
|
+
description:
|
|
15
|
+
'Learn what agents are, how they manage state, and why to use the ToolLoopAgent.',
|
|
15
16
|
href: '/docs/agents/overview',
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
19
|
title: 'Building Agents',
|
|
19
|
-
description:
|
|
20
|
+
description:
|
|
21
|
+
'Create ToolLoopAgent instances with tools, runtime context, and loop control.',
|
|
20
22
|
href: '/docs/agents/building-agents',
|
|
21
23
|
},
|
|
22
24
|
{
|
|
@@ -127,21 +127,35 @@ const result = await generateText({
|
|
|
127
127
|
// ... your tools
|
|
128
128
|
},
|
|
129
129
|
|
|
130
|
-
experimental_onStart({
|
|
131
|
-
console.log('Generation started', {
|
|
130
|
+
experimental_onStart({ modelId }) {
|
|
131
|
+
console.log('Generation started', { modelId });
|
|
132
132
|
},
|
|
133
133
|
|
|
134
|
-
experimental_onStepStart({ stepNumber,
|
|
135
|
-
console.log(`Step ${stepNumber} starting`, {
|
|
134
|
+
experimental_onStepStart({ stepNumber, modelId, messages }) {
|
|
135
|
+
console.log(`Step ${stepNumber} starting`, { modelId });
|
|
136
136
|
},
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
console.log(
|
|
138
|
+
experimental_onLanguageModelCallStart({ modelId, messages }) {
|
|
139
|
+
console.log('Model call starting', { modelId, messageCount: messages.length });
|
|
140
140
|
},
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
console.log(
|
|
144
|
-
|
|
142
|
+
experimental_onLanguageModelCallEnd({ modelId, finishReason, content }) {
|
|
143
|
+
console.log('Model call finished', {
|
|
144
|
+
modelId,
|
|
145
|
+
finishReason,
|
|
146
|
+
contentParts: content.length,
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
experimental_onToolExecutionStart({ toolCall }) {
|
|
151
|
+
console.log(`Tool call starting: ${toolCall.toolName}`, {
|
|
152
|
+
toolCallId: toolCall.toolCallId,
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
experimental_onToolExecutionEnd({ toolCall, durationMs, toolOutput }) {
|
|
157
|
+
console.log(`Tool call finished: ${toolCall.toolName} (${durationMs}ms)`, {
|
|
158
|
+
success: toolOutput.type === 'tool-result',
|
|
145
159
|
});
|
|
146
160
|
},
|
|
147
161
|
|
|
@@ -153,11 +167,13 @@ const result = await generateText({
|
|
|
153
167
|
|
|
154
168
|
The available lifecycle callbacks are:
|
|
155
169
|
|
|
156
|
-
- **`experimental_onStart`**: Called once when the `generateText` operation begins, before any LLM calls. Receives model info,
|
|
157
|
-
- **`experimental_onStepStart`**: Called before each step (LLM call). Receives the step number, model,
|
|
158
|
-
- **`
|
|
159
|
-
- **`
|
|
160
|
-
- **`
|
|
170
|
+
- **`experimental_onStart`**: Called once when the `generateText` operation begins, before any LLM calls. Receives model info, messages, settings, and `runtimeContext`.
|
|
171
|
+
- **`experimental_onStepStart`**: Called before each step (LLM call). Receives the step number, model, messages being sent, tools, and prior steps.
|
|
172
|
+
- **`experimental_onLanguageModelCallStart`**: Called immediately before the provider model call begins. Useful when you want to observe the model invocation separately from later tool execution.
|
|
173
|
+
- **`experimental_onLanguageModelCallEnd`**: Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Receives the model-call content parts, usage, and finish reason.
|
|
174
|
+
- **`experimental_onToolExecutionStart`**: Called right before a tool's `execute` function runs. Receives the tool call object, messages, and `toolContext`.
|
|
175
|
+
- **`experimental_onToolExecutionEnd`**: Called right after a tool's `execute` function completes or errors. Receives the tool call object, `durationMs`, and a `toolOutput` discriminated union (`type: 'tool-result'` with `output`, or `type: 'tool-error'` with `error`).
|
|
176
|
+
- **`onStepFinish`**: Called after each step finishes. Includes `stepNumber` (zero-based index of the completed step).
|
|
161
177
|
|
|
162
178
|
## `streamText`
|
|
163
179
|
|
|
@@ -319,12 +335,24 @@ const result = streamText({
|
|
|
319
335
|
// ... your tools
|
|
320
336
|
},
|
|
321
337
|
|
|
322
|
-
experimental_onStart({
|
|
323
|
-
console.log('Streaming started', {
|
|
338
|
+
experimental_onStart({ modelId, system, messages }) {
|
|
339
|
+
console.log('Streaming started', { modelId });
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
experimental_onStepStart({ stepNumber, modelId, messages }) {
|
|
343
|
+
console.log(`Step ${stepNumber} starting`, { modelId });
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
experimental_onLanguageModelCallStart({ modelId, messages }) {
|
|
347
|
+
console.log('Model call starting', { modelId, messageCount: messages.length });
|
|
324
348
|
},
|
|
325
349
|
|
|
326
|
-
|
|
327
|
-
console.log(
|
|
350
|
+
experimental_onLanguageModelCallEnd({ modelId, finishReason, content }) {
|
|
351
|
+
console.log('Model call finished', {
|
|
352
|
+
modelId,
|
|
353
|
+
finishReason,
|
|
354
|
+
contentParts: content.length,
|
|
355
|
+
});
|
|
328
356
|
},
|
|
329
357
|
|
|
330
358
|
experimental_onToolExecutionStart({ toolCall }) {
|
|
@@ -333,9 +361,9 @@ const result = streamText({
|
|
|
333
361
|
});
|
|
334
362
|
},
|
|
335
363
|
|
|
336
|
-
experimental_onToolExecutionEnd({ toolCall, durationMs,
|
|
364
|
+
experimental_onToolExecutionEnd({ toolCall, durationMs, toolOutput }) {
|
|
337
365
|
console.log(`Tool call finished: ${toolCall.toolName} (${durationMs}ms)`, {
|
|
338
|
-
success,
|
|
366
|
+
success: toolOutput.type === 'tool-result',
|
|
339
367
|
});
|
|
340
368
|
},
|
|
341
369
|
|
|
@@ -347,10 +375,12 @@ const result = streamText({
|
|
|
347
375
|
|
|
348
376
|
The available lifecycle callbacks are:
|
|
349
377
|
|
|
350
|
-
- **`experimental_onStart`**: Called once when the `streamText` operation begins, before any LLM calls. Receives model info,
|
|
378
|
+
- **`experimental_onStart`**: Called once when the `streamText` operation begins, before any LLM calls. Receives model info, messages, settings, and `runtimeContext`.
|
|
351
379
|
- **`experimental_onStepStart`**: Called before each step (LLM call). Receives the step number, model, messages being sent, tools, and prior steps.
|
|
352
|
-
- **`
|
|
353
|
-
- **`
|
|
380
|
+
- **`experimental_onLanguageModelCallStart`**: Called immediately before the provider model call begins. Useful when you want to observe the model invocation separately from later tool execution.
|
|
381
|
+
- **`experimental_onLanguageModelCallEnd`**: Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Receives the model-call content parts, usage, and finish reason.
|
|
382
|
+
- **`experimental_onToolExecutionStart`**: Called right before a tool's `execute` function runs. Receives the tool call object, messages, and `toolContext`.
|
|
383
|
+
- **`experimental_onToolExecutionEnd`**: Called right after a tool's `execute` function completes or errors. Receives the tool call object, `durationMs`, and a `toolOutput` discriminated union (`type: 'tool-result'` with `output`, or `type: 'tool-error'` with `error`).
|
|
354
384
|
- **`onStepFinish`**: Called after each step finishes. Receives the finish reason, usage, and other step details.
|
|
355
385
|
|
|
356
386
|
### `fullStream` property
|