Call Tools
Learn how to call tools using the AI TOOLKIT and Next.js
Some models allow developers to provide a list of tools that can be called at any time during a generation. This is useful for extending the capabilities of a language model to either use logic or data to interact with systems external to the model. history={[ { role: 'User', content: 'How is it going?' }, { role: 'Assistant', content: 'All good, how may I help you?' }, ]} inputMessage={{ role: 'User', content: 'What is the weather in Paris and New York?', }} outputMessage={{ role: 'Assistant', content: 'The weather is 24°C in New York and 25°C in Paris. It is sunny in both cities.', }} />
Run it locally
$ npm install aiClient
Let's create a React component that imports the useChat hook from the @ai-toolkit/react module. The useChat hook will call the /api/chat endpoint when the user sends a message. The endpoint will generate the assistant's response based on the conversation history and stream it to the client. If the assistant responds with a tool call, the hook will automatically display them as well.
'use client';
import { useChat } from '@ai-toolkit/react';
import { DefaultChatTransport } from 'ai-toolkit';
import { useState } from 'react';
import type { ChatMessage } from './api/chat/route';
export default function Page() {
const [input, setInput] = useState('');
const { messages, sendMessage } = useChat<ChatMessage>({
transport: new DefaultChatTransport({
api: '/api/chat',
}),
});
return (
<div>
<input
className="border"
value={input}
onChange={event => {
setInput(event.target.value);
}}
onKeyDown={async event => {
if (event.key === 'Enter') {
sendMessage({
text: input,
});
setInput('');
}
}}
/>
{messages.map((message, index) => (
<div key={index}>
{message.parts.map(part => {
switch (part.type) {
case 'text':
return <div key={${message.id}-text}>{part.text}</div>;
case 'tool-getWeather':
return (
<div key={${message.id}-weather}>
{JSON.stringify(part, null, 2)}
</div>
);
}
})}
</div>
))}
</div>
);
}
- 1'use client';
- 2import { useChat } from '@ai-toolkit/react';
- 3import { DefaultChatTransport } from 'ai-toolkit';
- 4import { useState } from 'react';
- 5import type { ChatMessage } from './api/chat/route';
- 6export default function Page() {
- 7 const [input, setInput] = useState('');
- 8 const { messages, sendMessage } = useChat<ChatMessage>({
- 9 transport: new DefaultChatTransport({
- 10 api: '/api/chat',
- 11 }),
- 12 });
- 13 return (
- 14 <div>
- 15 <input
- 16 className="border"
- 17 value={input}
- 18 onChange={event => {
- 19 setInput(event.target.value);
- 20 }}
- 21 onKeyDown={async event => {
- 22 if (event.key === 'Enter') {
- 23 sendMessage({
- 24 text: input,
- 25 });
- 26 setInput('');
- 27 }
- 28 }}
- 29 />
- 30 {messages.map((message, index) => (
- 31 <div key={index}>
- 32 {message.parts.map(part => {
- 33 switch (part.type) {
- 34 case 'text':
- 35 return <div key={`${message.id}-text`}>{part.text}</div>;
- 36 case 'tool-getWeather':
- 37 return (
- 38 <div key={`${message.id}-weather`}>
- 39 {JSON.stringify(part, null, 2)}
- 40 </div>
- 41 );
- 42 }
- 43 })}
- 44 </div>
- 45 ))}
- 46 </div>
- 47 );
- 48}
Server
You will create a new route at /api/chat that will use the streamText function from the ai module to generate the assistant's response based on the conversation history.
You will use the `tools` parameter to specify a tool called celsiusToFahrenheit that will convert a user given value in celsius to fahrenheit.
You will also use zod to specify the schema for the celsiusToFahrenheit function's parameters.
import {
type InferUITools,
type ToolSet,
type UIDataTypes,
type UIMessage,
convertToModelMessages,
stepCountIs,
streamText,
tool,
} from 'ai-toolkit';
import { z } from 'zod';
const tools = {
getWeather: tool({
description: 'Get the weather for a location',
inputSchema: z.object({
city: z.string().describe('The city to get the weather for'),
unit: z
.enum(['C', 'F'])
.describe('The unit to display the temperature in'),
}),
execute: async ({ city, unit }) => {
const weather = {
value: 24,
description: 'Sunny',
};
return It is currently ${weather.value}°${unit} and ${weather.description} in ${city}!;
},
}),
} satisfies ToolSet;
export type ChatTools = InferUITools<typeof tools>;
export type ChatMessage = UIMessage<never, UIDataTypes, ChatTools>;
export async function POST(req: Request) {
const { messages }: { messages: ChatMessage[] } = await req.json();
const result = streamText({
model: 'openai/gpt-4o',
system: 'You are a helpful assistant.',
messages: await convertToModelMessages(messages),
stopWhen: stepCountIs(5),
tools,
});
return result.toUIMessageStreamResponse();
}
---
<GithubLink link="https://github.com/khulnasoft/ai-toolkit/blob/main/examples/next-openai-pages/pages/tools/call-tool/index.tsx" />
- 1import {
- 2 type InferUITools,
- 3 type ToolSet,
- 4 type UIDataTypes,
- 5 type UIMessage,
- 6 convertToModelMessages,
- 7 stepCountIs,
- 8 streamText,
- 9 tool,
- 10} from 'ai-toolkit';
- 11import { z } from 'zod';
- 12const tools = {
- 13 getWeather: tool({
- 14 description: 'Get the weather for a location',
- 15 inputSchema: z.object({
- 16 city: z.string().describe('The city to get the weather for'),
- 17 unit: z
- 18 .enum(['C', 'F'])
- 19 .describe('The unit to display the temperature in'),
- 20 }),
- 21 execute: async ({ city, unit }) => {
- 22 const weather = {
- 23 value: 24,
- 24 description: 'Sunny',
- 25 };
- 26 return `It is currently ${weather.value}°${unit} and ${weather.description} in ${city}!`;
- 27 },
- 28 }),
- 29} satisfies ToolSet;
- 30export type ChatTools = InferUITools<typeof tools>;
- 31export type ChatMessage = UIMessage<never, UIDataTypes, ChatTools>;
- 32export async function POST(req: Request) {
- 33 const { messages }: { messages: ChatMessage[] } = await req.json();
- 34 const result = streamText({
- 35 model: 'openai/gpt-4o',
- 36 system: 'You are a helpful assistant.',
- 37 messages: await convertToModelMessages(messages),
- 38 stopWhen: stepCountIs(5),
- 39 tools,
- 40 });
- 41 return result.toUIMessageStreamResponse();
- 42}