@applica-software-guru/persona-sdk 0.1.50 → 0.1.53

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.
@@ -0,0 +1,214 @@
1
+ "use client";
2
+
3
+ import { PropsWithChildren, useEffect, useState, type FC } from "react";
4
+ import { CircleXIcon, FileIcon, PaperclipIcon } from "lucide-react";
5
+ import {
6
+ AttachmentPrimitive,
7
+ ComposerPrimitive,
8
+ MessagePrimitive,
9
+ useAttachment,
10
+ } from "@assistant-ui/react";
11
+ import { useShallow } from "zustand/shallow";
12
+ import {
13
+ Tooltip,
14
+ TooltipContent,
15
+ TooltipTrigger,
16
+ } from "@/components/ui/tooltip";
17
+ import {
18
+ Dialog,
19
+ DialogTitle,
20
+ DialogTrigger,
21
+ DialogOverlay,
22
+ DialogPortal,
23
+ } from "@/components/ui/dialog";
24
+ import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
25
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
26
+ import { DialogContent as DialogPrimitiveContent } from "@radix-ui/react-dialog";
27
+
28
+ const useFileSrc = (file: File | undefined) => {
29
+ const [src, setSrc] = useState<string | undefined>(undefined);
30
+
31
+ useEffect(() => {
32
+ if (!file) {
33
+ setSrc(undefined);
34
+ return;
35
+ }
36
+
37
+ const objectUrl = URL.createObjectURL(file);
38
+ setSrc(objectUrl);
39
+
40
+ return () => {
41
+ URL.revokeObjectURL(objectUrl);
42
+ };
43
+ }, [file]);
44
+
45
+ return src;
46
+ };
47
+
48
+ const useAttachmentSrc = () => {
49
+ const { file, src } = useAttachment(
50
+ useShallow((a): { file?: File; src?: string } => {
51
+ if (a.type !== "image") return {};
52
+ if (a.file) return { file: a.file };
53
+ const src = a.content?.filter((c) => c.type === "image")[0]?.image;
54
+ if (!src) return {};
55
+ return { src };
56
+ }),
57
+ );
58
+
59
+ return useFileSrc(file) ?? src;
60
+ };
61
+
62
+ type AttachmentPreviewProps = {
63
+ src: string;
64
+ };
65
+
66
+ const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
67
+ const [isLoaded, setIsLoaded] = useState(false);
68
+
69
+ return (
70
+ // eslint-disable-next-line @next/next/no-img-element
71
+ <img
72
+ src={src}
73
+ style={{
74
+ width: "auto",
75
+ height: "auto",
76
+ maxWidth: "75dvh",
77
+ maxHeight: "75dvh",
78
+ display: isLoaded ? "block" : "none",
79
+ overflow: "clip",
80
+ }}
81
+ onLoad={() => setIsLoaded(true)}
82
+ alt="Preview"
83
+ />
84
+ );
85
+ };
86
+
87
+ const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
88
+ const src = useAttachmentSrc();
89
+
90
+ if (!src) return children;
91
+
92
+ return (
93
+ <Dialog>
94
+ <DialogTrigger className="hover:bg-accent/50 cursor-pointer transition-colors" asChild>
95
+ {children}
96
+ </DialogTrigger>
97
+ <AttachmentDialogContent>
98
+ <DialogTitle className="aui-sr-only">
99
+ Image Attachment Preview
100
+ </DialogTitle>
101
+ <AttachmentPreview src={src} />
102
+ </AttachmentDialogContent>
103
+ </Dialog>
104
+ );
105
+ };
106
+
107
+ const AttachmentThumb: FC = () => {
108
+ const isImage = useAttachment((a) => a.type === "image");
109
+ const src = useAttachmentSrc();
110
+ return (
111
+ <Avatar className="bg-muted flex size-10 items-center justify-center rounded border text-sm">
112
+ <AvatarFallback delayMs={isImage ? 200 : 0}>
113
+ <FileIcon />
114
+ </AvatarFallback>
115
+ <AvatarImage src={src} />
116
+ </Avatar>
117
+ );
118
+ };
119
+
120
+ const AttachmentUI: FC = () => {
121
+ const canRemove = useAttachment((a) => a.source !== "message");
122
+ const typeLabel = useAttachment((a) => {
123
+ const type = a.type;
124
+ switch (type) {
125
+ case "image":
126
+ return "Image";
127
+ case "document":
128
+ return "Document";
129
+ case "file":
130
+ return "File";
131
+ default:
132
+ const _exhaustiveCheck: never = type;
133
+ throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
134
+ }
135
+ });
136
+ return (
137
+ <Tooltip>
138
+ <AttachmentPrimitive.Root className="relative mt-3">
139
+ <AttachmentPreviewDialog>
140
+ <TooltipTrigger asChild>
141
+ <div className="flex h-12 w-40 items-center justify-center gap-2 rounded-lg border p-1">
142
+ <AttachmentThumb />
143
+ <div className="flex-grow basis-0">
144
+ <p className="text-muted-foreground line-clamp-1 text-ellipsis break-all text-xs font-bold">
145
+ <AttachmentPrimitive.Name />
146
+ </p>
147
+ <p className="text-muted-foreground text-xs">{typeLabel}</p>
148
+ </div>
149
+ </div>
150
+ </TooltipTrigger>
151
+ </AttachmentPreviewDialog>
152
+ {canRemove && <AttachmentRemove />}
153
+ </AttachmentPrimitive.Root>
154
+ <TooltipContent side="top">
155
+ <AttachmentPrimitive.Name />
156
+ </TooltipContent>
157
+ </Tooltip>
158
+ );
159
+ };
160
+
161
+ const AttachmentRemove: FC = () => {
162
+ return (
163
+ <AttachmentPrimitive.Remove asChild>
164
+ <TooltipIconButton
165
+ tooltip="Remove file"
166
+ className="text-muted-foreground [&>svg]:bg-background absolute -right-3 -top-3 size-6 [&>svg]:size-4 [&>svg]:rounded-full"
167
+ side="top"
168
+ >
169
+ <CircleXIcon />
170
+ </TooltipIconButton>
171
+ </AttachmentPrimitive.Remove>
172
+ );
173
+ };
174
+
175
+ export const UserMessageAttachments: FC = () => {
176
+ return (
177
+ <div className="flex w-full flex-row gap-3 col-span-full col-start-1 row-start-1 justify-end">
178
+ <MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
179
+ </div>
180
+ );
181
+ };
182
+
183
+ export const ComposerAttachments: FC = () => {
184
+ return (
185
+ <div className="flex w-full flex-row gap-3 px-10">
186
+ <ComposerPrimitive.Attachments
187
+ components={{ Attachment: AttachmentUI }}
188
+ />
189
+ </div>
190
+ );
191
+ };
192
+
193
+ export const ComposerAddAttachment: FC = () => {
194
+ return (
195
+ <ComposerPrimitive.AddAttachment asChild>
196
+ <TooltipIconButton
197
+ className="my-2.5 size-8 p-2 transition-opacity ease-in"
198
+ tooltip="Add Attachment"
199
+ variant="ghost"
200
+ >
201
+ <PaperclipIcon />
202
+ </TooltipIconButton>
203
+ </ComposerPrimitive.AddAttachment>
204
+ );
205
+ };
206
+
207
+ const AttachmentDialogContent: FC<PropsWithChildren> = ({ children }) => (
208
+ <DialogPortal>
209
+ <DialogOverlay />
210
+ <DialogPrimitiveContent className="aui-dialog-content">
211
+ {children}
212
+ </DialogPrimitiveContent>
213
+ </DialogPortal>
214
+ );
@@ -30,6 +30,7 @@ import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button
30
30
  import { ToolFallback } from '@/components/assistant-ui/tool-fallback';
