Skip to content

Commit ab1087b

Browse files
bel0vgr2m
andauthored
feat(ai): chat.addToolResult() is now chat.addToolOutput() (#10039)
## Summary * Renamed `addToolResult()` into `addToolOutput()` * `addToolResult` in `chat` and `useChat` is left with deprecation notice, pointing to `addToolOutput` * Updated method call in tests; Copied one test with `addToolResult` to make sure it works the same * Updated docs & v5 migration guide * Added codemod ## Related Issues Fixes #8575 --------- Co-authored-by: Gregor Martynus <[email protected]>
1 parent 6322761 commit ab1087b

File tree

32 files changed

+712
-150
lines changed

32 files changed

+712
-150
lines changed

.changeset/early-maps-grin.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@ai-sdk/react': patch
3+
'ai': patch
4+
---
5+
6+
feat(ai): `chat.addToolResult()` is now `chat.addToolOutput()`

content/cookbook/01-next/75-human-in-the-loop.mdx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export async function POST(req: Request) {
185185

186186
On the frontend, you map through the messages, either rendering the message content or checking for tool invocations and rendering custom UI.
187187

188-
You can check if the tool requiring confirmation has been called and, if so, present options to either confirm or deny the proposed tool call. This confirmation is done using the `addToolResult` function to create a tool result and append it to the associated tool call.
188+
You can check if the tool requiring confirmation has been called and, if so, present options to either confirm or deny the proposed tool call. This confirmation is done using the `addToolOutput` function to create a tool result and append it to the associated tool call.
189189

190190
```tsx filename="app/page.tsx"
191191
'use client';
@@ -195,7 +195,7 @@ import { DefaultChatTransport, isToolUIPart, getToolName } from 'ai';
195195
import { useState } from 'react';
196196

197197
export default function Chat() {
198-
const { messages, addToolResult, sendMessage } = useChat({
198+
const { messages, addToolOutput, sendMessage } = useChat({
199199
transport: new DefaultChatTransport({
200200
api: '/api/chat',
201201
}),
@@ -227,7 +227,7 @@ export default function Chat() {
227227
<div>
228228
<button
229229
onClick={async () => {
230-
await addToolResult({
230+
await addToolOutput({
231231
toolCallId,
232232
tool: toolName,
233233
output: 'Yes, confirmed.',
@@ -239,7 +239,7 @@ export default function Chat() {
239239
</button>
240240
<button
241241
onClick={async () => {
242-
await addToolResult({
242+
await addToolOutput({
243243
toolCallId,
244244
tool: toolName,
245245
output: 'No, denied.',
@@ -281,13 +281,13 @@ export default function Chat() {
281281
```
282282

283283
<Note>
284-
The `sendMessage()` function after `addToolResult` will trigger a call to your
284+
The `sendMessage()` function after `addToolOutput` will trigger a call to your
285285
route handler.
286286
</Note>
287287

288288
### Handle Confirmation Response
289289

290-
Adding a tool result and sending the message will trigger another call to your route handler. Before sending the new messages to the language model, you pull out the last message and map through the message parts to see if the tool requiring confirmation was called and whether it's in a "result" state. If those conditions are met, you check the confirmation state (the tool result state that you set on the frontend with the `addToolResult` function).
290+
Adding a tool result and sending the message will trigger another call to your route handler. Before sending the new messages to the language model, you pull out the last message and map through the message parts to see if the tool requiring confirmation was called and whether it's in a "result" state. If those conditions are met, you check the confirmation state (the tool result state that you set on the frontend with the `addToolOutput` function).
291291

292292
```ts filename="api/chat/route.ts"
293293
import { openai } from '@ai-sdk/openai';
@@ -388,7 +388,7 @@ async function executeWeatherTool({ city }: { city: string }) {
388388
}
389389
```
390390

391-
In this implementation, you use simple strings like "Yes, the user confirmed" or "No, the user declined" as states. If confirmed, you execute the tool. If declined, you do not execute the tool. In both cases, you update the tool result from the arbitrary data you sent with the `addToolResult` function to either the result of the execute function or an "Execution declined" statement. You send the updated tool result back to the frontend to maintain state synchronization.
391+
In this implementation, you use simple strings like "Yes, the user confirmed" or "No, the user declined" as states. If confirmed, you execute the tool. If declined, you do not execute the tool. In both cases, you update the tool result from the arbitrary data you sent with the `addToolOutput` function to either the result of the execute function or an "Execution declined" statement. You send the updated tool result back to the frontend to maintain state synchronization.
392392

393393
After handling the tool result, your API route continues. This triggers another generation with the updated tool result, allowing the LLM to continue attempting to solve the query.
394394

@@ -666,7 +666,7 @@ import { useState } from 'react';
666666
import { HumanInTheLoopUIMessage, MyTools } from '../api/chat/types';
667667

668668
export default function Chat() {
669-
const { messages, addToolResult, sendMessage } =
669+
const { messages, addToolOutput, sendMessage } =
670670
useChat<HumanInTheLoopUIMessage>({
671671
transport: new DefaultChatTransport({
672672
api: '/api/chat',
@@ -716,7 +716,7 @@ export default function Chat() {
716716
<button
717717
className="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700"
718718
onClick={async () => {
719-
await addToolResult({
719+
await addToolOutput({
720720
toolCallId,
721721
tool: toolName,
722722
output: APPROVAL.YES,
@@ -729,7 +729,7 @@ export default function Chat() {
729729
<button
730730
className="px-4 py-2 font-bold text-white bg-red-500 rounded hover:bg-red-700"
731731
onClick={async () => {
732-
await addToolResult({
732+
await addToolOutput({
733733
toolCallId,
734734
tool: toolName,
735735
output: APPROVAL.NO,

content/cookbook/01-next/90-render-visual-interface-in-chat.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import { ChatMessage } from './api/chat/route';
5454

5555
export default function Chat() {
5656
const [input, setInput] = useState('');
57-
const { messages, sendMessage, addToolResult } = useChat<ChatMessage>({
57+
const { messages, sendMessage, addToolOutput } = useChat<ChatMessage>({
5858
transport: new DefaultChatTransport({
5959
api: '/api/chat',
6060
}),
@@ -67,7 +67,7 @@ export default function Chat() {
6767
const cities = ['New York', 'Los Angeles', 'Chicago', 'San Francisco'];
6868

6969
// No await - avoids potential deadlocks
70-
addToolResult({
70+
addToolOutput({
7171
tool: 'getLocation',
7272
toolCallId: toolCall.toolCallId,
7373
output: cities[Math.floor(Math.random() * cities.length)],
@@ -100,7 +100,7 @@ export default function Chat() {
100100
<button
101101
className="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700"
102102
onClick={() =>
103-
addToolResult({
103+
addToolOutput({
104104
tool: 'askForConfirmation',
105105
toolCallId: part.toolCallId,
106106
output: 'Yes, confirmed.',
@@ -112,7 +112,7 @@ export default function Chat() {
112112
<button
113113
className="px-4 py-2 font-bold text-white bg-red-500 rounded hover:bg-red-700"
114114
onClick={() =>
115-
addToolResult({
115+
addToolOutput({
116116
tool: 'askForConfirmation',
117117
toolCallId: part.toolCallId,
118118
output: 'No, denied',

content/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ The flow is as follows:
2020
1. All tool calls are forwarded to the client.
2121
1. Server-side tools are executed using their `execute` method and their results are forwarded to the client.
2222
1. Client-side tools that should be automatically executed are handled with the `onToolCall` callback.
23-
You must call `addToolResult` to provide the tool result.
23+
You must call `addToolOutput` to provide the tool result.
2424
1. Client-side tool that require user interactions can be displayed in the UI.
2525
The tool calls and results are available as tool invocation parts in the `parts` property of the last assistant message.
26-
1. When the user interaction is done, `addToolResult` can be used to add the tool result to the chat.
26+
1. When the user interaction is done, `addToolOutput` can be used to add the tool result to the chat.
2727
1. The chat can be configured to automatically submit when all tool results are available using `sendAutomaticallyWhen`.
2828
This triggers another iteration of this flow.
2929

@@ -104,21 +104,21 @@ There are three things worth mentioning:
104104

105105
1. The [`onToolCall`](/docs/reference/ai-sdk-ui/use-chat#on-tool-call) callback is used to handle client-side tools that should be automatically executed.
106106
In this example, the `getLocation` tool is a client-side tool that returns a random city.
107-
You call `addToolResult` to provide the result (without `await` to avoid potential deadlocks).
107+
You call `addToolOutput` to provide the result (without `await` to avoid potential deadlocks).
108108

109109
<Note>
110110
Always check `if (toolCall.dynamic)` first in your `onToolCall` handler.
111111
Without this check, TypeScript will throw an error like: `Type 'string' is
112112
not assignable to type '"toolName1" | "toolName2"'` when you try to use
113-
`toolCall.toolName` in `addToolResult`.
113+
`toolCall.toolName` in `addToolOutput`.
114114
</Note>
115115

116116
2. The [`sendAutomaticallyWhen`](/docs/reference/ai-sdk-ui/use-chat#send-automatically-when) option with `lastAssistantMessageIsCompleteWithToolCalls` helper automatically submits when all tool results are available.
117117

118118
3. The `parts` array of assistant messages contains tool parts with typed names like `tool-askForConfirmation`.
119119
The client-side tool `askForConfirmation` is displayed in the UI.
120120
It asks the user for confirmation and displays the result once the user confirms or denies the execution.
121-
The result is added to the chat using `addToolResult` with the `tool` parameter for type safety.
121+
The result is added to the chat using `addToolOutput` with the `tool` parameter for type safety.
122122

123123
```tsx filename='app/page.tsx' highlight="2,6,10,14-20"
124124
'use client';
@@ -131,7 +131,7 @@ import {
131131
import { useState } from 'react';
132132

133133
export default function Chat() {
134-
const { messages, sendMessage, addToolResult } = useChat({
134+
const { messages, sendMessage, addToolOutput } = useChat({
135135
transport: new DefaultChatTransport({
136136
api: '/api/chat',
137137
}),
@@ -149,7 +149,7 @@ export default function Chat() {
149149
const cities = ['New York', 'Los Angeles', 'Chicago', 'San Francisco'];
150150

151151
// No await - avoids potential deadlocks
152-
addToolResult({
152+
addToolOutput({
153153
tool: 'getLocation',
154154
toolCallId: toolCall.toolCallId,
155155
output: cities[Math.floor(Math.random() * cities.length)],
@@ -186,7 +186,7 @@ export default function Chat() {
186186
<div>
187187
<button
188188
onClick={() =>
189-
addToolResult({
189+
addToolOutput({
190190
tool: 'askForConfirmation',
191191
toolCallId: callId,
192192
output: 'Yes, confirmed.',
@@ -197,7 +197,7 @@ export default function Chat() {
197197
</button>
198198
<button
199199
onClick={() =>
200-
addToolResult({
200+
addToolOutput({
201201
tool: 'askForConfirmation',
202202
toolCallId: callId,
203203
output: 'No, denied',
@@ -298,7 +298,7 @@ export default function Chat() {
298298

299299
### Error handling
300300

301-
Sometimes an error may occur during client-side tool execution. Use the `addToolResult` method with a `state` of `output-error` and `errorText` value instead of `output` record the error.
301+
Sometimes an error may occur during client-side tool execution. Use the `addToolOutput` method with a `state` of `output-error` and `errorText` value instead of `output` record the error.
302302

303303
```tsx filename='app/page.tsx' highlight="19,36-41"
304304
'use client';
@@ -311,7 +311,7 @@ import {
311311
import { useState } from 'react';
312312

313313
export default function Chat() {
314-
const { messages, sendMessage, addToolResult } = useChat({
314+
const { messages, sendMessage, addToolOutput } = useChat({
315315
transport: new DefaultChatTransport({
316316
api: '/api/chat',
317317
}),
@@ -330,13 +330,13 @@ export default function Chat() {
330330
const weather = await getWeatherInformation(toolCall.input);
331331

332332
// No await - avoids potential deadlocks
333-
addToolResult({
333+
addToolOutput({
334334
tool: 'getWeatherInformation',
335335
toolCallId: toolCall.toolCallId,
336336
output: weather,
337337
});
338338
} catch (err) {
339-
addToolResult({
339+
addToolOutput({
340340
tool: 'getWeatherInformation',
341341
toolCallId: toolCall.toolCallId,
342342
state: 'output-error',

content/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Allows you to easily create a conversational user interface for your chatbot app
230230
type: '({toolCall: ToolCall}) => void | Promise<void>',
231231
isOptional: true,
232232
description:
233-
'Optional callback function that is invoked when a tool call is received. You must call addToolResult to provide the tool result.',
233+
'Optional callback function that is invoked when a tool call is received. You must call addToolOutput to provide the tool result.',
234234
},
235235
{
236236
name: 'sendAutomaticallyWhen',
@@ -418,7 +418,7 @@ Allows you to easily create a conversational user interface for your chatbot app
418418
'Function to resume an interrupted streaming response. Useful when a network error occurs during streaming.',
419419
},
420420
{
421-
name: 'addToolResult',
421+
name: 'addToolOutput',
422422
type: '(options: { tool: string; toolCallId: string; output: unknown } | { tool: string; toolCallId: string; state: "output-error", errorText: string }) => void',
423423
description:
424424
'Function to add a tool result to the chat. This will update the chat messages with the tool result. If sendAutomaticallyWhen is configured, it may trigger an automatic submission.',

content/docs/08-migration-guides/26-migration-guide-5-0.mdx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,15 +1294,15 @@ import {
12941294
lastAssistantMessageIsCompleteWithToolCalls,
12951295
} from 'ai';
12961296

1297-
const { messages, sendMessage, addToolResult } = useChat({
1297+
const { messages, sendMessage, addToolOutput } = useChat({
12981298
// Automatically submit when all tool results are available
12991299
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
13001300

13011301
async onToolCall({ toolCall }) {
13021302
const result = await executeToolCall(toolCall);
13031303

1304-
// Important: Don't await addToolResult inside onToolCall to avoid deadlocks
1305-
addToolResult({
1304+
// Important: Don't await addToolOutput inside onToolCall to avoid deadlocks
1305+
addToolOutput({
13061306
tool: toolCall.toolName,
13071307
toolCallId: toolCall.toolCallId,
13081308
output: result,
@@ -1313,7 +1313,7 @@ const { messages, sendMessage, addToolResult } = useChat({
13131313

13141314
<Note>
13151315
Important: When using `sendAutomaticallyWhen`, don't use `await` with
1316-
`addToolResult` inside `onToolCall` as it can cause deadlocks. The `await` is
1316+
`addToolOutput` inside `onToolCall` as it can cause deadlocks. The `await` is
13171317
useful when you're not using automatic submission and need to ensure the
13181318
messages are updated before manually calling `sendMessage()`.
13191319
</Note>
@@ -1613,9 +1613,9 @@ import type { RequestOptions } from 'ai';
16131613
import type { CompletionRequestOptions } from 'ai';
16141614
```
16151615

1616-
#### addToolResult Changes
1616+
#### addToolResult Renamed to addToolOutput
16171617

1618-
In the `addToolResult` function, the `result` parameter has been renamed to `output` for consistency with other tool-related APIs.
1618+
The `addToolResult` method has been renamed to `addToolOutput`. Additionally, the `result` parameter has been renamed to `output` for consistency with other tool-related APIs.
16191619

16201620
```tsx filename="AI SDK 4.0"
16211621
const { addToolResult } = useChat();
@@ -1628,24 +1628,29 @@ addToolResult({
16281628
```
16291629

16301630
```tsx filename="AI SDK 5.0"
1631-
const { addToolResult } = useChat();
1631+
const { addToolOutput } = useChat();
16321632

1633-
// Add tool result with 'output' parameter and 'tool' name for type safety
1634-
addToolResult({
1633+
// Add tool output with 'output' parameter and 'tool' name for type safety
1634+
addToolOutput({
16351635
tool: 'getWeather',
16361636
toolCallId: 'tool-call-123',
16371637
output: 'Weather: 72°F, sunny',
16381638
});
16391639
```
16401640

1641+
<Note>
1642+
`addToolResult` is still available but deprecated. It will be removed in
1643+
version 6.
1644+
</Note>
1645+
16411646
#### Tool Result Submission Changes
16421647

16431648
The automatic tool result submission behavior has been updated in `useChat` and the `Chat` component. You now have more control and flexibility over when tool results are submitted.
16441649

16451650
- `onToolCall` no longer supports returning values to automatically submit tool results
1646-
- You must explicitly call `addToolResult` to provide tool results
1651+
- You must explicitly call `addToolOutput` to provide tool results
16471652
- Use `sendAutomaticallyWhen` with `lastAssistantMessageIsCompleteWithToolCalls` helper for automatic submission
1648-
- Important: Don't use `await` with `addToolResult` inside `onToolCall` to avoid deadlocks
1653+
- Important: Don't use `await` with `addToolOutput` inside `onToolCall` to avoid deadlocks
16491654
- The `maxSteps` parameter has been removed from the `Chat` component and `useChat` hook
16501655
- For multi-step tool execution, use server-side `stopWhen` conditions instead (see [maxSteps Removal](#maxsteps-removal))
16511656

@@ -1670,7 +1675,7 @@ import {
16701675
lastAssistantMessageIsCompleteWithToolCalls,
16711676
} from 'ai';
16721677

1673-
const { messages, sendMessage, addToolResult } = useChat({
1678+
const { messages, sendMessage, addToolOutput } = useChat({
16741679
// Automatic submission with helper
16751680
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
16761681

@@ -1679,7 +1684,7 @@ const { messages, sendMessage, addToolResult } = useChat({
16791684
const cities = ['New York', 'Los Angeles', 'Chicago', 'San Francisco'];
16801685

16811686
// Important: Don't await inside onToolCall to avoid deadlocks
1682-
addToolResult({
1687+
addToolOutput({
16831688
tool: 'getLocation',
16841689
toolCallId: toolCall.toolCallId,
16851690
output: cities[Math.floor(Math.random() * cities.length)],

0 commit comments

Comments
 (0)