@aomi-labs/widget-lib 1.0.0 → 1.1.0
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/SHADCN-FETCH-GUIDE.md +105 -0
- package/components.json +10 -0
- package/dist/accordion.json +18 -0
- package/dist/alert.json +17 -0
- package/dist/aomi-frame.json +24 -0
- package/dist/assistant-thread-list.json +22 -0
- package/dist/assistant-thread.json +27 -0
- package/dist/assistant-threadlist-collapsible.json +23 -0
- package/dist/assistant-threadlist-sidebar.json +20 -0
- package/dist/assistant-tool-fallback.json +20 -0
- package/dist/avatar.json +17 -0
- package/dist/badge.json +17 -0
- package/dist/breadcrumb.json +17 -0
- package/dist/button.json +18 -0
- package/dist/card.json +15 -0
- package/dist/collapsible.json +17 -0
- package/dist/command.json +21 -0
- package/dist/dialog.json +18 -0
- package/dist/drawer.json +17 -0
- package/dist/input.json +15 -0
- package/dist/label.json +15 -0
- package/dist/notification.json +20 -0
- package/dist/popover.json +17 -0
- package/dist/registry.json +429 -0
- package/dist/separator.json +17 -0
- package/dist/sheet.json +18 -0
- package/dist/sidebar.json +18 -0
- package/dist/skeleton.json +15 -0
- package/dist/sonner.json +17 -0
- package/dist/tooltip.json +17 -0
- package/package.json +24 -88
- package/scripts/build-registry.js +74 -0
- package/src/components/aomi-frame.tsx +128 -0
- package/src/components/assistant-ui/attachment.tsx +235 -0
- package/src/components/assistant-ui/markdown-text.tsx +228 -0
- package/src/components/assistant-ui/thread-list.tsx +106 -0
- package/src/components/assistant-ui/thread.tsx +457 -0
- package/src/components/assistant-ui/threadlist-sidebar.tsx +71 -0
- package/src/components/assistant-ui/tool-fallback.tsx +48 -0
- package/src/components/assistant-ui/tooltip-icon-button.tsx +42 -0
- package/src/components/test/ThreadContextTest.tsx +204 -0
- package/src/components/tools/example-tool/ExampleTool.tsx +102 -0
- package/src/components/ui/accordion.tsx +58 -0
- package/src/components/ui/alert.tsx +62 -0
- package/src/components/ui/avatar.tsx +53 -0
- package/src/components/ui/badge.tsx +37 -0
- package/src/components/ui/breadcrumb.tsx +109 -0
- package/src/components/ui/button.tsx +59 -0
- package/src/components/ui/card.tsx +86 -0
- package/src/components/ui/collapsible.tsx +12 -0
- package/src/components/ui/command.tsx +156 -0
- package/src/components/ui/dialog.tsx +143 -0
- package/src/components/ui/drawer.tsx +118 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +20 -0
- package/src/components/ui/notification.tsx +57 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +139 -0
- package/src/components/ui/sidebar.tsx +820 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/sonner.tsx +29 -0
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/index.ts +26 -0
- package/src/registry.ts +218 -0
- package/{dist/styles.css → src/themes/default.css} +21 -3
- package/src/themes/tokens.config.ts +39 -0
- package/tsconfig.json +19 -0
- package/README.md +0 -41
- package/dist/index.cjs +0 -3780
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -302
- package/dist/index.d.ts +0 -302
- package/dist/index.js +0 -3696
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ArrowDownIcon,
|
|
5
|
+
ArrowUpIcon,
|
|
6
|
+
CheckIcon,
|
|
7
|
+
ChevronLeftIcon,
|
|
8
|
+
ChevronRightIcon,
|
|
9
|
+
CopyIcon,
|
|
10
|
+
PencilIcon,
|
|
11
|
+
RefreshCwIcon,
|
|
12
|
+
Square,
|
|
13
|
+
} from "lucide-react";
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
ActionBarPrimitive,
|
|
17
|
+
BranchPickerPrimitive,
|
|
18
|
+
ComposerPrimitive,
|
|
19
|
+
ErrorPrimitive,
|
|
20
|
+
MessagePrimitive,
|
|
21
|
+
ThreadPrimitive,
|
|
22
|
+
} from "@assistant-ui/react";
|
|
23
|
+
|
|
24
|
+
import type { FC } from "react";
|
|
25
|
+
import { useEffect } from "react";
|
|
26
|
+
import { LazyMotion, MotionConfig, domAnimation } from "motion/react";
|
|
27
|
+
import * as m from "motion/react-m";
|
|
28
|
+
|
|
29
|
+
import { Button } from "@/components/ui/button";
|
|
30
|
+
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
31
|
+
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
|
32
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
33
|
+
import {
|
|
34
|
+
ComposerAddAttachment,
|
|
35
|
+
ComposerAttachments,
|
|
36
|
+
UserMessageAttachments,
|
|
37
|
+
} from "@/components/assistant-ui/attachment";
|
|
38
|
+
|
|
39
|
+
import { cn, useNotification, useThreadContext } from "@aomi-labs/react";
|
|
40
|
+
import { useAssistantApi, useMessage } from "@assistant-ui/react";
|
|
41
|
+
|
|
42
|
+
const seenSystemMessages = new Set<string>();
|
|
43
|
+
|
|
44
|
+
export const Thread: FC = () => {
|
|
45
|
+
const api = useAssistantApi();
|
|
46
|
+
const { threadViewKey } = useThreadContext();
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
try {
|
|
50
|
+
const composer = api.composer();
|
|
51
|
+
composer.setText("");
|
|
52
|
+
void composer.clearAttachments?.();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error("Failed to reset composer input:", error);
|
|
55
|
+
}
|
|
56
|
+
}, [api, threadViewKey]);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<LazyMotion features={domAnimation}>
|
|
60
|
+
<MotionConfig reducedMotion="user">
|
|
61
|
+
<ThreadPrimitive.Root
|
|
62
|
+
className="aui-root aui-thread-root @container bg-background flex h-full flex-col"
|
|
63
|
+
style={{
|
|
64
|
+
["--thread-max-width" as string]: "44rem",
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<ThreadPrimitive.Viewport className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4">
|
|
68
|
+
<ThreadPrimitive.If empty>
|
|
69
|
+
<ThreadWelcome />
|
|
70
|
+
</ThreadPrimitive.If>
|
|
71
|
+
|
|
72
|
+
<ThreadPrimitive.Messages
|
|
73
|
+
components={{
|
|
74
|
+
UserMessage,
|
|
75
|
+
EditComposer,
|
|
76
|
+
AssistantMessage,
|
|
77
|
+
SystemMessage,
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
|
|
81
|
+
<ThreadPrimitive.If empty={false}>
|
|
82
|
+
<div className="aui-thread-viewport-spacer min-h-8 grow" />
|
|
83
|
+
</ThreadPrimitive.If>
|
|
84
|
+
|
|
85
|
+
<Composer />
|
|
86
|
+
</ThreadPrimitive.Viewport>
|
|
87
|
+
</ThreadPrimitive.Root>
|
|
88
|
+
</MotionConfig>
|
|
89
|
+
</LazyMotion>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const ThreadScrollToBottom: FC = () => {
|
|
94
|
+
return (
|
|
95
|
+
<ThreadPrimitive.ScrollToBottom asChild>
|
|
96
|
+
<TooltipIconButton
|
|
97
|
+
tooltip="Scroll to bottom"
|
|
98
|
+
variant="outline"
|
|
99
|
+
className="aui-thread-scroll-to-bottom dark:bg-background dark:hover:bg-accent absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible"
|
|
100
|
+
>
|
|
101
|
+
<ArrowDownIcon />
|
|
102
|
+
</TooltipIconButton>
|
|
103
|
+
</ThreadPrimitive.ScrollToBottom>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const ThreadWelcome: FC = () => {
|
|
108
|
+
return (
|
|
109
|
+
<div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col">
|
|
110
|
+
<div className="aui-thread-welcome-center flex w-full flex-grow flex-col items-center justify-center">
|
|
111
|
+
<div className="aui-thread-welcome-message flex size-full flex-col justify-center px-8">
|
|
112
|
+
<m.div
|
|
113
|
+
initial={{ opacity: 0, y: 10 }}
|
|
114
|
+
animate={{ opacity: 1, y: 0 }}
|
|
115
|
+
exit={{ opacity: 0, y: 10 }}
|
|
116
|
+
className="aui-thread-welcome-message-motion-1 text-2xl font-semibold"
|
|
117
|
+
>
|
|
118
|
+
Hello there!
|
|
119
|
+
</m.div>
|
|
120
|
+
<m.div
|
|
121
|
+
initial={{ opacity: 0, y: 10 }}
|
|
122
|
+
animate={{ opacity: 1, y: 0 }}
|
|
123
|
+
exit={{ opacity: 0, y: 10 }}
|
|
124
|
+
transition={{ delay: 0.1 }}
|
|
125
|
+
className="aui-thread-welcome-message-motion-2 text-muted-foreground/65 text-2xl"
|
|
126
|
+
>
|
|
127
|
+
How can I help you today?
|
|
128
|
+
</m.div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<ThreadSuggestions />
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const ThreadSuggestions: FC = () => {
|
|
137
|
+
return (
|
|
138
|
+
<div className="aui-thread-welcome-suggestions @md:grid-cols-2 grid w-full gap-2 pb-4">
|
|
139
|
+
{[
|
|
140
|
+
{
|
|
141
|
+
title: "Show my wallet balances",
|
|
142
|
+
label: "and positions",
|
|
143
|
+
action: "Show my wallet balances and positions",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
title: "Swap 1 ETH to USDC",
|
|
147
|
+
label: "with the best price",
|
|
148
|
+
action: "Swap 1 ETH to USDC with the best price",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
title: "Stake half of my ETH",
|
|
152
|
+
label: "in the highest yield pool",
|
|
153
|
+
action: "Stake half of my ETH in the highest yield pool",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
title: "Bridge 100 USDC",
|
|
157
|
+
label: "from Ethereum to Arbitrum",
|
|
158
|
+
action: "Bridge 100 USDC from Ethereum to Arbitrum",
|
|
159
|
+
},
|
|
160
|
+
].map((suggestedAction, index) => (
|
|
161
|
+
<m.div
|
|
162
|
+
initial={{ opacity: 0, y: 20 }}
|
|
163
|
+
animate={{ opacity: 1, y: 0 }}
|
|
164
|
+
exit={{ opacity: 0, y: 20 }}
|
|
165
|
+
transition={{ delay: 0.05 * index }}
|
|
166
|
+
key={`suggested-action-${suggestedAction.title}-${index}`}
|
|
167
|
+
className="aui-thread-welcome-suggestion-display @md:[&:nth-child(n+3)]:block [&:nth-child(n+3)]:hidden"
|
|
168
|
+
>
|
|
169
|
+
<ThreadPrimitive.Suggestion
|
|
170
|
+
prompt={suggestedAction.action}
|
|
171
|
+
send
|
|
172
|
+
asChild
|
|
173
|
+
>
|
|
174
|
+
<Button
|
|
175
|
+
variant="ghost"
|
|
176
|
+
className="aui-thread-welcome-suggestion @md:flex-col dark:hover:bg-accent/60 h-auto w-full flex-1 flex-wrap items-start justify-start gap-1 rounded-3xl border px-5 py-4 text-left text-sm"
|
|
177
|
+
aria-label={suggestedAction.action}
|
|
178
|
+
>
|
|
179
|
+
<span className="aui-thread-welcome-suggestion-text-1 font-medium">
|
|
180
|
+
{suggestedAction.title}
|
|
181
|
+
</span>
|
|
182
|
+
<span className="aui-thread-welcome-suggestion-text-2 text-muted-foreground">
|
|
183
|
+
{suggestedAction.label}
|
|
184
|
+
</span>
|
|
185
|
+
</Button>
|
|
186
|
+
</ThreadPrimitive.Suggestion>
|
|
187
|
+
</m.div>
|
|
188
|
+
))}
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const Composer: FC = () => {
|
|
194
|
+
return (
|
|
195
|
+
<div className="aui-composer-wrapper bg-background sticky bottom-0 mx-auto flex w-full max-w-[var(--thread-max-width)] flex-col gap-4 overflow-visible rounded-t-3xl pb-4 md:pb-6">
|
|
196
|
+
<ThreadScrollToBottom />
|
|
197
|
+
<ComposerPrimitive.Root className="aui-composer-root rounded-4xl dark:border-muted-foreground/15 relative flex w-full flex-col border bg-white px-1 pt-2 shadow-[0_9px_9px_0px_rgba(0,0,0,0.01),0_2px_5px_0px_rgba(0,0,0,0.06)]">
|
|
198
|
+
<ComposerAttachments />
|
|
199
|
+
<ComposerPrimitive.Input
|
|
200
|
+
placeholder="Send a message..."
|
|
201
|
+
className="aui-composer-input placeholder:text-muted-foreground focus:outline-primary ml-3 mt-2 max-h-32 min-h-16 w-full resize-none bg-transparent px-3.5 pb-3 pt-1.5 text-sm text-stone-800 outline-none"
|
|
202
|
+
rows={1}
|
|
203
|
+
autoFocus
|
|
204
|
+
aria-label="Message input"
|
|
205
|
+
/>
|
|
206
|
+
<ComposerAction />
|
|
207
|
+
</ComposerPrimitive.Root>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const ComposerAction: FC = () => {
|
|
213
|
+
return (
|
|
214
|
+
<div className="aui-composer-action-wrapper relative mx-1 mb-2 mt-2 flex items-center justify-between">
|
|
215
|
+
<ComposerAddAttachment />
|
|
216
|
+
|
|
217
|
+
<ThreadPrimitive.If running={false}>
|
|
218
|
+
<ComposerPrimitive.Send asChild>
|
|
219
|
+
<TooltipIconButton
|
|
220
|
+
tooltip="Send message"
|
|
221
|
+
side="bottom"
|
|
222
|
+
type="submit"
|
|
223
|
+
variant="default"
|
|
224
|
+
size="icon"
|
|
225
|
+
className="aui-composer-send mb-3 mr-3 size-[34px] rounded-full p-1"
|
|
226
|
+
aria-label="Send message"
|
|
227
|
+
>
|
|
228
|
+
<ArrowUpIcon className="aui-composer-send-icon size-5" />
|
|
229
|
+
</TooltipIconButton>
|
|
230
|
+
</ComposerPrimitive.Send>
|
|
231
|
+
</ThreadPrimitive.If>
|
|
232
|
+
|
|
233
|
+
<ThreadPrimitive.If running>
|
|
234
|
+
<ComposerPrimitive.Cancel asChild>
|
|
235
|
+
<Button
|
|
236
|
+
type="button"
|
|
237
|
+
variant="default"
|
|
238
|
+
size="icon"
|
|
239
|
+
className="aui-composer-cancel border-muted-foreground/60 hover:bg-primary/75 dark:border-muted-foreground/90 size-[34px] rounded-full border"
|
|
240
|
+
aria-label="Stop generating"
|
|
241
|
+
>
|
|
242
|
+
<Square className="aui-composer-cancel-icon size-3.5 fill-white dark:fill-black" />
|
|
243
|
+
</Button>
|
|
244
|
+
</ComposerPrimitive.Cancel>
|
|
245
|
+
</ThreadPrimitive.If>
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const MessageError: FC = () => {
|
|
251
|
+
return (
|
|
252
|
+
<MessagePrimitive.Error>
|
|
253
|
+
<ErrorPrimitive.Root className="aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-md border p-3 text-sm dark:text-red-200">
|
|
254
|
+
<ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
|
|
255
|
+
</ErrorPrimitive.Root>
|
|
256
|
+
</MessagePrimitive.Error>
|
|
257
|
+
);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const AssistantMessage: FC = () => {
|
|
261
|
+
return (
|
|
262
|
+
<MessagePrimitive.Root asChild>
|
|
263
|
+
<div
|
|
264
|
+
className="aui-assistant-message-root animate-in fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-[var(--thread-max-width)] py-4 duration-150 ease-out last:mb-24"
|
|
265
|
+
data-role="assistant"
|
|
266
|
+
>
|
|
267
|
+
<div className="aui-assistant-message-content text-foreground mx-2 break-words text-sm leading-5">
|
|
268
|
+
<MessagePrimitive.Parts
|
|
269
|
+
components={{
|
|
270
|
+
Text: MarkdownText,
|
|
271
|
+
tools: { Fallback: ToolFallback },
|
|
272
|
+
}}
|
|
273
|
+
/>
|
|
274
|
+
<MessageError />
|
|
275
|
+
</div>
|
|
276
|
+
|
|
277
|
+
<div className="aui-assistant-message-footer ml-2 mt-2 flex">
|
|
278
|
+
<BranchPicker />
|
|
279
|
+
<AssistantActionBar />
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
</MessagePrimitive.Root>
|
|
283
|
+
);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const AssistantActionBar: FC = () => {
|
|
287
|
+
return (
|
|
288
|
+
<ActionBarPrimitive.Root
|
|
289
|
+
hideWhenRunning
|
|
290
|
+
autohide="not-last"
|
|
291
|
+
autohideFloat="single-branch"
|
|
292
|
+
className="aui-assistant-action-bar-root text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm col-start-3 row-start-2 -ml-1 flex gap-1"
|
|
293
|
+
>
|
|
294
|
+
<ActionBarPrimitive.Copy asChild>
|
|
295
|
+
<TooltipIconButton tooltip="Copy">
|
|
296
|
+
<MessagePrimitive.If copied>
|
|
297
|
+
<CheckIcon />
|
|
298
|
+
</MessagePrimitive.If>
|
|
299
|
+
<MessagePrimitive.If copied={false}>
|
|
300
|
+
<CopyIcon />
|
|
301
|
+
</MessagePrimitive.If>
|
|
302
|
+
</TooltipIconButton>
|
|
303
|
+
</ActionBarPrimitive.Copy>
|
|
304
|
+
<ActionBarPrimitive.Reload asChild>
|
|
305
|
+
<TooltipIconButton tooltip="Refresh">
|
|
306
|
+
<RefreshCwIcon />
|
|
307
|
+
</TooltipIconButton>
|
|
308
|
+
</ActionBarPrimitive.Reload>
|
|
309
|
+
</ActionBarPrimitive.Root>
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const UserMessage: FC = () => {
|
|
314
|
+
return (
|
|
315
|
+
<MessagePrimitive.Root asChild>
|
|
316
|
+
<div
|
|
317
|
+
className="aui-user-message-root animate-in fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-[var(--thread-max-width)] auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] gap-y-2 px-2 py-4 duration-150 ease-out first:mt-3 last:mb-5 [&:where(>*)]:col-start-2"
|
|
318
|
+
data-role="user"
|
|
319
|
+
>
|
|
320
|
+
<UserMessageAttachments />
|
|
321
|
+
|
|
322
|
+
<div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
|
|
323
|
+
<div className="aui-user-message-content bg-muted text-foreground break-words rounded-3xl px-5 py-2.5 text-sm">
|
|
324
|
+
<MessagePrimitive.Parts />
|
|
325
|
+
</div>
|
|
326
|
+
<div className="aui-user-action-bar-wrapper absolute left-0 top-1/2 -translate-x-full -translate-y-1/2 pr-2">
|
|
327
|
+
<UserActionBar />
|
|
328
|
+
</div>
|
|
329
|
+
</div>
|
|
330
|
+
|
|
331
|
+
<BranchPicker className="aui-user-branch-picker col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
|
|
332
|
+
</div>
|
|
333
|
+
</MessagePrimitive.Root>
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const UserActionBar: FC = () => {
|
|
338
|
+
return (
|
|
339
|
+
<ActionBarPrimitive.Root
|
|
340
|
+
hideWhenRunning
|
|
341
|
+
autohide="not-last"
|
|
342
|
+
className="aui-user-action-bar-root flex flex-col items-end"
|
|
343
|
+
>
|
|
344
|
+
<ActionBarPrimitive.Edit asChild>
|
|
345
|
+
<TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
|
|
346
|
+
<PencilIcon />
|
|
347
|
+
</TooltipIconButton>
|
|
348
|
+
</ActionBarPrimitive.Edit>
|
|
349
|
+
</ActionBarPrimitive.Root>
|
|
350
|
+
);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const EditComposer: FC = () => {
|
|
354
|
+
return (
|
|
355
|
+
<div className="aui-edit-composer-wrapper mx-auto flex w-full max-w-[var(--thread-max-width)] flex-col gap-4 px-2 first:mt-4">
|
|
356
|
+
<ComposerPrimitive.Root className="aui-edit-composer-root max-w-7/8 bg-muted ml-auto flex w-full flex-col rounded-xl">
|
|
357
|
+
<ComposerPrimitive.Input
|
|
358
|
+
className="aui-edit-composer-input text-foreground flex min-h-[60px] w-full resize-none bg-transparent p-4 outline-none"
|
|
359
|
+
autoFocus
|
|
360
|
+
/>
|
|
361
|
+
|
|
362
|
+
<div className="aui-edit-composer-footer mx-3 mb-3 flex items-center justify-center gap-2 self-end">
|
|
363
|
+
<ComposerPrimitive.Cancel asChild>
|
|
364
|
+
<Button variant="ghost" size="sm" aria-label="Cancel edit">
|
|
365
|
+
Cancel
|
|
366
|
+
</Button>
|
|
367
|
+
</ComposerPrimitive.Cancel>
|
|
368
|
+
<ComposerPrimitive.Send asChild>
|
|
369
|
+
<Button size="sm" aria-label="Update message">
|
|
370
|
+
Update
|
|
371
|
+
</Button>
|
|
372
|
+
</ComposerPrimitive.Send>
|
|
373
|
+
</div>
|
|
374
|
+
</ComposerPrimitive.Root>
|
|
375
|
+
</div>
|
|
376
|
+
);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
380
|
+
className,
|
|
381
|
+
...rest
|
|
382
|
+
}) => {
|
|
383
|
+
return (
|
|
384
|
+
<BranchPickerPrimitive.Root
|
|
385
|
+
hideWhenSingleBranch
|
|
386
|
+
className={cn(
|
|
387
|
+
"aui-branch-picker-root text-muted-foreground -ml-2 mr-2 inline-flex items-center text-xs",
|
|
388
|
+
className,
|
|
389
|
+
)}
|
|
390
|
+
{...rest}
|
|
391
|
+
>
|
|
392
|
+
<BranchPickerPrimitive.Previous asChild>
|
|
393
|
+
<TooltipIconButton tooltip="Previous">
|
|
394
|
+
<ChevronLeftIcon />
|
|
395
|
+
</TooltipIconButton>
|
|
396
|
+
</BranchPickerPrimitive.Previous>
|
|
397
|
+
<span className="aui-branch-picker-state font-medium">
|
|
398
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
399
|
+
</span>
|
|
400
|
+
<BranchPickerPrimitive.Next asChild>
|
|
401
|
+
<TooltipIconButton tooltip="Next">
|
|
402
|
+
<ChevronRightIcon />
|
|
403
|
+
</TooltipIconButton>
|
|
404
|
+
</BranchPickerPrimitive.Next>
|
|
405
|
+
</BranchPickerPrimitive.Root>
|
|
406
|
+
);
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const SystemMessage: FC = () => {
|
|
410
|
+
const { showNotification } = useNotification();
|
|
411
|
+
const messageId = useMessage((state) => state.id);
|
|
412
|
+
const content = useMessage((state) => state.content) as Array<{
|
|
413
|
+
type: string;
|
|
414
|
+
text?: string;
|
|
415
|
+
}>;
|
|
416
|
+
const custom = useMessage((state) => state.metadata?.custom) as
|
|
417
|
+
| { kind?: string; title?: string }
|
|
418
|
+
| undefined;
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
const text = content
|
|
421
|
+
.filter((part) => part.type === "text")
|
|
422
|
+
.map((part) => part.text ?? "")
|
|
423
|
+
.join("")
|
|
424
|
+
.trim();
|
|
425
|
+
|
|
426
|
+
if (!text) return;
|
|
427
|
+
|
|
428
|
+
const key = messageId ?? text;
|
|
429
|
+
if (seenSystemMessages.has(key)) return;
|
|
430
|
+
seenSystemMessages.add(key);
|
|
431
|
+
|
|
432
|
+
const inferredKind =
|
|
433
|
+
custom?.kind ??
|
|
434
|
+
(text.startsWith("Wallet transaction request:")
|
|
435
|
+
? "wallet_tx_request"
|
|
436
|
+
: "system_notice");
|
|
437
|
+
|
|
438
|
+
const type =
|
|
439
|
+
inferredKind === "system_error"
|
|
440
|
+
? "error"
|
|
441
|
+
: inferredKind === "system_success"
|
|
442
|
+
? "success"
|
|
443
|
+
: "notice";
|
|
444
|
+
|
|
445
|
+
const title =
|
|
446
|
+
custom?.title ??
|
|
447
|
+
(inferredKind === "wallet_tx_request"
|
|
448
|
+
? "Wallet transaction request"
|
|
449
|
+
: inferredKind === "system_error"
|
|
450
|
+
? "Error"
|
|
451
|
+
: "System notice");
|
|
452
|
+
|
|
453
|
+
showNotification({ type, title, message: text });
|
|
454
|
+
}, [content, custom, showNotification, messageId]);
|
|
455
|
+
|
|
456
|
+
return null;
|
|
457
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import Image from "next/image";
|
|
6
|
+
import {
|
|
7
|
+
Sidebar,
|
|
8
|
+
SidebarContent,
|
|
9
|
+
SidebarFooter,
|
|
10
|
+
SidebarHeader,
|
|
11
|
+
SidebarMenu,
|
|
12
|
+
SidebarMenuButton,
|
|
13
|
+
SidebarMenuItem,
|
|
14
|
+
SidebarRail,
|
|
15
|
+
} from "@/components/ui/sidebar";
|
|
16
|
+
import { ThreadList } from "@/components/assistant-ui/thread-list";
|
|
17
|
+
|
|
18
|
+
type ThreadListSidebarProps = React.ComponentProps<typeof Sidebar> & {
|
|
19
|
+
/** Optional footer component (e.g., WalletFooter from consumer app) */
|
|
20
|
+
footer?: React.ReactNode;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function ThreadListSidebar({
|
|
24
|
+
footer,
|
|
25
|
+
...props
|
|
26
|
+
}: ThreadListSidebarProps) {
|
|
27
|
+
return (
|
|
28
|
+
<Sidebar
|
|
29
|
+
collapsible="offcanvas"
|
|
30
|
+
variant="inset"
|
|
31
|
+
className="relative"
|
|
32
|
+
{...props}
|
|
33
|
+
>
|
|
34
|
+
<SidebarHeader className="aomi-sidebar-header">
|
|
35
|
+
<div className="aomi-sidebar-header-content flex items-center justify-between">
|
|
36
|
+
<SidebarMenu>
|
|
37
|
+
<SidebarMenuItem>
|
|
38
|
+
<SidebarMenuButton size="lg" asChild>
|
|
39
|
+
<Link
|
|
40
|
+
href="https://aomi.dev"
|
|
41
|
+
target="_blank"
|
|
42
|
+
rel="noopener noreferrer"
|
|
43
|
+
>
|
|
44
|
+
<div className="aomi-sidebar-header-icon-wrapper flex aspect-square size-8 items-center justify-center rounded-lg bg-white">
|
|
45
|
+
<Image
|
|
46
|
+
src="/assets/images/bubble.svg"
|
|
47
|
+
alt="Logo"
|
|
48
|
+
width={28}
|
|
49
|
+
height={28}
|
|
50
|
+
className="aomi-sidebar-header-icon ml-3 size-7"
|
|
51
|
+
priority
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
</Link>
|
|
55
|
+
</SidebarMenuButton>
|
|
56
|
+
</SidebarMenuItem>
|
|
57
|
+
</SidebarMenu>
|
|
58
|
+
</div>
|
|
59
|
+
</SidebarHeader>
|
|
60
|
+
<SidebarContent className="aomi-sidebar-content">
|
|
61
|
+
<ThreadList />
|
|
62
|
+
</SidebarContent>
|
|
63
|
+
<SidebarRail />
|
|
64
|
+
{footer && (
|
|
65
|
+
<SidebarFooter className="aomi-sidebar-footer border-sm border-t py-4">
|
|
66
|
+
{footer}
|
|
67
|
+
</SidebarFooter>
|
|
68
|
+
)}
|
|
69
|
+
</Sidebar>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
4
|
+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
|
|
8
|
+
export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
9
|
+
toolName,
|
|
10
|
+
argsText,
|
|
11
|
+
result,
|
|
12
|
+
}) => {
|
|
13
|
+
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
14
|
+
return (
|
|
15
|
+
<div className="aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3">
|
|
16
|
+
<div className="aui-tool-fallback-header flex items-center gap-2 px-4">
|
|
17
|
+
<CheckIcon className="aui-tool-fallback-icon size-4" />
|
|
18
|
+
<p className="aui-tool-fallback-title flex-grow">
|
|
19
|
+
Used tool: <b>{toolName}</b>
|
|
20
|
+
</p>
|
|
21
|
+
<Button onClick={() => setIsCollapsed(!isCollapsed)}>
|
|
22
|
+
{isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
23
|
+
</Button>
|
|
24
|
+
</div>
|
|
25
|
+
{!isCollapsed && (
|
|
26
|
+
<div className="aui-tool-fallback-content bg-muted flex flex-col gap-2 border-t pt-2">
|
|
27
|
+
<div className="aui-tool-fallback-args-root px-4">
|
|
28
|
+
<pre className="aui-tool-fallback-args-value whitespace-pre-wrap">
|
|
29
|
+
{argsText}
|
|
30
|
+
</pre>
|
|
31
|
+
</div>
|
|
32
|
+
{result !== undefined && (
|
|
33
|
+
<div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
|
|
34
|
+
<p className="aui-tool-fallback-result-header font-semibold">
|
|
35
|
+
Result:
|
|
36
|
+
</p>
|
|
37
|
+
<pre className="aui-tool-fallback-result-content whitespace-pre-wrap text-[012px]">
|
|
38
|
+
{typeof result === "string"
|
|
39
|
+
? result
|
|
40
|
+
: JSON.stringify(result, null, 2)}
|
|
41
|
+
</pre>
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ComponentPropsWithRef, forwardRef } from "react";
|
|
4
|
+
import { Slottable } from "@radix-ui/react-slot";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Tooltip,
|
|
8
|
+
TooltipContent,
|
|
9
|
+
TooltipTrigger,
|
|
10
|
+
} from "@/components/ui/tooltip";
|
|
11
|
+
import { Button } from "@/components/ui/button";
|
|
12
|
+
import { cn } from "@aomi-labs/react";
|
|
13
|
+
|
|
14
|
+
export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
|
|
15
|
+
tooltip: string;
|
|
16
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const TooltipIconButton = forwardRef<
|
|
20
|
+
HTMLButtonElement,
|
|
21
|
+
TooltipIconButtonProps
|
|
22
|
+
>(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
|
|
23
|
+
return (
|
|
24
|
+
<Tooltip>
|
|
25
|
+
<TooltipTrigger asChild>
|
|
26
|
+
<Button
|
|
27
|
+
variant="ghost"
|
|
28
|
+
size="icon"
|
|
29
|
+
{...rest}
|
|
30
|
+
className={cn("aui-button-icon size-6 p-1", className)}
|
|
31
|
+
ref={ref}
|
|
32
|
+
>
|
|
33
|
+
<Slottable>{children}</Slottable>
|
|
34
|
+
<span className="aui-sr-only sr-only">{tooltip}</span>
|
|
35
|
+
</Button>
|
|
36
|
+
</TooltipTrigger>
|
|
37
|
+
<TooltipContent side={side}>{tooltip}</TooltipContent>
|
|
38
|
+
</Tooltip>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
TooltipIconButton.displayName = "TooltipIconButton";
|