@applica-software-guru/persona-sdk 0.0.1-preview0

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.
Files changed (66) hide show
  1. package/.eslintrc.cjs +11 -0
  2. package/.nvmrc +1 -0
  3. package/.prettierignore +5 -0
  4. package/.prettierrc +8 -0
  5. package/README.md +66 -0
  6. package/bitbucket-pipelines.yml +29 -0
  7. package/dist/bundle.cjs.js +27 -0
  8. package/dist/bundle.cjs.js.map +1 -0
  9. package/dist/bundle.es.js +6585 -0
  10. package/dist/bundle.es.js.map +1 -0
  11. package/dist/bundle.iife.js +27 -0
  12. package/dist/bundle.iife.js.map +1 -0
  13. package/dist/bundle.umd.js +27 -0
  14. package/dist/bundle.umd.js.map +1 -0
  15. package/dist/index.d.ts +5 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/logging.d.ts +18 -0
  18. package/dist/logging.d.ts.map +1 -0
  19. package/dist/messages.d.ts +7 -0
  20. package/dist/messages.d.ts.map +1 -0
  21. package/dist/protocol/base.d.ts +23 -0
  22. package/dist/protocol/base.d.ts.map +1 -0
  23. package/dist/protocol/index.d.ts +5 -0
  24. package/dist/protocol/index.d.ts.map +1 -0
  25. package/dist/protocol/rest.d.ts +22 -0
  26. package/dist/protocol/rest.d.ts.map +1 -0
  27. package/dist/protocol/webrtc.d.ts +56 -0
  28. package/dist/protocol/webrtc.d.ts.map +1 -0
  29. package/dist/protocol/websocket.d.ts +22 -0
  30. package/dist/protocol/websocket.d.ts.map +1 -0
  31. package/dist/runtime.d.ts +21 -0
  32. package/dist/runtime.d.ts.map +1 -0
  33. package/dist/types.d.ts +79 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/jsconfig.node.json +10 -0
  36. package/package.json +72 -0
  37. package/playground/index.html +14 -0
  38. package/playground/src/app.tsx +10 -0
  39. package/playground/src/chat.tsx +52 -0
  40. package/playground/src/components/assistant-ui/assistant-modal.tsx +57 -0
  41. package/playground/src/components/assistant-ui/markdown-text.tsx +119 -0
  42. package/playground/src/components/assistant-ui/thread-list.tsx +62 -0
  43. package/playground/src/components/assistant-ui/thread.tsx +249 -0
  44. package/playground/src/components/assistant-ui/tool-fallback.tsx +33 -0
  45. package/playground/src/components/assistant-ui/tooltip-icon-button.tsx +38 -0
  46. package/playground/src/components/ui/avatar.tsx +35 -0
  47. package/playground/src/components/ui/button.tsx +43 -0
  48. package/playground/src/components/ui/tooltip.tsx +32 -0
  49. package/playground/src/lib/utils.ts +6 -0
  50. package/playground/src/main.tsx +10 -0
  51. package/playground/src/styles.css +1 -0
  52. package/playground/src/vite-env.d.ts +1 -0
  53. package/preview.sh +13 -0
  54. package/src/index.ts +4 -0
  55. package/src/logging.ts +34 -0
  56. package/src/messages.ts +79 -0
  57. package/src/protocol/base.ts +55 -0
  58. package/src/protocol/index.ts +4 -0
  59. package/src/protocol/rest.ts +64 -0
  60. package/src/protocol/webrtc.ts +337 -0
  61. package/src/protocol/websocket.ts +106 -0
  62. package/src/runtime.tsx +214 -0
  63. package/src/types.ts +98 -0
  64. package/tsconfig.json +36 -0
  65. package/tsconfig.node.json +15 -0
  66. package/vite.config.ts +69 -0
