Call Tools

Learn how to call tools using the AI TOOLKIT and React Server Components.

2 min readrsctool 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 24 celsius in fahrenheit?', }} outputMessage={{ role: 'Assistant', content: '24°C is 75.20°F', }} />

Run it locally

$ npm install ai

Client

Let's create a simple conversation between a user and model and place a button that will call continueConversation.

'use client';

import { useState } from 'react';

import { Message, continueConversation } from './actions';

// Allow streaming responses up to 30 seconds

export const maxDuration = 30;

export default function Home() {

const [conversation, setConversation] = useState<Message[]>([]);

const [input, setInput] = useState<string>('');

return (

<div>

<div>

{conversation.map((message, index) => (

<div key={index}>

{message.role}: {message.content}

</div>

))}

</div>

<div>

<input

type="text"

value={input}

onChange={event => {

setInput(event.target.value);

}}

/>

<button

onClick={async () => {

const { messages } = await continueConversation([

...conversation,

{ role: 'user', content: input },

]);

setConversation(messages);

}}

>

Send Message

</button>

</div>

</div>

);

}

app/page.tsx
tsx
  1. 1'use client';
  2. 2import { useState } from 'react';
  3. 3import { Message, continueConversation } from './actions';
  4. 4// Allow streaming responses up to 30 seconds
  5. 5export const maxDuration = 30;
  6. 6export default function Home() {
  7. 7 const [conversation, setConversation] = useState<Message[]>([]);
  8. 8 const [input, setInput] = useState<string>('');
  9. 9 return (
  10. 10 <div>
  11. 11 <div>
  12. 12 {conversation.map((message, index) => (
  13. 13 <div key={index}>
  14. 14 {message.role}: {message.content}
  15. 15 </div>
  16. 16 ))}
  17. 17 </div>
  18. 18 <div>
  19. 19 <input
  20. 20 type="text"
  21. 21 value={input}
  22. 22 onChange={event => {
  23. 23 setInput(event.target.value);
  24. 24 }}
  25. 25 />
  26. 26 <button
  27. 27 onClick={async () => {
  28. 28 const { messages } = await continueConversation([
  29. 29 ...conversation,
  30. 30 { role: 'user', content: input },
  31. 31 ]);
  32. 32 setConversation(messages);
  33. 33 }}
  34. 34 >
  35. 35 Send Message
  36. 36 </button>
  37. 37 </div>
  38. 38 </div>
  39. 39 );
  40. 40}

Server

Now, let's implement the continueConversation action that uses generateText to generate a response to the user's question. We will use the `tools` parameter to specify our own function called celsiusToFahrenheit that will convert a user given value in celsius to fahrenheit.

We will use zod to specify the schema for the celsiusToFahrenheit function's parameters.

'use server';

import { generateText } from 'ai-toolkit';

import { openai } from '@ai-toolkit/openai';

import { z } from 'zod';

export interface Message {

role: 'user' | 'assistant';

content: string;

}

export async function continueConversation(history: Message[]) {

'use server';

const { text, toolResults } = await generateText({

model: openai('gpt-3.5-turbo'),

system: 'You are a friendly assistant!',

messages: history,

tools: {

celsiusToFahrenheit: {

description: 'Converts celsius to fahrenheit',

inputSchema: z.object({

value: z.string().describe('The value in celsius'),

}),

execute: async ({ value }) => {

const celsius = parseFloat(value);

const fahrenheit = celsius * (9 / 5) + 32;

return ${celsius}°C is ${fahrenheit.toFixed(2)}°F;

},

},

},

});

return {

messages: [

...history,

{

role: 'assistant' as const,

content:

text || toolResults.map(toolResult => toolResult.result).join('\n'),

},

],

};

}

app/actions.ts
tsx
  1. 1'use server';
  2. 2import { generateText } from 'ai-toolkit';
  3. 3import { openai } from '@ai-toolkit/openai';
  4. 4import { z } from 'zod';
  5. 5export interface Message {
  6. 6 role: 'user' | 'assistant';
  7. 7 content: string;
  8. 8}
  9. 9export async function continueConversation(history: Message[]) {
  10. 10 'use server';
  11. 11 const { text, toolResults } = await generateText({
  12. 12 model: openai('gpt-3.5-turbo'),
  13. 13 system: 'You are a friendly assistant!',
  14. 14 messages: history,
  15. 15 tools: {
  16. 16 celsiusToFahrenheit: {
  17. 17 description: 'Converts celsius to fahrenheit',
  18. 18 inputSchema: z.object({
  19. 19 value: z.string().describe('The value in celsius'),
  20. 20 }),
  21. 21 execute: async ({ value }) => {
  22. 22 const celsius = parseFloat(value);
  23. 23 const fahrenheit = celsius * (9 / 5) + 32;
  24. 24 return `${celsius}°C is ${fahrenheit.toFixed(2)}°F`;
  25. 25 },
  26. 26 },
  27. 27 },
  28. 28 });
  29. 29 return {
  30. 30 messages: [
  31. 31 ...history,
  32. 32 {
  33. 33 role: 'assistant' as const,
  34. 34 content:
  35. 35 text || toolResults.map(toolResult => toolResult.result).join('\n'),
  36. 36 },
  37. 37 ],
  38. 38 };
  39. 39}