Tools

Adding new tools are a core functionality of the starterkit. This is very easy if you follow the next steps.

Creating A Tool

  1. Create a new file: lib/ai/tools/new-tool-name.ts
  2. Make the tool :)
lib/ai/tools/new-tool-name.ts
import { tool } from 'ai';
import { z } from 'zod';
 
export const newToolName = tool({
  description: 'Describe the tool to the AI model',
  parameters: z.object({   // the parameters for this 
    parameterOne: z.number(),
    parameterTwo: z.string(),
  }),
  execute: async ({ parameterOne, parameterTwo }) => {
    return {
        newString: `${parameterTwo}: ${parameterOne}$`
    }
  },
});

Now we need to give the AI access to the new tool

app/(chat)/api/chat/route.ts
    return createDataStreamResponse({
        execute: (dataStream) => {
          const result = streamText({
            model: myProvider.languageModel(selectedChatModel),
            system: systemPrompt({ selectedChatModel }),
            messages,
            maxSteps: 5,
            experimental_activeTools:
              selectedChatModel === 'chat-model-reasoning'
                ? []
                : [
                  'getWeather',
                  'createDocument',
                  'updateDocument',
                  'requestSuggestions',
                  'generateImageTool',
                  'getRandomWord',
                  'newToolName'
                ],
            experimental_transform: smoothStream({ chunking: 'word' }),
            experimental_generateMessageId: generateUUID,
            tools: {
              getWeather,
              createDocument: createDocument({ userId: user.id, dataStream }),
              updateDocument: updateDocument({ userId: user.id, dataStream }),
              requestSuggestions: requestSuggestions({
                userId: user.id,
                dataStream,
              }),
              generateImageTool,
              getRandomWord,
              newToolName
            },
            onFinish: async ({ response, reasoning }) => {
 
              posthog.capture('chat_response', {
                'chat_id': id,
                'model': selectedChatModel
              })
 
              if (user.id) {
                try {
                  const sanitizedResponseMessages = sanitizeResponseMessages({
                    messages: response.messages,
                    reasoning,
                  });
 
                  await saveMessages({
                    messages: sanitizedResponseMessages.map((message) => {
                      return {
                        id: message.id,
                        chatId: id,
                        role: message.role,
                        content: message.content,
                        createdAt: new Date(),
                      };
                    }),
                  });
                } catch (error) {
                  console.error('Failed to save chat');
                }
              }
            },
            experimental_telemetry: {
              isEnabled: true,
              functionId: 'stream-text',
            },
          });
 
          result.consumeStream();
 
          result.mergeIntoDataStream(dataStream, {
            sendReasoning: true,
          });
        },
        onError: () => {
          return 'Oops, an error occured!';
        },
    });

the last step in the process is showing the data visually.

components/message.tsx
{/* Full Response Component */}
return (
  <div key={toolCallId}>
    {toolName === 'getWeather' ? (
      <Weather weatherAtLocation={result} />
    ) : toolName === 'createDocument' ? (
      <DocumentPreview
        isReadonly={isReadonly}
        result={result}
      />
    ) : toolName === 'updateDocument' ? (
      <DocumentToolResult
        type="update"
        result={result}
        isReadonly={isReadonly}
      />
    ) : toolName === 'requestSuggestions' ? (
      <DocumentToolResult
        type="request-suggestions"
        result={result}
        isReadonly={isReadonly}
      />
    ) : toolName === 'generateImageTool' ? (
      <img src={result.imageUrl} className='w-full rounded-3xl' />
    ) : toolName === 'getRandomWord' ? (
      <code>{result.word}</code>
    ) : toolName === 'newToolName' (
      <p>result.newString</p>
    ) : (
      <pre>{JSON.stringify(result, null, 2)}</pre>
    )}
  </div>
);
components/message.tsx
{/* Skeleton */}
{toolName === 'getWeather' ? (
  <Weather />
) : toolName === 'createDocument' ? (
  <DocumentPreview isReadonly={isReadonly} args={args} />
) : toolName === 'updateDocument' ? (
  <DocumentToolCall
    type="update"
    args={args}
    isReadonly={isReadonly}
  />
) : toolName === 'requestSuggestions' ? (
  <DocumentToolCall
    type="request-suggestions"
    args={args}
    isReadonly={isReadonly}
  />
) : toolName === 'generateImageTool' ? (
  <ImageSkeleton args={args} />
) : toolName === 'getRandomWord' ? (
  <code>Getting Random word</code>
) : toolName === 'newToolName' ? (
  <p>Loading Results For New Tool</p>
) : null}

Now your tool should be available in the chat app. Be proud of your first tool, enjoy the dopamine rush.

Last updated on