@wallavi/widget 1.7.0 → 1.7.2
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/dist/index.d.mts +80 -4
- package/dist/index.d.ts +80 -4
- package/dist/index.js +1680 -545
- package/dist/index.mjs +1679 -547
- package/dist/styles.css +1 -0
- package/package.json +11 -8
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { useRef, useEffect, useState, useCallback, useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Loader2, CheckCircle2, AlertCircle, Zap, Check, X, ChevronDown, UploadCloud, Phone, RotateCcw, Square, Mic, Paperclip, ArrowUp, MicOff, PhoneOff, Search, FileText, FileSpreadsheet } from 'lucide-react';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { extendTailwindMerge, twMerge as twMerge$1 } from 'tailwind-merge';
|
|
5
5
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
6
6
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
import ReactMarkdownLib from 'react-markdown';
|
|
8
8
|
import remarkGfm from 'remark-gfm';
|
|
9
|
+
import { LiveKitRoom, RoomAudioRenderer, useVoiceAssistant, BarVisualizer, useLocalParticipant, useRoomContext } from '@livekit/components-react';
|
|
10
|
+
import '@livekit/components-styles';
|
|
9
11
|
|
|
10
12
|
// #style-inject:#style-inject
|
|
11
13
|
function styleInject(css, { insertAt } = {}) {
|
|
@@ -30,11 +32,11 @@ function styleInject(css, { insertAt } = {}) {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
// src/styles.css
|
|
33
|
-
styleInject(".ww-pointer-events-none {\n pointer-events: none;\n}\n.ww-absolute {\n position: absolute;\n}\n.ww-relative {\n position: relative;\n}\n.ww-inset-0 {\n inset: 0px;\n}\n.ww-left-2\\.5 {\n left: 0.625rem;\n}\n.ww-top-1\\/2 {\n top: 50%;\n}\n.ww-z-50 {\n z-index: 50;\n}\n.ww-mb-1 {\n margin-bottom: 0.25rem;\n}\n.ww-mb-2 {\n margin-bottom: 0.5rem;\n}\n.ww-ml-0\\.5 {\n margin-left: 0.125rem;\n}\n.ww-mt-0\\.5 {\n margin-top: 0.125rem;\n}\n.ww-mt-1 {\n margin-top: 0.25rem;\n}\n.ww-block {\n display: block;\n}\n.ww-inline-block {\n display: inline-block;\n}\n.ww-flex {\n display: flex;\n}\n.ww-inline-flex {\n display: inline-flex;\n}\n.ww-grid {\n display: grid;\n}\n.ww-hidden {\n display: none;\n}\n.ww-h-10 {\n height: 2.5rem;\n}\n.ww-h-2 {\n height: 0.5rem;\n}\n.ww-h-2\\.5 {\n height: 0.625rem;\n}\n.ww-h-20 {\n height: 5rem;\n}\n.ww-h-3 {\n height: 0.75rem;\n}\n.ww-h-3\\.5 {\n height: 0.875rem;\n}\n.ww-h-4 {\n height: 1rem;\n}\n.ww-h-6 {\n height: 1.5rem;\n}\n.ww-h-7 {\n height: 1.75rem;\n}\n.ww-h-8 {\n height: 2rem;\n}\n.ww-h-full {\n height: 100%;\n}\n.ww-max-h-32 {\n max-height: 8rem;\n}\n.ww-max-h-48 {\n max-height: 12rem;\n}\n.ww-max-h-\\[168px\\] {\n max-height: 168px;\n}\n.ww-max-h-\\[180px\\] {\n max-height: 180px;\n}\n.ww-w-0\\.5 {\n width: 0.125rem;\n}\n.ww-w-10 {\n width: 2.5rem;\n}\n.ww-w-2 {\n width: 0.5rem;\n}\n.ww-w-2\\.5 {\n width: 0.625rem;\n}\n.ww-w-20 {\n width: 5rem;\n}\n.ww-w-3 {\n width: 0.75rem;\n}\n.ww-w-3\\.5 {\n width: 0.875rem;\n}\n.ww-w-4 {\n width: 1rem;\n}\n.ww-w-6 {\n width: 1.5rem;\n}\n.ww-w-7 {\n width: 1.75rem;\n}\n.ww-w-8 {\n width: 2rem;\n}\n.ww-w-fit {\n width: -moz-fit-content;\n width: fit-content;\n}\n.ww-w-full {\n width: 100%;\n}\n.ww-min-w-0 {\n min-width: 0px;\n}\n.ww-max-w-\\[120px\\] {\n max-width: 120px;\n}\n.ww-max-w-\\[200px\\] {\n max-width: 200px;\n}\n.ww-max-w-\\[78\\%\\] {\n max-width: 78%;\n}\n.ww-max-w-\\[82\\%\\] {\n max-width: 82%;\n}\n.ww-max-w-none {\n max-width: none;\n}\n.ww-flex-1 {\n flex: 1 1 0%;\n}\n.ww-shrink-0 {\n flex-shrink: 0;\n}\n.ww-rotate-180 {\n --tw-rotate: 180deg;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n@keyframes ww-ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n.ww-animate-ping {\n animation: ww-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\n}\n@keyframes ww-pulse {\n 50% {\n opacity: .5;\n }\n}\n.ww-animate-pulse {\n animation: ww-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n@keyframes ww-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.ww-animate-spin {\n animation: ww-spin 1s linear infinite;\n}\n.ww-cursor-default {\n cursor: default;\n}\n.ww-cursor-pointer {\n cursor: pointer;\n}\n.ww-select-none {\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.ww-resize-none {\n resize: none;\n}\n.ww-grid-cols-2 {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.ww-flex-col {\n flex-direction: column;\n}\n.ww-flex-wrap {\n flex-wrap: wrap;\n}\n.ww-items-start {\n align-items: flex-start;\n}\n.ww-items-end {\n align-items: flex-end;\n}\n.ww-items-center {\n align-items: center;\n}\n.ww-justify-end {\n justify-content: flex-end;\n}\n.ww-justify-center {\n justify-content: center;\n}\n.ww-justify-between {\n justify-content: space-between;\n}\n.ww-gap-0\\.5 {\n gap: 0.125rem;\n}\n.ww-gap-1 {\n gap: 0.25rem;\n}\n.ww-gap-1\\.5 {\n gap: 0.375rem;\n}\n.ww-gap-2 {\n gap: 0.5rem;\n}\n.ww-gap-2\\.5 {\n gap: 0.625rem;\n}\n.ww-gap-4 {\n gap: 1rem;\n}\n.ww-divide-y > :not([hidden]) ~ :not([hidden]) {\n --tw-divide-y-reverse: 0;\n border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));\n border-bottom-width: calc(1px * var(--tw-divide-y-reverse));\n}\n.ww-divide-border\\/40 > :not([hidden]) ~ :not([hidden]) {\n border-color: hsl(var(--border) / 0.4);\n}\n.ww-overflow-hidden {\n overflow: hidden;\n}\n.ww-overflow-y-auto {\n overflow-y: auto;\n}\n.ww-overscroll-contain {\n overscroll-behavior: contain;\n}\n.ww-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ww-whitespace-pre-wrap {\n white-space: pre-wrap;\n}\n.ww-rounded {\n border-radius: 0.25rem;\n}\n.ww-rounded-2xl {\n border-radius: 1rem;\n}\n.ww-rounded-full {\n border-radius: 9999px;\n}\n.ww-rounded-lg {\n border-radius: var(--radius);\n}\n.ww-rounded-xl {\n border-radius: 0.75rem;\n}\n.ww-rounded-tl-none {\n border-top-left-radius: 0px;\n}\n.ww-rounded-tl-sm {\n border-top-left-radius: calc(var(--radius) - 4px);\n}\n.ww-rounded-tr-sm {\n border-top-right-radius: calc(var(--radius) - 4px);\n}\n.ww-border {\n border-width: 1px;\n}\n.ww-border-2 {\n border-width: 2px;\n}\n.ww-border-b {\n border-bottom-width: 1px;\n}\n.ww-border-l-2 {\n border-left-width: 2px;\n}\n.ww-border-t {\n border-top-width: 1px;\n}\n.ww-border-background {\n border-color: hsl(var(--background));\n}\n.ww-border-black\\/10 {\n border-color: rgb(0 0 0 / 0.1);\n}\n.ww-border-border {\n border-color: hsl(var(--border));\n}\n.ww-border-border\\/30 {\n border-color: hsl(var(--border) / 0.3);\n}\n.ww-border-border\\/40 {\n border-color: hsl(var(--border) / 0.4);\n}\n.ww-border-border\\/50 {\n border-color: hsl(var(--border) / 0.5);\n}\n.ww-border-border\\/60 {\n border-color: hsl(var(--border) / 0.6);\n}\n.ww-border-border\\/70 {\n border-color: hsl(var(--border) / 0.7);\n}\n.ww-border-muted {\n border-color: hsl(var(--muted));\n}\n.ww-border-muted-foreground\\/30 {\n border-color: hsl(var(--muted-foreground) / 0.3);\n}\n.ww-border-red-200 {\n --tw-border-opacity: 1;\n border-color: rgb(254 202 202 / var(--tw-border-opacity, 1));\n}\n.ww-border-white\\/20 {\n border-color: rgb(255 255 255 / 0.2);\n}\n.ww-bg-background {\n background-color: hsl(var(--background));\n}\n.ww-bg-background\\/20 {\n background-color: hsl(var(--background) / 0.2);\n}\n.ww-bg-background\\/40 {\n background-color: hsl(var(--background) / 0.4);\n}\n.ww-bg-background\\/50 {\n background-color: hsl(var(--background) / 0.5);\n}\n.ww-bg-background\\/90 {\n background-color: hsl(var(--background) / 0.9);\n}\n.ww-bg-black\\/10 {\n background-color: rgb(0 0 0 / 0.1);\n}\n.ww-bg-emerald-400 {\n --tw-bg-opacity: 1;\n background-color: rgb(52 211 153 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-emerald-500 {\n --tw-bg-opacity: 1;\n background-color: rgb(16 185 129 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-foreground {\n background-color: hsl(var(--foreground));\n}\n.ww-bg-foreground\\/60 {\n background-color: hsl(var(--foreground) / 0.6);\n}\n.ww-bg-muted {\n background-color: hsl(var(--muted));\n}\n.ww-bg-muted-foreground\\/10 {\n background-color: hsl(var(--muted-foreground) / 0.1);\n}\n.ww-bg-muted\\/50 {\n background-color: hsl(var(--muted) / 0.5);\n}\n.ww-bg-muted\\/60 {\n background-color: hsl(var(--muted) / 0.6);\n}\n.ww-bg-primary {\n background-color: hsl(var(--primary));\n}\n.ww-bg-primary\\/5 {\n background-color: hsl(var(--primary) / 0.05);\n}\n.ww-bg-red-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 242 242 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-transparent {\n background-color: transparent;\n}\n.ww-bg-white\\/10 {\n background-color: rgb(255 255 255 / 0.1);\n}\n.ww-bg-white\\/15 {\n background-color: rgb(255 255 255 / 0.15);\n}\n.ww-fill-current {\n fill: currentColor;\n}\n.ww-object-cover {\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ww-p-0\\.5 {\n padding: 0.125rem;\n}\n.ww-p-1\\.5 {\n padding: 0.375rem;\n}\n.ww-p-3 {\n padding: 0.75rem;\n}\n.ww-px-1 {\n padding-left: 0.25rem;\n padding-right: 0.25rem;\n}\n.ww-px-2 {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n}\n.ww-px-2\\.5 {\n padding-left: 0.625rem;\n padding-right: 0.625rem;\n}\n.ww-px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.ww-px-3\\.5 {\n padding-left: 0.875rem;\n padding-right: 0.875rem;\n}\n.ww-px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.ww-py-0\\.5 {\n padding-top: 0.125rem;\n padding-bottom: 0.125rem;\n}\n.ww-py-1 {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n}\n.ww-py-1\\.5 {\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n}\n.ww-py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.ww-py-2\\.5 {\n padding-top: 0.625rem;\n padding-bottom: 0.625rem;\n}\n.ww-py-3 {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n}\n.ww-py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.ww-pb-1\\.5 {\n padding-bottom: 0.375rem;\n}\n.ww-pb-2 {\n padding-bottom: 0.5rem;\n}\n.ww-pb-4 {\n padding-bottom: 1rem;\n}\n.ww-pl-2 {\n padding-left: 0.5rem;\n}\n.ww-pl-7 {\n padding-left: 1.75rem;\n}\n.ww-pr-0\\.5 {\n padding-right: 0.125rem;\n}\n.ww-pr-3 {\n padding-right: 0.75rem;\n}\n.ww-pt-2 {\n padding-top: 0.5rem;\n}\n.ww-pt-5 {\n padding-top: 1.25rem;\n}\n.ww-text-left {\n text-align: left;\n}\n.ww-text-center {\n text-align: center;\n}\n.ww-align-middle {\n vertical-align: middle;\n}\n.ww-text-\\[10\\.5px\\] {\n font-size: 10.5px;\n}\n.ww-text-\\[10px\\] {\n font-size: 10px;\n}\n.ww-text-\\[11px\\] {\n font-size: 11px;\n}\n.ww-text-\\[12\\.5px\\] {\n font-size: 12.5px;\n}\n.ww-text-\\[12px\\] {\n font-size: 12px;\n}\n.ww-text-\\[8px\\] {\n font-size: 8px;\n}\n.ww-text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.ww-text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.ww-font-medium {\n font-weight: 500;\n}\n.ww-font-semibold {\n font-weight: 600;\n}\n.ww-uppercase {\n text-transform: uppercase;\n}\n.ww-leading-none {\n line-height: 1;\n}\n.ww-leading-relaxed {\n line-height: 1.625;\n}\n.ww-leading-snug {\n line-height: 1.375;\n}\n.ww-leading-tight {\n line-height: 1.25;\n}\n.ww-tracking-widest {\n letter-spacing: 0.1em;\n}\n.ww-text-background {\n color: hsl(var(--background));\n}\n.ww-text-black\\/40 {\n color: rgb(0 0 0 / 0.4);\n}\n.ww-text-black\\/60 {\n color: rgb(0 0 0 / 0.6);\n}\n.ww-text-destructive {\n color: hsl(var(--destructive));\n}\n.ww-text-destructive\\/70 {\n color: hsl(var(--destructive) / 0.7);\n}\n.ww-text-emerald-500 {\n --tw-text-opacity: 1;\n color: rgb(16 185 129 / var(--tw-text-opacity, 1));\n}\n.ww-text-foreground {\n color: hsl(var(--foreground));\n}\n.ww-text-foreground\\/60 {\n color: hsl(var(--foreground) / 0.6);\n}\n.ww-text-foreground\\/70 {\n color: hsl(var(--foreground) / 0.7);\n}\n.ww-text-foreground\\/80 {\n color: hsl(var(--foreground) / 0.8);\n}\n.ww-text-muted-foreground {\n color: hsl(var(--muted-foreground));\n}\n.ww-text-muted-foreground\\/40 {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.ww-text-muted-foreground\\/50 {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.ww-text-muted-foreground\\/70 {\n color: hsl(var(--muted-foreground) / 0.7);\n}\n.ww-text-muted-foreground\\/80 {\n color: hsl(var(--muted-foreground) / 0.8);\n}\n.ww-text-primary {\n color: hsl(var(--primary));\n}\n.ww-text-primary-foreground {\n color: hsl(var(--primary-foreground));\n}\n.ww-text-primary\\/70 {\n color: hsl(var(--primary) / 0.7);\n}\n.ww-text-primary\\/80 {\n color: hsl(var(--primary) / 0.8);\n}\n.ww-text-red-400 {\n --tw-text-opacity: 1;\n color: rgb(248 113 113 / var(--tw-text-opacity, 1));\n}\n.ww-text-red-500 {\n --tw-text-opacity: 1;\n color: rgb(239 68 68 / var(--tw-text-opacity, 1));\n}\n.ww-text-red-600 {\n --tw-text-opacity: 1;\n color: rgb(220 38 38 / var(--tw-text-opacity, 1));\n}\n.ww-text-white\\/60 {\n color: rgb(255 255 255 / 0.6);\n}\n.ww-text-white\\/80 {\n color: rgb(255 255 255 / 0.8);\n}\n.ww-line-through {\n text-decoration-line: line-through;\n}\n.ww-no-underline {\n text-decoration-line: none;\n}\n.ww-decoration-foreground\\/20 {\n text-decoration-color: hsl(var(--foreground) / 0.2);\n}\n.ww-opacity-100 {\n opacity: 1;\n}\n.ww-opacity-25 {\n opacity: 0.25;\n}\n.ww-opacity-30 {\n opacity: 0.3;\n}\n.ww-opacity-35 {\n opacity: 0.35;\n}\n.ww-opacity-40 {\n opacity: 0.4;\n}\n.ww-opacity-60 {\n opacity: 0.6;\n}\n.ww-opacity-70 {\n opacity: 0.7;\n}\n.ww-opacity-75 {\n opacity: 0.75;\n}\n.ww-opacity-80 {\n opacity: 0.8;\n}\n.ww-shadow-2xl {\n --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-sm {\n --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-xl {\n --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-outline-none {\n outline: 2px solid transparent;\n outline-offset: 2px;\n}\n.ww-ring-2 {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.ww-ring-inset {\n --tw-ring-inset: inset;\n}\n.ww-ring-primary\\/60 {\n --tw-ring-color: hsl(var(--primary) / 0.6);\n}\n.ww-backdrop-blur-sm {\n --tw-backdrop-blur: blur(4px);\n backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);\n}\n.ww-transition-all {\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-colors {\n transition-property:\n color,\n background-color,\n border-color,\n text-decoration-color,\n fill,\n stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-opacity {\n transition-property: opacity;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-shadow {\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-transform {\n transition-property: transform;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-duration-100 {\n transition-duration: 100ms;\n}\n.ww-duration-150 {\n transition-duration: 150ms;\n}\n.ww-duration-200 {\n transition-duration: 200ms;\n}\n@keyframes enter {\n from {\n opacity: var(--tw-enter-opacity, 1);\n transform: translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0));\n }\n}\n@keyframes exit {\n to {\n opacity: var(--tw-exit-opacity, 1);\n transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));\n }\n}\n.ww-duration-100 {\n animation-duration: 100ms;\n}\n.ww-duration-150 {\n animation-duration: 150ms;\n}\n.ww-duration-200 {\n animation-duration: 200ms;\n}\n.wallavi-widget *,\n.wallavi-widget *::before,\n.wallavi-widget *::after {\n box-sizing: border-box;\n border-width: 0;\n border-style: solid;\n}\n.wallavi-widget button {\n -moz-appearance: none;\n appearance: none;\n -webkit-appearance: none;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n.wallavi-widget textarea,\n.wallavi-widget input,\n.wallavi-widget select {\n font-family: inherit;\n font-size: inherit;\n}\n.wallavi-widget img,\n.wallavi-widget video {\n max-width: 100%;\n height: auto;\n}\n.placeholder\\:ww-text-muted-foreground\\/40::-moz-placeholder {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.placeholder\\:ww-text-muted-foreground\\/40::placeholder {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.placeholder\\:ww-text-muted-foreground\\/50::-moz-placeholder {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.placeholder\\:ww-text-muted-foreground\\/50::placeholder {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.focus-within\\:ww-ring-1:focus-within {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.focus-within\\:ww-ring-ring\\/40:focus-within {\n --tw-ring-color: hsl(var(--ring) / 0.4);\n}\n.hover\\:ww-border-foreground\\/25:hover {\n border-color: hsl(var(--foreground) / 0.25);\n}\n.hover\\:ww-border-foreground\\/30:hover {\n border-color: hsl(var(--foreground) / 0.3);\n}\n.hover\\:ww-bg-background:hover {\n background-color: hsl(var(--background));\n}\n.hover\\:ww-bg-foreground\\/10:hover {\n background-color: hsl(var(--foreground) / 0.1);\n}\n.hover\\:ww-bg-muted:hover {\n background-color: hsl(var(--muted));\n}\n.hover\\:ww-bg-white\\/10:hover {\n background-color: rgb(255 255 255 / 0.1);\n}\n.hover\\:ww-text-foreground:hover {\n color: hsl(var(--foreground));\n}\n.hover\\:ww-opacity-80:hover {\n opacity: 0.8;\n}\n.hover\\:ww-opacity-85:hover {\n opacity: 0.85;\n}\n.focus\\:ww-ring-1:focus {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.focus\\:ww-ring-ring\\/40:focus {\n --tw-ring-color: hsl(var(--ring) / 0.4);\n}\n.active\\:ww-scale-\\[0\\.98\\]:active {\n --tw-scale-x: 0.98;\n --tw-scale-y: 0.98;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.disabled\\:ww-pointer-events-none:disabled {\n pointer-events: none;\n}\n.disabled\\:ww-opacity-40:disabled {\n opacity: 0.4;\n}\n.disabled\\:ww-opacity-50:disabled {\n opacity: 0.5;\n}\n.dark\\:ww-border-red-800:is(.ww-dark *) {\n --tw-border-opacity: 1;\n border-color: rgb(153 27 27 / var(--tw-border-opacity, 1));\n}\n.dark\\:ww-bg-red-950:is(.ww-dark *) {\n --tw-bg-opacity: 1;\n background-color: rgb(69 10 10 / var(--tw-bg-opacity, 1));\n}\n.dark\\:ww-text-red-400:is(.ww-dark *) {\n --tw-text-opacity: 1;\n color: rgb(248 113 113 / var(--tw-text-opacity, 1));\n}\n");
|
|
35
|
+
styleInject(".ww-pointer-events-none {\n pointer-events: none;\n}\n.ww-absolute {\n position: absolute;\n}\n.ww-relative {\n position: relative;\n}\n.ww-inset-0 {\n inset: 0px;\n}\n.ww-inset-4 {\n inset: 1rem;\n}\n.ww-inset-8 {\n inset: 2rem;\n}\n.ww-left-2\\.5 {\n left: 0.625rem;\n}\n.ww-top-1\\/2 {\n top: 50%;\n}\n.ww-z-50 {\n z-index: 50;\n}\n.ww-z-\\[100\\] {\n z-index: 100;\n}\n.ww-mb-1 {\n margin-bottom: 0.25rem;\n}\n.ww-mb-12 {\n margin-bottom: 3rem;\n}\n.ww-mb-2 {\n margin-bottom: 0.5rem;\n}\n.ww-ml-0\\.5 {\n margin-left: 0.125rem;\n}\n.ww-mt-0\\.5 {\n margin-top: 0.125rem;\n}\n.ww-mt-1 {\n margin-top: 0.25rem;\n}\n.ww-block {\n display: block;\n}\n.ww-inline-block {\n display: inline-block;\n}\n.ww-flex {\n display: flex;\n}\n.ww-inline-flex {\n display: inline-flex;\n}\n.ww-grid {\n display: grid;\n}\n.ww-hidden {\n display: none;\n}\n.ww-h-10 {\n height: 2.5rem;\n}\n.ww-h-16 {\n height: 4rem;\n}\n.ww-h-2 {\n height: 0.5rem;\n}\n.ww-h-2\\.5 {\n height: 0.625rem;\n}\n.ww-h-20 {\n height: 5rem;\n}\n.ww-h-3 {\n height: 0.75rem;\n}\n.ww-h-3\\.5 {\n height: 0.875rem;\n}\n.ww-h-4 {\n height: 1rem;\n}\n.ww-h-40 {\n height: 10rem;\n}\n.ww-h-48 {\n height: 12rem;\n}\n.ww-h-6 {\n height: 1.5rem;\n}\n.ww-h-7 {\n height: 1.75rem;\n}\n.ww-h-8 {\n height: 2rem;\n}\n.ww-h-full {\n height: 100%;\n}\n.ww-max-h-32 {\n max-height: 8rem;\n}\n.ww-max-h-48 {\n max-height: 12rem;\n}\n.ww-max-h-\\[168px\\] {\n max-height: 168px;\n}\n.ww-max-h-\\[180px\\] {\n max-height: 180px;\n}\n.ww-w-0\\.5 {\n width: 0.125rem;\n}\n.ww-w-10 {\n width: 2.5rem;\n}\n.ww-w-16 {\n width: 4rem;\n}\n.ww-w-2 {\n width: 0.5rem;\n}\n.ww-w-2\\.5 {\n width: 0.625rem;\n}\n.ww-w-20 {\n width: 5rem;\n}\n.ww-w-3 {\n width: 0.75rem;\n}\n.ww-w-3\\.5 {\n width: 0.875rem;\n}\n.ww-w-4 {\n width: 1rem;\n}\n.ww-w-48 {\n width: 12rem;\n}\n.ww-w-6 {\n width: 1.5rem;\n}\n.ww-w-7 {\n width: 1.75rem;\n}\n.ww-w-8 {\n width: 2rem;\n}\n.ww-w-fit {\n width: -moz-fit-content;\n width: fit-content;\n}\n.ww-w-full {\n width: 100%;\n}\n.ww-min-w-0 {\n min-width: 0px;\n}\n.ww-max-w-\\[120px\\] {\n max-width: 120px;\n}\n.ww-max-w-\\[200px\\] {\n max-width: 200px;\n}\n.ww-max-w-\\[78\\%\\] {\n max-width: 78%;\n}\n.ww-max-w-\\[82\\%\\] {\n max-width: 82%;\n}\n.ww-max-w-none {\n max-width: none;\n}\n.ww-flex-1 {\n flex: 1 1 0%;\n}\n.ww-shrink-0 {\n flex-shrink: 0;\n}\n.ww-rotate-180 {\n --tw-rotate: 180deg;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.ww-scale-100 {\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.ww-scale-105 {\n --tw-scale-x: 1.05;\n --tw-scale-y: 1.05;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.ww-scale-110 {\n --tw-scale-x: 1.1;\n --tw-scale-y: 1.1;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.ww-scale-90 {\n --tw-scale-x: .9;\n --tw-scale-y: .9;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n@keyframes ww-ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n.ww-animate-ping {\n animation: ww-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\n}\n@keyframes ww-pulse {\n 50% {\n opacity: .5;\n }\n}\n.ww-animate-pulse {\n animation: ww-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n@keyframes ww-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.ww-animate-spin {\n animation: ww-spin 1s linear infinite;\n}\n.ww-cursor-default {\n cursor: default;\n}\n.ww-cursor-pointer {\n cursor: pointer;\n}\n.ww-touch-none {\n touch-action: none;\n}\n.ww-select-none {\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.ww-resize-none {\n resize: none;\n}\n.ww-grid-cols-2 {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.ww-flex-col {\n flex-direction: column;\n}\n.ww-flex-wrap {\n flex-wrap: wrap;\n}\n.ww-items-start {\n align-items: flex-start;\n}\n.ww-items-end {\n align-items: flex-end;\n}\n.ww-items-center {\n align-items: center;\n}\n.ww-justify-end {\n justify-content: flex-end;\n}\n.ww-justify-center {\n justify-content: center;\n}\n.ww-justify-between {\n justify-content: space-between;\n}\n.ww-gap-0\\.5 {\n gap: 0.125rem;\n}\n.ww-gap-1 {\n gap: 0.25rem;\n}\n.ww-gap-1\\.5 {\n gap: 0.375rem;\n}\n.ww-gap-2 {\n gap: 0.5rem;\n}\n.ww-gap-2\\.5 {\n gap: 0.625rem;\n}\n.ww-gap-4 {\n gap: 1rem;\n}\n.ww-gap-6 {\n gap: 1.5rem;\n}\n.ww-gap-8 {\n gap: 2rem;\n}\n.ww-divide-y > :not([hidden]) ~ :not([hidden]) {\n --tw-divide-y-reverse: 0;\n border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));\n border-bottom-width: calc(1px * var(--tw-divide-y-reverse));\n}\n.ww-divide-border\\/40 > :not([hidden]) ~ :not([hidden]) {\n border-color: hsl(var(--border) / 0.4);\n}\n.ww-overflow-hidden {\n overflow: hidden;\n}\n.ww-overflow-y-auto {\n overflow-y: auto;\n}\n.ww-overscroll-contain {\n overscroll-behavior: contain;\n}\n.ww-overscroll-none {\n overscroll-behavior: none;\n}\n.ww-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ww-whitespace-pre-wrap {\n white-space: pre-wrap;\n}\n.ww-rounded {\n border-radius: 0.25rem;\n}\n.ww-rounded-2xl {\n border-radius: 1rem;\n}\n.ww-rounded-full {\n border-radius: 9999px;\n}\n.ww-rounded-lg {\n border-radius: var(--radius);\n}\n.ww-rounded-xl {\n border-radius: 0.75rem;\n}\n.ww-rounded-tl-none {\n border-top-left-radius: 0px;\n}\n.ww-rounded-tl-sm {\n border-top-left-radius: calc(var(--radius) - 4px);\n}\n.ww-rounded-tr-sm {\n border-top-right-radius: calc(var(--radius) - 4px);\n}\n.ww-border {\n border-width: 1px;\n}\n.ww-border-2 {\n border-width: 2px;\n}\n.ww-border-b {\n border-bottom-width: 1px;\n}\n.ww-border-l-2 {\n border-left-width: 2px;\n}\n.ww-border-t {\n border-top-width: 1px;\n}\n.ww-border-background {\n border-color: hsl(var(--background));\n}\n.ww-border-black\\/10 {\n border-color: rgb(0 0 0 / 0.1);\n}\n.ww-border-border {\n border-color: hsl(var(--border));\n}\n.ww-border-border\\/30 {\n border-color: hsl(var(--border) / 0.3);\n}\n.ww-border-border\\/40 {\n border-color: hsl(var(--border) / 0.4);\n}\n.ww-border-border\\/50 {\n border-color: hsl(var(--border) / 0.5);\n}\n.ww-border-border\\/60 {\n border-color: hsl(var(--border) / 0.6);\n}\n.ww-border-border\\/80 {\n border-color: hsl(var(--border) / 0.8);\n}\n.ww-border-muted {\n border-color: hsl(var(--muted));\n}\n.ww-border-muted-foreground\\/30 {\n border-color: hsl(var(--muted-foreground) / 0.3);\n}\n.ww-border-red-200 {\n --tw-border-opacity: 1;\n border-color: rgb(254 202 202 / var(--tw-border-opacity, 1));\n}\n.ww-border-transparent {\n border-color: transparent;\n}\n.ww-border-white\\/20 {\n border-color: rgb(255 255 255 / 0.2);\n}\n.ww-bg-background {\n background-color: hsl(var(--background));\n}\n.ww-bg-background\\/20 {\n background-color: hsl(var(--background) / 0.2);\n}\n.ww-bg-background\\/90 {\n background-color: hsl(var(--background) / 0.9);\n}\n.ww-bg-background\\/95 {\n background-color: hsl(var(--background) / 0.95);\n}\n.ww-bg-black\\/10 {\n background-color: rgb(0 0 0 / 0.1);\n}\n.ww-bg-emerald-400 {\n --tw-bg-opacity: 1;\n background-color: rgb(52 211 153 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-emerald-500 {\n --tw-bg-opacity: 1;\n background-color: rgb(16 185 129 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-emerald-500\\/10 {\n background-color: rgb(16 185 129 / 0.1);\n}\n.ww-bg-emerald-500\\/20 {\n background-color: rgb(16 185 129 / 0.2);\n}\n.ww-bg-foreground\\/20 {\n background-color: hsl(var(--foreground) / 0.2);\n}\n.ww-bg-foreground\\/5 {\n background-color: hsl(var(--foreground) / 0.05);\n}\n.ww-bg-foreground\\/60 {\n background-color: hsl(var(--foreground) / 0.6);\n}\n.ww-bg-muted {\n background-color: hsl(var(--muted));\n}\n.ww-bg-muted-foreground\\/10 {\n background-color: hsl(var(--muted-foreground) / 0.1);\n}\n.ww-bg-muted\\/30 {\n background-color: hsl(var(--muted) / 0.3);\n}\n.ww-bg-muted\\/40 {\n background-color: hsl(var(--muted) / 0.4);\n}\n.ww-bg-muted\\/50 {\n background-color: hsl(var(--muted) / 0.5);\n}\n.ww-bg-muted\\/60 {\n background-color: hsl(var(--muted) / 0.6);\n}\n.ww-bg-primary {\n background-color: hsl(var(--primary));\n}\n.ww-bg-primary\\/5 {\n background-color: hsl(var(--primary) / 0.05);\n}\n.ww-bg-purple-500\\/20 {\n background-color: rgb(168 85 247 / 0.2);\n}\n.ww-bg-purple-500\\/30 {\n background-color: rgb(168 85 247 / 0.3);\n}\n.ww-bg-red-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 242 242 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-transparent {\n background-color: transparent;\n}\n.ww-bg-white\\/10 {\n background-color: rgb(255 255 255 / 0.1);\n}\n.ww-bg-white\\/15 {\n background-color: rgb(255 255 255 / 0.15);\n}\n.ww-fill-current {\n fill: currentColor;\n}\n.ww-object-cover {\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ww-p-0\\.5 {\n padding: 0.125rem;\n}\n.ww-p-1\\.5 {\n padding: 0.375rem;\n}\n.ww-p-3 {\n padding: 0.75rem;\n}\n.ww-px-1 {\n padding-left: 0.25rem;\n padding-right: 0.25rem;\n}\n.ww-px-2 {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n}\n.ww-px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.ww-px-3\\.5 {\n padding-left: 0.875rem;\n padding-right: 0.875rem;\n}\n.ww-px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.ww-py-0\\.5 {\n padding-top: 0.125rem;\n padding-bottom: 0.125rem;\n}\n.ww-py-1 {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n}\n.ww-py-1\\.5 {\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n}\n.ww-py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.ww-py-2\\.5 {\n padding-top: 0.625rem;\n padding-bottom: 0.625rem;\n}\n.ww-py-3 {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n}\n.ww-py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.ww-pb-1\\.5 {\n padding-bottom: 0.375rem;\n}\n.ww-pb-2 {\n padding-bottom: 0.5rem;\n}\n.ww-pb-4 {\n padding-bottom: 1rem;\n}\n.ww-pl-2 {\n padding-left: 0.5rem;\n}\n.ww-pl-7 {\n padding-left: 1.75rem;\n}\n.ww-pr-0\\.5 {\n padding-right: 0.125rem;\n}\n.ww-pr-3 {\n padding-right: 0.75rem;\n}\n.ww-pt-2 {\n padding-top: 0.5rem;\n}\n.ww-pt-5 {\n padding-top: 1.25rem;\n}\n.ww-text-left {\n text-align: left;\n}\n.ww-text-center {\n text-align: center;\n}\n.ww-align-middle {\n vertical-align: middle;\n}\n.ww-text-\\[10\\.5px\\] {\n font-size: 10.5px;\n}\n.ww-text-\\[10px\\] {\n font-size: 10px;\n}\n.ww-text-\\[11px\\] {\n font-size: 11px;\n}\n.ww-text-\\[12\\.5px\\] {\n font-size: 12.5px;\n}\n.ww-text-\\[13px\\] {\n font-size: 13px;\n}\n.ww-text-\\[8px\\] {\n font-size: 8px;\n}\n.ww-text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.ww-text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.ww-font-medium {\n font-weight: 500;\n}\n.ww-font-semibold {\n font-weight: 600;\n}\n.ww-uppercase {\n text-transform: uppercase;\n}\n.ww-leading-none {\n line-height: 1;\n}\n.ww-leading-relaxed {\n line-height: 1.625;\n}\n.ww-leading-snug {\n line-height: 1.375;\n}\n.ww-leading-tight {\n line-height: 1.25;\n}\n.ww-tracking-wide {\n letter-spacing: 0.025em;\n}\n.ww-tracking-widest {\n letter-spacing: 0.1em;\n}\n.ww-text-black\\/40 {\n color: rgb(0 0 0 / 0.4);\n}\n.ww-text-black\\/60 {\n color: rgb(0 0 0 / 0.6);\n}\n.ww-text-destructive {\n color: hsl(var(--destructive));\n}\n.ww-text-destructive\\/70 {\n color: hsl(var(--destructive) / 0.7);\n}\n.ww-text-emerald-500 {\n --tw-text-opacity: 1;\n color: rgb(16 185 129 / var(--tw-text-opacity, 1));\n}\n.ww-text-foreground {\n color: hsl(var(--foreground));\n}\n.ww-text-foreground\\/60 {\n color: hsl(var(--foreground) / 0.6);\n}\n.ww-text-foreground\\/70 {\n color: hsl(var(--foreground) / 0.7);\n}\n.ww-text-foreground\\/80 {\n color: hsl(var(--foreground) / 0.8);\n}\n.ww-text-muted-foreground {\n color: hsl(var(--muted-foreground));\n}\n.ww-text-muted-foreground\\/40 {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.ww-text-muted-foreground\\/50 {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.ww-text-muted-foreground\\/70 {\n color: hsl(var(--muted-foreground) / 0.7);\n}\n.ww-text-muted-foreground\\/80 {\n color: hsl(var(--muted-foreground) / 0.8);\n}\n.ww-text-primary {\n color: hsl(var(--primary));\n}\n.ww-text-primary-foreground {\n color: hsl(var(--primary-foreground));\n}\n.ww-text-primary\\/70 {\n color: hsl(var(--primary) / 0.7);\n}\n.ww-text-primary\\/80 {\n color: hsl(var(--primary) / 0.8);\n}\n.ww-text-red-400 {\n --tw-text-opacity: 1;\n color: rgb(248 113 113 / var(--tw-text-opacity, 1));\n}\n.ww-text-red-500 {\n --tw-text-opacity: 1;\n color: rgb(239 68 68 / var(--tw-text-opacity, 1));\n}\n.ww-text-red-600 {\n --tw-text-opacity: 1;\n color: rgb(220 38 38 / var(--tw-text-opacity, 1));\n}\n.ww-text-white {\n --tw-text-opacity: 1;\n color: rgb(255 255 255 / var(--tw-text-opacity, 1));\n}\n.ww-text-white\\/60 {\n color: rgb(255 255 255 / 0.6);\n}\n.ww-text-white\\/80 {\n color: rgb(255 255 255 / 0.8);\n}\n.ww-line-through {\n text-decoration-line: line-through;\n}\n.ww-no-underline {\n text-decoration-line: none;\n}\n.ww-decoration-foreground\\/20 {\n text-decoration-color: hsl(var(--foreground) / 0.2);\n}\n.ww-opacity-100 {\n opacity: 1;\n}\n.ww-opacity-25 {\n opacity: 0.25;\n}\n.ww-opacity-30 {\n opacity: 0.3;\n}\n.ww-opacity-40 {\n opacity: 0.4;\n}\n.ww-opacity-60 {\n opacity: 0.6;\n}\n.ww-opacity-70 {\n opacity: 0.7;\n}\n.ww-opacity-75 {\n opacity: 0.75;\n}\n.ww-opacity-80 {\n opacity: 0.8;\n}\n.ww-opacity-90 {\n opacity: 0.9;\n}\n.ww-shadow-2xl {\n --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-lg {\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-md {\n --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-sm {\n --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-xl {\n --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-outline-none {\n outline: 2px solid transparent;\n outline-offset: 2px;\n}\n.ww-ring-2 {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.ww-ring-inset {\n --tw-ring-inset: inset;\n}\n.ww-ring-primary\\/20 {\n --tw-ring-color: hsl(var(--primary) / 0.2);\n}\n.ww-ring-primary\\/60 {\n --tw-ring-color: hsl(var(--primary) / 0.6);\n}\n.ww-backdrop-blur-sm {\n --tw-backdrop-blur: blur(4px);\n backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);\n}\n.ww-backdrop-blur-xl {\n --tw-backdrop-blur: blur(24px);\n backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);\n}\n.ww-transition-all {\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-colors {\n transition-property:\n color,\n background-color,\n border-color,\n text-decoration-color,\n fill,\n stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-opacity {\n transition-property: opacity;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-shadow {\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-transform {\n transition-property: transform;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-duration-1000 {\n transition-duration: 1000ms;\n}\n.ww-duration-200 {\n transition-duration: 200ms;\n}\n.ww-duration-300 {\n transition-duration: 300ms;\n}\n.ww-duration-500 {\n transition-duration: 500ms;\n}\n.ww-duration-700 {\n transition-duration: 700ms;\n}\n@keyframes enter {\n from {\n opacity: var(--tw-enter-opacity, 1);\n transform: translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0));\n }\n}\n@keyframes exit {\n to {\n opacity: var(--tw-exit-opacity, 1);\n transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));\n }\n}\n.ww-duration-1000 {\n animation-duration: 1000ms;\n}\n.ww-duration-200 {\n animation-duration: 200ms;\n}\n.ww-duration-300 {\n animation-duration: 300ms;\n}\n.ww-duration-500 {\n animation-duration: 500ms;\n}\n.ww-duration-700 {\n animation-duration: 700ms;\n}\n.wallavi-widget *,\n.wallavi-widget *::before,\n.wallavi-widget *::after {\n box-sizing: border-box;\n border-width: 0;\n border-style: solid;\n}\n.wallavi-widget button {\n -moz-appearance: none;\n appearance: none;\n -webkit-appearance: none;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n.wallavi-widget textarea,\n.wallavi-widget input,\n.wallavi-widget select {\n font-family: inherit;\n font-size: inherit;\n}\n.wallavi-widget img,\n.wallavi-widget video {\n max-width: 100%;\n height: auto;\n}\n.wallavi-widget .lk-control-bar {\n background: transparent !important;\n border: none !important;\n box-shadow: none !important;\n padding: 0 !important;\n gap: 1.5rem !important;\n justify-content: center !important;\n}\n.wallavi-widget .lk-button {\n background: rgba(25, 25, 28, 0.05) !important;\n border-radius: 9999px !important;\n padding: 1.25rem !important;\n color: var(--ww-fg, #19191c) !important;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;\n border: 1px solid rgba(25, 25, 28, 0.1) !important;\n}\n.wallavi-widget .lk-button:hover {\n background: rgba(25, 25, 28, 0.1) !important;\n transform: scale(1.05) !important;\n}\n.wallavi-widget .lk-disconnect-button {\n background: #ef4444 !important;\n color: white !important;\n border: none !important;\n}\n.wallavi-widget .lk-disconnect-button:hover {\n background: #dc2626 !important;\n}\n.wallavi-widget .lk-device-menu {\n bottom: 100% !important;\n top: auto !important;\n margin-bottom: 1rem !important;\n max-width: 250px !important;\n width: -moz-max-content !important;\n width: max-content !important;\n left: 50% !important;\n transform: translateX(-50%) !important;\n background: #ffffff !important;\n border-radius: 16px !important;\n box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.15), 0 10px 20px -10px rgba(0, 0, 0, 0.1) !important;\n z-index: 1000 !important;\n overflow: hidden !important;\n border: 1px solid rgba(0, 0, 0, 0.05) !important;\n padding: 0.5rem !important;\n}\n.wallavi-widget .lk-device-menu > li {\n padding: 0.75rem 1rem !important;\n font-size: 0.875rem !important;\n color: #19191c !important;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n border-radius: 8px !important;\n transition: background 0.15s !important;\n}\n.wallavi-widget .lk-device-menu > li:hover {\n background: rgba(0, 0, 0, 0.05) !important;\n}\n.wallavi-widget .lk-device-menu > li.lk-active {\n background: rgba(0, 0, 0, 0.08) !important;\n font-weight: 600 !important;\n}\n.placeholder\\:ww-text-muted-foreground\\/40::-moz-placeholder {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.placeholder\\:ww-text-muted-foreground\\/40::placeholder {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.placeholder\\:ww-text-muted-foreground\\/50::-moz-placeholder {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.placeholder\\:ww-text-muted-foreground\\/50::placeholder {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.focus-within\\:ww-ring-1:focus-within {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.focus-within\\:ww-ring-ring\\/40:focus-within {\n --tw-ring-color: hsl(var(--ring) / 0.4);\n}\n.hover\\:-ww-translate-y-1:hover {\n --tw-translate-y: -0.25rem;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.hover\\:ww-border-primary\\/40:hover {\n border-color: hsl(var(--primary) / 0.4);\n}\n.hover\\:ww-bg-accent:hover {\n background-color: hsl(var(--accent));\n}\n.hover\\:ww-bg-foreground\\/10:hover {\n background-color: hsl(var(--foreground) / 0.1);\n}\n.hover\\:ww-bg-foreground\\/30:hover {\n background-color: hsl(var(--foreground) / 0.3);\n}\n.hover\\:ww-bg-muted:hover {\n background-color: hsl(var(--muted));\n}\n.hover\\:ww-bg-white\\/10:hover {\n background-color: rgb(255 255 255 / 0.1);\n}\n.hover\\:ww-text-accent-foreground:hover {\n color: hsl(var(--accent-foreground));\n}\n.hover\\:ww-text-foreground:hover {\n color: hsl(var(--foreground));\n}\n.hover\\:ww-text-primary:hover {\n color: hsl(var(--primary));\n}\n.hover\\:ww-opacity-80:hover {\n opacity: 0.8;\n}\n.hover\\:ww-opacity-85:hover {\n opacity: 0.85;\n}\n.hover\\:ww-shadow-sm:hover {\n --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.hover\\:ww-shadow-xl:hover {\n --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.focus\\:ww-ring-1:focus {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.focus\\:ww-ring-ring\\/40:focus {\n --tw-ring-color: hsl(var(--ring) / 0.4);\n}\n.active\\:ww-scale-\\[0\\.98\\]:active {\n --tw-scale-x: 0.98;\n --tw-scale-y: 0.98;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.disabled\\:ww-pointer-events-none:disabled {\n pointer-events: none;\n}\n.disabled\\:ww-opacity-40:disabled {\n opacity: 0.4;\n}\n.disabled\\:ww-opacity-50:disabled {\n opacity: 0.5;\n}\n.dark\\:ww-border-red-800:is(.ww-dark *) {\n --tw-border-opacity: 1;\n border-color: rgb(153 27 27 / var(--tw-border-opacity, 1));\n}\n.dark\\:ww-bg-red-950:is(.ww-dark *) {\n --tw-bg-opacity: 1;\n background-color: rgb(69 10 10 / var(--tw-bg-opacity, 1));\n}\n.dark\\:ww-text-red-400:is(.ww-dark *) {\n --tw-text-opacity: 1;\n color: rgb(248 113 113 / var(--tw-text-opacity, 1));\n}\n");
|
|
34
36
|
var twMerge = extendTailwindMerge({ prefix: "ww-" });
|
|
35
37
|
var cn = (...inputs) => twMerge(clsx(inputs));
|
|
36
38
|
|
|
37
|
-
// src/types.ts
|
|
39
|
+
// src/lib/types.ts
|
|
38
40
|
function getContrastColor(hex) {
|
|
39
41
|
const clean = hex.replace("#", "");
|
|
40
42
|
if (clean.length < 6) return "#ffffff";
|
|
@@ -46,15 +48,16 @@ function getContrastColor(hex) {
|
|
|
46
48
|
function formatToolName(name) {
|
|
47
49
|
return name.replace(/([A-Z])/g, " $1").replace(/_/g, " ").trim();
|
|
48
50
|
}
|
|
51
|
+
|
|
52
|
+
// src/core/stream-protocol.ts
|
|
49
53
|
var STREAM_DELIMITER = "\u03B6\u236E";
|
|
50
54
|
async function consumeStream(body, handler) {
|
|
51
55
|
const reader = body.getReader();
|
|
52
56
|
const decoder = new TextDecoder();
|
|
53
57
|
let buffer = "";
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
buffer += decoder.decode(value, { stream: true });
|
|
58
|
+
let textAccumulator = "";
|
|
59
|
+
let eventCount = 0;
|
|
60
|
+
const processBuffer = () => {
|
|
58
61
|
const chunks = buffer.split(STREAM_DELIMITER);
|
|
59
62
|
buffer = chunks.pop() ?? "";
|
|
60
63
|
for (const chunk of chunks) {
|
|
@@ -62,19 +65,220 @@ async function consumeStream(body, handler) {
|
|
|
62
65
|
if (!raw) continue;
|
|
63
66
|
try {
|
|
64
67
|
const parsed = JSON.parse(raw);
|
|
65
|
-
|
|
68
|
+
const proto = parsed.data?.uiMessageProtocol;
|
|
69
|
+
if (proto) {
|
|
70
|
+
eventCount++;
|
|
71
|
+
if (proto.type === "text-delta") {
|
|
72
|
+
textAccumulator += proto.delta ?? "";
|
|
73
|
+
}
|
|
74
|
+
handler(proto);
|
|
75
|
+
}
|
|
66
76
|
} catch {
|
|
67
77
|
}
|
|
68
78
|
}
|
|
79
|
+
};
|
|
80
|
+
while (true) {
|
|
81
|
+
const { done, value } = await reader.read();
|
|
82
|
+
if (done) break;
|
|
83
|
+
buffer += decoder.decode(value, { stream: true });
|
|
84
|
+
processBuffer();
|
|
85
|
+
}
|
|
86
|
+
if (buffer.trim()) {
|
|
87
|
+
buffer += STREAM_DELIMITER;
|
|
88
|
+
processBuffer();
|
|
69
89
|
}
|
|
90
|
+
return { textAccumulator, eventCount };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/core/chat-reducer.ts
|
|
94
|
+
function applyUiEventToMessages(prev, proto, msgId) {
|
|
95
|
+
let idx = prev.findIndex((m) => m.id === msgId);
|
|
96
|
+
if (idx === -1) {
|
|
97
|
+
if (proto.type === "finish" || proto.type === "debug-trace" || proto.type === "step-start" || proto.type === "step-end" || proto.type === "navigate" || proto.type === "suggestions") {
|
|
98
|
+
return prev;
|
|
99
|
+
}
|
|
100
|
+
prev = [...prev, { id: msgId, role: "assistant", parts: [] }];
|
|
101
|
+
idx = prev.length - 1;
|
|
102
|
+
}
|
|
103
|
+
const existing = prev[idx];
|
|
104
|
+
const msg = {
|
|
105
|
+
id: existing.id,
|
|
106
|
+
role: existing.role,
|
|
107
|
+
parts: [...existing.parts]
|
|
108
|
+
};
|
|
109
|
+
switch (proto.type) {
|
|
110
|
+
case "text-delta": {
|
|
111
|
+
const textIdx = msg.parts.findIndex((p) => p.type === "text");
|
|
112
|
+
if (textIdx === -1) {
|
|
113
|
+
msg.parts.push({ type: "text", text: proto.delta });
|
|
114
|
+
} else {
|
|
115
|
+
const p = msg.parts[textIdx];
|
|
116
|
+
msg.parts[textIdx] = { type: "text", text: p.text + proto.delta };
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "reasoning-delta": {
|
|
121
|
+
const rIdx = msg.parts.findIndex((p) => p.type === "reasoning");
|
|
122
|
+
if (rIdx === -1) {
|
|
123
|
+
msg.parts.unshift({ type: "reasoning", text: proto.delta });
|
|
124
|
+
} else {
|
|
125
|
+
const p = msg.parts[rIdx];
|
|
126
|
+
msg.parts[rIdx] = {
|
|
127
|
+
type: "reasoning",
|
|
128
|
+
text: p.text + proto.delta
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case "tool-input-available": {
|
|
134
|
+
msg.parts.push({
|
|
135
|
+
type: "tool",
|
|
136
|
+
toolCallId: proto.toolCallId,
|
|
137
|
+
toolName: proto.toolName,
|
|
138
|
+
input: proto.input ?? {},
|
|
139
|
+
status: "running"
|
|
140
|
+
});
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case "tool-output-available": {
|
|
144
|
+
const tIdx = msg.parts.findIndex(
|
|
145
|
+
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
146
|
+
);
|
|
147
|
+
if (tIdx !== -1) {
|
|
148
|
+
msg.parts[tIdx] = {
|
|
149
|
+
...msg.parts[tIdx],
|
|
150
|
+
status: "done",
|
|
151
|
+
output: proto.output
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "tool-output-error": {
|
|
157
|
+
const tIdx = msg.parts.findIndex(
|
|
158
|
+
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
159
|
+
);
|
|
160
|
+
if (tIdx !== -1) {
|
|
161
|
+
msg.parts[tIdx] = {
|
|
162
|
+
...msg.parts[tIdx],
|
|
163
|
+
status: "error",
|
|
164
|
+
errorText: proto.errorText
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case "picker": {
|
|
170
|
+
const safeOptions = (proto.options ?? []).map((o) => ({
|
|
171
|
+
value: typeof o.value === "string" ? o.value : JSON.stringify(o.value ?? ""),
|
|
172
|
+
label: typeof o.label === "string" ? o.label : JSON.stringify(o.label ?? "")
|
|
173
|
+
}));
|
|
174
|
+
msg.parts.push({
|
|
175
|
+
type: "picker",
|
|
176
|
+
pickerId: proto.pickerId,
|
|
177
|
+
paramName: proto.paramName,
|
|
178
|
+
toolName: proto.toolName,
|
|
179
|
+
label: typeof proto.label === "string" ? proto.label : String(proto.label),
|
|
180
|
+
options: safeOptions
|
|
181
|
+
});
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case "plan-created": {
|
|
185
|
+
msg.parts.push({
|
|
186
|
+
type: "plan",
|
|
187
|
+
planId: proto.planId,
|
|
188
|
+
goal: proto.goal,
|
|
189
|
+
steps: proto.steps.map((s) => ({
|
|
190
|
+
...s,
|
|
191
|
+
status: "pending"
|
|
192
|
+
}))
|
|
193
|
+
});
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case "plan-step-update": {
|
|
197
|
+
const pIdx = msg.parts.findIndex(
|
|
198
|
+
(p) => p.type === "plan" && p.planId === proto.planId
|
|
199
|
+
);
|
|
200
|
+
if (pIdx !== -1) {
|
|
201
|
+
const prevPlan = msg.parts[pIdx];
|
|
202
|
+
msg.parts[pIdx] = {
|
|
203
|
+
...prevPlan,
|
|
204
|
+
steps: prevPlan.steps.map(
|
|
205
|
+
(s) => s.index === proto.stepIndex ? {
|
|
206
|
+
...s,
|
|
207
|
+
status: proto.status,
|
|
208
|
+
...proto.error ? { error: proto.error } : {}
|
|
209
|
+
} : s
|
|
210
|
+
)
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const copy = [...prev];
|
|
217
|
+
copy[idx] = msg;
|
|
218
|
+
return copy;
|
|
70
219
|
}
|
|
71
220
|
var API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
221
|
+
function useVoiceCall({
|
|
222
|
+
agentId,
|
|
223
|
+
threadId,
|
|
224
|
+
workspaceId,
|
|
225
|
+
customBackend
|
|
226
|
+
}) {
|
|
227
|
+
const [active, setActive] = useState(false);
|
|
228
|
+
const [token, setToken] = useState(null);
|
|
229
|
+
const [serverUrl, setServerUrl] = useState(null);
|
|
230
|
+
const [loading, setLoading] = useState(false);
|
|
231
|
+
const [error, setError] = useState(null);
|
|
232
|
+
const start = useCallback(async () => {
|
|
233
|
+
if (customBackend) return;
|
|
234
|
+
setLoading(true);
|
|
235
|
+
setError(null);
|
|
236
|
+
try {
|
|
237
|
+
const isPrivate = Boolean(workspaceId);
|
|
238
|
+
const url = isPrivate ? `${API_URL}/api/threads/${threadId}/livekit-token?agentId=${encodeURIComponent(agentId)}` : `${API_URL}/api/chat/livekit-token?agentId=${encodeURIComponent(agentId)}&threadId=${encodeURIComponent(threadId)}`;
|
|
239
|
+
const res = await fetch(url, {
|
|
240
|
+
headers: isPrivate && typeof window !== "undefined" ? (
|
|
241
|
+
// @ts-ignore
|
|
242
|
+
{
|
|
243
|
+
Authorization: `Bearer ${await window.Clerk?.session?.getToken()}`
|
|
244
|
+
}
|
|
245
|
+
) : {}
|
|
246
|
+
});
|
|
247
|
+
const data = await res.json();
|
|
248
|
+
if (!res.ok) throw new Error(data.error || "Failed to start call");
|
|
249
|
+
setToken(data.token);
|
|
250
|
+
setServerUrl(data.url);
|
|
251
|
+
setActive(true);
|
|
252
|
+
} catch (err) {
|
|
253
|
+
setError(err.message);
|
|
254
|
+
}
|
|
255
|
+
setLoading(false);
|
|
256
|
+
}, [agentId, threadId, workspaceId, customBackend]);
|
|
257
|
+
const stop = useCallback(() => {
|
|
258
|
+
setActive(false);
|
|
259
|
+
setToken(null);
|
|
260
|
+
setServerUrl(null);
|
|
261
|
+
}, []);
|
|
262
|
+
return customBackend?.voiceCall ?? {
|
|
263
|
+
active,
|
|
264
|
+
token,
|
|
265
|
+
serverUrl,
|
|
266
|
+
start,
|
|
267
|
+
stop,
|
|
268
|
+
loading,
|
|
269
|
+
error
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/hooks/use-chat.ts
|
|
274
|
+
var API_URL2 = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
72
275
|
function newId() {
|
|
73
276
|
return Math.random().toString(36).slice(2, 10);
|
|
74
277
|
}
|
|
75
278
|
function useChat({
|
|
76
279
|
agentId,
|
|
77
280
|
workspaceId = "",
|
|
281
|
+
envId,
|
|
78
282
|
source = "playground",
|
|
79
283
|
userContext,
|
|
80
284
|
persist = false,
|
|
@@ -82,7 +286,8 @@ function useChat({
|
|
|
82
286
|
playgroundOverrides,
|
|
83
287
|
customBackend
|
|
84
288
|
}) {
|
|
85
|
-
const
|
|
289
|
+
const userId = userContext?.userId;
|
|
290
|
+
const persistKey = persist ? userId ? `wallavi_${agentId}_${userId}` : `wallavi_${agentId}` : null;
|
|
86
291
|
const onNavigateRef = useRef(onNavigate);
|
|
87
292
|
useEffect(() => {
|
|
88
293
|
onNavigateRef.current = onNavigate;
|
|
@@ -106,6 +311,119 @@ function useChat({
|
|
|
106
311
|
return crypto.randomUUID();
|
|
107
312
|
});
|
|
108
313
|
const streamingMsgIdRef = useRef(null);
|
|
314
|
+
const [debugTraces, setDebugTraces] = useState([]);
|
|
315
|
+
const initializedThreadsRef = useRef(/* @__PURE__ */ new Set());
|
|
316
|
+
const messagesRef = useRef(messages);
|
|
317
|
+
useEffect(() => {
|
|
318
|
+
messagesRef.current = messages;
|
|
319
|
+
}, [messages]);
|
|
320
|
+
const applyStreamEvent = useCallback(
|
|
321
|
+
(proto, msgId) => {
|
|
322
|
+
if (proto.type === "navigate") {
|
|
323
|
+
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (proto.type === "debug-trace") {
|
|
327
|
+
setDebugTraces((prev) => [
|
|
328
|
+
...prev,
|
|
329
|
+
proto.trace
|
|
330
|
+
]);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
setMessages((prev) => applyUiEventToMessages(prev, proto, msgId));
|
|
334
|
+
},
|
|
335
|
+
[]
|
|
336
|
+
);
|
|
337
|
+
const fetchAndStream = useCallback(
|
|
338
|
+
async (opts) => {
|
|
339
|
+
const { input: userInput, msgId, extraMetadata, attachments } = opts;
|
|
340
|
+
const isPrivate = Boolean(workspaceId);
|
|
341
|
+
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
342
|
+
const url = isPrivate ? `${API_URL2}/api/threads/${threadId}/stream` : `${API_URL2}/api/chat/stream`;
|
|
343
|
+
const res = await fetch(url, {
|
|
344
|
+
method: "POST",
|
|
345
|
+
headers: {
|
|
346
|
+
"Content-Type": "application/json",
|
|
347
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
348
|
+
},
|
|
349
|
+
body: JSON.stringify({
|
|
350
|
+
input: userInput,
|
|
351
|
+
agentId,
|
|
352
|
+
...isPrivate ? {
|
|
353
|
+
workspaceId,
|
|
354
|
+
...playgroundOverrides ? { playgroundOverrides } : {},
|
|
355
|
+
...envId ? { envId } : {}
|
|
356
|
+
} : { threadId },
|
|
357
|
+
source,
|
|
358
|
+
...attachments?.length ? { attachments } : {},
|
|
359
|
+
...userContext?.userName ? { userName: userContext.userName } : {},
|
|
360
|
+
...userContext?.userEmail ? { userEmail: userContext.userEmail } : {},
|
|
361
|
+
userMetadata: {
|
|
362
|
+
...userContext?.metadata ?? {},
|
|
363
|
+
...userContext?.pageContext ? { pageContext: userContext.pageContext } : {},
|
|
364
|
+
headers: {
|
|
365
|
+
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
366
|
+
...userContext?.headers ?? {},
|
|
367
|
+
...userContext?.metadata?.headers ?? {}
|
|
368
|
+
},
|
|
369
|
+
...extraMetadata ?? {}
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
});
|
|
373
|
+
if (!res.ok) {
|
|
374
|
+
const errText = await res.text().catch(() => "");
|
|
375
|
+
throw new Error(errText || `API error ${res.status}`);
|
|
376
|
+
}
|
|
377
|
+
if (!res.body) throw new Error("No stream body");
|
|
378
|
+
const { textAccumulator, eventCount } = await consumeStream(
|
|
379
|
+
res.body,
|
|
380
|
+
(proto) => applyStreamEvent(proto, msgId)
|
|
381
|
+
);
|
|
382
|
+
if (textAccumulator) {
|
|
383
|
+
setMessages((prev) => {
|
|
384
|
+
const idx = prev.findIndex((m) => m.id === msgId);
|
|
385
|
+
if (idx === -1) {
|
|
386
|
+
return [
|
|
387
|
+
...prev,
|
|
388
|
+
{
|
|
389
|
+
id: msgId,
|
|
390
|
+
role: "assistant",
|
|
391
|
+
parts: [{ type: "text", text: textAccumulator }]
|
|
392
|
+
}
|
|
393
|
+
];
|
|
394
|
+
}
|
|
395
|
+
const existing = prev[idx];
|
|
396
|
+
const textPart = existing.parts.find((p) => p.type === "text");
|
|
397
|
+
if (!textPart?.text || textPart.text.length < textAccumulator.length) {
|
|
398
|
+
const copy = [...prev];
|
|
399
|
+
const parts = [
|
|
400
|
+
...existing.parts.filter((p) => p.type !== "text"),
|
|
401
|
+
{ type: "text", text: textAccumulator }
|
|
402
|
+
];
|
|
403
|
+
copy[idx] = { ...existing, parts };
|
|
404
|
+
return copy;
|
|
405
|
+
}
|
|
406
|
+
return prev;
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
[
|
|
411
|
+
agentId,
|
|
412
|
+
workspaceId,
|
|
413
|
+
envId,
|
|
414
|
+
source,
|
|
415
|
+
threadId,
|
|
416
|
+
userContext,
|
|
417
|
+
playgroundOverrides,
|
|
418
|
+
applyStreamEvent
|
|
419
|
+
]
|
|
420
|
+
);
|
|
421
|
+
const voiceCall = useVoiceCall({
|
|
422
|
+
agentId,
|
|
423
|
+
threadId,
|
|
424
|
+
workspaceId,
|
|
425
|
+
customBackend
|
|
426
|
+
});
|
|
109
427
|
useEffect(() => {
|
|
110
428
|
if (customBackend || !persistKey) return;
|
|
111
429
|
try {
|
|
@@ -122,30 +440,108 @@ function useChat({
|
|
|
122
440
|
}, [customBackend, persistKey, threadId]);
|
|
123
441
|
useEffect(() => {
|
|
124
442
|
if (customBackend || !persistKey || typeof window === "undefined") return;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
})).filter((m) => m.parts.length > 0);
|
|
139
|
-
if (restored.length > 0) setMessages(restored);
|
|
140
|
-
} catch {
|
|
443
|
+
const savedTid = localStorage.getItem(`${persistKey}_tid`);
|
|
444
|
+
if (savedTid) {
|
|
445
|
+
if (savedTid !== threadId) {
|
|
446
|
+
setThreadId(savedTid);
|
|
447
|
+
const savedMsgs = sessionStorage.getItem(`${persistKey}_msgs`);
|
|
448
|
+
if (savedMsgs) {
|
|
449
|
+
try {
|
|
450
|
+
setMessages(JSON.parse(savedMsgs));
|
|
451
|
+
} catch {
|
|
452
|
+
}
|
|
453
|
+
} else {
|
|
454
|
+
setMessages([]);
|
|
455
|
+
}
|
|
141
456
|
}
|
|
142
|
-
}
|
|
143
|
-
|
|
457
|
+
} else {
|
|
458
|
+
const newTid = crypto.randomUUID();
|
|
459
|
+
setThreadId(newTid);
|
|
460
|
+
setMessages([]);
|
|
461
|
+
localStorage.setItem(`${persistKey}_tid`, newTid);
|
|
462
|
+
}
|
|
463
|
+
}, [customBackend, persistKey]);
|
|
464
|
+
useEffect(() => {
|
|
465
|
+
if (customBackend || typeof window === "undefined") return;
|
|
466
|
+
if (initializedThreadsRef.current.has(threadId)) return;
|
|
467
|
+
initializedThreadsRef.current.add(threadId);
|
|
468
|
+
if (persistKey) {
|
|
469
|
+
if (messagesRef.current.length > 0) return;
|
|
470
|
+
void (async () => {
|
|
471
|
+
try {
|
|
472
|
+
const isPrivate = Boolean(workspaceId);
|
|
473
|
+
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
474
|
+
const url = isPrivate ? `${API_URL2}/api/threads/${threadId}/messages` : `${API_URL2}/api/chat/messages?agentId=${encodeURIComponent(agentId)}&threadId=${encodeURIComponent(threadId)}`;
|
|
475
|
+
const res = await fetch(url, {
|
|
476
|
+
headers: {
|
|
477
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
if (!res.ok) return;
|
|
481
|
+
const { data } = await res.json();
|
|
482
|
+
if (!data?.length) {
|
|
483
|
+
try {
|
|
484
|
+
fetchAndStream({
|
|
485
|
+
input: "__INIT__",
|
|
486
|
+
msgId: "init",
|
|
487
|
+
extraMetadata: { isSilentInit: true }
|
|
488
|
+
});
|
|
489
|
+
} catch {
|
|
490
|
+
}
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const restored = data.map((m) => ({
|
|
494
|
+
id: m.id,
|
|
495
|
+
role: m.role,
|
|
496
|
+
parts: m.parts.filter((p) => p?.type).map((p) => {
|
|
497
|
+
if (p.type === "picker" && Array.isArray(p.options)) {
|
|
498
|
+
return {
|
|
499
|
+
...p,
|
|
500
|
+
label: typeof p.label === "string" ? p.label : String(p.label ?? ""),
|
|
501
|
+
options: p.options.map((o) => ({
|
|
502
|
+
...o,
|
|
503
|
+
value: typeof o.value === "string" ? o.value : JSON.stringify(o.value ?? ""),
|
|
504
|
+
label: typeof o.label === "string" ? o.label : JSON.stringify(o.label ?? "")
|
|
505
|
+
}))
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
return p;
|
|
509
|
+
})
|
|
510
|
+
})).filter((m) => m.parts.length > 0);
|
|
511
|
+
if (restored.length > 0) {
|
|
512
|
+
setMessages(restored);
|
|
513
|
+
} else {
|
|
514
|
+
try {
|
|
515
|
+
fetchAndStream({
|
|
516
|
+
input: "__INIT__",
|
|
517
|
+
msgId: "init",
|
|
518
|
+
extraMetadata: { isSilentInit: true }
|
|
519
|
+
});
|
|
520
|
+
} catch {
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
} catch {
|
|
524
|
+
}
|
|
525
|
+
})();
|
|
526
|
+
} else {
|
|
527
|
+
if (messagesRef.current.length === 0) {
|
|
528
|
+
try {
|
|
529
|
+
fetchAndStream({
|
|
530
|
+
input: "__INIT__",
|
|
531
|
+
msgId: "init",
|
|
532
|
+
extraMetadata: { isSilentInit: true }
|
|
533
|
+
});
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}, [threadId, agentId, workspaceId, envId, persistKey, fetchAndStream]);
|
|
144
539
|
const reset = useCallback(() => {
|
|
145
540
|
setMessages([]);
|
|
146
541
|
setInput("");
|
|
147
542
|
setStreaming(false);
|
|
148
543
|
setThreadId(crypto.randomUUID());
|
|
544
|
+
setDebugTraces([]);
|
|
149
545
|
streamingMsgIdRef.current = null;
|
|
150
546
|
if (persistKey) {
|
|
151
547
|
try {
|
|
@@ -156,143 +552,6 @@ function useChat({
|
|
|
156
552
|
}
|
|
157
553
|
}
|
|
158
554
|
}, [persistKey]);
|
|
159
|
-
const applyStreamEvent = useCallback((proto, msgId) => {
|
|
160
|
-
if (proto.type === "navigate") {
|
|
161
|
-
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
setMessages((prev) => {
|
|
165
|
-
const idx = prev.findIndex((m) => m.id === msgId);
|
|
166
|
-
if (idx === -1) return prev;
|
|
167
|
-
const existing = prev[idx];
|
|
168
|
-
const msg = { id: existing.id, role: existing.role, parts: [...existing.parts] };
|
|
169
|
-
switch (proto.type) {
|
|
170
|
-
case "text-delta": {
|
|
171
|
-
const textIdx = msg.parts.findIndex((p) => p.type === "text");
|
|
172
|
-
if (textIdx === -1) {
|
|
173
|
-
msg.parts.push({ type: "text", text: proto.delta });
|
|
174
|
-
} else {
|
|
175
|
-
const p = msg.parts[textIdx];
|
|
176
|
-
msg.parts[textIdx] = { type: "text", text: p.text + proto.delta };
|
|
177
|
-
}
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
case "reasoning-delta": {
|
|
181
|
-
const rIdx = msg.parts.findIndex((p) => p.type === "reasoning");
|
|
182
|
-
if (rIdx === -1) {
|
|
183
|
-
msg.parts.unshift({ type: "reasoning", text: proto.delta });
|
|
184
|
-
} else {
|
|
185
|
-
const p = msg.parts[rIdx];
|
|
186
|
-
msg.parts[rIdx] = { type: "reasoning", text: p.text + proto.delta };
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
case "tool-input-available": {
|
|
191
|
-
msg.parts.push({
|
|
192
|
-
type: "tool",
|
|
193
|
-
toolCallId: proto.toolCallId,
|
|
194
|
-
toolName: proto.toolName,
|
|
195
|
-
input: proto.input ?? {},
|
|
196
|
-
status: "running"
|
|
197
|
-
});
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
case "tool-output-available": {
|
|
201
|
-
const tIdx = msg.parts.findIndex(
|
|
202
|
-
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
203
|
-
);
|
|
204
|
-
if (tIdx !== -1) {
|
|
205
|
-
msg.parts[tIdx] = { ...msg.parts[tIdx], status: "done", output: proto.output };
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
case "tool-output-error": {
|
|
210
|
-
const tIdx = msg.parts.findIndex(
|
|
211
|
-
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
212
|
-
);
|
|
213
|
-
if (tIdx !== -1) {
|
|
214
|
-
msg.parts[tIdx] = { ...msg.parts[tIdx], status: "error", errorText: proto.errorText };
|
|
215
|
-
}
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
case "picker": {
|
|
219
|
-
msg.parts.push({
|
|
220
|
-
type: "picker",
|
|
221
|
-
pickerId: proto.pickerId,
|
|
222
|
-
paramName: proto.paramName,
|
|
223
|
-
toolName: proto.toolName,
|
|
224
|
-
label: proto.label,
|
|
225
|
-
options: proto.options
|
|
226
|
-
});
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
case "plan-created": {
|
|
230
|
-
msg.parts.push({
|
|
231
|
-
type: "plan",
|
|
232
|
-
planId: proto.planId,
|
|
233
|
-
goal: proto.goal,
|
|
234
|
-
steps: proto.steps.map((s) => ({ ...s, status: "pending" }))
|
|
235
|
-
});
|
|
236
|
-
break;
|
|
237
|
-
}
|
|
238
|
-
case "plan-step-update": {
|
|
239
|
-
const pIdx = msg.parts.findIndex(
|
|
240
|
-
(p) => p.type === "plan" && p.planId === proto.planId
|
|
241
|
-
);
|
|
242
|
-
if (pIdx !== -1) {
|
|
243
|
-
const prev2 = msg.parts[pIdx];
|
|
244
|
-
msg.parts[pIdx] = {
|
|
245
|
-
...prev2,
|
|
246
|
-
steps: prev2.steps.map(
|
|
247
|
-
(s) => s.index === proto.stepIndex ? { ...s, status: proto.status, ...proto.error ? { error: proto.error } : {} } : s
|
|
248
|
-
)
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
break;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const copy = [...prev];
|
|
255
|
-
copy[idx] = msg;
|
|
256
|
-
return copy;
|
|
257
|
-
});
|
|
258
|
-
}, []);
|
|
259
|
-
const fetchAndStream = useCallback(async (opts) => {
|
|
260
|
-
const { input: userInput, msgId, extraMetadata, attachments } = opts;
|
|
261
|
-
const isPrivate = Boolean(workspaceId);
|
|
262
|
-
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
263
|
-
const url = isPrivate ? `${API_URL}/api/threads/${threadId}/stream` : `${API_URL}/api/chat/stream`;
|
|
264
|
-
const res = await fetch(url, {
|
|
265
|
-
method: "POST",
|
|
266
|
-
headers: {
|
|
267
|
-
"Content-Type": "application/json",
|
|
268
|
-
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
269
|
-
},
|
|
270
|
-
body: JSON.stringify({
|
|
271
|
-
input: userInput,
|
|
272
|
-
agentId,
|
|
273
|
-
...isPrivate ? { workspaceId, ...playgroundOverrides ? { playgroundOverrides } : {} } : { threadId },
|
|
274
|
-
source,
|
|
275
|
-
...attachments?.length ? { attachments } : {},
|
|
276
|
-
...userContext?.userName ? { userName: userContext.userName } : {},
|
|
277
|
-
...userContext?.userEmail ? { userEmail: userContext.userEmail } : {},
|
|
278
|
-
userMetadata: {
|
|
279
|
-
...userContext?.metadata ?? {},
|
|
280
|
-
...userContext?.pageContext ? { pageContext: userContext.pageContext } : {},
|
|
281
|
-
headers: {
|
|
282
|
-
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
283
|
-
...userContext?.headers ?? {}
|
|
284
|
-
},
|
|
285
|
-
...extraMetadata ?? {}
|
|
286
|
-
}
|
|
287
|
-
})
|
|
288
|
-
});
|
|
289
|
-
if (!res.ok) {
|
|
290
|
-
const errText = await res.text().catch(() => "");
|
|
291
|
-
throw new Error(errText || `API error ${res.status}`);
|
|
292
|
-
}
|
|
293
|
-
if (!res.body) throw new Error("No stream body");
|
|
294
|
-
await consumeStream(res.body, (proto) => applyStreamEvent(proto, msgId));
|
|
295
|
-
}, [agentId, workspaceId, source, threadId, userContext, playgroundOverrides, applyStreamEvent]);
|
|
296
555
|
const pendingAttachmentsRef = useRef([]);
|
|
297
556
|
const send = useCallback(
|
|
298
557
|
async (text) => {
|
|
@@ -300,7 +559,8 @@ function useChat({
|
|
|
300
559
|
const content = (text ?? input).trim();
|
|
301
560
|
const attachments2 = pendingAttachmentsRef.current.length > 0 ? [...pendingAttachmentsRef.current] : void 0;
|
|
302
561
|
pendingAttachmentsRef.current = [];
|
|
303
|
-
if (!content && !attachments2?.length || customBackend.streaming)
|
|
562
|
+
if (!content && !attachments2?.length || customBackend.streaming)
|
|
563
|
+
return;
|
|
304
564
|
setInput("");
|
|
305
565
|
await customBackend.send(content, attachments2);
|
|
306
566
|
return;
|
|
@@ -323,16 +583,32 @@ function useChat({
|
|
|
323
583
|
setStreaming(true);
|
|
324
584
|
const assistantMsgId = newId();
|
|
325
585
|
streamingMsgIdRef.current = assistantMsgId;
|
|
326
|
-
setMessages((prev) => [
|
|
586
|
+
setMessages((prev) => [
|
|
587
|
+
...prev,
|
|
588
|
+
{ id: assistantMsgId, role: "assistant", parts: [] }
|
|
589
|
+
]);
|
|
327
590
|
try {
|
|
328
|
-
await fetchAndStream({
|
|
591
|
+
await fetchAndStream({
|
|
592
|
+
input: userInput,
|
|
593
|
+
msgId: assistantMsgId,
|
|
594
|
+
attachments
|
|
595
|
+
});
|
|
329
596
|
} catch {
|
|
330
597
|
setMessages((prev) => {
|
|
331
598
|
const idx = prev.findIndex((m) => m.id === assistantMsgId);
|
|
332
599
|
if (idx === -1) return prev;
|
|
333
600
|
const copy = [...prev];
|
|
334
601
|
const err = copy[idx];
|
|
335
|
-
copy[idx] = {
|
|
602
|
+
copy[idx] = {
|
|
603
|
+
id: err.id,
|
|
604
|
+
role: err.role,
|
|
605
|
+
parts: [
|
|
606
|
+
{
|
|
607
|
+
type: "text",
|
|
608
|
+
text: "Sorry, something went wrong. Please try again."
|
|
609
|
+
}
|
|
610
|
+
]
|
|
611
|
+
};
|
|
336
612
|
return copy;
|
|
337
613
|
});
|
|
338
614
|
}
|
|
@@ -348,19 +624,27 @@ function useChat({
|
|
|
348
624
|
(prev) => prev.map((msg) => ({
|
|
349
625
|
...msg,
|
|
350
626
|
parts: msg.parts.map(
|
|
351
|
-
(part) => part.type === "picker" && part.pickerId === pickerId ? {
|
|
627
|
+
(part) => part.type === "picker" && part.pickerId === pickerId ? {
|
|
628
|
+
...part,
|
|
629
|
+
selectedValue: value
|
|
630
|
+
} : part
|
|
352
631
|
)
|
|
353
632
|
}))
|
|
354
633
|
);
|
|
355
634
|
setStreaming(true);
|
|
356
635
|
const assistantMsgId = newId();
|
|
357
636
|
streamingMsgIdRef.current = assistantMsgId;
|
|
358
|
-
setMessages((prev) => [
|
|
637
|
+
setMessages((prev) => [
|
|
638
|
+
...prev,
|
|
639
|
+
{ id: assistantMsgId, role: "assistant", parts: [] }
|
|
640
|
+
]);
|
|
359
641
|
try {
|
|
360
642
|
await fetchAndStream({
|
|
361
643
|
input: label,
|
|
362
644
|
msgId: assistantMsgId,
|
|
363
|
-
extraMetadata: {
|
|
645
|
+
extraMetadata: {
|
|
646
|
+
__pickerSelection: { pickerId, paramName, value, label }
|
|
647
|
+
}
|
|
364
648
|
});
|
|
365
649
|
} catch {
|
|
366
650
|
setMessages((prev) => {
|
|
@@ -368,7 +652,16 @@ function useChat({
|
|
|
368
652
|
if (idx === -1) return prev;
|
|
369
653
|
const copy = [...prev];
|
|
370
654
|
const err = copy[idx];
|
|
371
|
-
copy[idx] = {
|
|
655
|
+
copy[idx] = {
|
|
656
|
+
id: err.id,
|
|
657
|
+
role: err.role,
|
|
658
|
+
parts: [
|
|
659
|
+
{
|
|
660
|
+
type: "text",
|
|
661
|
+
text: "Sorry, something went wrong. Please try again."
|
|
662
|
+
}
|
|
663
|
+
]
|
|
664
|
+
};
|
|
372
665
|
return copy;
|
|
373
666
|
});
|
|
374
667
|
}
|
|
@@ -403,7 +696,9 @@ function useChat({
|
|
|
403
696
|
queueAttachments,
|
|
404
697
|
regenerate,
|
|
405
698
|
reset: customBackend?.reset ?? reset,
|
|
406
|
-
selectPickerOption
|
|
699
|
+
selectPickerOption,
|
|
700
|
+
debugTraces,
|
|
701
|
+
voiceCall
|
|
407
702
|
};
|
|
408
703
|
}
|
|
409
704
|
function getPreferredMimeType() {
|
|
@@ -423,7 +718,12 @@ function mimeTypeToExtension(mimeType) {
|
|
|
423
718
|
return "webm";
|
|
424
719
|
}
|
|
425
720
|
var DEFAULT_API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
426
|
-
function useVoice({
|
|
721
|
+
function useVoice({
|
|
722
|
+
agentId,
|
|
723
|
+
apiUrl,
|
|
724
|
+
onTranscript,
|
|
725
|
+
onError
|
|
726
|
+
}) {
|
|
427
727
|
const [voiceState, setVoiceState] = useState("idle");
|
|
428
728
|
const recorderRef = useRef(null);
|
|
429
729
|
const chunksRef = useRef([]);
|
|
@@ -439,10 +739,14 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
439
739
|
const form = new FormData();
|
|
440
740
|
form.append("audio", blob, `recording.${ext}`);
|
|
441
741
|
form.append("agentId", agentId);
|
|
442
|
-
const res = await fetch(`${base}/api/chat/transcribe`, {
|
|
742
|
+
const res = await fetch(`${base}/api/chat/transcribe`, {
|
|
743
|
+
method: "POST",
|
|
744
|
+
body: form
|
|
745
|
+
});
|
|
443
746
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
444
747
|
const data = await res.json();
|
|
445
|
-
if (!data.text?.trim())
|
|
748
|
+
if (!data.text?.trim())
|
|
749
|
+
throw new Error(data.error ?? "Empty transcript");
|
|
446
750
|
onTranscript(data.text.trim());
|
|
447
751
|
setVoiceState("idle");
|
|
448
752
|
} catch (err) {
|
|
@@ -460,14 +764,19 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
460
764
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
461
765
|
streamRef.current = stream;
|
|
462
766
|
const mimeType = getPreferredMimeType();
|
|
463
|
-
const recorder = new MediaRecorder(
|
|
767
|
+
const recorder = new MediaRecorder(
|
|
768
|
+
stream,
|
|
769
|
+
mimeType ? { mimeType } : void 0
|
|
770
|
+
);
|
|
464
771
|
chunksRef.current = [];
|
|
465
772
|
recorder.ondataavailable = (e) => {
|
|
466
773
|
if (e.data.size > 0) chunksRef.current.push(e.data);
|
|
467
774
|
};
|
|
468
775
|
recorder.onstop = async () => {
|
|
469
776
|
stream.getTracks().forEach((t) => t.stop());
|
|
470
|
-
const blob = new Blob(chunksRef.current, {
|
|
777
|
+
const blob = new Blob(chunksRef.current, {
|
|
778
|
+
type: mimeType || "audio/webm"
|
|
779
|
+
});
|
|
471
780
|
if (blob.size === 0) {
|
|
472
781
|
onError?.("Recording was empty \u2014 please try again.");
|
|
473
782
|
setVoiceState("idle");
|
|
@@ -493,7 +802,8 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
493
802
|
useEffect(() => {
|
|
494
803
|
return () => {
|
|
495
804
|
if (errorTimerRef.current) clearTimeout(errorTimerRef.current);
|
|
496
|
-
if (recorderRef.current?.state === "recording")
|
|
805
|
+
if (recorderRef.current?.state === "recording")
|
|
806
|
+
recorderRef.current.stop();
|
|
497
807
|
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
498
808
|
};
|
|
499
809
|
}, []);
|
|
@@ -516,7 +826,10 @@ function useAttachments({
|
|
|
516
826
|
form.append("file", file);
|
|
517
827
|
form.append("agentId", agentId);
|
|
518
828
|
try {
|
|
519
|
-
const res = await fetch(`${base}/api/chat/upload`, {
|
|
829
|
+
const res = await fetch(`${base}/api/chat/upload`, {
|
|
830
|
+
method: "POST",
|
|
831
|
+
body: form
|
|
832
|
+
});
|
|
520
833
|
if (!res.ok) {
|
|
521
834
|
const data = await res.json().catch(() => ({}));
|
|
522
835
|
setAttachments(
|
|
@@ -532,7 +845,9 @@ function useAttachments({
|
|
|
532
845
|
}
|
|
533
846
|
const payload = await res.json();
|
|
534
847
|
setAttachments(
|
|
535
|
-
(prev) => prev.map(
|
|
848
|
+
(prev) => prev.map(
|
|
849
|
+
(a) => a.id === id ? { ...a, status: "ready", payload } : a
|
|
850
|
+
)
|
|
536
851
|
);
|
|
537
852
|
} catch (err) {
|
|
538
853
|
const msg = err instanceof Error ? err.message : "Upload failed";
|
|
@@ -576,16 +891,13 @@ function useAttachments({
|
|
|
576
891
|
return { attachments, attach, remove, clear, isUploading, readyPayloads };
|
|
577
892
|
}
|
|
578
893
|
function DefaultIcon() {
|
|
579
|
-
return /* @__PURE__ */
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
"
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}
|
|
587
|
-
)
|
|
588
|
-
] });
|
|
894
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 26, height: 26 }, children: /* @__PURE__ */ jsx(
|
|
895
|
+
"path",
|
|
896
|
+
{
|
|
897
|
+
d: "M4 8.5C4 6.57 5.57 5 7.5 5h9C18.43 5 20 6.57 20 8.5v5c0 1.93-1.57 3.5-3.5 3.5H13l-3 2.5V17H7.5C5.57 17 4 15.43 4 13.5v-5Z",
|
|
898
|
+
fill: "currentColor"
|
|
899
|
+
}
|
|
900
|
+
) });
|
|
589
901
|
}
|
|
590
902
|
function ExpandIcon() {
|
|
591
903
|
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 11, height: 11 }, children: /* @__PURE__ */ jsx(
|
|
@@ -611,9 +923,58 @@ function MinimizeIcon() {
|
|
|
611
923
|
}
|
|
612
924
|
) });
|
|
613
925
|
}
|
|
614
|
-
var Avatar = ({
|
|
615
|
-
|
|
616
|
-
|
|
926
|
+
var Avatar = ({
|
|
927
|
+
style,
|
|
928
|
+
...p
|
|
929
|
+
}) => /* @__PURE__ */ jsx(
|
|
930
|
+
AvatarPrimitive.Root,
|
|
931
|
+
{
|
|
932
|
+
style: {
|
|
933
|
+
position: "relative",
|
|
934
|
+
display: "flex",
|
|
935
|
+
flexShrink: 0,
|
|
936
|
+
overflow: "hidden",
|
|
937
|
+
borderRadius: "9999px",
|
|
938
|
+
...style
|
|
939
|
+
},
|
|
940
|
+
...p
|
|
941
|
+
}
|
|
942
|
+
);
|
|
943
|
+
var AvatarImage = ({
|
|
944
|
+
style,
|
|
945
|
+
...p
|
|
946
|
+
}) => /* @__PURE__ */ jsx(
|
|
947
|
+
AvatarPrimitive.Image,
|
|
948
|
+
{
|
|
949
|
+
style: {
|
|
950
|
+
position: "absolute",
|
|
951
|
+
inset: 0,
|
|
952
|
+
width: "100%",
|
|
953
|
+
height: "100%",
|
|
954
|
+
objectFit: "cover",
|
|
955
|
+
...style
|
|
956
|
+
},
|
|
957
|
+
...p
|
|
958
|
+
}
|
|
959
|
+
);
|
|
960
|
+
var AvatarFallback = ({
|
|
961
|
+
style,
|
|
962
|
+
...p
|
|
963
|
+
}) => /* @__PURE__ */ jsx(
|
|
964
|
+
AvatarPrimitive.Fallback,
|
|
965
|
+
{
|
|
966
|
+
style: {
|
|
967
|
+
display: "flex",
|
|
968
|
+
width: "100%",
|
|
969
|
+
height: "100%",
|
|
970
|
+
alignItems: "center",
|
|
971
|
+
justifyContent: "center",
|
|
972
|
+
borderRadius: "9999px",
|
|
973
|
+
...style
|
|
974
|
+
},
|
|
975
|
+
...p
|
|
976
|
+
}
|
|
977
|
+
);
|
|
617
978
|
function ChatHeader({
|
|
618
979
|
title,
|
|
619
980
|
profilePicture,
|
|
@@ -622,22 +983,39 @@ function ChatHeader({
|
|
|
622
983
|
onReset,
|
|
623
984
|
onClose,
|
|
624
985
|
onExpand,
|
|
625
|
-
expanded
|
|
986
|
+
expanded,
|
|
987
|
+
onCall,
|
|
988
|
+
isCallLoading
|
|
626
989
|
}) {
|
|
627
990
|
return /* @__PURE__ */ jsxs(
|
|
628
991
|
"header",
|
|
629
992
|
{
|
|
630
|
-
className: "ww-flex ww-items-center ww-justify-between ww-px-4 ww-py-3 ww-shrink-0",
|
|
631
|
-
style: {
|
|
993
|
+
className: "ww-flex ww-items-center ww-justify-between ww-px-4 ww-py-3 ww-shrink-0 ww-touch-none",
|
|
994
|
+
style: {
|
|
995
|
+
backgroundColor: headerBg,
|
|
996
|
+
color: headerText,
|
|
997
|
+
borderBottom: `1px solid ${headerText}18`
|
|
998
|
+
},
|
|
632
999
|
children: [
|
|
633
1000
|
/* @__PURE__ */ jsxs("div", { className: "ww-flex ww-items-center ww-gap-2.5 ww-min-w-0", children: [
|
|
634
|
-
/* @__PURE__ */ jsx(
|
|
635
|
-
|
|
1001
|
+
/* @__PURE__ */ jsx(
|
|
1002
|
+
Avatar,
|
|
636
1003
|
{
|
|
637
|
-
style: {
|
|
638
|
-
children:
|
|
1004
|
+
style: { width: 32, height: 32, border: `2px solid ${headerText}30` },
|
|
1005
|
+
children: profilePicture ? /* @__PURE__ */ jsx(AvatarImage, { src: profilePicture, alt: title }) : /* @__PURE__ */ jsx(
|
|
1006
|
+
AvatarFallback,
|
|
1007
|
+
{
|
|
1008
|
+
style: {
|
|
1009
|
+
backgroundColor: `${headerText}20`,
|
|
1010
|
+
color: headerText,
|
|
1011
|
+
fontSize: 11,
|
|
1012
|
+
fontWeight: 700
|
|
1013
|
+
},
|
|
1014
|
+
children: title.slice(0, 2).toUpperCase()
|
|
1015
|
+
}
|
|
1016
|
+
)
|
|
639
1017
|
}
|
|
640
|
-
)
|
|
1018
|
+
),
|
|
641
1019
|
/* @__PURE__ */ jsxs("div", { className: "ww-min-w-0", children: [
|
|
642
1020
|
/* @__PURE__ */ jsx("p", { className: "ww-font-semibold ww-text-sm ww-truncate ww-leading-tight", children: title }),
|
|
643
1021
|
/* @__PURE__ */ jsx("p", { className: "ww-text-[10px] ww-opacity-70 ww-leading-tight", children: "AI Assistant" })
|
|
@@ -653,13 +1031,64 @@ function ChatHeader({
|
|
|
653
1031
|
children: expanded ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(ExpandIcon, {})
|
|
654
1032
|
}
|
|
655
1033
|
),
|
|
1034
|
+
onCall && /* @__PURE__ */ jsx(
|
|
1035
|
+
"button",
|
|
1036
|
+
{
|
|
1037
|
+
onClick: onCall,
|
|
1038
|
+
disabled: isCallLoading,
|
|
1039
|
+
className: "ww-rounded-full ww-p-1.5 ww-transition-colors hover:ww-bg-white/10 disabled:ww-opacity-50",
|
|
1040
|
+
title: "Voice Call",
|
|
1041
|
+
children: isCallLoading ? /* @__PURE__ */ jsxs(
|
|
1042
|
+
"svg",
|
|
1043
|
+
{
|
|
1044
|
+
className: "ww-animate-spin ww-h-3.5 ww-w-3.5",
|
|
1045
|
+
viewBox: "0 0 24 24",
|
|
1046
|
+
fill: "none",
|
|
1047
|
+
style: { color: headerText },
|
|
1048
|
+
children: [
|
|
1049
|
+
/* @__PURE__ */ jsx(
|
|
1050
|
+
"circle",
|
|
1051
|
+
{
|
|
1052
|
+
className: "ww-opacity-25",
|
|
1053
|
+
cx: "12",
|
|
1054
|
+
cy: "12",
|
|
1055
|
+
r: "10",
|
|
1056
|
+
stroke: "currentColor",
|
|
1057
|
+
strokeWidth: "4"
|
|
1058
|
+
}
|
|
1059
|
+
),
|
|
1060
|
+
/* @__PURE__ */ jsx(
|
|
1061
|
+
"path",
|
|
1062
|
+
{
|
|
1063
|
+
className: "ww-opacity-75",
|
|
1064
|
+
fill: "currentColor",
|
|
1065
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
1066
|
+
}
|
|
1067
|
+
)
|
|
1068
|
+
]
|
|
1069
|
+
}
|
|
1070
|
+
) : /* @__PURE__ */ jsx(
|
|
1071
|
+
Phone,
|
|
1072
|
+
{
|
|
1073
|
+
className: "ww-h-3.5 ww-w-3.5",
|
|
1074
|
+
style: { color: headerText }
|
|
1075
|
+
}
|
|
1076
|
+
)
|
|
1077
|
+
}
|
|
1078
|
+
),
|
|
656
1079
|
/* @__PURE__ */ jsx(
|
|
657
1080
|
"button",
|
|
658
1081
|
{
|
|
659
1082
|
onClick: onReset,
|
|
660
1083
|
className: "ww-rounded-full ww-p-1.5 ww-transition-colors hover:ww-bg-white/10",
|
|
661
1084
|
title: "New conversation",
|
|
662
|
-
children: /* @__PURE__ */ jsx(
|
|
1085
|
+
children: /* @__PURE__ */ jsx(
|
|
1086
|
+
RotateCcw,
|
|
1087
|
+
{
|
|
1088
|
+
className: "ww-h-3.5 ww-w-3.5",
|
|
1089
|
+
style: { color: headerText }
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
663
1092
|
}
|
|
664
1093
|
),
|
|
665
1094
|
onClose && /* @__PURE__ */ jsx(
|
|
@@ -683,8 +1112,10 @@ function formatBytes(bytes) {
|
|
|
683
1112
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
684
1113
|
}
|
|
685
1114
|
function ChipLeading({ a }) {
|
|
686
|
-
if (a.status === "uploading")
|
|
687
|
-
|
|
1115
|
+
if (a.status === "uploading")
|
|
1116
|
+
return /* @__PURE__ */ jsx(Loader2, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-animate-spin" });
|
|
1117
|
+
if (a.status === "error")
|
|
1118
|
+
return /* @__PURE__ */ jsx(AlertCircle, { className: "ww-h-3 ww-w-3 ww-shrink-0" });
|
|
688
1119
|
const thumbSrc = a.payload?.url ?? a.payload?.base64;
|
|
689
1120
|
if (a.mimeType.startsWith("image/") && thumbSrc) {
|
|
690
1121
|
return /* @__PURE__ */ jsx(
|
|
@@ -696,14 +1127,19 @@ function ChipLeading({ a }) {
|
|
|
696
1127
|
}
|
|
697
1128
|
);
|
|
698
1129
|
}
|
|
699
|
-
if (a.mimeType.startsWith("image/"))
|
|
700
|
-
|
|
1130
|
+
if (a.mimeType.startsWith("image/"))
|
|
1131
|
+
return /* @__PURE__ */ jsx("div", { className: "ww-h-6 ww-w-6 ww-rounded ww-bg-muted-foreground/10 ww-border ww-border-border/30 ww-shrink-0 ww-flex ww-items-center ww-justify-center", children: /* @__PURE__ */ jsx("span", { className: "ww-text-[8px] ww-font-semibold ww-text-muted-foreground/50", children: "IMG" }) });
|
|
1132
|
+
if (a.mimeType === "application/pdf")
|
|
1133
|
+
return /* @__PURE__ */ jsx(FileText, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-text-red-400" });
|
|
701
1134
|
if (a.mimeType.includes("csv") || a.mimeType.includes("spreadsheet") || a.name.endsWith(".csv")) {
|
|
702
1135
|
return /* @__PURE__ */ jsx(FileSpreadsheet, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-text-emerald-500" });
|
|
703
1136
|
}
|
|
704
1137
|
return /* @__PURE__ */ jsx(FileText, { className: "ww-h-3 ww-w-3 ww-shrink-0" });
|
|
705
1138
|
}
|
|
706
|
-
function AttachmentChips({
|
|
1139
|
+
function AttachmentChips({
|
|
1140
|
+
attachments,
|
|
1141
|
+
onRemove
|
|
1142
|
+
}) {
|
|
707
1143
|
if (attachments.length === 0) return null;
|
|
708
1144
|
return /* @__PURE__ */ jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1.5 ww-px-1 ww-pb-1.5", children: attachments.map((a) => /* @__PURE__ */ jsxs(
|
|
709
1145
|
"div",
|
|
@@ -731,41 +1167,49 @@ function AttachmentChips({ attachments, onRemove }) {
|
|
|
731
1167
|
a.id
|
|
732
1168
|
)) });
|
|
733
1169
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
function SentAttachments({ attachments, contrastColor }) {
|
|
1170
|
+
function SentAttachments({
|
|
1171
|
+
attachments,
|
|
1172
|
+
contrastColor
|
|
1173
|
+
}) {
|
|
739
1174
|
const images = attachments.filter((a) => a.contentType === "image");
|
|
740
1175
|
const files = attachments.filter((a) => a.contentType !== "image");
|
|
741
1176
|
const isDark = contrastColor === "#ffffff" || contrastColor === "#fff";
|
|
742
1177
|
return /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-gap-1.5 ww-w-full", children: [
|
|
743
|
-
images.length > 0 && /* @__PURE__ */ jsx(
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1178
|
+
images.length > 0 && /* @__PURE__ */ jsx(
|
|
1179
|
+
"div",
|
|
1180
|
+
{
|
|
1181
|
+
className: cn(
|
|
1182
|
+
"ww-flex ww-gap-1.5 ww-flex-wrap",
|
|
1183
|
+
images.length === 1 && ""
|
|
1184
|
+
),
|
|
1185
|
+
children: images.map((img) => {
|
|
1186
|
+
const src = img.url ?? img.base64;
|
|
1187
|
+
return src ? /* @__PURE__ */ jsx(
|
|
1188
|
+
"img",
|
|
1189
|
+
{
|
|
1190
|
+
src,
|
|
1191
|
+
alt: img.name,
|
|
1192
|
+
className: cn(
|
|
1193
|
+
"ww-rounded-xl ww-object-cover ww-border",
|
|
1194
|
+
images.length === 1 ? "ww-w-full ww-max-h-48" : "ww-h-20 ww-w-20",
|
|
1195
|
+
isDark ? "ww-border-white/20" : "ww-border-black/10"
|
|
1196
|
+
)
|
|
1197
|
+
},
|
|
1198
|
+
img.id
|
|
1199
|
+
) : /* @__PURE__ */ jsx(
|
|
1200
|
+
"div",
|
|
1201
|
+
{
|
|
1202
|
+
className: cn(
|
|
1203
|
+
"ww-h-20 ww-w-20 ww-rounded-xl ww-flex ww-items-center ww-justify-center ww-text-[10px] ww-font-medium",
|
|
1204
|
+
isDark ? "ww-bg-white/10 ww-text-white/60" : "ww-bg-black/10 ww-text-black/40"
|
|
1205
|
+
),
|
|
1206
|
+
children: "IMG"
|
|
1207
|
+
},
|
|
1208
|
+
img.id
|
|
1209
|
+
);
|
|
1210
|
+
})
|
|
1211
|
+
}
|
|
1212
|
+
),
|
|
769
1213
|
files.length > 0 && /* @__PURE__ */ jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1", children: files.map((f) => /* @__PURE__ */ jsxs(
|
|
770
1214
|
"div",
|
|
771
1215
|
{
|
|
@@ -783,12 +1227,19 @@ function SentAttachments({ attachments, contrastColor }) {
|
|
|
783
1227
|
] });
|
|
784
1228
|
}
|
|
785
1229
|
function PlanStepIcon({ status }) {
|
|
786
|
-
if (status === "executing")
|
|
787
|
-
|
|
788
|
-
if (status === "
|
|
1230
|
+
if (status === "executing")
|
|
1231
|
+
return /* @__PURE__ */ jsx(Loader2, { className: "ww-h-3 ww-w-3 ww-animate-spin ww-text-primary" });
|
|
1232
|
+
if (status === "success")
|
|
1233
|
+
return /* @__PURE__ */ jsx(CheckCircle2, { className: "ww-h-3 ww-w-3 ww-text-emerald-500" });
|
|
1234
|
+
if (status === "failed")
|
|
1235
|
+
return /* @__PURE__ */ jsx(AlertCircle, { className: "ww-h-3 ww-w-3 ww-text-destructive" });
|
|
789
1236
|
return /* @__PURE__ */ jsx("div", { className: "ww-h-3 ww-w-3 ww-rounded-full ww-border-2 ww-border-muted-foreground/30" });
|
|
790
1237
|
}
|
|
791
|
-
function PlanCard({
|
|
1238
|
+
function PlanCard({
|
|
1239
|
+
part,
|
|
1240
|
+
onSend,
|
|
1241
|
+
disabled
|
|
1242
|
+
}) {
|
|
792
1243
|
const successCount = part.steps.filter((s) => s.status === "success").length;
|
|
793
1244
|
const hasExecuting = part.steps.some((s) => s.status === "executing");
|
|
794
1245
|
const allDone = successCount === part.steps.length && part.steps.length > 0;
|
|
@@ -842,7 +1293,10 @@ function PlanCard({ part, onSend, disabled }) {
|
|
|
842
1293
|
onClick: () => onSend("s\xED, proceder"),
|
|
843
1294
|
disabled,
|
|
844
1295
|
className: "ww-flex-1 ww-flex ww-items-center ww-justify-center ww-gap-1.5 ww-rounded-lg ww-py-1.5 ww-text-xs ww-font-semibold ww-transition-opacity hover:ww-opacity-85 active:ww-scale-[0.98] disabled:ww-opacity-50 disabled:ww-pointer-events-none",
|
|
845
|
-
style: {
|
|
1296
|
+
style: {
|
|
1297
|
+
backgroundColor: "var(--primary, #18181b)",
|
|
1298
|
+
color: "var(--primary-foreground, #fff)"
|
|
1299
|
+
},
|
|
846
1300
|
children: [
|
|
847
1301
|
/* @__PURE__ */ jsx(Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
848
1302
|
"Proceder"
|
|
@@ -924,7 +1378,15 @@ function ReasoningBlock({ text }) {
|
|
|
924
1378
|
children: [
|
|
925
1379
|
/* @__PURE__ */ jsx(Zap, { className: "ww-h-3 ww-w-3" }),
|
|
926
1380
|
/* @__PURE__ */ jsx("span", { children: "Reasoning" }),
|
|
927
|
-
/* @__PURE__ */ jsx(
|
|
1381
|
+
/* @__PURE__ */ jsx(
|
|
1382
|
+
ChevronDown,
|
|
1383
|
+
{
|
|
1384
|
+
className: cn(
|
|
1385
|
+
"ww-h-3 ww-w-3 ww-transition-transform",
|
|
1386
|
+
open && "ww-rotate-180"
|
|
1387
|
+
)
|
|
1388
|
+
}
|
|
1389
|
+
)
|
|
928
1390
|
]
|
|
929
1391
|
}
|
|
930
1392
|
),
|
|
@@ -946,98 +1408,292 @@ function PickerSelector({
|
|
|
946
1408
|
}, [part.options, query]);
|
|
947
1409
|
const isConsumed = !!part.selectedValue;
|
|
948
1410
|
const handleClick = (opt) => {
|
|
949
|
-
if (!disabled && !isConsumed)
|
|
1411
|
+
if (!disabled && !isConsumed)
|
|
1412
|
+
onSelect(part.pickerId, part.paramName, opt.value, opt.label);
|
|
950
1413
|
};
|
|
951
|
-
return /* @__PURE__ */ jsxs(
|
|
952
|
-
"
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
"
|
|
960
|
-
{
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
"
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
"
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1414
|
+
return /* @__PURE__ */ jsxs(
|
|
1415
|
+
"div",
|
|
1416
|
+
{
|
|
1417
|
+
className: cn(
|
|
1418
|
+
"ww-flex ww-flex-col ww-gap-2.5 ww-rounded-xl ww-rounded-tl-none ww-border ww-bg-muted/60 ww-p-3",
|
|
1419
|
+
"ww-border-border/50"
|
|
1420
|
+
),
|
|
1421
|
+
children: [
|
|
1422
|
+
/* @__PURE__ */ jsx("p", { className: "ww-text-[10.5px] ww-font-semibold ww-uppercase ww-tracking-widest ww-text-muted-foreground/70 ww-leading-none", children: part.label }),
|
|
1423
|
+
mode === "list" && /* @__PURE__ */ jsxs("div", { className: "ww-relative", children: [
|
|
1424
|
+
/* @__PURE__ */ jsx(Search, { className: "ww-absolute ww-left-2.5 ww-top-1/2 -translate-y-1/2 ww-h-3 ww-w-3 ww-text-muted-foreground/50 ww-pointer-events-none" }),
|
|
1425
|
+
/* @__PURE__ */ jsx(
|
|
1426
|
+
"input",
|
|
1427
|
+
{
|
|
1428
|
+
type: "text",
|
|
1429
|
+
value: query,
|
|
1430
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1431
|
+
placeholder: "Search\u2026",
|
|
1432
|
+
disabled: disabled || isConsumed,
|
|
1433
|
+
className: "ww-w-full ww-rounded-lg ww-border ww-bg-background ww-pl-7 ww-pr-3 ww-py-1.5 ww-text-xs ww-outline-none focus:ww-ring-1 focus:ww-ring-ring/40 placeholder:ww-text-muted-foreground/40 disabled:ww-opacity-50"
|
|
1434
|
+
}
|
|
1435
|
+
)
|
|
1436
|
+
] }),
|
|
1437
|
+
mode === "pills" && /* @__PURE__ */ jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1.5", children: part.options.map((opt, i) => {
|
|
1438
|
+
const sel = part.selectedValue === opt.value;
|
|
1439
|
+
const faded = isConsumed && !sel;
|
|
1440
|
+
return /* @__PURE__ */ jsxs(
|
|
1441
|
+
"button",
|
|
1442
|
+
{
|
|
1443
|
+
disabled: disabled || isConsumed,
|
|
1444
|
+
onClick: () => handleClick(opt),
|
|
1445
|
+
className: cn(
|
|
1446
|
+
"ww-inline-flex ww-items-center ww-gap-1.5 ww-rounded-full ww-px-3.5 ww-py-1.5 ww-text-[12.5px] ww-font-medium ww-transition-all ww-duration-200 ww-select-none",
|
|
1447
|
+
sel ? "ww-bg-primary ww-text-primary-foreground ww-shadow-md ww-ring-2 ww-ring-primary/20" : faded ? "ww-bg-muted/50 ww-border ww-border-transparent ww-text-muted-foreground ww-opacity-70 ww-cursor-default" : "ww-bg-background ww-border ww-border-border/80 ww-text-foreground hover:ww-border-primary/40 hover:ww-shadow-sm hover:ww-text-primary ww-cursor-pointer",
|
|
1448
|
+
disabled && !isConsumed && "ww-opacity-60 ww-pointer-events-none"
|
|
1449
|
+
),
|
|
1450
|
+
children: [
|
|
1451
|
+
sel && /* @__PURE__ */ jsx(Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
1452
|
+
opt.label
|
|
1453
|
+
]
|
|
1454
|
+
},
|
|
1455
|
+
`${opt.value}-${i}`
|
|
1456
|
+
);
|
|
1457
|
+
}) }),
|
|
1458
|
+
mode === "grid" && /* @__PURE__ */ jsx("div", { className: "ww-grid ww-grid-cols-2 ww-gap-1.5 ww-max-h-[168px] ww-overflow-y-auto ww-pr-0.5 scrollbar-thin", children: part.options.map((opt, i) => {
|
|
1459
|
+
const sel = part.selectedValue === opt.value;
|
|
1460
|
+
const faded = isConsumed && !sel;
|
|
1461
|
+
return /* @__PURE__ */ jsxs(
|
|
1462
|
+
"button",
|
|
1463
|
+
{
|
|
1464
|
+
disabled: disabled || isConsumed,
|
|
1465
|
+
onClick: () => handleClick(opt),
|
|
1466
|
+
className: cn(
|
|
1467
|
+
"ww-flex ww-items-center ww-gap-2 ww-rounded-xl ww-px-3 ww-py-2 ww-text-[12.5px] ww-font-medium ww-text-left ww-transition-all ww-duration-200 ww-select-none ww-truncate",
|
|
1468
|
+
sel ? "ww-bg-primary ww-text-primary-foreground ww-shadow-md ww-ring-2 ww-ring-primary/20" : faded ? "ww-bg-muted/40 ww-border ww-border-transparent ww-text-muted-foreground ww-opacity-70 ww-cursor-default" : "ww-bg-background ww-border ww-border-border/60 ww-text-foreground hover:ww-border-primary/40 hover:ww-shadow-sm hover:ww-text-primary ww-cursor-pointer",
|
|
1469
|
+
disabled && !isConsumed && "ww-opacity-60 ww-pointer-events-none"
|
|
1470
|
+
),
|
|
1471
|
+
children: [
|
|
1472
|
+
sel ? /* @__PURE__ */ jsx(Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }) : /* @__PURE__ */ jsx("span", { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
1473
|
+
/* @__PURE__ */ jsx("span", { className: "ww-truncate", children: opt.label })
|
|
1474
|
+
]
|
|
1475
|
+
},
|
|
1476
|
+
`${opt.value}-${i}`
|
|
1477
|
+
);
|
|
1478
|
+
}) }),
|
|
1479
|
+
mode === "list" && /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-gap-0.5 ww-max-h-[180px] ww-overflow-y-auto ww-pr-0.5", children: [
|
|
1480
|
+
filtered.length === 0 && /* @__PURE__ */ jsx("p", { className: "ww-py-3 ww-text-center ww-text-xs ww-text-muted-foreground/50", children: "No results" }),
|
|
1481
|
+
filtered.map((opt, i) => {
|
|
1482
|
+
const sel = part.selectedValue === opt.value;
|
|
1483
|
+
const faded = isConsumed && !sel;
|
|
1484
|
+
return /* @__PURE__ */ jsxs(
|
|
1485
|
+
"button",
|
|
1486
|
+
{
|
|
1487
|
+
disabled: disabled || isConsumed,
|
|
1488
|
+
onClick: () => handleClick(opt),
|
|
1489
|
+
className: cn(
|
|
1490
|
+
"ww-flex ww-items-center ww-gap-2.5 ww-rounded-xl ww-px-3 ww-py-2.5 ww-text-[13px] ww-text-left ww-transition-all ww-duration-200 ww-select-none",
|
|
1491
|
+
sel ? "ww-bg-primary ww-text-primary-foreground ww-shadow-md ww-font-semibold ww-ring-2 ww-ring-primary/20" : faded ? "ww-opacity-70 ww-text-muted-foreground ww-bg-muted/30 ww-cursor-default" : "hover:ww-bg-accent hover:ww-text-accent-foreground ww-text-foreground ww-cursor-pointer",
|
|
1492
|
+
disabled && !isConsumed && "ww-opacity-60 ww-pointer-events-none"
|
|
1493
|
+
),
|
|
1494
|
+
children: [
|
|
1495
|
+
/* @__PURE__ */ jsx(
|
|
1496
|
+
"span",
|
|
1497
|
+
{
|
|
1498
|
+
className: cn(
|
|
1499
|
+
"ww-flex ww-h-4 ww-w-4 ww-shrink-0 ww-items-center ww-justify-center ww-rounded-full ww-border ww-text-[10px]",
|
|
1500
|
+
sel ? "ww-border-background ww-bg-background/20" : "ww-border-border/50"
|
|
1501
|
+
),
|
|
1502
|
+
children: sel && /* @__PURE__ */ jsx(Check, { className: "ww-h-2.5 ww-w-2.5" })
|
|
1503
|
+
}
|
|
1504
|
+
),
|
|
1505
|
+
/* @__PURE__ */ jsx("span", { className: "ww-truncate", children: opt.label })
|
|
1506
|
+
]
|
|
1507
|
+
},
|
|
1508
|
+
`${opt.value}-${i}`
|
|
1509
|
+
);
|
|
1510
|
+
})
|
|
1511
|
+
] })
|
|
1512
|
+
]
|
|
1513
|
+
}
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
var ReactMarkdown = ReactMarkdownLib;
|
|
1517
|
+
function MarkdownContent({ text }) {
|
|
1518
|
+
return /* @__PURE__ */ jsx(
|
|
1519
|
+
ReactMarkdown,
|
|
1520
|
+
{
|
|
1521
|
+
remarkPlugins: [remarkGfm],
|
|
1522
|
+
components: {
|
|
1523
|
+
p: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "4px 0" }, children }),
|
|
1524
|
+
h1: ({ children }) => /* @__PURE__ */ jsx(
|
|
1525
|
+
"p",
|
|
1526
|
+
{
|
|
1527
|
+
style: {
|
|
1528
|
+
margin: "6px 0",
|
|
1529
|
+
fontWeight: 700,
|
|
1530
|
+
fontSize: "1em"
|
|
1531
|
+
},
|
|
1532
|
+
children
|
|
1533
|
+
}
|
|
1534
|
+
),
|
|
1535
|
+
h2: ({ children }) => /* @__PURE__ */ jsx(
|
|
1536
|
+
"p",
|
|
1537
|
+
{
|
|
1538
|
+
style: {
|
|
1539
|
+
margin: "6px 0",
|
|
1540
|
+
fontWeight: 700,
|
|
1541
|
+
fontSize: "1em"
|
|
1542
|
+
},
|
|
1543
|
+
children
|
|
1544
|
+
}
|
|
1545
|
+
),
|
|
1546
|
+
h3: ({ children }) => /* @__PURE__ */ jsx(
|
|
1547
|
+
"p",
|
|
1019
1548
|
{
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
"
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1549
|
+
style: {
|
|
1550
|
+
margin: "6px 0",
|
|
1551
|
+
fontWeight: 600,
|
|
1552
|
+
fontSize: "0.95em"
|
|
1553
|
+
},
|
|
1554
|
+
children
|
|
1555
|
+
}
|
|
1556
|
+
),
|
|
1557
|
+
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1558
|
+
ol: ({ children }) => /* @__PURE__ */ jsx("ol", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1559
|
+
li: ({ children }) => /* @__PURE__ */ jsx("li", { style: { margin: "2px 0" }, children }),
|
|
1560
|
+
strong: ({ children }) => /* @__PURE__ */ jsx("strong", { style: { fontWeight: 600 }, children }),
|
|
1561
|
+
code: ({ children }) => /* @__PURE__ */ jsx(
|
|
1562
|
+
"code",
|
|
1563
|
+
{
|
|
1564
|
+
style: {
|
|
1565
|
+
fontSize: "0.85em",
|
|
1566
|
+
backgroundColor: "rgba(0,0,0,0.07)",
|
|
1567
|
+
borderRadius: 4,
|
|
1568
|
+
padding: "1px 5px",
|
|
1569
|
+
fontFamily: "monospace"
|
|
1570
|
+
},
|
|
1571
|
+
children
|
|
1572
|
+
}
|
|
1573
|
+
),
|
|
1574
|
+
pre: ({ children }) => /* @__PURE__ */ jsx(
|
|
1575
|
+
"pre",
|
|
1576
|
+
{
|
|
1577
|
+
style: {
|
|
1578
|
+
overflowX: "auto",
|
|
1579
|
+
margin: "6px 0",
|
|
1580
|
+
padding: "8px 10px",
|
|
1581
|
+
backgroundColor: "rgba(0,0,0,0.06)",
|
|
1582
|
+
borderRadius: 8,
|
|
1583
|
+
fontSize: "0.82em",
|
|
1584
|
+
fontFamily: "monospace"
|
|
1585
|
+
},
|
|
1586
|
+
children
|
|
1587
|
+
}
|
|
1588
|
+
),
|
|
1589
|
+
a: ({
|
|
1590
|
+
href,
|
|
1591
|
+
children
|
|
1592
|
+
}) => /* @__PURE__ */ jsx(
|
|
1593
|
+
"a",
|
|
1594
|
+
{
|
|
1595
|
+
href,
|
|
1596
|
+
target: "_blank",
|
|
1597
|
+
rel: "noopener noreferrer",
|
|
1598
|
+
style: { textDecoration: "underline", opacity: 0.75 },
|
|
1599
|
+
children
|
|
1600
|
+
}
|
|
1601
|
+
),
|
|
1602
|
+
table: ({ children }) => /* @__PURE__ */ jsx(
|
|
1603
|
+
"div",
|
|
1604
|
+
{
|
|
1605
|
+
style: {
|
|
1606
|
+
overflowX: "auto",
|
|
1607
|
+
margin: "6px 0",
|
|
1608
|
+
borderRadius: 8,
|
|
1609
|
+
border: "1px solid rgba(0,0,0,0.1)"
|
|
1610
|
+
},
|
|
1611
|
+
children: /* @__PURE__ */ jsx(
|
|
1612
|
+
"table",
|
|
1613
|
+
{
|
|
1614
|
+
style: {
|
|
1615
|
+
borderCollapse: "collapse",
|
|
1616
|
+
minWidth: "100%",
|
|
1617
|
+
fontSize: "0.82em"
|
|
1618
|
+
},
|
|
1619
|
+
children
|
|
1620
|
+
}
|
|
1621
|
+
)
|
|
1622
|
+
}
|
|
1623
|
+
),
|
|
1624
|
+
thead: ({ children }) => /* @__PURE__ */ jsx("thead", { style: { backgroundColor: "rgba(0,0,0,0.04)" }, children }),
|
|
1625
|
+
tbody: ({ children }) => /* @__PURE__ */ jsx("tbody", { children }),
|
|
1626
|
+
tr: ({ children }) => /* @__PURE__ */ jsx("tr", { style: { borderBottom: "1px solid rgba(0,0,0,0.07)" }, children }),
|
|
1627
|
+
th: ({ children }) => /* @__PURE__ */ jsx(
|
|
1628
|
+
"th",
|
|
1629
|
+
{
|
|
1630
|
+
style: {
|
|
1631
|
+
padding: "6px 10px",
|
|
1632
|
+
textAlign: "left",
|
|
1633
|
+
fontWeight: 600,
|
|
1634
|
+
whiteSpace: "nowrap"
|
|
1635
|
+
},
|
|
1636
|
+
children
|
|
1637
|
+
}
|
|
1638
|
+
),
|
|
1639
|
+
td: ({ children }) => /* @__PURE__ */ jsx("td", { style: { padding: "5px 10px", verticalAlign: "top" }, children })
|
|
1640
|
+
},
|
|
1641
|
+
children: text
|
|
1642
|
+
}
|
|
1643
|
+
);
|
|
1040
1644
|
}
|
|
1645
|
+
var Avatar2 = ({
|
|
1646
|
+
style,
|
|
1647
|
+
...p
|
|
1648
|
+
}) => /* @__PURE__ */ jsx(
|
|
1649
|
+
AvatarPrimitive.Root,
|
|
1650
|
+
{
|
|
1651
|
+
style: {
|
|
1652
|
+
position: "relative",
|
|
1653
|
+
display: "flex",
|
|
1654
|
+
flexShrink: 0,
|
|
1655
|
+
overflow: "hidden",
|
|
1656
|
+
borderRadius: "9999px",
|
|
1657
|
+
...style
|
|
1658
|
+
},
|
|
1659
|
+
...p
|
|
1660
|
+
}
|
|
1661
|
+
);
|
|
1662
|
+
var AvatarImage2 = ({
|
|
1663
|
+
style,
|
|
1664
|
+
...p
|
|
1665
|
+
}) => /* @__PURE__ */ jsx(
|
|
1666
|
+
AvatarPrimitive.Image,
|
|
1667
|
+
{
|
|
1668
|
+
style: {
|
|
1669
|
+
position: "absolute",
|
|
1670
|
+
inset: 0,
|
|
1671
|
+
width: "100%",
|
|
1672
|
+
height: "100%",
|
|
1673
|
+
objectFit: "cover",
|
|
1674
|
+
...style
|
|
1675
|
+
},
|
|
1676
|
+
...p
|
|
1677
|
+
}
|
|
1678
|
+
);
|
|
1679
|
+
var AvatarFallback2 = ({
|
|
1680
|
+
style,
|
|
1681
|
+
...p
|
|
1682
|
+
}) => /* @__PURE__ */ jsx(
|
|
1683
|
+
AvatarPrimitive.Fallback,
|
|
1684
|
+
{
|
|
1685
|
+
style: {
|
|
1686
|
+
display: "flex",
|
|
1687
|
+
width: "100%",
|
|
1688
|
+
height: "100%",
|
|
1689
|
+
alignItems: "center",
|
|
1690
|
+
justifyContent: "center",
|
|
1691
|
+
borderRadius: "9999px",
|
|
1692
|
+
...style
|
|
1693
|
+
},
|
|
1694
|
+
...p
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1041
1697
|
function MessageBubble({
|
|
1042
1698
|
message,
|
|
1043
1699
|
userColor,
|
|
@@ -1051,9 +1707,15 @@ function MessageBubble({
|
|
|
1051
1707
|
const isUser = message.role === "user";
|
|
1052
1708
|
const textPart = message.parts.find((p) => p.type === "text");
|
|
1053
1709
|
const reasoningPart = message.parts.find((p) => p.type === "reasoning");
|
|
1054
|
-
const toolParts = message.parts.filter(
|
|
1055
|
-
|
|
1056
|
-
|
|
1710
|
+
const toolParts = message.parts.filter(
|
|
1711
|
+
(p) => p.type === "tool"
|
|
1712
|
+
);
|
|
1713
|
+
const pickerParts = message.parts.filter(
|
|
1714
|
+
(p) => p.type === "picker"
|
|
1715
|
+
);
|
|
1716
|
+
const planParts = message.parts.filter(
|
|
1717
|
+
(p) => p.type === "plan"
|
|
1718
|
+
);
|
|
1057
1719
|
const contrastColor = getContrastColor(userColor);
|
|
1058
1720
|
if (isUser) {
|
|
1059
1721
|
return /* @__PURE__ */ jsx("div", { className: "ww-flex ww-justify-end", children: /* @__PURE__ */ jsxs(
|
|
@@ -1062,7 +1724,13 @@ function MessageBubble({
|
|
|
1062
1724
|
className: "ww-max-w-[78%] ww-rounded-2xl ww-rounded-tr-sm ww-px-4 ww-py-2.5 ww-text-sm ww-leading-relaxed ww-flex ww-flex-col ww-gap-2",
|
|
1063
1725
|
style: { backgroundColor: userColor, color: contrastColor },
|
|
1064
1726
|
children: [
|
|
1065
|
-
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx(
|
|
1727
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx(
|
|
1728
|
+
SentAttachments,
|
|
1729
|
+
{
|
|
1730
|
+
attachments: message.attachments,
|
|
1731
|
+
contrastColor
|
|
1732
|
+
}
|
|
1733
|
+
),
|
|
1066
1734
|
textPart?.text && /* @__PURE__ */ jsx("span", { children: textPart.text })
|
|
1067
1735
|
]
|
|
1068
1736
|
}
|
|
@@ -1071,10 +1739,40 @@ function MessageBubble({
|
|
|
1071
1739
|
const visibleToolParts = showThinking ? toolParts : [];
|
|
1072
1740
|
const isEmpty = !textPart?.text && visibleToolParts.length === 0 && pickerParts.length === 0 && planParts.length === 0;
|
|
1073
1741
|
return /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start", children: [
|
|
1074
|
-
/* @__PURE__ */ jsx(
|
|
1742
|
+
/* @__PURE__ */ jsx(
|
|
1743
|
+
Avatar2,
|
|
1744
|
+
{
|
|
1745
|
+
style: {
|
|
1746
|
+
width: 28,
|
|
1747
|
+
height: 28,
|
|
1748
|
+
marginTop: 2,
|
|
1749
|
+
border: "1px solid rgba(0,0,0,0.08)"
|
|
1750
|
+
},
|
|
1751
|
+
children: profilePicture ? /* @__PURE__ */ jsx(AvatarImage2, { src: profilePicture, alt: agentName }) : /* @__PURE__ */ jsx(
|
|
1752
|
+
AvatarFallback2,
|
|
1753
|
+
{
|
|
1754
|
+
style: {
|
|
1755
|
+
fontSize: 10,
|
|
1756
|
+
fontWeight: 600,
|
|
1757
|
+
backgroundColor: "var(--primary, #19191c)",
|
|
1758
|
+
color: "var(--primary-foreground, #fff)"
|
|
1759
|
+
},
|
|
1760
|
+
children: agentName.slice(0, 2).toUpperCase()
|
|
1761
|
+
}
|
|
1762
|
+
)
|
|
1763
|
+
}
|
|
1764
|
+
),
|
|
1075
1765
|
/* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-gap-1.5 ww-min-w-0 ww-max-w-[82%]", children: [
|
|
1076
1766
|
showThinking && reasoningPart && /* @__PURE__ */ jsx(ReasoningBlock, { text: reasoningPart.text }),
|
|
1077
|
-
planParts.map((p) => /* @__PURE__ */ jsx(
|
|
1767
|
+
planParts.map((p) => /* @__PURE__ */ jsx(
|
|
1768
|
+
PlanCard,
|
|
1769
|
+
{
|
|
1770
|
+
part: p,
|
|
1771
|
+
onSend,
|
|
1772
|
+
disabled: isStreaming
|
|
1773
|
+
},
|
|
1774
|
+
p.planId
|
|
1775
|
+
)),
|
|
1078
1776
|
visibleToolParts.map((t) => /* @__PURE__ */ jsx(ToolCallBadge, { part: t }, t.toolCallId)),
|
|
1079
1777
|
pickerParts.map((p) => /* @__PURE__ */ jsx(
|
|
1080
1778
|
PickerSelector,
|
|
@@ -1087,40 +1785,39 @@ function MessageBubble({
|
|
|
1087
1785
|
p.pickerId
|
|
1088
1786
|
)),
|
|
1089
1787
|
isEmpty && isStreaming ? /* @__PURE__ */ jsx(ThinkingDots, {}) : textPart?.text ? /* @__PURE__ */ jsxs("div", { className: "ww-rounded-2xl ww-rounded-tl-sm ww-bg-muted ww-px-4 ww-py-2.5 ww-text-sm ww-leading-relaxed ww-overflow-hidden ww-prose ww-prose-sm ww-max-w-none prose-p:ww-my-1 prose-headings:ww-font-semibold prose-headings:ww-my-1.5 prose-ul:ww-my-1 prose-li:ww-my-0.5 prose-strong:ww-font-semibold", children: [
|
|
1090
|
-
/* @__PURE__ */ jsx(
|
|
1091
|
-
ReactMarkdown,
|
|
1092
|
-
{
|
|
1093
|
-
remarkPlugins: [remarkGfm],
|
|
1094
|
-
components: {
|
|
1095
|
-
p: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "4px 0" }, children }),
|
|
1096
|
-
h1: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "6px 0", fontWeight: 700, fontSize: "1em" }, children }),
|
|
1097
|
-
h2: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "6px 0", fontWeight: 700, fontSize: "1em" }, children }),
|
|
1098
|
-
h3: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "6px 0", fontWeight: 600, fontSize: "0.95em" }, children }),
|
|
1099
|
-
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1100
|
-
ol: ({ children }) => /* @__PURE__ */ jsx("ol", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1101
|
-
li: ({ children }) => /* @__PURE__ */ jsx("li", { style: { margin: "2px 0" }, children }),
|
|
1102
|
-
strong: ({ children }) => /* @__PURE__ */ jsx("strong", { style: { fontWeight: 600 }, children }),
|
|
1103
|
-
code: ({ children }) => /* @__PURE__ */ jsx("code", { style: { fontSize: "0.85em", backgroundColor: "rgba(0,0,0,0.07)", borderRadius: 4, padding: "1px 5px", fontFamily: "monospace" }, children }),
|
|
1104
|
-
pre: ({ children }) => /* @__PURE__ */ jsx("pre", { style: { overflowX: "auto", margin: "6px 0", padding: "8px 10px", backgroundColor: "rgba(0,0,0,0.06)", borderRadius: 8, fontSize: "0.82em", fontFamily: "monospace" }, children }),
|
|
1105
|
-
a: ({ href, children }) => /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "underline", opacity: 0.75 }, children }),
|
|
1106
|
-
table: ({ children }) => /* @__PURE__ */ jsx("div", { style: { overflowX: "auto", margin: "6px 0", borderRadius: 8, border: "1px solid rgba(0,0,0,0.1)" }, children: /* @__PURE__ */ jsx("table", { style: { borderCollapse: "collapse", minWidth: "100%", fontSize: "0.82em" }, children }) }),
|
|
1107
|
-
thead: ({ children }) => /* @__PURE__ */ jsx("thead", { style: { backgroundColor: "rgba(0,0,0,0.04)" }, children }),
|
|
1108
|
-
tbody: ({ children }) => /* @__PURE__ */ jsx("tbody", { children }),
|
|
1109
|
-
tr: ({ children }) => /* @__PURE__ */ jsx("tr", { style: { borderBottom: "1px solid rgba(0,0,0,0.07)" }, children }),
|
|
1110
|
-
th: ({ children }) => /* @__PURE__ */ jsx("th", { style: { padding: "6px 10px", textAlign: "left", fontWeight: 600, whiteSpace: "nowrap" }, children }),
|
|
1111
|
-
td: ({ children }) => /* @__PURE__ */ jsx("td", { style: { padding: "5px 10px", verticalAlign: "top" }, children })
|
|
1112
|
-
},
|
|
1113
|
-
children: textPart.text
|
|
1114
|
-
}
|
|
1115
|
-
),
|
|
1788
|
+
/* @__PURE__ */ jsx(MarkdownContent, { text: textPart.text }),
|
|
1116
1789
|
isStreaming && /* @__PURE__ */ jsx("span", { className: "ww-inline-block ww-w-0.5 ww-h-3.5 ww-bg-foreground/60 ww-ml-0.5 ww-animate-pulse ww-align-middle" })
|
|
1117
1790
|
] }) : null
|
|
1118
1791
|
] })
|
|
1119
1792
|
] });
|
|
1120
1793
|
}
|
|
1121
|
-
var Avatar3 = ({
|
|
1794
|
+
var Avatar3 = ({
|
|
1795
|
+
className,
|
|
1796
|
+
...p
|
|
1797
|
+
}) => /* @__PURE__ */ jsx(
|
|
1798
|
+
AvatarPrimitive.Root,
|
|
1799
|
+
{
|
|
1800
|
+
className: [
|
|
1801
|
+
"ww-relative ww-flex ww-h-10 ww-w-10 ww-shrink-0 ww-overflow-hidden ww-rounded-full",
|
|
1802
|
+
className
|
|
1803
|
+
].filter(Boolean).join(" "),
|
|
1804
|
+
...p
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1122
1807
|
var AvatarImage3 = AvatarPrimitive.Image;
|
|
1123
|
-
var AvatarFallback3 = ({
|
|
1808
|
+
var AvatarFallback3 = ({
|
|
1809
|
+
className,
|
|
1810
|
+
...p
|
|
1811
|
+
}) => /* @__PURE__ */ jsx(
|
|
1812
|
+
AvatarPrimitive.Fallback,
|
|
1813
|
+
{
|
|
1814
|
+
className: [
|
|
1815
|
+
"ww-flex ww-h-full ww-w-full ww-items-center ww-justify-center ww-rounded-full ww-bg-muted",
|
|
1816
|
+
className
|
|
1817
|
+
].filter(Boolean).join(" "),
|
|
1818
|
+
...p
|
|
1819
|
+
}
|
|
1820
|
+
);
|
|
1124
1821
|
function ChatMessages({
|
|
1125
1822
|
messages,
|
|
1126
1823
|
streaming,
|
|
@@ -1134,14 +1831,15 @@ function ChatMessages({
|
|
|
1134
1831
|
onPickerSelect
|
|
1135
1832
|
}) {
|
|
1136
1833
|
const bottomRef = useRef(null);
|
|
1834
|
+
const greetText = initialMessages[0];
|
|
1137
1835
|
const showGreeting = messages.length === 0;
|
|
1138
1836
|
useEffect(() => {
|
|
1139
1837
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1140
1838
|
}, [messages, streaming]);
|
|
1141
1839
|
return /* @__PURE__ */ jsxs("div", { className: "ww-flex-1 ww-flex ww-flex-col ww-overflow-y-auto ww-overscroll-contain", children: [
|
|
1142
|
-
showGreeting && /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start ww-px-4 ww-pt-5", children: [
|
|
1840
|
+
showGreeting && greetText && /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start ww-px-4 ww-pt-5", children: [
|
|
1143
1841
|
/* @__PURE__ */ jsx(Avatar3, { className: "ww-h-7 ww-w-7 ww-shrink-0 ww-mt-0.5 ww-border", children: profilePicture ? /* @__PURE__ */ jsx(AvatarImage3, { src: profilePicture, alt: agentName }) : /* @__PURE__ */ jsx(AvatarFallback3, { className: "ww-text-[10px] ww-font-semibold ww-bg-primary ww-text-primary-foreground", children: agentName.slice(0, 2).toUpperCase() }) }),
|
|
1144
|
-
/* @__PURE__ */ jsx("div", { className: "ww-rounded-2xl ww-rounded-tl-sm ww-bg-muted ww-px-4 ww-py-2.5 ww-text-sm ww-leading-relaxed ww-max-w-[82%]", children:
|
|
1842
|
+
/* @__PURE__ */ jsx("div", { className: "ww-rounded-2xl ww-rounded-tl-sm ww-bg-muted ww-px-4 ww-py-2.5 ww-text-sm ww-leading-relaxed ww-max-w-[82%]", children: greetText })
|
|
1145
1843
|
] }),
|
|
1146
1844
|
showGreeting && /* @__PURE__ */ jsx("div", { className: "ww-flex-1" }),
|
|
1147
1845
|
/* @__PURE__ */ jsx("div", { className: "ww-flex ww-flex-col ww-gap-4 ww-px-4 ww-py-4", children: messages.map((msg, i) => /* @__PURE__ */ jsx(
|
|
@@ -1170,7 +1868,13 @@ function ChatMessages({
|
|
|
1170
1868
|
"div",
|
|
1171
1869
|
{
|
|
1172
1870
|
className: "ww-bg-muted",
|
|
1173
|
-
style: {
|
|
1871
|
+
style: {
|
|
1872
|
+
display: "inline-flex",
|
|
1873
|
+
alignItems: "center",
|
|
1874
|
+
gap: 6,
|
|
1875
|
+
borderRadius: "18px 18px 18px 4px",
|
|
1876
|
+
padding: "13px 18px"
|
|
1877
|
+
},
|
|
1174
1878
|
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
|
|
1175
1879
|
"span",
|
|
1176
1880
|
{
|
|
@@ -1254,7 +1958,13 @@ function ChatInput({
|
|
|
1254
1958
|
}
|
|
1255
1959
|
),
|
|
1256
1960
|
/* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-rounded-2xl ww-border ww-bg-background ww-shadow-sm focus-within:ww-ring-1 focus-within:ww-ring-ring/40 ww-transition-shadow", children: [
|
|
1257
|
-
hasAttachments && attachments && attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "ww-px-2 ww-pt-2", children: /* @__PURE__ */ jsx(
|
|
1961
|
+
hasAttachments && attachments && attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "ww-px-2 ww-pt-2", children: /* @__PURE__ */ jsx(
|
|
1962
|
+
AttachmentChips,
|
|
1963
|
+
{
|
|
1964
|
+
attachments,
|
|
1965
|
+
onRemove: (id) => onRemoveAttachment?.(id)
|
|
1966
|
+
}
|
|
1967
|
+
) }),
|
|
1258
1968
|
hasAttachments && /* @__PURE__ */ jsx(
|
|
1259
1969
|
"input",
|
|
1260
1970
|
{
|
|
@@ -1344,7 +2054,10 @@ function ChatInput({
|
|
|
1344
2054
|
"ww-h-7 ww-w-7 ww-shrink-0 ww-rounded-xl ww-flex ww-items-center ww-justify-center ww-transition-all ww-duration-200",
|
|
1345
2055
|
hasText || streaming ? "ww-opacity-100 ww-shadow-sm" : "ww-opacity-30"
|
|
1346
2056
|
),
|
|
1347
|
-
style: hasText || streaming ? {
|
|
2057
|
+
style: hasText || streaming ? {
|
|
2058
|
+
backgroundColor: accentColor,
|
|
2059
|
+
color: getContrastColor(accentColor)
|
|
2060
|
+
} : { backgroundColor: "transparent", color: "currentColor" },
|
|
1348
2061
|
children: streaming ? /* @__PURE__ */ jsx(Loader2, { className: "ww-h-3.5 ww-w-3.5 ww-animate-spin" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "ww-h-3.5 ww-w-3.5" })
|
|
1349
2062
|
}
|
|
1350
2063
|
)
|
|
@@ -1352,6 +2065,126 @@ function ChatInput({
|
|
|
1352
2065
|
] })
|
|
1353
2066
|
] });
|
|
1354
2067
|
}
|
|
2068
|
+
function CustomControlBar({ onClose }) {
|
|
2069
|
+
const { localParticipant, isMicrophoneEnabled } = useLocalParticipant();
|
|
2070
|
+
const room = useRoomContext();
|
|
2071
|
+
const toggleMic = async () => {
|
|
2072
|
+
if (isMicrophoneEnabled) {
|
|
2073
|
+
await localParticipant.setMicrophoneEnabled(false);
|
|
2074
|
+
} else {
|
|
2075
|
+
await localParticipant.setMicrophoneEnabled(true);
|
|
2076
|
+
}
|
|
2077
|
+
};
|
|
2078
|
+
const disconnect = () => {
|
|
2079
|
+
room.disconnect();
|
|
2080
|
+
onClose();
|
|
2081
|
+
};
|
|
2082
|
+
return /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-items-center ww-justify-center ww-gap-6", children: [
|
|
2083
|
+
/* @__PURE__ */ jsx(
|
|
2084
|
+
"button",
|
|
2085
|
+
{
|
|
2086
|
+
onClick: toggleMic,
|
|
2087
|
+
className: `ww-flex ww-items-center ww-justify-center ww-h-16 ww-w-16 ww-rounded-full ww-transition-all ww-duration-300 ${isMicrophoneEnabled ? "ww-bg-foreground/5 hover:ww-bg-foreground/10 ww-text-foreground" : "ww-bg-foreground/20 hover:ww-bg-foreground/30 ww-text-foreground"}`,
|
|
2088
|
+
title: isMicrophoneEnabled ? "Silenciar micr\xF3fono" : "Activar micr\xF3fono",
|
|
2089
|
+
children: isMicrophoneEnabled ? /* @__PURE__ */ jsx(Mic, { className: "ww-w-6 ww-h-6" }) : /* @__PURE__ */ jsx(MicOff, { className: "ww-w-6 ww-h-6" })
|
|
2090
|
+
}
|
|
2091
|
+
),
|
|
2092
|
+
/* @__PURE__ */ jsx(
|
|
2093
|
+
"button",
|
|
2094
|
+
{
|
|
2095
|
+
onClick: disconnect,
|
|
2096
|
+
className: "ww-flex ww-items-center ww-justify-center ww-h-16 ww-w-16 ww-rounded-full ww-text-white ww-transition-all ww-duration-300 ww-shadow-lg hover:ww-shadow-xl hover:-ww-translate-y-1",
|
|
2097
|
+
style: { backgroundColor: "#ef4444" },
|
|
2098
|
+
title: "Desconectar",
|
|
2099
|
+
children: /* @__PURE__ */ jsx(PhoneOff, { className: "ww-w-6 ww-h-6" })
|
|
2100
|
+
}
|
|
2101
|
+
)
|
|
2102
|
+
] });
|
|
2103
|
+
}
|
|
2104
|
+
function ChatGPTOrb() {
|
|
2105
|
+
const { state, audioTrack } = useVoiceAssistant();
|
|
2106
|
+
const isSpeaking = state === "speaking";
|
|
2107
|
+
const isListening = state === "listening";
|
|
2108
|
+
const getGradient = () => {
|
|
2109
|
+
if (isSpeaking) {
|
|
2110
|
+
return "linear-gradient(135deg, rgba(59, 130, 246, 0.9), rgba(147, 51, 234, 0.9))";
|
|
2111
|
+
} else if (isListening) {
|
|
2112
|
+
return "linear-gradient(135deg, rgba(16, 185, 129, 0.85), rgba(20, 184, 166, 0.85))";
|
|
2113
|
+
}
|
|
2114
|
+
return "linear-gradient(135deg, rgba(25, 25, 28, 0.8), rgba(25, 25, 28, 0.95))";
|
|
2115
|
+
};
|
|
2116
|
+
const getGlow = () => {
|
|
2117
|
+
if (isSpeaking) return "ww-bg-purple-500/30 ww-animate-ping";
|
|
2118
|
+
if (isListening) return "ww-bg-emerald-500/20 ww-animate-pulse";
|
|
2119
|
+
return "ww-bg-transparent ww-scale-90";
|
|
2120
|
+
};
|
|
2121
|
+
const getRing = () => {
|
|
2122
|
+
if (isSpeaking) return "ww-bg-purple-500/20 ww-scale-110";
|
|
2123
|
+
if (isListening) return "ww-bg-emerald-500/10 ww-scale-105";
|
|
2124
|
+
return "ww-bg-foreground/5 ww-scale-100";
|
|
2125
|
+
};
|
|
2126
|
+
return /* @__PURE__ */ jsxs("div", { className: "ww-relative ww-w-48 ww-h-48 ww-flex ww-items-center ww-justify-center", children: [
|
|
2127
|
+
/* @__PURE__ */ jsx(
|
|
2128
|
+
"div",
|
|
2129
|
+
{
|
|
2130
|
+
className: `ww-absolute ww-inset-0 ww-rounded-full ww-transition-all ww-duration-1000 ${getGlow()}`
|
|
2131
|
+
}
|
|
2132
|
+
),
|
|
2133
|
+
/* @__PURE__ */ jsx(
|
|
2134
|
+
"div",
|
|
2135
|
+
{
|
|
2136
|
+
className: `ww-absolute ww-inset-4 ww-rounded-full ww-transition-all ww-duration-500 ${getRing()}`
|
|
2137
|
+
}
|
|
2138
|
+
),
|
|
2139
|
+
/* @__PURE__ */ jsx(
|
|
2140
|
+
"div",
|
|
2141
|
+
{
|
|
2142
|
+
className: "ww-absolute ww-inset-8 ww-rounded-full ww-shadow-2xl ww-transition-all ww-duration-700 ww-flex ww-items-center ww-justify-center ww-overflow-hidden",
|
|
2143
|
+
style: {
|
|
2144
|
+
background: getGradient(),
|
|
2145
|
+
transform: isSpeaking ? "scale(1.05)" : "scale(1)"
|
|
2146
|
+
},
|
|
2147
|
+
children: /* @__PURE__ */ jsx("div", { className: "ww-opacity-90 ww-flex ww-items-center ww-justify-center ww-w-full ww-h-full", children: /* @__PURE__ */ jsx(
|
|
2148
|
+
BarVisualizer,
|
|
2149
|
+
{
|
|
2150
|
+
state,
|
|
2151
|
+
barCount: 5,
|
|
2152
|
+
trackRef: audioTrack,
|
|
2153
|
+
options: { minHeight: 6 },
|
|
2154
|
+
style: { color: "rgba(255, 255, 255, 0.95)" }
|
|
2155
|
+
}
|
|
2156
|
+
) })
|
|
2157
|
+
}
|
|
2158
|
+
)
|
|
2159
|
+
] });
|
|
2160
|
+
}
|
|
2161
|
+
function AssistantVisualizer({ onClose }) {
|
|
2162
|
+
const { state } = useVoiceAssistant();
|
|
2163
|
+
return /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-items-center ww-justify-center ww-h-full ww-w-full", children: [
|
|
2164
|
+
/* @__PURE__ */ jsx("div", { className: "ww-flex-1 ww-flex ww-items-center ww-justify-center", children: /* @__PURE__ */ jsx(ChatGPTOrb, {}) }),
|
|
2165
|
+
/* @__PURE__ */ jsxs("div", { className: "ww-h-40 ww-flex ww-flex-col ww-items-center ww-justify-center ww-gap-8 ww-mb-12", children: [
|
|
2166
|
+
/* @__PURE__ */ jsx("div", { className: "ww-text-sm ww-font-medium ww-tracking-wide ww-text-foreground/60 ww-uppercase", children: state === "connecting" || state === "initializing" ? "Conectando..." : state === "listening" ? "Escuchando..." : state === "speaking" ? "Hablando..." : "Listo" }),
|
|
2167
|
+
/* @__PURE__ */ jsx(CustomControlBar, { onClose })
|
|
2168
|
+
] })
|
|
2169
|
+
] });
|
|
2170
|
+
}
|
|
2171
|
+
function VoiceOverlay({ token, serverUrl, onClose }) {
|
|
2172
|
+
return /* @__PURE__ */ jsx("div", { className: "ww-absolute ww-inset-0 ww-z-[100] ww-flex ww-flex-col ww-bg-background/95 ww-backdrop-blur-xl", children: /* @__PURE__ */ jsxs(
|
|
2173
|
+
LiveKitRoom,
|
|
2174
|
+
{
|
|
2175
|
+
token,
|
|
2176
|
+
serverUrl,
|
|
2177
|
+
connect: true,
|
|
2178
|
+
audio: true,
|
|
2179
|
+
video: false,
|
|
2180
|
+
className: "ww-flex-1",
|
|
2181
|
+
children: [
|
|
2182
|
+
/* @__PURE__ */ jsx(RoomAudioRenderer, {}),
|
|
2183
|
+
/* @__PURE__ */ jsx(AssistantVisualizer, { onClose })
|
|
2184
|
+
]
|
|
2185
|
+
}
|
|
2186
|
+
) });
|
|
2187
|
+
}
|
|
1355
2188
|
function ChatWidget({
|
|
1356
2189
|
agentId,
|
|
1357
2190
|
workspaceId,
|
|
@@ -1383,9 +2216,21 @@ function ChatWidget({
|
|
|
1383
2216
|
onReset,
|
|
1384
2217
|
onExpand,
|
|
1385
2218
|
expanded,
|
|
1386
|
-
embedded = false
|
|
2219
|
+
embedded = false,
|
|
2220
|
+
envId,
|
|
2221
|
+
onDebugTrace
|
|
1387
2222
|
}) {
|
|
1388
|
-
const chat = useChat({
|
|
2223
|
+
const chat = useChat({
|
|
2224
|
+
agentId,
|
|
2225
|
+
workspaceId,
|
|
2226
|
+
envId,
|
|
2227
|
+
source,
|
|
2228
|
+
userContext,
|
|
2229
|
+
persist,
|
|
2230
|
+
onNavigate,
|
|
2231
|
+
playgroundOverrides,
|
|
2232
|
+
customBackend
|
|
2233
|
+
});
|
|
1389
2234
|
const voice = useVoice({
|
|
1390
2235
|
agentId,
|
|
1391
2236
|
onTranscript: (text) => {
|
|
@@ -1397,29 +2242,47 @@ function ChatWidget({
|
|
|
1397
2242
|
}
|
|
1398
2243
|
});
|
|
1399
2244
|
const attachmentHook = useAttachments({ agentId });
|
|
2245
|
+
const debugTraceLenRef = useRef(0);
|
|
2246
|
+
useEffect(() => {
|
|
2247
|
+
if (!onDebugTrace || chat.debugTraces.length <= debugTraceLenRef.current)
|
|
2248
|
+
return;
|
|
2249
|
+
for (let i = debugTraceLenRef.current; i < chat.debugTraces.length; i++) {
|
|
2250
|
+
onDebugTrace(chat.debugTraces[i]);
|
|
2251
|
+
}
|
|
2252
|
+
debugTraceLenRef.current = chat.debugTraces.length;
|
|
2253
|
+
}, [chat.debugTraces, onDebugTrace]);
|
|
1400
2254
|
const [isDragOver, setIsDragOver] = useState(false);
|
|
1401
|
-
const handleDragOver = useCallback(
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
2255
|
+
const handleDragOver = useCallback(
|
|
2256
|
+
(e) => {
|
|
2257
|
+
if (!enableAttachments) return;
|
|
2258
|
+
e.preventDefault();
|
|
2259
|
+
e.stopPropagation();
|
|
2260
|
+
if (e.dataTransfer.types.includes("Files")) setIsDragOver(true);
|
|
2261
|
+
},
|
|
2262
|
+
[enableAttachments]
|
|
2263
|
+
);
|
|
2264
|
+
const handleDragLeave = useCallback(
|
|
2265
|
+
(e) => {
|
|
2266
|
+
if (!enableAttachments) return;
|
|
2267
|
+
e.preventDefault();
|
|
2268
|
+
e.stopPropagation();
|
|
2269
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
2270
|
+
setIsDragOver(false);
|
|
2271
|
+
}
|
|
2272
|
+
},
|
|
2273
|
+
[enableAttachments]
|
|
2274
|
+
);
|
|
2275
|
+
const handleDrop = useCallback(
|
|
2276
|
+
(e) => {
|
|
2277
|
+
if (!enableAttachments) return;
|
|
2278
|
+
e.preventDefault();
|
|
2279
|
+
e.stopPropagation();
|
|
1412
2280
|
setIsDragOver(false);
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
e.stopPropagation();
|
|
1419
|
-
setIsDragOver(false);
|
|
1420
|
-
const files = e.dataTransfer.files;
|
|
1421
|
-
if (files.length > 0) attachmentHook.attach(files);
|
|
1422
|
-
}, [enableAttachments, attachmentHook]);
|
|
2281
|
+
const files = e.dataTransfer.files;
|
|
2282
|
+
if (files.length > 0) attachmentHook.attach(files);
|
|
2283
|
+
},
|
|
2284
|
+
[enableAttachments, attachmentHook]
|
|
2285
|
+
);
|
|
1423
2286
|
const handleSend = () => {
|
|
1424
2287
|
const payloads = attachmentHook.readyPayloads;
|
|
1425
2288
|
if (payloads.length > 0) {
|
|
@@ -1461,7 +2324,7 @@ function ChatWidget({
|
|
|
1461
2324
|
"div",
|
|
1462
2325
|
{
|
|
1463
2326
|
className: cn(
|
|
1464
|
-
"wallavi-widget ww-flex ww-flex-col ww-overflow-hidden ww-bg-background ww-h-full ww-relative",
|
|
2327
|
+
"wallavi-widget ww-flex ww-flex-col ww-overflow-hidden ww-bg-background ww-h-full ww-relative ww-overscroll-none",
|
|
1465
2328
|
!embedded && "ww-rounded-2xl ww-border ww-shadow-xl",
|
|
1466
2329
|
isDragOver && "ww-ring-2 ww-ring-inset ww-ring-primary/60",
|
|
1467
2330
|
className
|
|
@@ -1487,7 +2350,18 @@ function ChatWidget({
|
|
|
1487
2350
|
onReset: handleReset,
|
|
1488
2351
|
onClose: hideCloseButton ? void 0 : onClose,
|
|
1489
2352
|
onExpand,
|
|
1490
|
-
expanded
|
|
2353
|
+
expanded,
|
|
2354
|
+
onCall: enableVoice && chat.voiceCall ? () => chat.voiceCall?.start() : void 0,
|
|
2355
|
+
isCallLoading: chat.voiceCall?.loading
|
|
2356
|
+
}
|
|
2357
|
+
),
|
|
2358
|
+
chat.voiceCall?.active && chat.voiceCall.token && chat.voiceCall.serverUrl && /* @__PURE__ */ jsx(
|
|
2359
|
+
VoiceOverlay,
|
|
2360
|
+
{
|
|
2361
|
+
token: chat.voiceCall.token,
|
|
2362
|
+
serverUrl: chat.voiceCall.serverUrl,
|
|
2363
|
+
onClose: chat.voiceCall.stop,
|
|
2364
|
+
accentColor: userMessageColor
|
|
1491
2365
|
}
|
|
1492
2366
|
),
|
|
1493
2367
|
customBackend?.mode === "human" && /* @__PURE__ */ jsxs(
|
|
@@ -1524,22 +2398,91 @@ function ChatWidget({
|
|
|
1524
2398
|
{
|
|
1525
2399
|
onClick: () => void customBackend.footerAction.onClick(),
|
|
1526
2400
|
disabled: customBackend.footerAction.loading,
|
|
1527
|
-
style: customBackend.footerAction.icon === "human" ? {
|
|
2401
|
+
style: customBackend.footerAction.icon === "human" ? {
|
|
2402
|
+
backgroundColor: userMessageColor,
|
|
2403
|
+
color: "#ffffff",
|
|
2404
|
+
boxShadow: `0 2px 12px ${userMessageColor}55`
|
|
2405
|
+
} : {
|
|
2406
|
+
borderColor: `${userMessageColor}35`,
|
|
2407
|
+
backgroundColor: `${userMessageColor}0d`,
|
|
2408
|
+
color: userMessageColor
|
|
2409
|
+
},
|
|
1528
2410
|
className: [
|
|
1529
2411
|
"ww-w-full ww-flex ww-items-center ww-gap-2 ww-rounded-full ww-px-3.5 ww-py-1.5 ww-text-xs ww-font-semibold ww-transition-all",
|
|
1530
2412
|
"hover:ww-opacity-85 active:ww-scale-[0.98] disabled:ww-opacity-50 disabled:ww-pointer-events-none",
|
|
1531
2413
|
customBackend.footerAction.icon === "human" ? "" : "ww-border"
|
|
1532
2414
|
].join(" "),
|
|
1533
2415
|
children: [
|
|
1534
|
-
customBackend.footerAction.loading ? /* @__PURE__ */ jsxs(
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
2416
|
+
customBackend.footerAction.loading ? /* @__PURE__ */ jsxs(
|
|
2417
|
+
"svg",
|
|
2418
|
+
{
|
|
2419
|
+
className: "ww-animate-spin ww-w-3.5 ww-h-3.5 ww-shrink-0",
|
|
2420
|
+
viewBox: "0 0 24 24",
|
|
2421
|
+
fill: "none",
|
|
2422
|
+
children: [
|
|
2423
|
+
/* @__PURE__ */ jsx(
|
|
2424
|
+
"circle",
|
|
2425
|
+
{
|
|
2426
|
+
className: "ww-opacity-25",
|
|
2427
|
+
cx: "12",
|
|
2428
|
+
cy: "12",
|
|
2429
|
+
r: "10",
|
|
2430
|
+
stroke: "currentColor",
|
|
2431
|
+
strokeWidth: "3"
|
|
2432
|
+
}
|
|
2433
|
+
),
|
|
2434
|
+
/* @__PURE__ */ jsx(
|
|
2435
|
+
"path",
|
|
2436
|
+
{
|
|
2437
|
+
className: "ww-opacity-75",
|
|
2438
|
+
fill: "currentColor",
|
|
2439
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
2440
|
+
}
|
|
2441
|
+
)
|
|
2442
|
+
]
|
|
2443
|
+
}
|
|
2444
|
+
) : customBackend.footerAction.icon === "ai" ? /* @__PURE__ */ jsx(
|
|
2445
|
+
"svg",
|
|
2446
|
+
{
|
|
2447
|
+
className: "ww-w-3.5 ww-h-3.5 ww-shrink-0",
|
|
2448
|
+
viewBox: "0 0 24 24",
|
|
2449
|
+
fill: "none",
|
|
2450
|
+
stroke: "currentColor",
|
|
2451
|
+
strokeWidth: "2",
|
|
2452
|
+
strokeLinecap: "round",
|
|
2453
|
+
strokeLinejoin: "round",
|
|
2454
|
+
children: /* @__PURE__ */ jsx("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" })
|
|
2455
|
+
}
|
|
2456
|
+
) : /* @__PURE__ */ jsxs(
|
|
2457
|
+
"svg",
|
|
2458
|
+
{
|
|
2459
|
+
className: "ww-w-3.5 ww-h-3.5 ww-shrink-0",
|
|
2460
|
+
viewBox: "0 0 24 24",
|
|
2461
|
+
fill: "none",
|
|
2462
|
+
stroke: "currentColor",
|
|
2463
|
+
strokeWidth: "2",
|
|
2464
|
+
strokeLinecap: "round",
|
|
2465
|
+
strokeLinejoin: "round",
|
|
2466
|
+
children: [
|
|
2467
|
+
/* @__PURE__ */ jsx("path", { d: "M3 18v-6a9 9 0 0 1 18 0v6" }),
|
|
2468
|
+
/* @__PURE__ */ jsx("path", { d: "M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z" })
|
|
2469
|
+
]
|
|
2470
|
+
}
|
|
2471
|
+
),
|
|
1541
2472
|
/* @__PURE__ */ jsx("span", { className: "ww-flex-1 ww-text-left ww-truncate", children: customBackend.footerAction.label }),
|
|
1542
|
-
/* @__PURE__ */ jsx(
|
|
2473
|
+
/* @__PURE__ */ jsx(
|
|
2474
|
+
"svg",
|
|
2475
|
+
{
|
|
2476
|
+
className: "ww-shrink-0 ww-w-3 ww-h-3 ww-opacity-60",
|
|
2477
|
+
viewBox: "0 0 24 24",
|
|
2478
|
+
fill: "none",
|
|
2479
|
+
stroke: "currentColor",
|
|
2480
|
+
strokeWidth: "2.5",
|
|
2481
|
+
strokeLinecap: "round",
|
|
2482
|
+
strokeLinejoin: "round",
|
|
2483
|
+
children: /* @__PURE__ */ jsx("path", { d: "M9 18l6-6-6-6" })
|
|
2484
|
+
}
|
|
2485
|
+
)
|
|
1543
2486
|
]
|
|
1544
2487
|
}
|
|
1545
2488
|
) }),
|
|
@@ -1567,7 +2510,7 @@ function ChatWidget({
|
|
|
1567
2510
|
} : {}
|
|
1568
2511
|
}
|
|
1569
2512
|
),
|
|
1570
|
-
watermark && /* @__PURE__ */ jsxs("footer", { className: "ww-shrink-0 ww-flex ww-items-center ww-justify-center ww-gap-1.5 ww-bg-muted/50 ww-py-1.5 ww-border-t", children: [
|
|
2513
|
+
watermark && /* @__PURE__ */ jsxs("footer", { className: "ww-shrink-0 ww-flex ww-items-center ww-justify-center ww-gap-1.5 ww-bg-muted/50 ww-py-1.5 ww-border-t ww-touch-none", children: [
|
|
1571
2514
|
/* @__PURE__ */ jsxs(
|
|
1572
2515
|
"a",
|
|
1573
2516
|
{
|
|
@@ -1617,19 +2560,27 @@ function useAutoConfig(agentId, enabled) {
|
|
|
1617
2560
|
if (cancelled) return;
|
|
1618
2561
|
const cfg = body?.data ?? {};
|
|
1619
2562
|
const remote = {};
|
|
1620
|
-
if (cfg.profilePicture != null)
|
|
1621
|
-
|
|
2563
|
+
if (cfg.profilePicture != null)
|
|
2564
|
+
remote.profilePicture = cfg.profilePicture;
|
|
2565
|
+
if (cfg.displayName != null)
|
|
2566
|
+
remote.displayName = cfg.displayName;
|
|
1622
2567
|
if (cfg.theme) remote.theme = cfg.theme;
|
|
1623
|
-
if (cfg.userMessageColor)
|
|
2568
|
+
if (cfg.userMessageColor)
|
|
2569
|
+
remote.userMessageColor = cfg.userMessageColor;
|
|
1624
2570
|
if (Array.isArray(cfg.initialMessages) && cfg.initialMessages.length > 0)
|
|
1625
2571
|
remote.initialMessages = cfg.initialMessages;
|
|
1626
2572
|
if (Array.isArray(cfg.suggestedMessages))
|
|
1627
2573
|
remote.suggestedMessages = cfg.suggestedMessages;
|
|
1628
|
-
if (cfg.messagePlaceholder != null)
|
|
2574
|
+
if (cfg.messagePlaceholder != null)
|
|
2575
|
+
remote.messagePlaceholder = cfg.messagePlaceholder;
|
|
1629
2576
|
if (cfg.watermark != null) remote.watermark = cfg.watermark;
|
|
1630
2577
|
if (cfg.footer != null) remote.footer = cfg.footer;
|
|
1631
|
-
if (cfg.showThinking != null)
|
|
1632
|
-
|
|
2578
|
+
if (cfg.showThinking != null)
|
|
2579
|
+
remote.showThinking = cfg.showThinking;
|
|
2580
|
+
if (cfg.regenerateMessage != null)
|
|
2581
|
+
remote.regenerateMessage = cfg.regenerateMessage;
|
|
2582
|
+
if (cfg.enableVoice != null)
|
|
2583
|
+
remote.enableVoice = cfg.enableVoice;
|
|
1633
2584
|
setResult({
|
|
1634
2585
|
remoteConfig: remote,
|
|
1635
2586
|
bubbleIconUrl: cfg.chatIcon || cfg.profilePicture || void 0,
|
|
@@ -1667,63 +2618,102 @@ function useSupportChat({
|
|
|
1667
2618
|
const enabled = Boolean(inboxToken) && inboxToken !== "__disabled__";
|
|
1668
2619
|
const STORAGE_KEY = `wlv_support_${inboxToken}`;
|
|
1669
2620
|
const base = apiBase.replace(/\/$/, "");
|
|
1670
|
-
const [session, setSession] = useState(
|
|
2621
|
+
const [session, setSession] = useState(() => {
|
|
2622
|
+
if (typeof window === "undefined") return null;
|
|
2623
|
+
try {
|
|
2624
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
2625
|
+
if (saved)
|
|
2626
|
+
return JSON.parse(saved).session ?? null;
|
|
2627
|
+
} catch {
|
|
2628
|
+
}
|
|
2629
|
+
return null;
|
|
2630
|
+
});
|
|
1671
2631
|
const [rawMessages, setRawMessages] = useState([]);
|
|
1672
2632
|
const [sending, setSending] = useState(false);
|
|
1673
|
-
const [isAiMode, setIsAiMode] = useState(
|
|
2633
|
+
const [isAiMode, setIsAiMode] = useState(() => {
|
|
2634
|
+
if (typeof window === "undefined") return false;
|
|
2635
|
+
try {
|
|
2636
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
2637
|
+
if (saved)
|
|
2638
|
+
return JSON.parse(saved).isAiMode ?? false;
|
|
2639
|
+
} catch {
|
|
2640
|
+
}
|
|
2641
|
+
return false;
|
|
2642
|
+
});
|
|
1674
2643
|
const [agentTyping, setAgentTyping] = useState(false);
|
|
1675
2644
|
const [requestingHuman, setRequestingHuman] = useState(false);
|
|
1676
2645
|
const [returningToAi, setReturningToAi] = useState(false);
|
|
2646
|
+
const [voiceActive, setVoiceActive] = useState(false);
|
|
2647
|
+
const [voiceToken, setVoiceToken] = useState(null);
|
|
2648
|
+
const [voiceServerUrl, setVoiceServerUrl] = useState(null);
|
|
2649
|
+
const [voiceLoading, setVoiceLoading] = useState(false);
|
|
2650
|
+
const [voiceError, setVoiceError] = useState(null);
|
|
1677
2651
|
const typingTimerRef = useRef(null);
|
|
1678
2652
|
useEffect(() => {
|
|
1679
2653
|
if (!enabled) return;
|
|
1680
2654
|
try {
|
|
1681
2655
|
const saved = localStorage.getItem(STORAGE_KEY);
|
|
1682
|
-
if (saved)
|
|
1683
|
-
const { session: s, isAiMode: ai } = JSON.parse(saved);
|
|
1684
|
-
setSession(s);
|
|
1685
|
-
setIsAiMode(ai ?? false);
|
|
1686
|
-
}
|
|
2656
|
+
if (saved) JSON.parse(saved);
|
|
1687
2657
|
} catch {
|
|
1688
2658
|
localStorage.removeItem(STORAGE_KEY);
|
|
2659
|
+
setSession(null);
|
|
2660
|
+
setIsAiMode(false);
|
|
1689
2661
|
}
|
|
1690
2662
|
}, [STORAGE_KEY, enabled]);
|
|
1691
|
-
const loadMessages = useCallback(
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
2663
|
+
const loadMessages = useCallback(
|
|
2664
|
+
async (sess) => {
|
|
2665
|
+
try {
|
|
2666
|
+
const res = await fetch(
|
|
2667
|
+
`${base}/api/support-chat/${sess.conversationId}/messages`,
|
|
2668
|
+
{
|
|
2669
|
+
headers: { "x-visitor-token": sess.visitorToken }
|
|
2670
|
+
}
|
|
2671
|
+
);
|
|
2672
|
+
const data = await res.json();
|
|
2673
|
+
if (Array.isArray(data.data)) setRawMessages(data.data);
|
|
2674
|
+
} catch {
|
|
2675
|
+
}
|
|
2676
|
+
},
|
|
2677
|
+
[base]
|
|
2678
|
+
);
|
|
1701
2679
|
useEffect(() => {
|
|
1702
2680
|
if (!enabled || !session) return;
|
|
1703
2681
|
void loadMessages(session);
|
|
1704
2682
|
let ablyClient = null;
|
|
1705
2683
|
const setupAbly = async () => {
|
|
1706
2684
|
try {
|
|
1707
|
-
const res = await fetch(
|
|
1708
|
-
|
|
1709
|
-
|
|
2685
|
+
const res = await fetch(
|
|
2686
|
+
`${base}/api/support-chat/${session.conversationId}/ably-token`,
|
|
2687
|
+
{
|
|
2688
|
+
headers: { "x-visitor-token": session.visitorToken }
|
|
2689
|
+
}
|
|
2690
|
+
);
|
|
1710
2691
|
if (!res.ok) return;
|
|
1711
2692
|
const { tokenRequest, channel: channelName } = await res.json();
|
|
1712
2693
|
const AblyLib = (await import('ably')).default;
|
|
1713
|
-
ablyClient = new AblyLib.Realtime({
|
|
2694
|
+
ablyClient = new AblyLib.Realtime({
|
|
2695
|
+
authCallback: (_, cb) => cb(null, tokenRequest)
|
|
2696
|
+
});
|
|
1714
2697
|
const ch = ablyClient.channels.get(channelName);
|
|
1715
2698
|
ch.subscribe((msg) => {
|
|
1716
2699
|
const event = { type: msg.name, ...msg.data };
|
|
1717
2700
|
if (event.type === "message.created" && event.message) {
|
|
1718
2701
|
setRawMessages((prev) => {
|
|
1719
|
-
if (prev.some((m) => m.id === event.message.id))
|
|
1720
|
-
|
|
2702
|
+
if (prev.some((m) => m.id === event.message.id))
|
|
2703
|
+
return prev;
|
|
2704
|
+
return [
|
|
2705
|
+
...prev.filter((m) => !m.id.startsWith("tmp_")),
|
|
2706
|
+
event.message
|
|
2707
|
+
];
|
|
1721
2708
|
});
|
|
1722
2709
|
} else if (event.type === "agent.typing") {
|
|
1723
2710
|
setAgentTyping(!!event.isTyping);
|
|
1724
2711
|
if (event.isTyping) {
|
|
1725
2712
|
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
1726
|
-
typingTimerRef.current = setTimeout(
|
|
2713
|
+
typingTimerRef.current = setTimeout(
|
|
2714
|
+
() => setAgentTyping(false),
|
|
2715
|
+
6e3
|
|
2716
|
+
);
|
|
1727
2717
|
} else {
|
|
1728
2718
|
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
1729
2719
|
}
|
|
@@ -1731,7 +2721,11 @@ function useSupportChat({
|
|
|
1731
2721
|
const newIsAi = event.mode === "auto";
|
|
1732
2722
|
setIsAiMode(newIsAi);
|
|
1733
2723
|
setSession((s) => {
|
|
1734
|
-
if (s)
|
|
2724
|
+
if (s)
|
|
2725
|
+
localStorage.setItem(
|
|
2726
|
+
STORAGE_KEY,
|
|
2727
|
+
JSON.stringify({ session: s, isAiMode: newIsAi })
|
|
2728
|
+
);
|
|
1735
2729
|
return s;
|
|
1736
2730
|
});
|
|
1737
2731
|
}
|
|
@@ -1742,84 +2736,117 @@ function useSupportChat({
|
|
|
1742
2736
|
void setupAbly();
|
|
1743
2737
|
const pollId = setInterval(() => void loadMessages(session), 3e4);
|
|
1744
2738
|
return () => {
|
|
1745
|
-
if (ablyClient)
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
2739
|
+
if (ablyClient)
|
|
2740
|
+
try {
|
|
2741
|
+
ablyClient.close();
|
|
2742
|
+
} catch {
|
|
2743
|
+
}
|
|
1749
2744
|
clearInterval(pollId);
|
|
1750
2745
|
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
1751
2746
|
};
|
|
1752
2747
|
}, [session, STORAGE_KEY, base, loadMessages]);
|
|
1753
|
-
const send = useCallback(
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
attachments
|
|
1766
|
-
})
|
|
1767
|
-
});
|
|
1768
|
-
const data = await res.json();
|
|
1769
|
-
if (data.data) {
|
|
1770
|
-
const sess = {
|
|
1771
|
-
conversationId: data.data.conversationId,
|
|
1772
|
-
visitorToken: data.data.visitorToken
|
|
1773
|
-
};
|
|
1774
|
-
const ai = data.data.isAiMode ?? false;
|
|
1775
|
-
localStorage.setItem(STORAGE_KEY, JSON.stringify({ session: sess, isAiMode: ai }));
|
|
1776
|
-
setSession(sess);
|
|
1777
|
-
setIsAiMode(ai);
|
|
1778
|
-
if (Array.isArray(data.data.messages)) {
|
|
1779
|
-
setRawMessages(data.data.messages);
|
|
2748
|
+
const send = useCallback(
|
|
2749
|
+
async (text, attachments) => {
|
|
2750
|
+
if (!text.trim() && !attachments?.length) return;
|
|
2751
|
+
if (sending) return;
|
|
2752
|
+
setSending(true);
|
|
2753
|
+
if (!session) {
|
|
2754
|
+
setRawMessages([
|
|
2755
|
+
{
|
|
2756
|
+
id: `tmp_${Date.now()}`,
|
|
2757
|
+
role: "customer",
|
|
2758
|
+
content: text || `[${attachments?.length ?? 0} archivo(s)]`,
|
|
2759
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2760
|
+
metadata: attachments?.length ? { attachments } : void 0
|
|
1780
2761
|
}
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
}]);
|
|
1792
|
-
try {
|
|
1793
|
-
const body = { content: text };
|
|
1794
|
-
if (attachments?.length) body.attachments = attachments;
|
|
1795
|
-
const res = await fetch(`${base}/api/support-chat/${session.conversationId}/messages`, {
|
|
1796
|
-
method: "POST",
|
|
1797
|
-
headers: { "Content-Type": "application/json", "x-visitor-token": session.visitorToken },
|
|
1798
|
-
body: JSON.stringify(body)
|
|
1799
|
-
});
|
|
1800
|
-
const data = await res.json();
|
|
1801
|
-
if (data.data?.aiReply) {
|
|
1802
|
-
setRawMessages((prev) => {
|
|
1803
|
-
const withoutTemp = prev.filter((m) => !m.id.startsWith("tmp_"));
|
|
1804
|
-
return [...withoutTemp, data.data.aiReply];
|
|
2762
|
+
]);
|
|
2763
|
+
try {
|
|
2764
|
+
const res = await fetch(`${base}/api/support-chat/start`, {
|
|
2765
|
+
method: "POST",
|
|
2766
|
+
headers: { "Content-Type": "application/json" },
|
|
2767
|
+
body: JSON.stringify({
|
|
2768
|
+
inboxToken,
|
|
2769
|
+
message: text || `[${attachments.length} archivo(s)]`,
|
|
2770
|
+
attachments
|
|
2771
|
+
})
|
|
1805
2772
|
});
|
|
2773
|
+
const data = await res.json();
|
|
2774
|
+
if (data.data) {
|
|
2775
|
+
const sess = {
|
|
2776
|
+
conversationId: data.data.conversationId,
|
|
2777
|
+
visitorToken: data.data.visitorToken
|
|
2778
|
+
};
|
|
2779
|
+
const ai = data.data.isAiMode ?? false;
|
|
2780
|
+
localStorage.setItem(
|
|
2781
|
+
STORAGE_KEY,
|
|
2782
|
+
JSON.stringify({ session: sess, isAiMode: ai })
|
|
2783
|
+
);
|
|
2784
|
+
setSession(sess);
|
|
2785
|
+
setIsAiMode(ai);
|
|
2786
|
+
if (Array.isArray(data.data.messages)) {
|
|
2787
|
+
setRawMessages(data.data.messages);
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
} catch {
|
|
2791
|
+
}
|
|
2792
|
+
} else {
|
|
2793
|
+
setRawMessages((prev) => [
|
|
2794
|
+
...prev,
|
|
2795
|
+
{
|
|
2796
|
+
id: `tmp_${Date.now()}`,
|
|
2797
|
+
role: "customer",
|
|
2798
|
+
content: text || `[${attachments.length} archivo(s)]`,
|
|
2799
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2800
|
+
metadata: attachments?.length ? { attachments } : void 0
|
|
2801
|
+
}
|
|
2802
|
+
]);
|
|
2803
|
+
try {
|
|
2804
|
+
const body = { content: text };
|
|
2805
|
+
if (attachments?.length) body.attachments = attachments;
|
|
2806
|
+
const res = await fetch(
|
|
2807
|
+
`${base}/api/support-chat/${session.conversationId}/messages`,
|
|
2808
|
+
{
|
|
2809
|
+
method: "POST",
|
|
2810
|
+
headers: {
|
|
2811
|
+
"Content-Type": "application/json",
|
|
2812
|
+
"x-visitor-token": session.visitorToken
|
|
2813
|
+
},
|
|
2814
|
+
body: JSON.stringify(body)
|
|
2815
|
+
}
|
|
2816
|
+
);
|
|
2817
|
+
const data = await res.json();
|
|
2818
|
+
if (data.data?.aiReply) {
|
|
2819
|
+
setRawMessages((prev) => {
|
|
2820
|
+
const withoutTemp = prev.filter((m) => !m.id.startsWith("tmp_"));
|
|
2821
|
+
if (withoutTemp.some((m) => m.id === data.data.aiReply.id))
|
|
2822
|
+
return withoutTemp;
|
|
2823
|
+
return [...withoutTemp, data.data.aiReply];
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
} catch {
|
|
1806
2827
|
}
|
|
1807
|
-
} catch {
|
|
1808
2828
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
2829
|
+
setSending(false);
|
|
2830
|
+
},
|
|
2831
|
+
[session, sending, inboxToken, base, STORAGE_KEY]
|
|
2832
|
+
);
|
|
1812
2833
|
const requestHuman = useCallback(async () => {
|
|
1813
2834
|
if (!session || !isAiMode || requestingHuman) return;
|
|
1814
2835
|
setRequestingHuman(true);
|
|
1815
2836
|
try {
|
|
1816
2837
|
await fetch(`${base}/api/support-chat/${session.conversationId}/mode`, {
|
|
1817
2838
|
method: "PATCH",
|
|
1818
|
-
headers: {
|
|
2839
|
+
headers: {
|
|
2840
|
+
"Content-Type": "application/json",
|
|
2841
|
+
"x-visitor-token": session.visitorToken
|
|
2842
|
+
},
|
|
1819
2843
|
body: JSON.stringify({ mode: "human" })
|
|
1820
2844
|
});
|
|
1821
2845
|
setIsAiMode(false);
|
|
1822
|
-
localStorage.setItem(
|
|
2846
|
+
localStorage.setItem(
|
|
2847
|
+
STORAGE_KEY,
|
|
2848
|
+
JSON.stringify({ session, isAiMode: false })
|
|
2849
|
+
);
|
|
1823
2850
|
} catch {
|
|
1824
2851
|
}
|
|
1825
2852
|
setRequestingHuman(false);
|
|
@@ -1830,15 +2857,47 @@ function useSupportChat({
|
|
|
1830
2857
|
try {
|
|
1831
2858
|
await fetch(`${base}/api/support-chat/${session.conversationId}/mode`, {
|
|
1832
2859
|
method: "PATCH",
|
|
1833
|
-
headers: {
|
|
2860
|
+
headers: {
|
|
2861
|
+
"Content-Type": "application/json",
|
|
2862
|
+
"x-visitor-token": session.visitorToken
|
|
2863
|
+
},
|
|
1834
2864
|
body: JSON.stringify({ mode: "auto" })
|
|
1835
2865
|
});
|
|
1836
2866
|
setIsAiMode(true);
|
|
1837
|
-
localStorage.setItem(
|
|
2867
|
+
localStorage.setItem(
|
|
2868
|
+
STORAGE_KEY,
|
|
2869
|
+
JSON.stringify({ session, isAiMode: true })
|
|
2870
|
+
);
|
|
1838
2871
|
} catch {
|
|
1839
2872
|
}
|
|
1840
2873
|
setReturningToAi(false);
|
|
1841
2874
|
}, [session, isAiMode, returningToAi, base, STORAGE_KEY]);
|
|
2875
|
+
const startVoiceCall = useCallback(async () => {
|
|
2876
|
+
if (!session || !isAiMode) return;
|
|
2877
|
+
setVoiceLoading(true);
|
|
2878
|
+
setVoiceError(null);
|
|
2879
|
+
try {
|
|
2880
|
+
const res = await fetch(
|
|
2881
|
+
`${base}/api/support-chat/${session.conversationId}/livekit-token`,
|
|
2882
|
+
{
|
|
2883
|
+
headers: { "x-visitor-token": session.visitorToken }
|
|
2884
|
+
}
|
|
2885
|
+
);
|
|
2886
|
+
const data = await res.json();
|
|
2887
|
+
if (!res.ok) throw new Error(data.error || "Failed to start call");
|
|
2888
|
+
setVoiceToken(data.token);
|
|
2889
|
+
setVoiceServerUrl(data.url);
|
|
2890
|
+
setVoiceActive(true);
|
|
2891
|
+
} catch (err) {
|
|
2892
|
+
setVoiceError(err.message);
|
|
2893
|
+
}
|
|
2894
|
+
setVoiceLoading(false);
|
|
2895
|
+
}, [session, isAiMode, base]);
|
|
2896
|
+
const stopVoiceCall = useCallback(() => {
|
|
2897
|
+
setVoiceActive(false);
|
|
2898
|
+
setVoiceToken(null);
|
|
2899
|
+
setVoiceServerUrl(null);
|
|
2900
|
+
}, []);
|
|
1842
2901
|
const reset = useCallback(() => {
|
|
1843
2902
|
localStorage.removeItem(STORAGE_KEY);
|
|
1844
2903
|
setSession(null);
|
|
@@ -1847,28 +2906,78 @@ function useSupportChat({
|
|
|
1847
2906
|
setAgentTyping(false);
|
|
1848
2907
|
setRequestingHuman(false);
|
|
1849
2908
|
setReturningToAi(false);
|
|
1850
|
-
|
|
2909
|
+
stopVoiceCall();
|
|
2910
|
+
}, [STORAGE_KEY, stopVoiceCall]);
|
|
1851
2911
|
const messages = useMemo(
|
|
1852
2912
|
() => rawMessages.filter((m) => m.role !== "system").map(toWidgetMsg),
|
|
1853
2913
|
[rawMessages]
|
|
1854
2914
|
);
|
|
1855
2915
|
const footerAction = useMemo(() => {
|
|
1856
2916
|
if (isAiMode) {
|
|
1857
|
-
return {
|
|
2917
|
+
return {
|
|
2918
|
+
label: requestHumanLabel,
|
|
2919
|
+
sublabel: "Te conectamos con un agente disponible",
|
|
2920
|
+
icon: "human",
|
|
2921
|
+
onClick: requestHuman,
|
|
2922
|
+
loading: requestingHuman
|
|
2923
|
+
};
|
|
1858
2924
|
}
|
|
1859
2925
|
if (!isAiMode && session && returnToAiLabel) {
|
|
1860
|
-
return {
|
|
2926
|
+
return {
|
|
2927
|
+
label: returnToAiLabel,
|
|
2928
|
+
sublabel: "Respuesta instant\xE1nea con inteligencia artificial",
|
|
2929
|
+
icon: "ai",
|
|
2930
|
+
onClick: returnToAi,
|
|
2931
|
+
loading: returningToAi
|
|
2932
|
+
};
|
|
1861
2933
|
}
|
|
1862
2934
|
return void 0;
|
|
1863
|
-
}, [
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
2935
|
+
}, [
|
|
2936
|
+
isAiMode,
|
|
2937
|
+
session,
|
|
2938
|
+
requestHumanLabel,
|
|
2939
|
+
requestHuman,
|
|
2940
|
+
requestingHuman,
|
|
2941
|
+
returnToAiLabel,
|
|
2942
|
+
returnToAi,
|
|
2943
|
+
returningToAi
|
|
2944
|
+
]);
|
|
2945
|
+
return useMemo(
|
|
2946
|
+
() => ({
|
|
2947
|
+
messages,
|
|
2948
|
+
streaming: sending || agentTyping,
|
|
2949
|
+
send,
|
|
2950
|
+
reset,
|
|
2951
|
+
mode: isAiMode || !session ? "ai" : "human",
|
|
2952
|
+
...footerAction ? { footerAction } : {},
|
|
2953
|
+
voiceCall: isAiMode && session ? {
|
|
2954
|
+
active: voiceActive,
|
|
2955
|
+
token: voiceToken,
|
|
2956
|
+
serverUrl: voiceServerUrl,
|
|
2957
|
+
start: startVoiceCall,
|
|
2958
|
+
stop: stopVoiceCall,
|
|
2959
|
+
loading: voiceLoading,
|
|
2960
|
+
error: voiceError
|
|
2961
|
+
} : void 0
|
|
2962
|
+
}),
|
|
2963
|
+
[
|
|
2964
|
+
messages,
|
|
2965
|
+
sending,
|
|
2966
|
+
agentTyping,
|
|
2967
|
+
send,
|
|
2968
|
+
reset,
|
|
2969
|
+
isAiMode,
|
|
2970
|
+
footerAction,
|
|
2971
|
+
voiceActive,
|
|
2972
|
+
voiceToken,
|
|
2973
|
+
voiceServerUrl,
|
|
2974
|
+
startVoiceCall,
|
|
2975
|
+
stopVoiceCall,
|
|
2976
|
+
voiceLoading,
|
|
2977
|
+
voiceError,
|
|
2978
|
+
session
|
|
2979
|
+
]
|
|
2980
|
+
);
|
|
1872
2981
|
}
|
|
1873
2982
|
var KEY_EXPANDED = "wallavi_bubble_expanded";
|
|
1874
2983
|
var KEY_DISMISSED = "wallavi_bubble_dismissed";
|
|
@@ -1895,50 +3004,62 @@ function BubbleWidget({
|
|
|
1895
3004
|
...chatProps
|
|
1896
3005
|
}) {
|
|
1897
3006
|
const supportBackend = useSupportChat(
|
|
1898
|
-
inboxToken ? {
|
|
3007
|
+
inboxToken ? {
|
|
3008
|
+
inboxToken,
|
|
3009
|
+
apiBase: supportApiBase,
|
|
3010
|
+
requestHumanLabel,
|
|
3011
|
+
returnToAiLabel
|
|
3012
|
+
} : { inboxToken: "__disabled__", apiBase: supportApiBase }
|
|
1899
3013
|
);
|
|
1900
3014
|
const isControlled = isOpenProp !== void 0;
|
|
1901
3015
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
1902
3016
|
const open = isControlled ? isOpenProp : internalOpen;
|
|
1903
|
-
const setOpen = useCallback(
|
|
1904
|
-
|
|
1905
|
-
if (
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
3017
|
+
const setOpen = useCallback(
|
|
3018
|
+
(valueOrUpdater) => {
|
|
3019
|
+
if (!isControlled) {
|
|
3020
|
+
if (typeof valueOrUpdater === "function") {
|
|
3021
|
+
setInternalOpen((prev) => {
|
|
3022
|
+
const next = valueOrUpdater(prev);
|
|
3023
|
+
onOpenChange?.(next);
|
|
3024
|
+
return next;
|
|
3025
|
+
});
|
|
3026
|
+
} else {
|
|
3027
|
+
setInternalOpen(valueOrUpdater);
|
|
3028
|
+
onOpenChange?.(valueOrUpdater);
|
|
3029
|
+
}
|
|
1911
3030
|
} else {
|
|
1912
|
-
|
|
1913
|
-
onOpenChange?.(
|
|
3031
|
+
const next = typeof valueOrUpdater === "function" ? valueOrUpdater(open) : valueOrUpdater;
|
|
3032
|
+
onOpenChange?.(next);
|
|
1914
3033
|
}
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
}
|
|
1919
|
-
}, [isControlled, open, onOpenChange]);
|
|
3034
|
+
},
|
|
3035
|
+
[isControlled, open, onOpenChange]
|
|
3036
|
+
);
|
|
1920
3037
|
const [expanded, setExpanded] = useState(false);
|
|
1921
3038
|
const panelRef = useRef(null);
|
|
1922
3039
|
const autoOpenedRef = useRef(false);
|
|
1923
3040
|
useEffect(() => {
|
|
1924
3041
|
if (localStorage.getItem(KEY_EXPANDED) === "true") setExpanded(true);
|
|
1925
3042
|
}, []);
|
|
1926
|
-
const remote = useAutoConfig(
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
const
|
|
1931
|
-
const
|
|
1932
|
-
const
|
|
1933
|
-
const
|
|
3043
|
+
const remote = useAutoConfig(
|
|
3044
|
+
inboxToken ? "" : chatProps.agentId ?? "",
|
|
3045
|
+
!inboxToken && autoConfig
|
|
3046
|
+
);
|
|
3047
|
+
const resolvedPosition = remote.position ?? positionProp;
|
|
3048
|
+
const resolvedBubbleIcon = remote.bubbleIconUrl ?? bubbleIconUrlProp;
|
|
3049
|
+
const resolvedAutoOpen = remote.autoOpen || autoOpenProp;
|
|
3050
|
+
const resolvedKeyboardShortcut = remote.keyboardShortcut || keyboardShortcutProp;
|
|
3051
|
+
const resolvedBubbleSize = remote.bubbleSize ?? bubbleSizeProp;
|
|
3052
|
+
const resolvedWidth = remote.panelWidth ?? widthProp;
|
|
3053
|
+
const resolvedHeight = remote.panelHeight ?? heightProp;
|
|
1934
3054
|
const definedChatProps = Object.fromEntries(
|
|
1935
3055
|
Object.entries(chatProps).filter(([, v]) => v !== void 0)
|
|
1936
3056
|
);
|
|
1937
3057
|
const mergedConfig = {
|
|
1938
|
-
...remote.remoteConfig,
|
|
1939
3058
|
...definedChatProps,
|
|
3059
|
+
...remote.remoteConfig,
|
|
1940
3060
|
agentId: chatProps.agentId ?? "",
|
|
1941
|
-
agentName: chatProps.agentName ?? ""
|
|
3061
|
+
agentName: remote.remoteConfig.agentName ?? chatProps.agentName ?? "Asistente",
|
|
3062
|
+
source: chatProps.source ?? remote.remoteConfig.source ?? "web"
|
|
1942
3063
|
};
|
|
1943
3064
|
const setOpenRef = useRef(setOpen);
|
|
1944
3065
|
useEffect(() => {
|
|
@@ -1955,7 +3076,7 @@ function BubbleWidget({
|
|
|
1955
3076
|
useEffect(() => {
|
|
1956
3077
|
if (!resolvedKeyboardShortcut) return;
|
|
1957
3078
|
const onKey = (e) => {
|
|
1958
|
-
if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
|
|
3079
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === shortcutKey.toLowerCase()) {
|
|
1959
3080
|
e.preventDefault();
|
|
1960
3081
|
setOpenRef.current((v) => !v);
|
|
1961
3082
|
}
|
|
@@ -1974,7 +3095,10 @@ function BubbleWidget({
|
|
|
1974
3095
|
const handleClose = () => {
|
|
1975
3096
|
setOpen(false);
|
|
1976
3097
|
if (!isControlled) {
|
|
1977
|
-
localStorage.setItem(
|
|
3098
|
+
localStorage.setItem(
|
|
3099
|
+
KEY_DISMISSED,
|
|
3100
|
+
String(Date.now() + 24 * 60 * 60 * 1e3)
|
|
3101
|
+
);
|
|
1978
3102
|
}
|
|
1979
3103
|
};
|
|
1980
3104
|
const toggleExpanded = () => setExpanded((v) => {
|
|
@@ -1983,7 +3107,10 @@ function BubbleWidget({
|
|
|
1983
3107
|
return next;
|
|
1984
3108
|
});
|
|
1985
3109
|
const isLeft = resolvedPosition === "bottom-left";
|
|
1986
|
-
const panelWidth = expanded ? Math.min(
|
|
3110
|
+
const panelWidth = expanded ? Math.min(
|
|
3111
|
+
expandedWidth,
|
|
3112
|
+
typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth
|
|
3113
|
+
) : resolvedWidth;
|
|
1987
3114
|
const panelHeight = expanded ? expandedHeight : resolvedHeight;
|
|
1988
3115
|
return /* @__PURE__ */ jsxs(
|
|
1989
3116
|
"div",
|
|
@@ -2041,15 +3168,20 @@ function BubbleWidget({
|
|
|
2041
3168
|
alignItems: "center",
|
|
2042
3169
|
justifyContent: "center",
|
|
2043
3170
|
transition: "transform 0.2s ease, box-shadow 0.2s ease",
|
|
2044
|
-
background: open ? "
|
|
2045
|
-
color: open ? "
|
|
3171
|
+
background: open ? "#19191c" : "#ffffff",
|
|
3172
|
+
color: open ? "#ffffff" : "#19191c"
|
|
2046
3173
|
},
|
|
2047
3174
|
children: open ? /* @__PURE__ */ jsx(X, { style: { width: 20, height: 20 } }) : resolvedBubbleIcon ? /* @__PURE__ */ jsx(
|
|
2048
3175
|
"img",
|
|
2049
3176
|
{
|
|
2050
3177
|
src: resolvedBubbleIcon,
|
|
2051
3178
|
alt: "",
|
|
2052
|
-
style: {
|
|
3179
|
+
style: {
|
|
3180
|
+
width: "100%",
|
|
3181
|
+
height: "100%",
|
|
3182
|
+
objectFit: "cover",
|
|
3183
|
+
display: "block"
|
|
3184
|
+
}
|
|
2053
3185
|
}
|
|
2054
3186
|
) : /* @__PURE__ */ jsx(DefaultIcon, {})
|
|
2055
3187
|
}
|
|
@@ -2059,4 +3191,4 @@ function BubbleWidget({
|
|
|
2059
3191
|
);
|
|
2060
3192
|
}
|
|
2061
3193
|
|
|
2062
|
-
export { BubbleWidget, ChatWidget, formatToolName, getContrastColor, useAttachments, useChat, useSupportChat, useVoice };
|
|
3194
|
+
export { BubbleWidget, ChatWidget, PlanCard, ReasoningBlock, ToolCallBadge, formatToolName, getContrastColor, useAttachments, useChat, useSupportChat, useVoice };
|