Skip to content

Commit ecfd352

Browse files
committed
bump chat-ui, update chat tools render
1 parent 8d3db71 commit ecfd352

File tree

3 files changed

+106
-49
lines changed

3 files changed

+106
-49
lines changed

templates/types/streaming/fastapi/app/api/routers/vercel_response.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ async def content_generator(self):
5151
event_response = event.to_response()
5252
yield self.convert_data(event_response)
5353
else:
54-
yield self.convert_data(
55-
{"type": "agent", "data": event.model_dump()}
56-
)
54+
yield self.convert_data(event.model_dump())
5755

5856
except asyncio.CancelledError:
5957
logger.warning("Client cancelled the request!")

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

Lines changed: 104 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,128 @@
11
import {
22
Message,
3-
MessageAnnotation,
43
getChatUIAnnotation,
4+
getCustomAnnotation,
55
useChatMessage,
66
useChatUI,
77
} from "@llamaindex/chat-ui";
8+
import { ChatEvents } from "@llamaindex/chat-ui/widgets";
89
import { JSONValue } from "ai";
910
import { useMemo } from "react";
11+
import { z } from "zod";
1012
import { Artifact, CodeArtifact } from "./artifact";
1113
import { WeatherCard, WeatherData } from "./weather-card";
1214

15+
const ToolCallSchema = z.object({
16+
tool_name: z.string(),
17+
tool_kwargs: z.record(z.unknown()),
18+
tool_id: z.string(),
19+
tool_output: z.optional(
20+
z
21+
.object({
22+
content: z.string(),
23+
tool_name: z.string(),
24+
raw_input: z.object({
25+
args: z.array(z.unknown()),
26+
kwargs: z.record(z.unknown()),
27+
}),
28+
raw_output: z.record(z.unknown()),
29+
is_error: z.boolean().optional(),
30+
})
31+
.optional(),
32+
),
33+
return_direct: z.boolean().optional(),
34+
});
35+
36+
type ToolCallEvent = z.infer<typeof ToolCallSchema>;
37+
38+
type GroupedToolCall = {
39+
initial: ToolCallEvent;
40+
output?: ToolCallEvent;
41+
};
42+
1343
export function ToolAnnotations() {
14-
// TODO: This is a bit of a hack to get the artifact version. better to generate the version in the tool call and
15-
// store it in CodeArtifact
1644
const { messages } = useChatUI();
1745
const { message } = useChatMessage();
1846
const artifactVersion = useMemo(
1947
() => getArtifactVersion(messages, message),
2048
[messages, message],
2149
);
22-
// Get the tool data from the message annotations
23-
const annotations = message.annotations as MessageAnnotation[] | undefined;
24-
const toolData = annotations
25-
? (getChatUIAnnotation(annotations, "tools") as unknown as ToolData[])
26-
: null;
27-
return toolData?.[0] ? (
28-
<ChatTools data={toolData[0]} artifactVersion={artifactVersion} />
29-
) : null;
30-
}
3150

32-
// TODO: Used to render outputs of tools. If needed, add more renderers here.
33-
function ChatTools({
34-
data,
35-
artifactVersion,
36-
}: {
37-
data: ToolData;
38-
artifactVersion: number | undefined;
39-
}) {
40-
if (!data) return null;
41-
const { toolCall, toolOutput } = data;
51+
const toolCallEvents = getCustomAnnotation<ToolCallEvent>(
52+
message.annotations,
53+
(annotation) => {
54+
const result = ToolCallSchema.safeParse(annotation);
55+
return result.success;
56+
},
57+
);
58+
59+
// Group tool calls by tool_id - we just need to take the latest event for each tool_id
60+
const groupedToolCalls = useMemo(() => {
61+
const groups = new Map<string, GroupedToolCall>();
4262

43-
if (toolOutput.isError) {
44-
return (
45-
<div className="border-l-2 border-red-400 pl-2">
46-
There was an error when calling the tool {toolCall.name} with input:{" "}
47-
<br />
48-
{JSON.stringify(toolCall.input)}
49-
</div>
50-
);
51-
}
63+
toolCallEvents?.forEach((event) => {
64+
groups.set(event.tool_id, { initial: event });
65+
});
5266

53-
switch (toolCall.name) {
54-
case "get_weather_information":
55-
const weatherData = toolOutput.output as unknown as WeatherData;
56-
return <WeatherCard data={weatherData} />;
57-
case "artifact":
58-
return (
59-
<Artifact
60-
artifact={toolOutput.output as CodeArtifact}
61-
version={artifactVersion}
62-
/>
63-
);
64-
default:
65-
return null;
66-
}
67+
return Array.from(groups.values());
68+
}, [toolCallEvents]);
69+
70+
return (
71+
<div className="space-y-4">
72+
{groupedToolCalls.map(({ initial }) => {
73+
switch (initial.tool_name) {
74+
case "query_index": {
75+
const query = initial.tool_kwargs.input;
76+
const eventData = [
77+
{
78+
title: initial.tool_output
79+
? `Got ${JSON.stringify((initial.tool_output?.raw_output as any).source_nodes?.length ?? 0)} sources for query: ${query}`
80+
: `Searching information for query: ${query}`,
81+
},
82+
];
83+
84+
return (
85+
<ChatEvents
86+
key={initial.tool_id}
87+
data={eventData}
88+
showLoading={!initial.tool_output}
89+
/>
90+
);
91+
}
92+
case "get_weather_information": {
93+
if (!initial.tool_output)
94+
return (
95+
<ChatEvents
96+
key={initial.tool_id}
97+
data={[
98+
{
99+
title: `Getting weather information for ${initial.tool_kwargs.location}`,
100+
},
101+
]}
102+
showLoading={false}
103+
/>
104+
);
105+
const weatherData = initial.tool_output
106+
?.raw_output as unknown as WeatherData;
107+
return <WeatherCard key={initial.tool_id} data={weatherData} />;
108+
}
109+
case "artifact": {
110+
const artifact = initial.tool_output
111+
?.content as unknown as CodeArtifact;
112+
return (
113+
<Artifact
114+
key={initial.tool_id}
115+
artifact={artifact}
116+
version={artifactVersion}
117+
/>
118+
);
119+
}
120+
default:
121+
return null;
122+
}
123+
})}
124+
</div>
125+
);
67126
}
68127

69128
type ToolData = {

templates/types/streaming/nextjs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"@radix-ui/react-select": "^2.1.1",
1818
"@radix-ui/react-slot": "^1.0.2",
1919
"@radix-ui/react-tabs": "^1.1.0",
20-
"@llamaindex/chat-ui": "0.0.14",
20+
"@llamaindex/chat-ui": "0.1.0",
2121
"ai": "^4.0.3",
2222
"ajv": "^8.12.0",
2323
"class-variance-authority": "^0.7.1",

0 commit comments

Comments
 (0)