@@ -0,0 +1,119 @@
1
+ 'use client';
2
+
3
+ import '@assistant-ui/react-markdown/styles/dot.css';
4
+
5
+ import {
6
+ CodeHeaderProps,
7
+ MarkdownTextPrimitive,
8
+ unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
9
+ useIsMarkdownCodeBlock,
10
+ } from '@assistant-ui/react-markdown';
11
+ import remarkGfm from 'remark-gfm';
12
+ import { FC, memo, useState } from 'react';
13
+ import { CheckIcon, CopyIcon } from 'lucide-react';
14
+
15
+ import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button';
16
+ import { cn } from '@/lib/utils';
17
+
18
+ const MarkdownTextImpl = () => {
19
+ return <MarkdownTextPrimitive remarkPlugins={[remarkGfm]} className="aui-md" components={defaultComponents} />;
20
+ };
21
+
22
+ export const MarkdownText = memo(MarkdownTextImpl);
23
+
24
+ const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
25
+ const { isCopied, copyToClipboard } = useCopyToClipboard();
26
+ const onCopy = () => {
27
+ if (!code || isCopied) return;
28
+ copyToClipboard(code);
29
+ };
30
+
31
+ return (
32
+ <div className="flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white">
33
+ <span className="lowercase [&>span]:text-xs">{language}</span>
34
+ <TooltipIconButton tooltip="Copy" onClick={onCopy}>
35
+ {!isCopied && <CopyIcon />}
36
+ {isCopied && <CheckIcon />}
37
+ </TooltipIconButton>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ const useCopyToClipboard = ({
43
+ copiedDuration = 3000,
44
+ }: {
45
+ copiedDuration?: number;
46
+ } = {}) => {
47
+ const [isCopied, setIsCopied] = useState<boolean>(false);
48
+
49
+ const copyToClipboard = (value: string) => {
50
+ if (!value) return;
51
+
52
+ navigator.clipboard.writeText(value).then(() => {
53
+ setIsCopied(true);
54
+ setTimeout(() => setIsCopied(false), copiedDuration);
55
+ });
56
+ };
57
+
58
+ return { isCopied, copyToClipboard };
59
+ };
60
+
61
+ const defaultComponents = memoizeMarkdownComponents({
62
+ h1: ({ className, ...props }) => (
63
+ <h1 className={cn('mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0', className)} {...props} />
64
+ ),
65
+ h2: ({ className, ...props }) => (
66
+ <h2 className={cn('mb-4 mt-8 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0', className)} {...props} />
67
+ ),
68
+ h3: ({ className, ...props }) => (
69
+ <h3 className={cn('mb-4 mt-6 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0', className)} {...props} />
70
+ ),
71
+ h4: ({ className, ...props }) => (
72
+ <h4 className={cn('mb-4 mt-6 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0', className)} {...props} />
73
+ ),
74
+ h5: ({ className, ...props }) => <h5 className={cn('my-4 text-lg font-semibold first:mt-0 last:mb-0', className)} {...props} />,
75
+ h6: ({ className, ...props }) => <h6 className={cn('my-4 font-semibold first:mt-0 last:mb-0', className)} {...props} />,
76
+ p: ({ className, ...props }) => <p className={cn('mb-5 mt-5 leading-7 first:mt-0 last:mb-0', className)} {...props} />,
77
+ a: ({ className, ...props }) => <a className={cn('text-primary font-medium underline underline-offset-4', className)} {...props} />,
78
+ blockquote: ({ className, ...props }) => <blockquote className={cn('border-l-2 pl-6 italic', className)} {...props} />,
79
+ ul: ({ className, ...props }) => <ul className={cn('my-5 ml-6 list-disc [&>li]:mt-2', className)} {...props} />,
80
+ ol: ({ className, ...props }) => <ol className={cn('my-5 ml-6 list-decimal [&>li]:mt-2', className)} {...props} />,
81
+ hr: ({ className, ...props }) => <hr className={cn('my-5 border-b', className)} {...props} />,
82
+ table: ({ className, ...props }) => (
83
+ <table className={cn('my-5 w-full border-separate border-spacing-0 overflow-y-auto', className)} {...props} />
84
+ ),
85
+ th: ({ className, ...props }) => (
86
+ <th
87
+ className={cn(
88
+ 'bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [&[align=center]]:text-center [&[align=right]]:text-right',
89
+ className,
90
+ )}
91
+ {...props}
92
+ />
93
+ ),
94
+ td: ({ className, ...props }) => (
95
+ <td
96
+ className={cn(
97
+ 'border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right',
98
+ className,
99
+ )}
100
+ {...props}
101
+ />
102
+ ),
103
+ tr: ({ className, ...props }) => (
104
+ <tr
105
+ className={cn(
106
+ 'm-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg',
107
+ className,
108
+ )}
109
+ {...props}
110
+ />
111
+ ),
112
+ sup: ({ className, ...props }) => <sup className={cn('[&>a]:text-xs [&>a]:no-underline', className)} {...props} />,
113
+ pre: ({ className, ...props }) => <pre className={cn('overflow-x-auto rounded-b-lg bg-black p-4 text-white', className)} {...props} />,
114
+ code: function Code({ className, ...props }) {
115
+ const isCodeBlock = useIsMarkdownCodeBlock();
116
+ return <code className={cn(!isCodeBlock && 'bg-muted rounded border font-semibold', className)} {...props} />;
117
+ },
118
+ CodeHeader,
119
+ });
@@ -0,0 +1,62 @@
1
+ import type { FC } from 'react';
2
+ import { ThreadListItemPrimitive, ThreadListPrimitive } from '@assistant-ui/react';
3
+ import { ArchiveIcon, PlusIcon } from 'lucide-react';
4
+
5
+ import { Button } from '@/components/ui/button';
6
+ import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button';
7
+
8
+ export const ThreadList: FC = () => {
9
+ return (
10
+ <ThreadListPrimitive.Root className="flex flex-col items-stretch gap-1.5">
11
+ <ThreadListNew />
12
+ <ThreadListItems />
13
+ </ThreadListPrimitive.Root>
14
+ );
15
+ };
16
+
17
+ const ThreadListNew: FC = () => {
18
+ return (
19
+ <ThreadListPrimitive.New asChild>
20
+ <Button
21
+ className="data-[active]:bg-muted hover:bg-muted flex items-center justify-start gap-1 rounded-lg px-2.5 py-2 text-start"
22
+ variant="ghost"
23
+ >
24
+ <PlusIcon />
25
+ New Thread
26
+ </Button>
27
+ </ThreadListPrimitive.New>
28
+ );
29
+ };
30
+
31
+ const ThreadListItems: FC = () => {
32
+ return <ThreadListPrimitive.Items components={{ ThreadListItem }} />;
33
+ };
34
+
35
+ const ThreadListItem: FC = () => {
36
+ return (
37
+ <ThreadListItemPrimitive.Root className="data-[active]:bg-muted hover:bg-muted focus-visible:bg-muted focus-visible:ring-ring flex items-center gap-2 rounded-lg transition-all focus-visible:outline-none focus-visible:ring-2">
38
+ <ThreadListItemPrimitive.Trigger className="flex-grow px-3 py-2 text-start">
39
+ <ThreadListItemTitle />
40
+ </ThreadListItemPrimitive.Trigger>
41
+ <ThreadListItemArchive />
42
+ </ThreadListItemPrimitive.Root>
43
+ );
44
+ };
45
+
46
+ const ThreadListItemTitle: FC = () => {
47
+ return (
48
+ <p className="text-sm">
49
+ <ThreadListItemPrimitive.Title fallback="New Chat" />
50
+ </p>
51
+ );
52
+ };
53
+
54
+ const ThreadListItemArchive: FC = () => {
55
+ return (
56
+ <ThreadListItemPrimitive.Archive asChild>
57
+ <TooltipIconButton className="hover:text-primary text-foreground ml-auto mr-3 size-4 p-0" variant="ghost" tooltip="Archive thread">
58
+ <ArchiveIcon />
59
+ </TooltipIconButton>
60
+ </ThreadListItemPrimitive.Archive>
61
+ );
62
+ };
@@ -0,0 +1,249 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import {
3
+ ActionBarPrimitive,
4
+ BranchPickerPrimitive,
5
+ ComposerPrimitive,
6
+ MessagePrimitive,
7
+ ReasoningContentPartProps,
8
+ ThreadPrimitive,
9
+ } from '@assistant-ui/react';
10
+ import { useCallback, useMemo, type FC } from 'react';
11
+ import { ArrowDownIcon, CheckIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, SendHorizontalIcon, MicIcon } from 'lucide-react';
12
+ import { cn } from '@/lib/utils';
13
+
14
+ import { Button } from '@/components/ui/button';
15
+ import { MarkdownText } from '@/components/assistant-ui/markdown-text';
16
+ import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button';
17
+ import { ToolFallback } from '@/components/assistant-ui/tool-fallback';
18
+
19
+ import { usePersonaRuntimeWebRTCProtocol } from '@applica-software-guru/persona-sdk';
20
+
21
+ export const Thread: FC = () => {
22
+ return (
23
+ <ThreadPrimitive.Root
24
+ className="bg-background box-border flex h-full flex-col overflow-hidden"
25
+ style={{
26
+ ['--thread-max-width' as string]: '42rem',
27
+ }}
28
+ >
29
+ <ThreadPrimitive.Viewport className="flex h-full flex-col items-center overflow-y-scroll scroll-smooth bg-inherit px-4 pt-8">
30
+ <ThreadWelcome />
31
+
32
+ <ThreadPrimitive.Messages
33
+ components={{
34
+ UserMessage: UserMessage,
35
+ EditComposer: EditComposer,
36
+ AssistantMessage: AssistantMessage,
37
+ }}
38
+ />
39
+
40
+ <ThreadPrimitive.If empty={false}>
41
+ <div className="min-h-8 flex-grow" />
42
+ </ThreadPrimitive.If>
43
+
44
+ <div className="sticky bottom-0 mt-3 flex w-full max-w-[var(--thread-max-width)] flex-col items-center justify-end rounded-t-lg bg-inherit pb-4">
45
+ <ThreadScrollToBottom />
46
+ <Composer />
47
+ </div>
48
+ </ThreadPrimitive.Viewport>
49
+ </ThreadPrimitive.Root>
50
+ );
51
+ };
52
+
53
+ const ThreadScrollToBottom: FC = () => {
54
+ return (
55
+ <ThreadPrimitive.ScrollToBottom asChild>
56
+ <TooltipIconButton tooltip="Scroll to bottom" variant="outline" className="absolute -top-8 rounded-full disabled:invisible">
57
+ <ArrowDownIcon />
58
+ </TooltipIconButton>
59
+ </ThreadPrimitive.ScrollToBottom>
60
+ );
61
+ };
62
+
63
+ const ThreadWelcome: FC = () => {
64
+ return (
65
+ <ThreadPrimitive.Empty>
66
+ <div className="flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col">
67
+ <div className="flex w-full flex-grow flex-col items-center justify-center">
68
+ <p className="mt-4 font-medium">Come posso aiutarti oggi?</p>
69
+ </div>
70
+ {/* <ThreadWelcomeSuggestions /> */}
71
+ </div>
72
+ </ThreadPrimitive.Empty>
73
+ );
74
+ };
75
+
76
+ const Composer: FC = () => {
77
+ return (
78
+ <ComposerPrimitive.Root className="focus-within:border-ring/20 flex w-full flex-wrap items-end rounded-lg border bg-inherit px-2.5 shadow-sm transition-colors ease-in">
79
+ <ComposerPrimitive.Input
80
+ rows={1}
81
+ autoFocus
82
+ placeholder="Write a message..."
83
+ className="placeholder:text-muted-foreground max-h-40 flex-grow resize-none border-none bg-transparent px-2 py-4 text-base outline-none focus:ring-0 disabled:cursor-not-allowed"
84
+ />
85
+ <ComposerAction />
86
+ </ComposerPrimitive.Root>
87
+ );
88
+ };
89
+
90
+ const SpeakButton: FC = () => {
91
+ const webrtcProtocol = usePersonaRuntimeWebRTCProtocol()!;
92
+
93
+ const isConnected = useMemo(() => webrtcProtocol?.status === 'connected', [webrtcProtocol?.status]);
94
+ const handleConnection = useCallback(() => {
95
+ if (webrtcProtocol.status === 'connected') {
96
+ webrtcProtocol.disconnect();
97
+ } else {
98
+ webrtcProtocol.connect();
99
+ }
100
+ }, [webrtcProtocol]);
101
+
102
+ if (!webrtcProtocol) {
103
+ return null;
104
+ }
105
+ return (
106
+ <TooltipIconButton
107
+ className={cn(
108
+ 'hover:text-primary my-2.5 size-8 p-2 ml-2 transition-opacity ease-in text-foreground cursor-pointer',
109
+ isConnected && 'animate-pulse text-blue-500',
110
+ )}
111
+ variant="default"
112
+ tooltip={isConnected ? 'Stop speaking' : 'Speak'}
113
+ onClick={handleConnection}
114
+ >
115
+ <MicIcon className={cn(isConnected && 'animate-pulse')} />
116
+ </TooltipIconButton>
117
+ );
118
+ };
119
+
120
+ const ComposerAction: FC = () => {
121
+ return (
122
+ <>
123
+ <ThreadPrimitive.If running={false}>
124
+ <ComposerPrimitive.Send asChild>
125
+ <TooltipIconButton tooltip="Send" variant="default" className="my-2.5 size-8 p-2 transition-opacity ease-in">
126
+ <SendHorizontalIcon />
127
+ </TooltipIconButton>
128
+ </ComposerPrimitive.Send>
129
+ </ThreadPrimitive.If>
130
+ <ThreadPrimitive.If running>
131
+ <ComposerPrimitive.Cancel asChild>
132
+ <TooltipIconButton tooltip="Cancel" variant="default" className="my-2.5 size-8 p-2 transition-opacity ease-in">
133
+ <CircleStopIcon />
134
+ </TooltipIconButton>
135
+ </ComposerPrimitive.Cancel>
136
+ </ThreadPrimitive.If>
137
+ <SpeakButton />
138
+ </>
139
+ );
140
+ };
141
+
142
+ const UserMessage: FC = () => {
143
+ return (
144
+ <MessagePrimitive.Root className="grid auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] gap-y-2 [&:where(>*)]:col-start-2 w-full max-w-[var(--thread-max-width)] py-4">
145
+ <div className="bg-muted text-foreground max-w-[calc(var(--thread-max-width)*0.8)] break-words rounded-3xl px-5 py-2.5 col-start-2 row-start-2">
146
+ <MessagePrimitive.Content />
147
+ </div>
148
+
149
+ <BranchPicker className="col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
150
+ </MessagePrimitive.Root>
151
+ );
152
+ };
153
+
154
+ const EditComposer: FC = () => {
155
+ return (
156
+ <ComposerPrimitive.Root className="bg-muted my-4 flex w-full max-w-[var(--thread-max-width)] flex-col gap-2 rounded-xl">
157
+ <ComposerPrimitive.Input className="text-foreground flex h-8 w-full resize-none bg-transparent p-4 pb-0 outline-none" />
158
+
159
+ <div className="mx-3 mb-3 flex items-center justify-center gap-2 self-end">
160
+ <ComposerPrimitive.Cancel asChild>
161
+ <Button variant="ghost">Cancel</Button>
162
+ </ComposerPrimitive.Cancel>
163
+ <ComposerPrimitive.Send asChild>
164
+ <Button>Send</Button>
165
+ </ComposerPrimitive.Send>
166
+ </div>
167
+ </ComposerPrimitive.Root>
168
+ );
169
+ };
170
+
171
+ const Reasoning: FC<ReasoningContentPartProps> = ({ text }: ReasoningContentPartProps) => {
172
+ return <div className="text-sm text-muted-foreground break-words whitespace-pre-wrap">{text}</div>;
173
+ };
174
+
175
+ const AssistantMessage: FC = () => {
176
+ return (
177
+ <MessagePrimitive.Root className="grid grid-cols-[auto_auto_1fr] grid-rows-[auto_1fr] relative w-full max-w-[var(--thread-max-width)] py-4">
178
+ <div className="text-foreground max-w-[calc(var(--thread-max-width)*0.8)] break-words leading-7 col-span-2 col-start-2 row-start-1 my-1.5">
179
+ <MessagePrimitive.Content
180
+ components={{
181
+ Text: MarkdownText,
182
+ Reasoning,
183
+ tools: {
184
+ Fallback: ToolFallback,
185
+ },
186
+ }}
187
+ />
188
+ </div>
189
+
190
+ <AssistantActionBar />
191
+
192
+ <BranchPicker className="col-start-2 row-start-2 -ml-2 mr-2" />
193
+ </MessagePrimitive.Root>
194
+ );
195
+ };
196
+
197
+ const AssistantActionBar: FC = () => {
198
+ return (
199
+ <ActionBarPrimitive.Root
200
+ hideWhenRunning
201
+ autohide="not-last"
202
+ autohideFloat="single-branch"
203
+ className="text-muted-foreground flex gap-1 col-start-3 row-start-2 -ml-1 data-[floating]:bg-background data-[floating]:absolute data-[floating]:rounded-md data-[floating]:border data-[floating]:p-1 data-[floating]:shadow-sm"
204
+ >
205
+ <ActionBarPrimitive.Copy asChild>
206
+ <TooltipIconButton tooltip="Copy">
207
+ <MessagePrimitive.If copied>
208
+ <CheckIcon />
209
+ </MessagePrimitive.If>
210
+ <MessagePrimitive.If copied={false}>
211
+ <CopyIcon />
212
+ </MessagePrimitive.If>
213
+ </TooltipIconButton>
214
+ </ActionBarPrimitive.Copy>
215
+ </ActionBarPrimitive.Root>
216
+ );
217
+ };
218
+
219
+ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({ className, ...rest }) => {
220
+ return (
221
+ <BranchPickerPrimitive.Root
222
+ hideWhenSingleBranch
223
+ className={cn('text-muted-foreground inline-flex items-center text-xs', className)}
224
+ {...rest}
225
+ >
226
+ <BranchPickerPrimitive.Previous asChild>
227
+ <TooltipIconButton tooltip="Previous">
228
+ <ChevronLeftIcon />
229
+ </TooltipIconButton>
230
+ </BranchPickerPrimitive.Previous>
231
+ <span className="font-medium">
232
+ <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
233
+ </span>
234
+ <BranchPickerPrimitive.Next asChild>
235
+ <TooltipIconButton tooltip="Next">
236
+ <ChevronRightIcon />
237
+ </TooltipIconButton>
238
+ </BranchPickerPrimitive.Next>
239
+ </BranchPickerPrimitive.Root>
240
+ );
241
+ };
242
+
243
+ const CircleStopIcon = () => {
244
+ return (
245
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" width="16" height="16">
246
+ <rect width="10" height="10" x="3" y="3" rx="2" />
247
+ </svg>
248
+ );
249
+ };
@@ -0,0 +1,33 @@
1
+ import { ToolCallContentPartComponent } from '@assistant-ui/react';
2
+ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
3
+ import { useState } from 'react';
4
+ import { Button } from '../ui/button';
5
+
6
+ export const ToolFallback: ToolCallContentPartComponent = ({ toolName, argsText, result }) => {
7
+ const [isCollapsed, setIsCollapsed] = useState(true);
8
+ return (
9
+ <div className="mb-4 flex w-full flex-col gap-3 rounded-lg border py-3">
10
+ <div className="flex items-center gap-2 px-4">
11
+ <CheckIcon className="size-4" />
12
+ <p className="">
13
+ Used tool: <b>{toolName}</b>
14
+ </p>
15
+ <div className="flex-grow" />
16
+ <Button onClick={() => setIsCollapsed(!isCollapsed)}>{isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}</Button>
17
+ </div>
18
+ {!isCollapsed && (
19
+ <div className="flex flex-col gap-2 border-t pt-2">
20
+ <div className="px-4">
21
+ <pre className="whitespace-pre-wrap">{argsText}</pre>
22
+ </div>
23
+ {result !== undefined && (
24
+ <div className="border-t border-dashed px-4 pt-2">
25
+ <p className="font-semibold">Result:</p>
26
+ <pre className="whitespace-pre-wrap">{typeof result === 'string' ? result : JSON.stringify(result, null, 2)}</pre>
27
+ </div>
28
+ )}
29
+ </div>
30
+ )}
31
+ </div>
32
+ );
33
+ };
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+
3
+ import { ComponentPropsWithoutRef, forwardRef } from 'react';
4
+
5
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
6
+ import { Button } from '@/components/ui/button';
7
+ import { cn } from '@/lib/utils';
8
+
9
+ export type TooltipIconButtonProps = ComponentPropsWithoutRef<typeof Button> & {
10
+ tooltip: string;
11
+ side?: 'top' | 'bottom' | 'left' | 'right';
12
+ };
13
+
14
+ export const TooltipIconButton = forwardRef<HTMLButtonElement, TooltipIconButtonProps>(
15
+ ({ children, tooltip, side = 'bottom', className, ...rest }, ref) => {
16
+ return (
17
+ <TooltipProvider>
18
+ <Tooltip>
19
+ <TooltipTrigger asChild>
20
+ <Button
21
+ // variant="ghost"
22
+ // size="icon"
23
+ {...rest}
24
+ className={cn('size-6 p-1', className)}
25
+ ref={ref}
26
+ >
27
+ {children}
28
+ <span className="sr-only">{tooltip}</span>
29
+ </Button>
30
+ </TooltipTrigger>
31
+ <TooltipContent side={side}>{tooltip}</TooltipContent>
32
+ </Tooltip>
33
+ </TooltipProvider>
34
+ );
35
+ },
36
+ );
37
+
38
+ TooltipIconButton.displayName = 'TooltipIconButton';
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
5
+
6
+ import { cn } from '@/lib/utils';
7
+
8
+ const Avatar = React.forwardRef<React.ElementRef<typeof AvatarPrimitive.Root>, React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>>(
9
+ ({ className, ...props }, ref) => (
10
+ <AvatarPrimitive.Root ref={ref} className={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)} {...props} />
11
+ ),
12
+ );
13
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
14
+
15
+ const AvatarImage = React.forwardRef<
16
+ React.ElementRef<typeof AvatarPrimitive.Image>,
17
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
18
+ >(({ className, ...props }, ref) => (
19
+ <AvatarPrimitive.Image ref={ref} className={cn('aspect-square h-full w-full', className)} {...props} />
20
+ ));
21
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
22
+
23
+ const AvatarFallback = React.forwardRef<
24
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
25
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
26
+ >(({ className, ...props }, ref) => (
27
+ <AvatarPrimitive.Fallback
28
+ ref={ref}
29
+ className={cn('flex h-full w-full items-center justify-center rounded-full bg-muted', className)}
30
+ {...props}
31
+ />
32
+ ));
33
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
34
+
35
+ export { Avatar, AvatarImage, AvatarFallback };
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva, type VariantProps } from 'class-variance-authority';
4
+
5
+ import { cn } from '@/lib/utils';
6
+
7
+ const buttonVariants = cva(
8
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
13
+ destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
14
+ outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
15
+ secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
16
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
17
+ link: 'text-primary underline-offset-4 hover:underline',
18
+ },
19
+ size: {
20
+ default: 'h-9 px-4 py-2',
21
+ sm: 'h-8 rounded-md px-3 text-xs',
22
+ lg: 'h-10 rounded-md px-8',
23
+ icon: 'h-9 w-9',
24
+ },
25
+ },
26
+ defaultVariants: {
27
+ variant: 'default',
28
+ size: 'default',
29
+ },
30
+ },
31
+ );
32
+
33
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
34
+ asChild?: boolean;
35
+ }
36
+
37
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, asChild = false, ...props }, ref) => {
38
+ const Comp = asChild ? Slot : 'button';
39
+ return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
40
+ });
41
+ Button.displayName = 'Button';
42
+
43
+ export { Button, buttonVariants };
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
5
+
6
+ import { cn } from '@/lib/utils';
7
+
8
+ const TooltipProvider = TooltipPrimitive.Provider;
9
+
10
+ const Tooltip = TooltipPrimitive.Root;
11
+
12
+ const TooltipTrigger = TooltipPrimitive.Trigger;
13
+
14
+ const TooltipContent = React.forwardRef<
15
+ React.ElementRef<typeof TooltipPrimitive.Content>,
16
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
17
+ >(({ className, sideOffset = 4, ...props }, ref) => (
18
+ <TooltipPrimitive.Portal>
19
+ <TooltipPrimitive.Content
20
+ ref={ref}
21
+ sideOffset={sideOffset}
22
+ className={cn(
23
+ 'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
24
+ className,
25
+ )}
26
+ {...props}
27
+ />
28
+ </TooltipPrimitive.Portal>
29
+ ));
30
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
31
+
32
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+
4
+ import { Chat } from './chat';
5
+
6
+ ReactDOM.createRoot(document.getElementById('app')!).render(
7
+ <React.StrictMode>
8
+ <Chat />
9
+ </React.StrictMode>,
10
+ );
@@ -0,0 +1 @@
1
+ @import 'tailwindcss';
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
package/preview.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ # Check if an argument is provided
4
+ if [ -z "$1" ]; then
5
+ echo "Usage: $0 <preview-tag>"
6
+ exit 1
7
+ fi
8
+
9
+ PREVIEW_TAG=$1
10
+
11
+ npm --no-git-tag-version version "0.0.1-$PREVIEW_TAG" -m "$PREVIEW_TAG"
12
+ npm run build
13
+ npm publish --tag "$PREVIEW_TAG" --access public
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './runtime';
2
+ export * from './logging';
3
+ export * from './protocol';
4
+ export * from './types';