Call Tools

Learn how to call tools using the AI TOOLKIT and Node

3 min readnodetool 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. import { generateText, tool } from 'ai-toolkit'; import { z } from 'zod'; const result = await generateText({ model: 'openai/gpt-4.1', tools: { weather: tool({ description: 'Get the weather in a location', inputSchema: z.object({ location: z.string().describe('The location to get the weather for'), }), execute: async ({ location }) => ({ location, temperature: 72 + Math.floor(Math.random() * 21) - 10, }), }), cityAttractions: tool({ inputSchema: z.object({ city: z.string() }), }), }, prompt: 'What is the weather in San Francisco and what attractions should I visit?', });

ts
  1. 1import { generateText, tool } from 'ai-toolkit';
  2. 2import { z } from 'zod';
  3. 3const result = await generateText({
  4. 4model: 'openai/gpt-4.1',
  5. 5tools: {
  6. 6weather: tool({
  7. 7description: 'Get the weather in a location',
  8. 8inputSchema: z.object({
  9. 9location: z.string().describe('The location to get the weather for'),
  10. 10}),
  11. 11execute: async ({ location }) => ({
  12. 12location,
  13. 13temperature: 72 + Math.floor(Math.random() * 21) - 10,
  14. 14}),
  15. 15}),
  16. 16cityAttractions: tool({
  17. 17inputSchema: z.object({ city: z.string() }),
  18. 18}),
  19. 19},
  20. 20prompt:
  21. 21'What is the weather in San Francisco and what attractions should I visit?',
  22. 22});

Run it locally

$ npm install ai

Accessing Tool Calls and Tool Results

If the model decides to call a tool, it will generate a tool call. You can access the tool call by checking the toolCalls property on the result.

import { generateText, tool } from 'ai-toolkit';

import dotenv from 'dotenv';

import { z } from 'zod';

dotenv.config();

async function main() {

const result = await generateText({

model: 'openai/gpt-4o',

maxOutputTokens: 512,

tools: {

weather: tool({

description: 'Get the weather in a location',

inputSchema: z.object({

location: z.string().describe('The location to get the weather for'),

}),

execute: async ({ location }) => ({

location,

temperature: 72 + Math.floor(Math.random() * 21) - 10,

}),

}),

cityAttractions: tool({

inputSchema: z.object({ city: z.string() }),

}),

},

prompt:

'What is the weather in San Francisco and what attractions should I visit?',

});

// typed tool calls:

for (const toolCall of result.toolCalls) {

if (toolCall.dynamic) {

continue;

}

switch (toolCall.toolName) {

case 'cityAttractions': {

toolCall.input.city; // string

break;

}

case 'weather': {

toolCall.input.location; // string

break;

}

}

}

console.log(JSON.stringify(result, null, 2));

}

main().catch(console.error);

ts
  1. 1import { generateText, tool } from 'ai-toolkit';
  2. 2import dotenv from 'dotenv';
  3. 3import { z } from 'zod';
  4. 4dotenv.config();
  5. 5async function main() {
  6. 6 const result = await generateText({
  7. 7 model: 'openai/gpt-4o',
  8. 8 maxOutputTokens: 512,
  9. 9 tools: {
  10. 10 weather: tool({
  11. 11 description: 'Get the weather in a location',
  12. 12 inputSchema: z.object({
  13. 13 location: z.string().describe('The location to get the weather for'),
  14. 14 }),
  15. 15 execute: async ({ location }) => ({
  16. 16 location,
  17. 17 temperature: 72 + Math.floor(Math.random() * 21) - 10,
  18. 18 }),
  19. 19 }),
  20. 20 cityAttractions: tool({
  21. 21 inputSchema: z.object({ city: z.string() }),
  22. 22 }),
  23. 23 },
  24. 24 prompt:
  25. 25 'What is the weather in San Francisco and what attractions should I visit?',
  26. 26 });
  27. 27 // typed tool calls:
  28. 28 for (const toolCall of result.toolCalls) {
  29. 29 if (toolCall.dynamic) {
  30. 30 continue;
  31. 31 }
  32. 32 switch (toolCall.toolName) {
  33. 33 case 'cityAttractions': {
  34. 34 toolCall.input.city; // string
  35. 35 break;
  36. 36 }
  37. 37 case 'weather': {
  38. 38 toolCall.input.location; // string
  39. 39 break;
  40. 40 }
  41. 41 }
  42. 42 }
  43. 43 console.log(JSON.stringify(result, null, 2));
  44. 44}
  45. 45main().catch(console.error);

