Call Tools

Learn how to call tools using the AI TOOLKIT and Next.js

3 min readnexttool useView source

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 ai

Client

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>

);

}

app/page.tsx
tsx
  1. 1'use client';
  2. 2import { useChat } from '@ai-toolkit/react';
  3. 3import { DefaultChatTransport } from 'ai-toolkit';
  4. 4import { useState } from 'react';
  5. 5import type { ChatMessage } from './api/chat/route';
  6. 6export default function Page() {
  7. 7 const [input, setInput] = useState('');
  8. 8 const { messages, sendMessage } = useChat<ChatMessage>({
  9. 9 transport: new DefaultChatTransport({
  10. 10 api: '/api/chat',
  11. 11 }),
  12. 12 });
  13. 13 return (
  14. 14 <div>
  15. 15 <input
  16. 16 className="border"
  17. 17 value={input}
  18. 18 onChange={event => {
  19. 19 setInput(event.target.value);
  20. 20 }}
  21. 21 onKeyDown={async event => {
  22. 22 if (event.key === 'Enter') {
  23. 23 sendMessage({
  24. 24 text: input,
  25. 25 });
  26. 26 setInput('');
  27. 27 }
  28. 28 }}
  29. 29 />
  30. 30 {messages.map((message, index) => (
  31. 31 <div key={index}>
  32. 32 {message.parts.map(part => {
  33. 33 switch (part.type) {
  34. 34 case 'text':
  35. 35 return <div key={`${message.id}-text`}>{part.text}</div>;
  36. 36 case 'tool-getWeather':
  37. 37 return (
  38. 38 <div key={`${message.id}-weather`}>
  39. 39 {JSON.stringify(part, null, 2)}
  40. 40 </div>
  41. 41 );
  42. 42 }
  43. 43 })}
  44. 44 </div>
  45. 45 ))}
  46. 46 </div>
  47. 47 );
  48. 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" />

app/api/chat/route.ts
tsx
  1. 1import {
  2. 2 type InferUITools,
  3. 3 type ToolSet,
  4. 4 type UIDataTypes,
  5. 5 type UIMessage,
  6. 6 convertToModelMessages,
  7. 7 stepCountIs,
  8. 8 streamText,
  9. 9 tool,
  10. 10} from 'ai-toolkit';
  11. 11import { z } from 'zod';
  12. 12const tools = {
  13. 13 getWeather: tool({
  14. 14 description: 'Get the weather for a location',
  15. 15 inputSchema: z.object({
  16. 16 city: z.string().describe('The city to get the weather for'),
  17. 17 unit: z
  18. 18 .enum(['C', 'F'])
  19. 19 .describe('The unit to display the temperature in'),
  20. 20 }),
  21. 21 execute: async ({ city, unit }) => {
  22. 22 const weather = {
  23. 23 value: 24,
  24. 24 description: 'Sunny',
  25. 25 };
  26. 26 return `It is currently ${weather.value}°${unit} and ${weather.description} in ${city}!`;
  27. 27 },
  28. 28 }),
  29. 29} satisfies ToolSet;
  30. 30export type ChatTools = InferUITools<typeof tools>;
  31. 31export type ChatMessage = UIMessage<never, UIDataTypes, ChatTools>;
  32. 32export async function POST(req: Request) {
  33. 33 const { messages }: { messages: ChatMessage[] } = await req.json();
  34. 34 const result = streamText({
  35. 35 model: 'openai/gpt-4o',
  36. 36 system: 'You are a helpful assistant.',
  37. 37 messages: await convertToModelMessages(messages),
  38. 38 stopWhen: stepCountIs(5),
  39. 39 tools,
  40. 40 });
  41. 41 return result.toUIMessageStreamResponse();
  42. 42}