Skip to content

Chat example with tools in Docs broken #4229

Open
@pkellner

Description

@pkellner

Description

  1. npx create-next-app
  2. npm i zod ai @ai-sdk/openai
  3. copy from docs, /app/page.tsx and /api/chat/route.ts
  4. npm run dev

copy in code from docs here: https://sdk.vercel.ai/cookbook/next/call-tools

The source files are pasted below (and are identical in the GitHub repo)

This is the broken branch with the issue: https://github.com/pkellner/ai-sdk-chat-issue1/tree/bug-broken-directly-from-ai-sdk-docs

This is the fixed branch with the chat app working as expected: https://github.com/pkellner/ai-sdk-chat-issue1/tree/bug-fixed-by-minor-div-changes

into /src/app/page.tsx:

'use client';

import { useChat } from 'ai/react';

export default function Page() {
  const { messages, input, setInput, append } = useChat({
    api: '/api/chat',
    maxSteps: 2,
  });

  return (
    <div>
      <input
        value={input}
        onChange={event => {
          setInput(event.target.value);
        }}
        onKeyDown={async event => {
          if (event.key === 'Enter') {
            append({ content: input, role: 'user' });
          }
        }}
      />

      {messages.map((message, index) => (
        <div key={index}>{message.content}</div>
      ))}
    </div>
  );
}

and /src/app/api/chat/route.ts

import { ToolInvocation, streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

interface Message {
  role: 'user' | 'assistant';
  content: string;
  toolInvocations?: ToolInvocation[];
}

export async function POST(req: Request) {
  const { messages }: { messages: Message[] } = await req.json();

  const result = streamText({
    model: openai('gpt-4o'),
    system: 'You are a helpful assistant.',
    messages,
    tools: {
      getWeather: {
        description: 'Get the weather for a location',
        parameters: 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}!`;
        },
      },
    },
  });

  return result.toDataStreamResponse();
}

Get blank page when running npm run dev

To Fix, I can give page.tsx to ChatGPT and say fix for blank render, and it gives me this:

'use client';

import { ToolInvocation } from 'ai';
import { Message, useChat } from 'ai/react';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit, addToolResult } =
    useChat({
      maxSteps: 5,
      async onToolCall({ toolCall }) {
        if (toolCall.toolName === 'getLocation') {
          const cities = ['New York', 'Los Angeles', 'Chicago', 'San Francisco'];
          return cities[Math.floor(Math.random() * cities.length)];
        }
      },
    });

  return (
    <div style={{ padding: '1rem' }}>
      {messages.length === 0 ? (
        <p>No messages yet. Type something below!</p>
      ) : (
        messages.map((m: Message) => (
          <div key={m.id} style={{ marginBottom: '1rem' }}>
            <strong>{m.role}:</strong> {m.content}
            {m.toolInvocations?.map((toolInvocation: ToolInvocation) => {
              const toolCallId = toolInvocation.toolCallId;
              const addResult = (result: string) =>
                addToolResult({ toolCallId, result });

              if (toolInvocation.toolName === 'askForConfirmation') {
                return (
                  <div key={toolCallId}>
                    {toolInvocation.args.message}
                    <div>
                      {'result' in toolInvocation ? (
                        <b>{toolInvocation.result}</b>
                      ) : (
                        <>
                          <button onClick={() => addResult('Yes')}>Yes</button>
                          <button onClick={() => addResult('No')}>No</button>
                        </>
                      )}
                    </div>
                  </div>
                );
              }

              return 'result' in toolInvocation ? (
                <div key={toolCallId}>
                  Tool call {toolInvocation.toolName}: {toolInvocation.result}
                </div>
              ) : (
                <div key={toolCallId}>Calling {toolInvocation.toolName}...</div>
              );
            })}
          </div>
        ))
      )}

      <form onSubmit={handleSubmit}>
        <input value={input} onChange={handleInputChange} />
        <button type="submit">Send</button>
      </form>
    </div>
  );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocsImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions