@cloudbase/agent-react-ui 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -0
- package/components.json +21 -0
- package/dist/index.css +4241 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +59 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +2169 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2182 -0
- package/dist/index.mjs.map +1 -0
- package/example/.env.sample +2 -0
- package/example/App.tsx +368 -0
- package/example/app.css +1 -0
- package/example/index.html +12 -0
- package/example/main.tsx +9 -0
- package/example/vite.config.ts +34 -0
- package/package.json +75 -0
- package/postcss.config.cjs +3 -0
- package/src/components/ai-elements/agent.tsx +140 -0
- package/src/components/ai-elements/artifact.tsx +147 -0
- package/src/components/ai-elements/attachments.tsx +421 -0
- package/src/components/ai-elements/audio-player.tsx +228 -0
- package/src/components/ai-elements/canvas.tsx +22 -0
- package/src/components/ai-elements/chain-of-thought.tsx +228 -0
- package/src/components/ai-elements/checkpoint.tsx +71 -0
- package/src/components/ai-elements/code-block.tsx +532 -0
- package/src/components/ai-elements/commit.tsx +448 -0
- package/src/components/ai-elements/confirmation.tsx +176 -0
- package/src/components/ai-elements/connection.tsx +28 -0
- package/src/components/ai-elements/context.tsx +408 -0
- package/src/components/ai-elements/controls.tsx +18 -0
- package/src/components/ai-elements/conversation.tsx +100 -0
- package/src/components/ai-elements/edge.tsx +140 -0
- package/src/components/ai-elements/environment-variables.tsx +295 -0
- package/src/components/ai-elements/file-tree.tsx +258 -0
- package/src/components/ai-elements/image.tsx +24 -0
- package/src/components/ai-elements/inline-citation.tsx +287 -0
- package/src/components/ai-elements/message.tsx +336 -0
- package/src/components/ai-elements/mic-selector.tsx +370 -0
- package/src/components/ai-elements/model-selector.tsx +211 -0
- package/src/components/ai-elements/node.tsx +71 -0
- package/src/components/ai-elements/open-in-chat.tsx +365 -0
- package/src/components/ai-elements/package-info.tsx +233 -0
- package/src/components/ai-elements/panel.tsx +15 -0
- package/src/components/ai-elements/persona.tsx +270 -0
- package/src/components/ai-elements/plan.tsx +142 -0
- package/src/components/ai-elements/prompt-input.tsx +1263 -0
- package/src/components/ai-elements/queue.tsx +274 -0
- package/src/components/ai-elements/reasoning.tsx +193 -0
- package/src/components/ai-elements/sandbox.tsx +126 -0
- package/src/components/ai-elements/schema-display.tsx +458 -0
- package/src/components/ai-elements/shimmer.tsx +64 -0
- package/src/components/ai-elements/snippet.tsx +139 -0
- package/src/components/ai-elements/sources.tsx +77 -0
- package/src/components/ai-elements/speech-input.tsx +301 -0
- package/src/components/ai-elements/stack-trace.tsx +482 -0
- package/src/components/ai-elements/suggestion.tsx +53 -0
- package/src/components/ai-elements/task.tsx +87 -0
- package/src/components/ai-elements/terminal.tsx +261 -0
- package/src/components/ai-elements/test-results.tsx +485 -0
- package/src/components/ai-elements/tool.tsx +174 -0
- package/src/components/ai-elements/toolbar.tsx +16 -0
- package/src/components/ai-elements/transcription.tsx +124 -0
- package/src/components/ai-elements/voice-selector.tsx +479 -0
- package/src/components/ai-elements/web-preview.tsx +263 -0
- package/src/components/chat/Chat.tsx +178 -0
- package/src/components/chat/Input.tsx +98 -0
- package/src/components/chat/Message.tsx +276 -0
- package/src/components/chat/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/components/ui/accordion.tsx +64 -0
- package/src/components/ui/alert.tsx +66 -0
- package/src/components/ui/avatar.tsx +107 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/button-group.tsx +83 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/carousel.tsx +239 -0
- package/src/components/ui/collapsible.tsx +31 -0
- package/src/components/ui/command.tsx +184 -0
- package/src/components/ui/dialog.tsx +158 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/hover-card.tsx +42 -0
- package/src/components/ui/input-group.tsx +168 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/popover.tsx +87 -0
- package/src/components/ui/progress.tsx +31 -0
- package/src/components/ui/scroll-area.tsx +56 -0
- package/src/components/ui/select.tsx +190 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/spinner.tsx +16 -0
- package/src/components/ui/switch.tsx +33 -0
- package/src/components/ui/tabs.tsx +91 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/css/global.css +123 -0
- package/src/css/index.css +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-copy-to-clipboard.ts +31 -0
- package/src/index.ts +4 -0
- package/src/lib/utils.ts +6 -0
- package/src/locales/context.ts +8 -0
- package/src/locales/hooks.ts +20 -0
- package/src/locales/index.ts +3 -0
- package/src/locales/langs/en.ts +17 -0
- package/src/locales/langs/index.ts +12 -0
- package/src/locales/langs/zh-cn.ts +18 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +21 -0
package/example/App.tsx
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { AgKitUI, type LocaleCode } from "..";
|
|
2
|
+
import {
|
|
3
|
+
AgKit,
|
|
4
|
+
CloudBaseTransport,
|
|
5
|
+
type ToolCallState,
|
|
6
|
+
useChat,
|
|
7
|
+
useClientTool,
|
|
8
|
+
useToolCall,
|
|
9
|
+
} from "@cloudbase/agent-react-core";
|
|
10
|
+
import {
|
|
11
|
+
Confirmation,
|
|
12
|
+
ConfirmationAccepted,
|
|
13
|
+
ConfirmationAction,
|
|
14
|
+
ConfirmationActions,
|
|
15
|
+
ConfirmationRejected,
|
|
16
|
+
ConfirmationRequest,
|
|
17
|
+
ConfirmationTitle,
|
|
18
|
+
} from "@/components/ai-elements/confirmation";
|
|
19
|
+
import { Button } from "@/components/ui/button";
|
|
20
|
+
import {
|
|
21
|
+
Select,
|
|
22
|
+
SelectContent,
|
|
23
|
+
SelectItem,
|
|
24
|
+
SelectTrigger,
|
|
25
|
+
SelectValue,
|
|
26
|
+
} from "@/components/ui/select";
|
|
27
|
+
import { z } from "zod";
|
|
28
|
+
import cloudbase from "@cloudbase/js-sdk";
|
|
29
|
+
import { useEffect, useRef, useState } from "react";
|
|
30
|
+
import "../dist/index.css";
|
|
31
|
+
import "./app.css";
|
|
32
|
+
|
|
33
|
+
const app = cloudbase.init({
|
|
34
|
+
env: import.meta.env.VITE_ENV,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
app.auth.signInAnonymously();
|
|
38
|
+
|
|
39
|
+
// Create transport
|
|
40
|
+
const transport = new CloudBaseTransport({
|
|
41
|
+
app,
|
|
42
|
+
agentId: import.meta.env.VITE_AGENT_ID,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const randomNameParameters = z
|
|
46
|
+
.object({
|
|
47
|
+
count: z.number().optional(),
|
|
48
|
+
})
|
|
49
|
+
.toJSONSchema();
|
|
50
|
+
|
|
51
|
+
const weatherParameters = z
|
|
52
|
+
.object({
|
|
53
|
+
city: z.string().optional(),
|
|
54
|
+
})
|
|
55
|
+
.toJSONSchema();
|
|
56
|
+
|
|
57
|
+
const languageParameters = z
|
|
58
|
+
.object({
|
|
59
|
+
locale: z.string().optional(),
|
|
60
|
+
})
|
|
61
|
+
.toJSONSchema();
|
|
62
|
+
|
|
63
|
+
const themeParameters = z
|
|
64
|
+
.object({
|
|
65
|
+
theme: z.string().optional(),
|
|
66
|
+
})
|
|
67
|
+
.toJSONSchema();
|
|
68
|
+
|
|
69
|
+
type ThemeMode = "light" | "dark";
|
|
70
|
+
|
|
71
|
+
function normalizeLocale(value: unknown, fallback: LocaleCode): LocaleCode {
|
|
72
|
+
const normalized = String(value ?? "")
|
|
73
|
+
.trim()
|
|
74
|
+
.toLowerCase();
|
|
75
|
+
if (normalized === "en" || normalized === "en-us") {
|
|
76
|
+
return "en-US";
|
|
77
|
+
}
|
|
78
|
+
if (normalized === "zh" || normalized === "zh-cn") {
|
|
79
|
+
return "zh-CN";
|
|
80
|
+
}
|
|
81
|
+
return fallback;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function normalizeTheme(value: unknown, fallback: ThemeMode): ThemeMode {
|
|
85
|
+
const normalized = String(value ?? "")
|
|
86
|
+
.trim()
|
|
87
|
+
.toLowerCase();
|
|
88
|
+
if (normalized === "dark") return "dark";
|
|
89
|
+
if (normalized === "light") return "light";
|
|
90
|
+
if (normalized === "toggle") return fallback === "dark" ? "light" : "dark";
|
|
91
|
+
return fallback;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface ThemeSwitchConfirmationProps {
|
|
95
|
+
toolCall: ToolCallState;
|
|
96
|
+
isDark: boolean;
|
|
97
|
+
setIsDark: (value: boolean) => void;
|
|
98
|
+
respond: (result: string) => void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function ThemeSwitchConfirmation({
|
|
102
|
+
toolCall,
|
|
103
|
+
isDark,
|
|
104
|
+
setIsDark,
|
|
105
|
+
respond,
|
|
106
|
+
}: ThemeSwitchConfirmationProps) {
|
|
107
|
+
const [state, setState] = useState<
|
|
108
|
+
"approval-requested" | "approval-responded"
|
|
109
|
+
>("approval-requested");
|
|
110
|
+
const [approved, setApproved] = useState<boolean | undefined>(undefined);
|
|
111
|
+
const requestedTheme = normalizeTheme(
|
|
112
|
+
toolCall.args?.theme,
|
|
113
|
+
isDark ? "dark" : "light"
|
|
114
|
+
);
|
|
115
|
+
const nextIsDark = requestedTheme === "dark";
|
|
116
|
+
const nextThemeLabel = nextIsDark ? "Dark" : "Light";
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Confirmation
|
|
120
|
+
approval={{ id: toolCall.toolCallId, approved }}
|
|
121
|
+
state={state as any}
|
|
122
|
+
className="bg-muted/30"
|
|
123
|
+
>
|
|
124
|
+
<ConfirmationTitle>
|
|
125
|
+
Theme switch requested: {nextThemeLabel} mode
|
|
126
|
+
</ConfirmationTitle>
|
|
127
|
+
<ConfirmationRequest>
|
|
128
|
+
<div className="text-sm text-muted-foreground">
|
|
129
|
+
Do you want to apply this theme change?
|
|
130
|
+
</div>
|
|
131
|
+
</ConfirmationRequest>
|
|
132
|
+
<ConfirmationActions>
|
|
133
|
+
<ConfirmationAction
|
|
134
|
+
variant="outline"
|
|
135
|
+
disabled={state !== "approval-requested"}
|
|
136
|
+
onClick={() => {
|
|
137
|
+
setApproved(false);
|
|
138
|
+
setState("approval-responded");
|
|
139
|
+
respond(
|
|
140
|
+
JSON.stringify({
|
|
141
|
+
success: false,
|
|
142
|
+
cancelled: true,
|
|
143
|
+
currentTheme: isDark ? "dark" : "light",
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
Cancel
|
|
149
|
+
</ConfirmationAction>
|
|
150
|
+
<ConfirmationAction
|
|
151
|
+
disabled={state !== "approval-requested"}
|
|
152
|
+
onClick={() => {
|
|
153
|
+
setIsDark(nextIsDark);
|
|
154
|
+
setApproved(true);
|
|
155
|
+
setState("approval-responded");
|
|
156
|
+
respond(
|
|
157
|
+
JSON.stringify({
|
|
158
|
+
success: true,
|
|
159
|
+
theme: nextIsDark ? "dark" : "light",
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
Confirm
|
|
165
|
+
</ConfirmationAction>
|
|
166
|
+
</ConfirmationActions>
|
|
167
|
+
<ConfirmationAccepted>
|
|
168
|
+
<div className="text-sm text-muted-foreground">
|
|
169
|
+
Theme changed to {nextThemeLabel} mode.
|
|
170
|
+
</div>
|
|
171
|
+
</ConfirmationAccepted>
|
|
172
|
+
<ConfirmationRejected>
|
|
173
|
+
<div className="text-sm text-muted-foreground">
|
|
174
|
+
Theme switch cancelled.
|
|
175
|
+
</div>
|
|
176
|
+
</ConfirmationRejected>
|
|
177
|
+
</Confirmation>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface ExampleToolRegistrationsProps {
|
|
182
|
+
locale: LocaleCode;
|
|
183
|
+
setLocale: (locale: LocaleCode) => void;
|
|
184
|
+
isDark: boolean;
|
|
185
|
+
setIsDark: (value: boolean) => void;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function ExampleToolRegistrations({
|
|
189
|
+
locale,
|
|
190
|
+
setLocale,
|
|
191
|
+
isDark,
|
|
192
|
+
setIsDark,
|
|
193
|
+
}: ExampleToolRegistrationsProps) {
|
|
194
|
+
useClientTool({
|
|
195
|
+
name: "generate_random_name",
|
|
196
|
+
description: "Generate a random name",
|
|
197
|
+
parameters: randomNameParameters,
|
|
198
|
+
handler: ({ args }) => {
|
|
199
|
+
const count = Number(args.count ?? 1);
|
|
200
|
+
const names = ["John", "Emma", "Olivia", "Liam", "Noah"];
|
|
201
|
+
return Array.from({ length: Math.max(1, count) })
|
|
202
|
+
.map((_, index) => names[index % names.length])
|
|
203
|
+
.join(", ");
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
useClientTool({
|
|
208
|
+
name: "get_local_weather",
|
|
209
|
+
description: "Get local weather for a city",
|
|
210
|
+
parameters: weatherParameters,
|
|
211
|
+
handler: ({ args }) => {
|
|
212
|
+
const city = String(args.city || "Shanghai");
|
|
213
|
+
return JSON.stringify({
|
|
214
|
+
city,
|
|
215
|
+
weather: "sunny",
|
|
216
|
+
temperature: "26C",
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
useClientTool({
|
|
222
|
+
name: "switch_language",
|
|
223
|
+
description: "Switch the UI language locale to zh-CN or en-US",
|
|
224
|
+
parameters: languageParameters,
|
|
225
|
+
handler: ({ args }) => {
|
|
226
|
+
const nextLocale = normalizeLocale(args.locale, locale);
|
|
227
|
+
setLocale(nextLocale);
|
|
228
|
+
return JSON.stringify({
|
|
229
|
+
success: true,
|
|
230
|
+
locale: nextLocale,
|
|
231
|
+
});
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
useClientTool({
|
|
236
|
+
name: "switch_theme",
|
|
237
|
+
description: "Switch UI theme.",
|
|
238
|
+
parameters: themeParameters,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
useToolCall({
|
|
242
|
+
name: "get_local_weather",
|
|
243
|
+
render: ({ toolCall }) => (
|
|
244
|
+
<div className="rounded-md border bg-muted/40 p-3 text-sm">
|
|
245
|
+
<div className="font-medium">Custom Weather Tool Renderer</div>
|
|
246
|
+
<div className="mt-1 text-muted-foreground">
|
|
247
|
+
Params: {JSON.stringify(toolCall.args || {})}
|
|
248
|
+
</div>
|
|
249
|
+
{toolCall.result !== undefined && (
|
|
250
|
+
<div className="mt-2">
|
|
251
|
+
Result:{" "}
|
|
252
|
+
<span className="font-medium">{String(toolCall.result)}</span>
|
|
253
|
+
</div>
|
|
254
|
+
)}
|
|
255
|
+
</div>
|
|
256
|
+
),
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
useToolCall({
|
|
260
|
+
name: "switch_theme",
|
|
261
|
+
render: ({ toolCall, respond }) => (
|
|
262
|
+
<ThemeSwitchConfirmation
|
|
263
|
+
toolCall={toolCall}
|
|
264
|
+
isDark={isDark}
|
|
265
|
+
setIsDark={setIsDark}
|
|
266
|
+
respond={respond}
|
|
267
|
+
/>
|
|
268
|
+
),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// External component demonstrating useChat access
|
|
275
|
+
interface ExternalControlsProps {
|
|
276
|
+
locale: LocaleCode;
|
|
277
|
+
onLocaleChange: (nextLocale: LocaleCode) => void;
|
|
278
|
+
isDark: boolean;
|
|
279
|
+
onToggleTheme: () => void;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function ExternalControls({
|
|
283
|
+
locale,
|
|
284
|
+
onLocaleChange,
|
|
285
|
+
isDark,
|
|
286
|
+
onToggleTheme,
|
|
287
|
+
}: ExternalControlsProps) {
|
|
288
|
+
const { uiMessages, streaming, sendMessage } = useChat();
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<div className="p-4 border-b border-border bg-background flex items-center justify-between">
|
|
292
|
+
<span className="text-sm text-muted-foreground">
|
|
293
|
+
Messages: {uiMessages.length} | {streaming ? "Streaming..." : "Ready"}
|
|
294
|
+
</span>
|
|
295
|
+
<div className="flex items-center gap-2">
|
|
296
|
+
<Select
|
|
297
|
+
value={locale}
|
|
298
|
+
onValueChange={(value) => onLocaleChange(value as LocaleCode)}
|
|
299
|
+
>
|
|
300
|
+
<SelectTrigger className="w-28 bg-background text-foreground border-border">
|
|
301
|
+
<SelectValue placeholder="Language" />
|
|
302
|
+
</SelectTrigger>
|
|
303
|
+
<SelectContent className="bg-background text-foreground border-border">
|
|
304
|
+
<SelectItem value="zh-CN">中文</SelectItem>
|
|
305
|
+
<SelectItem value="en-US">English</SelectItem>
|
|
306
|
+
</SelectContent>
|
|
307
|
+
</Select>
|
|
308
|
+
<Button
|
|
309
|
+
variant="outline"
|
|
310
|
+
className="bg-background text-foreground border-border"
|
|
311
|
+
onClick={onToggleTheme}
|
|
312
|
+
>
|
|
313
|
+
{isDark ? "Dark" : "Light"}
|
|
314
|
+
</Button>
|
|
315
|
+
<Button onClick={() => sendMessage("Hello from external button!")}>
|
|
316
|
+
Send from outside
|
|
317
|
+
</Button>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export function App() {
|
|
324
|
+
const [locale, setLocale] = useState<LocaleCode>("zh-CN");
|
|
325
|
+
const [isDark, setIsDark] = useState(false);
|
|
326
|
+
const threadId = useRef(`threadId_${Date.now()}`);
|
|
327
|
+
const suggestions =
|
|
328
|
+
locale === "zh-CN"
|
|
329
|
+
? ["切换到英文界面", "请切换到深色模式", "帮我查一下上海天气"]
|
|
330
|
+
: [
|
|
331
|
+
"Switch UI language to Chinese",
|
|
332
|
+
"Please switch to dark mode",
|
|
333
|
+
"Check weather in Shanghai",
|
|
334
|
+
];
|
|
335
|
+
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
document.documentElement.classList.toggle("dark", isDark);
|
|
338
|
+
return () => {
|
|
339
|
+
document.documentElement.classList.remove("dark");
|
|
340
|
+
};
|
|
341
|
+
}, [isDark]);
|
|
342
|
+
|
|
343
|
+
return (
|
|
344
|
+
<AgKit transport={transport} defaultThreadId={threadId.current}>
|
|
345
|
+
<div className="h-screen w-screen flex flex-col">
|
|
346
|
+
<ExampleToolRegistrations
|
|
347
|
+
locale={locale}
|
|
348
|
+
setLocale={setLocale}
|
|
349
|
+
isDark={isDark}
|
|
350
|
+
setIsDark={setIsDark}
|
|
351
|
+
/>
|
|
352
|
+
|
|
353
|
+
{/* External component using useChat - shares the same state */}
|
|
354
|
+
<ExternalControls
|
|
355
|
+
locale={locale}
|
|
356
|
+
onLocaleChange={setLocale}
|
|
357
|
+
isDark={isDark}
|
|
358
|
+
onToggleTheme={() => setIsDark((prev) => !prev)}
|
|
359
|
+
/>
|
|
360
|
+
|
|
361
|
+
{/* Main chat component */}
|
|
362
|
+
<div className="flex-1 max-h-[calc(100vh-60px)]">
|
|
363
|
+
<AgKitUI locale={locale} suggestions={suggestions} />
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</AgKit>
|
|
367
|
+
);
|
|
368
|
+
}
|
package/example/app.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Agent UI</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="./main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
package/example/main.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import react from '@vitejs/plugin-react';
|
|
4
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
5
|
+
|
|
6
|
+
const ROOT_DIR = resolve(__dirname);
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
root: ROOT_DIR,
|
|
10
|
+
base: '/AgKitUI',
|
|
11
|
+
|
|
12
|
+
server: {
|
|
13
|
+
host: true,
|
|
14
|
+
port: 2024,
|
|
15
|
+
open: false,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
plugins: [
|
|
19
|
+
react(),
|
|
20
|
+
tailwindcss(),
|
|
21
|
+
],
|
|
22
|
+
|
|
23
|
+
resolve: {
|
|
24
|
+
alias: {
|
|
25
|
+
'@': resolve(ROOT_DIR, '../src'),
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
build: {
|
|
30
|
+
target: 'es2018',
|
|
31
|
+
emptyOutDir: true,
|
|
32
|
+
outDir: resolve(ROOT_DIR, 'dist'),
|
|
33
|
+
},
|
|
34
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudbase/agent-react-ui",
|
|
3
|
+
"version": "0.0.23",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./styles.css": "./dist/index.css"
|
|
14
|
+
},
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@radix-ui/react-use-controllable-state": "^1.2.2",
|
|
21
|
+
"@rive-app/react-webgl2": "^4.26.2",
|
|
22
|
+
"@streamdown/cjk": "^1.0.1",
|
|
23
|
+
"@streamdown/code": "^1.0.1",
|
|
24
|
+
"@streamdown/math": "^1.0.1",
|
|
25
|
+
"@streamdown/mermaid": "^1.0.1",
|
|
26
|
+
"@xyflow/react": "^12.10.0",
|
|
27
|
+
"ai": "^5.0.108",
|
|
28
|
+
"ai-elements": "^1.8.2",
|
|
29
|
+
"ansi-to-react": "^6.2.6",
|
|
30
|
+
"class-variance-authority": "^0.7.1",
|
|
31
|
+
"clsx": "^2.1.1",
|
|
32
|
+
"cmdk": "^1.1.1",
|
|
33
|
+
"embla-carousel-react": "^8.6.0",
|
|
34
|
+
"lucide-react": "^0.544.0",
|
|
35
|
+
"media-chrome": "^4.17.2",
|
|
36
|
+
"motion": "^12.23.25",
|
|
37
|
+
"nanoid": "^5.1.6",
|
|
38
|
+
"radix-ui": "^1.4.3",
|
|
39
|
+
"react": "19.2.0",
|
|
40
|
+
"shiki": "^3.22.0",
|
|
41
|
+
"streamdown": "^1.6.10",
|
|
42
|
+
"tailwind-merge": "^3.4.0",
|
|
43
|
+
"tokenlens": "^1.3.1",
|
|
44
|
+
"tw-animate-css": "^1.4.0",
|
|
45
|
+
"use-stick-to-bottom": "^1.1.1",
|
|
46
|
+
"uuid": "^13.0.0",
|
|
47
|
+
"vite": "^7.3.1",
|
|
48
|
+
"zod": "^4.3.6",
|
|
49
|
+
"@cloudbase/agent-react-core": "^0.0.23"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@cloudbase/js-sdk": "^2.25.4",
|
|
53
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
54
|
+
"@tailwindcss/vite": "^4.1.17",
|
|
55
|
+
"@types/react": "^19",
|
|
56
|
+
"@types/react-dom": "^19",
|
|
57
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
58
|
+
"autoprefixer": "^10.4.22",
|
|
59
|
+
"postcss": "^8.5.6",
|
|
60
|
+
"react-dom": "19.2.0",
|
|
61
|
+
"tailwindcss": "^4.1.18",
|
|
62
|
+
"tsup": "^8.5.1",
|
|
63
|
+
"zustand": "^5.0.11"
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"dev": "tsup --watch --config tsup.config.ts",
|
|
70
|
+
"build": "tsup --config tsup.config.ts",
|
|
71
|
+
"example:dev": "vite --config example/vite.config.ts",
|
|
72
|
+
"example:build": "vite build --config example/vite.config.ts",
|
|
73
|
+
"example:preview": "vite preview --config example/vite.config.ts"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Accordion,
|
|
5
|
+
AccordionContent,
|
|
6
|
+
AccordionItem,
|
|
7
|
+
AccordionTrigger,
|
|
8
|
+
} from "@/components/ui/accordion";
|
|
9
|
+
import { Badge } from "@/components/ui/badge";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
import type { Tool } from "ai";
|
|
12
|
+
import { BotIcon } from "lucide-react";
|
|
13
|
+
import type { ComponentProps } from "react";
|
|
14
|
+
import { memo } from "react";
|
|
15
|
+
import { CodeBlock } from "./code-block";
|
|
16
|
+
|
|
17
|
+
export type AgentProps = ComponentProps<"div">;
|
|
18
|
+
|
|
19
|
+
export const Agent = memo(({ className, ...props }: AgentProps) => (
|
|
20
|
+
<div
|
|
21
|
+
className={cn("not-prose w-full rounded-md border", className)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
export type AgentHeaderProps = ComponentProps<"div"> & {
|
|
27
|
+
name: string;
|
|
28
|
+
model?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const AgentHeader = memo(
|
|
32
|
+
({ className, name, model, ...props }: AgentHeaderProps) => (
|
|
33
|
+
<div
|
|
34
|
+
className={cn(
|
|
35
|
+
"flex w-full items-center justify-between gap-4 p-3",
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
>
|
|
40
|
+
<div className="flex items-center gap-2">
|
|
41
|
+
<BotIcon className="size-4 text-muted-foreground" />
|
|
42
|
+
<span className="font-medium text-sm">{name}</span>
|
|
43
|
+
{model && (
|
|
44
|
+
<Badge className="font-mono text-xs" variant="secondary">
|
|
45
|
+
{model}
|
|
46
|
+
</Badge>
|
|
47
|
+
)}
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export type AgentContentProps = ComponentProps<"div">;
|
|
54
|
+
|
|
55
|
+
export const AgentContent = memo(
|
|
56
|
+
({ className, ...props }: AgentContentProps) => (
|
|
57
|
+
<div className={cn("space-y-4 p-4 pt-0", className)} {...props} />
|
|
58
|
+
)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export type AgentInstructionsProps = ComponentProps<"div"> & {
|
|
62
|
+
children: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const AgentInstructions = memo(
|
|
66
|
+
({ className, children, ...props }: AgentInstructionsProps) => (
|
|
67
|
+
<div className={cn("space-y-2", className)} {...props}>
|
|
68
|
+
<span className="font-medium text-muted-foreground text-sm">
|
|
69
|
+
Instructions
|
|
70
|
+
</span>
|
|
71
|
+
<div className="rounded-md bg-muted/50 p-3 text-muted-foreground text-sm">
|
|
72
|
+
<p>{children}</p>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export type AgentToolsProps = ComponentProps<typeof Accordion>;
|
|
79
|
+
|
|
80
|
+
export const AgentTools = memo(({ className, ...props }: AgentToolsProps) => (
|
|
81
|
+
<div className={cn("space-y-2", className)}>
|
|
82
|
+
<span className="font-medium text-muted-foreground text-sm">Tools</span>
|
|
83
|
+
<Accordion className="rounded-md border" {...props} />
|
|
84
|
+
</div>
|
|
85
|
+
));
|
|
86
|
+
|
|
87
|
+
export type AgentToolProps = ComponentProps<typeof AccordionItem> & {
|
|
88
|
+
tool: Tool;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const AgentTool = memo(
|
|
92
|
+
({ className, tool, value, ...props }: AgentToolProps) => {
|
|
93
|
+
const schema =
|
|
94
|
+
"jsonSchema" in tool && tool.jsonSchema
|
|
95
|
+
? tool.jsonSchema
|
|
96
|
+
: tool.inputSchema;
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<AccordionItem
|
|
100
|
+
className={cn("border-b last:border-b-0", className)}
|
|
101
|
+
value={value}
|
|
102
|
+
{...props}
|
|
103
|
+
>
|
|
104
|
+
<AccordionTrigger className="px-3 py-2 text-sm hover:no-underline">
|
|
105
|
+
{tool.description ?? "No description"}
|
|
106
|
+
</AccordionTrigger>
|
|
107
|
+
<AccordionContent className="px-3 pb-3">
|
|
108
|
+
<div className="rounded-md bg-muted/50">
|
|
109
|
+
<CodeBlock code={JSON.stringify(schema, null, 2)} language="json" />
|
|
110
|
+
</div>
|
|
111
|
+
</AccordionContent>
|
|
112
|
+
</AccordionItem>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
export type AgentOutputProps = ComponentProps<"div"> & {
|
|
118
|
+
schema: string;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const AgentOutput = memo(
|
|
122
|
+
({ className, schema, ...props }: AgentOutputProps) => (
|
|
123
|
+
<div className={cn("space-y-2", className)} {...props}>
|
|
124
|
+
<span className="font-medium text-muted-foreground text-sm">
|
|
125
|
+
Output Schema
|
|
126
|
+
</span>
|
|
127
|
+
<div className="rounded-md bg-muted/50">
|
|
128
|
+
<CodeBlock code={schema} language="typescript" />
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
Agent.displayName = "Agent";
|
|
135
|
+
AgentHeader.displayName = "AgentHeader";
|
|
136
|
+
AgentContent.displayName = "AgentContent";
|
|
137
|
+
AgentInstructions.displayName = "AgentInstructions";
|
|
138
|
+
AgentTools.displayName = "AgentTools";
|
|
139
|
+
AgentTool.displayName = "AgentTool";
|
|
140
|
+
AgentOutput.displayName = "AgentOutput";
|