31
31
 
32
32
  import { usePersonaRuntimeEndpoint, usePersonaRuntimeWebRTCProtocol } from '@applica-software-guru/persona-sdk';
33
+ import { ComposerAddAttachment, ComposerAttachments, UserMessageAttachments } from './attachment';
33
34
 
34
35
  export const Thread: FC = () => {
35
36
  return (
@@ -89,6 +90,8 @@ const ThreadWelcome: FC = () => {
89
90
  const Composer: FC = () => {
90
91
  return (
91
92
  <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">
93
+ <ComposerAttachments />
94
+ <ComposerAddAttachment />
92
95
  <ComposerPrimitive.Input
93
96
  rows={1}
94
97
  autoFocus
@@ -118,7 +121,7 @@ const SpeakButton: FC = () => {
118
121
  return (
119
122
  <TooltipIconButton
120
123
  className={cn(
121
- 'hover:text-primary my-2.5 size-8 p-2 ml-2 transition-opacity ease-in text-foreground cursor-pointer',
124
+ 'hover:text-primary my-2.5 size-8 p-2 ml-2 transition-opacity ease-in cursor-pointer',
122
125
  isConnected && 'animate-pulse text-blue-500',
123
126
  )}
124
127
  variant="default"
@@ -156,6 +159,7 @@ const UserMessage: FC = () => {
156
159
  return (
157
160
  <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">
158
161
  <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">
162
+ <UserMessageAttachments />
159
163
  <MessagePrimitive.Content />
160
164
  </div>
161
165
 
@@ -0,0 +1,133 @@
1
+ import * as React from "react"
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
3
+ import { XIcon } from "lucide-react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ function Dialog({
8
+ ...props
9
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
10
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
11
+ }
12
+
13
+ function DialogTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
16
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
17
+ }
18
+
19
+ function DialogPortal({
20
+ ...props
21
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
22
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
23
+ }
24
+
25
+ function DialogClose({
26
+ ...props
27
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
28
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
29
+ }
30
+
31
+ function DialogOverlay({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
35
+ return (
36
+ <DialogPrimitive.Overlay
37
+ data-slot="dialog-overlay"
38
+ className={cn(
39
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ function DialogContent({
48
+ className,
49
+ children,
50
+ ...props
51
+ }: React.ComponentProps<typeof DialogPrimitive.Content>) {
52
+ return (
53
+ <DialogPortal data-slot="dialog-portal">
54
+ <DialogOverlay />
55
+ <DialogPrimitive.Content
56
+ data-slot="dialog-content"
57
+ className={cn(
58
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
59
+ className
60
+ )}
61
+ {...props}
62
+ >
63
+ {children}
64
+ <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
65
+ <XIcon />
66
+ <span className="sr-only">Close</span>
67
+ </DialogPrimitive.Close>
68
+ </DialogPrimitive.Content>
69
+ </DialogPortal>
70
+ )
71
+ }
72
+
73
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
74
+ return (
75
+ <div
76
+ data-slot="dialog-header"
77
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
84
+ return (
85
+ <div
86
+ data-slot="dialog-footer"
87
+ className={cn(
88
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ )
94
+ }
95
+
96
+ function DialogTitle({
97
+ className,
98
+ ...props
99
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
100
+ return (
101
+ <DialogPrimitive.Title
102
+ data-slot="dialog-title"
103
+ className={cn("text-lg leading-none font-semibold", className)}
104
+ {...props}
105
+ />
106
+ )
107
+ }
108
+
109
+ function DialogDescription({
110
+ className,
111
+ ...props
112
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
113
+ return (
114
+ <DialogPrimitive.Description
115
+ data-slot="dialog-description"
116
+ className={cn("text-muted-foreground text-sm", className)}
117
+ {...props}
118
+ />
119
+ )
120
+ }
121
+
122
+ export {
123
+ Dialog,
124
+ DialogClose,
125
+ DialogContent,
126
+ DialogDescription,
127
+ DialogFooter,
128
+ DialogHeader,
129
+ DialogOverlay,
130
+ DialogPortal,
131
+ DialogTitle,
132
+ DialogTrigger,
133
+ }
@@ -1,6 +1,6 @@
1
- import { type ClassValue, clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
3
 
4
4
  export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
5
+ return twMerge(clsx(inputs))
6
6
  }
@@ -1 +1,120 @@
1
1
  @import 'tailwindcss';
2
+ @import "tw-animate-css";
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+
6
+ @theme inline {
7
+ --radius-sm: calc(var(--radius) - 4px);
8
+ --radius-md: calc(var(--radius) - 2px);
9
+ --radius-lg: var(--radius);
10
+ --radius-xl: calc(var(--radius) + 4px);
11
+ --color-background: var(--background);
12
+ --color-foreground: var(--foreground);
13
+ --color-card: var(--card);
14
+ --color-card-foreground: var(--card-foreground);
15
+ --color-popover: var(--popover);
16
+ --color-popover-foreground: var(--popover-foreground);
17
+ --color-primary: var(--primary);
18
+ --color-primary-foreground: var(--primary-foreground);
19
+ --color-secondary: var(--secondary);
20
+ --color-secondary-foreground: var(--secondary-foreground);
21
+ --color-muted: var(--muted);
22
+ --color-muted-foreground: var(--muted-foreground);
23
+ --color-accent: var(--accent);
24
+ --color-accent-foreground: var(--accent-foreground);
25
+ --color-destructive: var(--destructive);
26
+ --color-border: var(--border);
27
+ --color-input: var(--input);
28
+ --color-ring: var(--ring);
29
+ --color-chart-1: var(--chart-1);
30
+ --color-chart-2: var(--chart-2);
31
+ --color-chart-3: var(--chart-3);
32
+ --color-chart-4: var(--chart-4);
33
+ --color-chart-5: var(--chart-5);
34
+ --color-sidebar: var(--sidebar);
35
+ --color-sidebar-foreground: var(--sidebar-foreground);
36
+ --color-sidebar-primary: var(--sidebar-primary);
37
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
38
+ --color-sidebar-accent: var(--sidebar-accent);
39
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
40
+ --color-sidebar-border: var(--sidebar-border);
41
+ --color-sidebar-ring: var(--sidebar-ring);
42
+ }
43
+
44
+ :root {
45
+ --radius: 0.625rem;
46
+ --background: oklch(1 0 0);
47
+ --foreground: oklch(0.145 0 0);
48
+ --card: oklch(1 0 0);
49
+ --card-foreground: oklch(0.145 0 0);
50
+ --popover: oklch(1 0 0);
51
+ --popover-foreground: oklch(0.145 0 0);
52
+ --primary: oklch(0.205 0 0);
53
+ --primary-foreground: oklch(0.985 0 0);
54
+ --secondary: oklch(0.97 0 0);
55
+ --secondary-foreground: oklch(0.205 0 0);
56
+ --muted: oklch(0.97 0 0);
57
+ --muted-foreground: oklch(0.556 0 0);
58
+ --accent: oklch(0.97 0 0);
59
+ --accent-foreground: oklch(0.205 0 0);
60
+ --destructive: oklch(0.577 0.245 27.325);
61
+ --border: oklch(0.922 0 0);
62
+ --input: oklch(0.922 0 0);
63
+ --ring: oklch(0.708 0 0);
64
+ --chart-1: oklch(0.646 0.222 41.116);
65
+ --chart-2: oklch(0.6 0.118 184.704);
66
+ --chart-3: oklch(0.398 0.07 227.392);
67
+ --chart-4: oklch(0.828 0.189 84.429);
68
+ --chart-5: oklch(0.769 0.188 70.08);
69
+ --sidebar: oklch(0.985 0 0);
70
+ --sidebar-foreground: oklch(0.145 0 0);
71
+ --sidebar-primary: oklch(0.205 0 0);
72
+ --sidebar-primary-foreground: oklch(0.985 0 0);
73
+ --sidebar-accent: oklch(0.97 0 0);
74
+ --sidebar-accent-foreground: oklch(0.205 0 0);
75
+ --sidebar-border: oklch(0.922 0 0);
76
+ --sidebar-ring: oklch(0.708 0 0);
77
+ }
78
+
79
+ .dark {
80
+ --background: oklch(0.145 0 0);
81
+ --foreground: oklch(0.985 0 0);
82
+ --card: oklch(0.205 0 0);
83
+ --card-foreground: oklch(0.985 0 0);
84
+ --popover: oklch(0.205 0 0);
85
+ --popover-foreground: oklch(0.985 0 0);
86
+ --primary: oklch(0.922 0 0);
87
+ --primary-foreground: oklch(0.205 0 0);
88
+ --secondary: oklch(0.269 0 0);
89
+ --secondary-foreground: oklch(0.985 0 0);
90
+ --muted: oklch(0.269 0 0);
91
+ --muted-foreground: oklch(0.708 0 0);
92
+ --accent: oklch(0.269 0 0);
93
+ --accent-foreground: oklch(0.985 0 0);
94
+ --destructive: oklch(0.704 0.191 22.216);
95
+ --border: oklch(1 0 0 / 10%);
96
+ --input: oklch(1 0 0 / 15%);
97
+ --ring: oklch(0.556 0 0);
98
+ --chart-1: oklch(0.488 0.243 264.376);
99
+ --chart-2: oklch(0.696 0.17 162.48);
100
+ --chart-3: oklch(0.769 0.188 70.08);
101
+ --chart-4: oklch(0.627 0.265 303.9);
102
+ --chart-5: oklch(0.645 0.246 16.439);
103
+ --sidebar: oklch(0.205 0 0);
104
+ --sidebar-foreground: oklch(0.985 0 0);
105
+ --sidebar-primary: oklch(0.488 0.243 264.376);
106
+ --sidebar-primary-foreground: oklch(0.985 0 0);
107
+ --sidebar-accent: oklch(0.269 0 0);
108
+ --sidebar-accent-foreground: oklch(0.985 0 0);
109
+ --sidebar-border: oklch(1 0 0 / 10%);
110
+ --sidebar-ring: oklch(0.556 0 0);
111
+ }
112
+
113
+ @layer base {
114
+ * {
115
+ @apply border-border outline-ring/50;
116
+ }
117
+ body {
118
+ @apply bg-background text-foreground;
119
+ }
120
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
- Message,
3
2
  MessageListenerCallback,
3
+ PersonaMessage,
4
4
  PersonaPayload,
5
5
  PersonaProtocol,
6
6
  PersonaTransaction,
@@ -58,7 +58,7 @@ abstract class PersonaProtocolBase implements PersonaProtocol {
58
58
  abstract getPriority(): number;
59
59
  abstract connect(session?: Session): Promise<Session>;
60
60
  abstract disconnect(): Promise<void>;
61
- abstract send(message: Message): Promise<void>;
61
+ abstract send(message: Array<PersonaMessage> | PersonaMessage): Promise<void>;
62
62
 
63
63
  public onTransaction(_: PersonaTransaction) {}
64
64
  }
@@ -1,5 +1,5 @@
1
1
  import { PersonaProtocolBase } from './base';
2
- import { Message, PersonaResponse, Session, ProtocolStatus, PersonaProtocolBaseConfig } from '../types';
2
+ import { PersonaResponse, Session, ProtocolStatus, PersonaProtocolBaseConfig, PersonaMessage } from '../types';
3
3
 
4
4
  type PersonaRESTProtocolConfig = PersonaProtocolBaseConfig & {
5
5
  apiUrl: string;
@@ -41,7 +41,7 @@ class PersonaRESTProtocol extends PersonaProtocolBase {
41
41
  this.session = session;
42
42
  }
43
43
 
44
- public async send(message: Message): Promise<void> {
44
+ public async send(message: Array<PersonaMessage> | PersonaMessage): Promise<void> {
45
45
  const { apiUrl, apiKey, agentId } = this.config;
46
46
  const sessionId = this.session ?? 'new';
47
47
  const input = message;
@@ -1,12 +1,12 @@
1
1
  import { PersonaProtocolBase } from './base';
2
2
  import {
3
- Message,
4
3
  Session,
5
4
  ProtocolStatus,
6
5
  PersonaProtocolBaseConfig,
7
6
  PersonaTransaction,
8
7
  FunctionCall,
9
8
  ReadonlyJSONObject,
9
+ PersonaMessage,
10
10
  } from '../types';
11
11
 
12
12
  type FinishTransactionRequest = {
@@ -78,7 +78,7 @@ class PersonaPersistableTransaction {
78
78
  }
79
79
  try {
80
80
  const result = await tool(functionArgs);
81
- await this.complete({ date: new Date().toISOString(), result });
81
+ await this.complete(result);
82
82
  } catch (error) {
83
83
  await this.fail(`Error executing tool ${functionName}: ${error}`);
84
84
  }
@@ -134,7 +134,7 @@ class PersonaTransactionProtocol extends PersonaProtocolBase {
134
134
  this.session = session;
135
135
  }
136
136
 
137
- public async send(message: Message): Promise<void> {
137
+ public async send(message: Array<PersonaMessage> | PersonaMessage): Promise<void> {
138
138
  this.config.logger?.debug('Sending message:', message);
139
139
  throw new Error('Not implemented');
140
140
  }
@@ -1,5 +1,5 @@
1
1
  import { PersonaProtocolBase } from './base';
2
- import { Message, PersonaPayload, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
2
+ import { PersonaMessage, PersonaPayload, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
3
3
 
4
4
  type AudioAnalysisData = {
5
5
  localAmplitude: number;
@@ -187,13 +187,13 @@ class PersonaWebRTCClient {
187
187
  };
188
188
  }
189
189
 
190
- public sendMessage(message: string): void {
190
+ public sendMessage(message: Array<PersonaMessage> | PersonaMessage): void {
191
191
  if (!this.dataChannel) {
192
192
  this.config.logger?.warn('Data channel is not open, cannot send message');
193
193
  return;
194
194
  }
195
195
 
196
- this.dataChannel.send(message);
196
+ this.dataChannel.send(JSON.stringify({ type: 'request', payload: message }));
197
197
  this.config.logger?.info('Sent message:', message);
198
198
  }
199
199
 
@@ -322,12 +322,12 @@ class PersonaWebRTCProtocol extends PersonaProtocolBase {
322
322
  this.config?.logger?.debug('Disconnected from WebRTC');
323
323
  }
324
324
 
325
- public send(message: Message): Promise<void> {
325
+ public send(message: Array<PersonaMessage> | PersonaMessage): Promise<void> {
326
326
  if (this.status !== 'connected') {
327
327
  return Promise.reject(new Error('Not connected'));
328
328
  }
329
329
 
330
- this.webRTCClient.sendMessage(message as string);
330
+ this.webRTCClient.sendMessage(message);
331
331
  return Promise.resolve();
332
332
  }
333
333
  }
@@ -1,4 +1,4 @@
1
- import { Message, PersonaPayload, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
1
+ import { PersonaMessage, PersonaPayload, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
2
2
  import { PersonaProtocolBase } from './base';
3
3
 
4
4
  type PersonaWebSocketProtocolConfig = PersonaProtocolBaseConfig & {
@@ -86,7 +86,7 @@ class PersonaWebSocketProtocol extends PersonaProtocolBase {
86
86
  return Promise.resolve();
87
87
  }
88
88
 
89
- public send(message: Message): Promise<void> {
89
+ public send(message: Array<PersonaMessage> | PersonaMessage): Promise<void> {
90
90
  if (this.webSocket && this.status === 'connected') {
91
91
  this.webSocket.send(JSON.stringify({ type: 'request', payload: message }));
92
92
  return Promise.resolve();