Accessing Tool Results

You can access the result of a tool call by checking the toolResults property on the result.

import { generateText, tool } from 'ai-toolkit';

import dotenv from 'dotenv';

import { z } from 'zod';

dotenv.config();

async function main() {

const result = await generateText({

model: 'openai/gpt-4o',

maxOutputTokens: 512,

tools: {

weather: tool({

description: 'Get the weather in a location',

inputSchema: z.object({

location: z.string().describe('The location to get the weather for'),

}),

execute: async ({ location }) => ({

location,

temperature: 72 + Math.floor(Math.random() * 21) - 10,

}),

}),

cityAttractions: tool({

inputSchema: z.object({ city: z.string() }),

}),

},

prompt:

'What is the weather in San Francisco and what attractions should I visit?',

});

// typed tool results for tools with execute method:

for (const toolResult of result.toolResults) {

if (toolResult.dynamic) {

continue;

}

switch (toolResult.toolName) {

case 'weather': {

toolResult.input.location; // string

toolResult.output.location; // string

toolResult.output.temperature; // number

break;

}

}

}

console.log(JSON.stringify(result, null, 2));

}

main().catch(console.error);

<Note>

toolResults will only be available if the tool has an execute function.

</Note>

ts
  1. 1import { generateText, tool } from 'ai-toolkit';
  2. 2import dotenv from 'dotenv';
  3. 3import { z } from 'zod';
  4. 4dotenv.config();
  5. 5async function main() {
  6. 6 const result = await generateText({
  7. 7 model: 'openai/gpt-4o',
  8. 8 maxOutputTokens: 512,
  9. 9 tools: {
  10. 10 weather: tool({
  11. 11 description: 'Get the weather in a location',
  12. 12 inputSchema: z.object({
  13. 13 location: z.string().describe('The location to get the weather for'),
  14. 14 }),
  15. 15 execute: async ({ location }) => ({
  16. 16 location,
  17. 17 temperature: 72 + Math.floor(Math.random() * 21) - 10,
  18. 18 }),
  19. 19 }),
  20. 20 cityAttractions: tool({
  21. 21 inputSchema: z.object({ city: z.string() }),
  22. 22 }),
  23. 23 },
  24. 24 prompt:
  25. 25 'What is the weather in San Francisco and what attractions should I visit?',
  26. 26 });
  27. 27 // typed tool results for tools with execute method:
  28. 28 for (const toolResult of result.toolResults) {
  29. 29 if (toolResult.dynamic) {
  30. 30 continue;
  31. 31 }
  32. 32 switch (toolResult.toolName) {
  33. 33 case 'weather': {
  34. 34 toolResult.input.location; // string
  35. 35 toolResult.output.location; // string
  36. 36 toolResult.output.temperature; // number
  37. 37 break;
  38. 38 }
  39. 39 }
  40. 40 }
  41. 41 console.log(JSON.stringify(result, null, 2));
  42. 42}
  43. 43main().catch(console.error);

Model Response

When using tools, it's important to note that the model won't respond with the tool call results by default.

This is because the model has technically already generated its response to the prompt: the tool call.

Many use cases will require the model to summarize the results of the tool call within the context of the original prompt automatically.

You can achieve this by using `stopWhen`

which will automatically send toolResults to the model to trigger another generation.