Skip to content

Commit 25144dc

Browse files
committed
add artifact tool component
1 parent c83fa96 commit 25144dc

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

templates/types/streaming/nextjs/app/components/ui/chat/chat-message-content.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { ChatMessage } from "@llamaindex/chat-ui";
22
import { DeepResearchCard } from "./custom/deep-research-card";
3+
import { ArtifactToolComponent } from "./tools/artifact";
34
import { ToolAnnotations } from "./tools/chat-tools";
45
import { ChatSourcesComponent, RetrieverComponent } from "./tools/query-index";
56
import { WeatherToolComponent } from "./tools/weather-card";
6-
77
export function ChatMessageContent() {
88
return (
99
<ChatMessage.Content>
@@ -13,6 +13,7 @@ export function ChatMessageContent() {
1313
<WeatherToolComponent />
1414
<DeepResearchCard />
1515
<ToolAnnotations />
16+
<ArtifactToolComponent />
1617
<ChatMessage.Content.Image />
1718
<ChatMessage.Content.Markdown />
1819
<ChatMessage.Content.DocumentFile />

templates/types/streaming/nextjs/app/components/ui/chat/tools/artifact.tsx

+63-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
"use client";
22

3+
import {
4+
getCustomAnnotation,
5+
useChatMessage,
6+
useChatUI,
7+
} from "@llamaindex/chat-ui";
38
import { Check, ChevronDown, Code, Copy, Loader2 } from "lucide-react";
4-
import { useEffect, useRef, useState } from "react";
9+
import { useEffect, useMemo, useRef, useState } from "react";
10+
import { z } from "zod";
511
import { Button, buttonVariants } from "../../button";
612
import {
713
Collapsible,
@@ -386,3 +392,59 @@ function closePanel() {
386392
panel.classList.add("hidden");
387393
});
388394
}
395+
396+
const ArtifactToolSchema = z.object({
397+
tool_name: z.literal("artifact"),
398+
tool_kwargs: z.object({
399+
query: z.string(),
400+
}),
401+
tool_id: z.string(),
402+
tool_output: z.object({
403+
content: z.string(),
404+
tool_name: z.string(),
405+
raw_input: z.object({
406+
args: z.array(z.unknown()),
407+
kwargs: z.object({
408+
query: z.string(),
409+
}),
410+
}),
411+
raw_output: z.custom<CodeArtifact>(),
412+
is_error: z.boolean(),
413+
}),
414+
return_direct: z.boolean().optional(),
415+
});
416+
417+
type ArtifactTool = z.infer<typeof ArtifactToolSchema>;
418+
419+
export function ArtifactToolComponent() {
420+
const { message } = useChatMessage();
421+
const { messages } = useChatUI();
422+
423+
const artifactOutputEvent = getCustomAnnotation<ArtifactTool>(
424+
message.annotations,
425+
(annotation: unknown) => {
426+
const result = ArtifactToolSchema.safeParse(annotation);
427+
return result.success;
428+
},
429+
).at(0);
430+
431+
const artifactVersion = useMemo(() => {
432+
const artifactToolCalls = messages.filter((m) =>
433+
m.annotations?.some(
434+
(a: unknown) => (a as ArtifactTool).tool_name === "artifact",
435+
),
436+
);
437+
return artifactToolCalls.length;
438+
}, [messages]);
439+
440+
return (
441+
<div className="flex flex-col gap-4">
442+
{artifactOutputEvent && (
443+
<Artifact
444+
artifact={artifactOutputEvent.tool_output.raw_output}
445+
version={artifactVersion}
446+
/>
447+
)}
448+
</div>
449+
);
450+
}

0 commit comments

Comments
 (0)