tool-invocation-demo

PreviousNext
Docs
simple-aiexample

Preview

Loading preview…
./src/registry/examples/tool-invocation-demo.tsx
"use client";

import type { UIMessage } from "@ai-sdk/react";
import type { InferUITools } from "ai";
import { tool } from "ai";
import z from "zod";
import {
	ChatMessage,
	ChatMessageAuthor,
	ChatMessageAvatar,
	ChatMessageAvatarFallback,
	ChatMessageAvatarImage,
	ChatMessageContainer,
	ChatMessageContent,
	ChatMessageHeader,
	ChatMessageMarkdown,
	ChatMessageTimestamp,
} from "@/registry/ui/chat-message";
import {
	ChatMessageArea,
	ChatMessageAreaContent,
	ChatMessageAreaScrollButton,
} from "@/registry/ui/chat-message-area";
import {
	ToolInvocation,
	ToolInvocationContentCollapsible,
	ToolInvocationHeader,
	ToolInvocationName,
	ToolInvocationRawData,
} from "@/registry/ui/tool-invocation";

const searchDatabaseTool = tool({
	name: "search-database",
	description: "Search the database for information",
	inputSchema: z.object({
		query: z.string(),
	}),
	outputSchema: z.string(),
	execute: () => {
		return "Result of searching the database";
	},
});

const toolSet = {
	"search-database": searchDatabaseTool,
};

const messages: Array<
	UIMessage<
		{
			member: {
				image: string;
				name: string;
			};
		},
		never,
		InferUITools<typeof toolSet>
	>
> = [
	{
		id: "1",
		parts: [
			{
				type: "text",
				text: "Can you search for information about magical forests?",
			},
		],
		role: "user",
		metadata: {
			member: {
				image: "/avatar-1.png",
				name: "You",
			},
		},
	},
	{
		id: "2",
		parts: [
			{
				type: "tool-search-database",
				toolCallId: "search-tool-1",
				state: "output-available",
				input: {
					query: "magical forest stories",
				},
				output: "Found several stories about magical forests, including 'The Whispering Woods' - a tale about a magical forest where trees can talk and animals sing beautiful songs. The story follows Luna, a young fox with silver fur who can speak with ancient trees.",
			},
			{
				type: "text",
				text: "I found some great information! There's a wonderful story called 'The Whispering Woods' about a magical forest where trees can talk and animals sing. The main character is Luna, a young fox with silver fur who has the special ability to communicate with ancient trees.",
			},
		],
		role: "assistant",
		metadata: {
			member: {
				image: "/avatar-2.png",
				name: "Assistant",
			},
		},
	},
];

export default function ChatMessageAreaDemo() {
	return (
		<ChatMessageArea>
			<ChatMessageAreaContent>
				{messages.map((message) => (
					<ChatMessage key={message.id}>
						<ChatMessageAvatar>
							<ChatMessageAvatarImage
								src={message.metadata?.member.image}
							/>
							<ChatMessageAvatarFallback>
								{message.metadata?.member.name
									.charAt(0)
									.toUpperCase()}
							</ChatMessageAvatarFallback>
						</ChatMessageAvatar>

						<ChatMessageContainer>
							<ChatMessageHeader>
								<ChatMessageAuthor>
									{message.metadata?.member.name}
								</ChatMessageAuthor>
								<ChatMessageTimestamp createdAt={new Date()} />
							</ChatMessageHeader>

							<ChatMessageContent>
								{message.parts.map((part) => {
									if (part.type === "text") {
										return (
											<ChatMessageMarkdown
												key={`${message.id}-text-${part.text.slice(0, 20)}`}
												content={part.text}
											/>
										);
									}
									if (part.type === "tool-search-database") {
										const hasInput =
											part.input != null &&
											part.input !== undefined;
										const hasOutput =
											part.output != null &&
											part.output !== undefined;

										const toolName = part.type.slice(5);
										return (
											<ToolInvocation
												key={part.toolCallId}
												className="w-full"
											>
												<ToolInvocationHeader>
													<ToolInvocationName
														name={toolName}
														type={part.state}
														isError={
															part.state ===
															"output-error"
														}
													/>
												</ToolInvocationHeader>
												{(hasInput ||
													hasOutput ||
													part.errorText) && (
													<ToolInvocationContentCollapsible>
														{hasInput && (
															<ToolInvocationRawData
																data={
																	part.input
																}
																title="Arguments"
															/>
														)}
														{part.errorText && (
															<ToolInvocationRawData
																data={{
																	error: part.errorText,
																}}
																title="Error"
															/>
														)}
														{hasOutput && (
															<ToolInvocationRawData
																data={
																	part.output
																}
																title="Result"
															/>
														)}
													</ToolInvocationContentCollapsible>
												)}
											</ToolInvocation>
										);
									}

									return null;
								})}
							</ChatMessageContent>
						</ChatMessageContainer>
					</ChatMessage>
				))}
			</ChatMessageAreaContent>
			<ChatMessageAreaScrollButton />
		</ChatMessageArea>
	);
}

Installation

npx shadcn@latest add @simple-ai/tool-invocation-demo

Usage

import { ToolInvocationDemo } from "@/components/tool-invocation-demo"
<ToolInvocationDemo />