@wallavi/widget 1.6.8 → 1.7.1
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 +152 -6
- package/dist/index.d.ts +152 -6
- package/dist/index.js +1923 -436
- package/dist/index.mjs +1921 -438
- package/dist/styles.css +1 -0
- package/package.json +12 -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\\.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\\.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-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-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-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-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-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-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 cursor: pointer;\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.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.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,26 +65,229 @@ 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();
|
|
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
|
+
}
|
|
69
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,
|
|
81
285
|
onNavigate,
|
|
82
|
-
playgroundOverrides
|
|
286
|
+
playgroundOverrides,
|
|
287
|
+
customBackend
|
|
83
288
|
}) {
|
|
84
|
-
const
|
|
289
|
+
const userId = userContext?.userId;
|
|
290
|
+
const persistKey = persist ? userId ? `wallavi_${agentId}_${userId}` : `wallavi_${agentId}` : null;
|
|
85
291
|
const onNavigateRef = useRef(onNavigate);
|
|
86
292
|
useEffect(() => {
|
|
87
293
|
onNavigateRef.current = onNavigate;
|
|
@@ -105,46 +311,237 @@ function useChat({
|
|
|
105
311
|
return crypto.randomUUID();
|
|
106
312
|
});
|
|
107
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
|
+
});
|
|
108
427
|
useEffect(() => {
|
|
109
|
-
if (!persistKey) return;
|
|
428
|
+
if (customBackend || !persistKey) return;
|
|
110
429
|
try {
|
|
111
430
|
sessionStorage.setItem(`${persistKey}_msgs`, JSON.stringify(messages));
|
|
112
431
|
} catch {
|
|
113
432
|
}
|
|
114
|
-
}, [persistKey, messages]);
|
|
433
|
+
}, [customBackend, persistKey, messages]);
|
|
115
434
|
useEffect(() => {
|
|
116
|
-
if (!persistKey) return;
|
|
435
|
+
if (customBackend || !persistKey) return;
|
|
117
436
|
try {
|
|
118
437
|
localStorage.setItem(`${persistKey}_tid`, threadId);
|
|
119
438
|
} catch {
|
|
120
439
|
}
|
|
121
|
-
}, [persistKey, threadId]);
|
|
440
|
+
}, [customBackend, persistKey, threadId]);
|
|
122
441
|
useEffect(() => {
|
|
123
|
-
if (!persistKey || typeof window === "undefined") return;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
})).filter((m) => m.parts.length > 0);
|
|
138
|
-
if (restored.length > 0) setMessages(restored);
|
|
139
|
-
} catch {
|
|
442
|
+
if (customBackend || !persistKey || typeof window === "undefined") return;
|
|
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
|
+
}
|
|
140
456
|
}
|
|
141
|
-
}
|
|
142
|
-
|
|
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]);
|
|
143
539
|
const reset = useCallback(() => {
|
|
144
540
|
setMessages([]);
|
|
145
541
|
setInput("");
|
|
146
542
|
setStreaming(false);
|
|
147
543
|
setThreadId(crypto.randomUUID());
|
|
544
|
+
setDebugTraces([]);
|
|
148
545
|
streamingMsgIdRef.current = null;
|
|
149
546
|
if (persistKey) {
|
|
150
547
|
try {
|
|
@@ -155,146 +552,19 @@ function useChat({
|
|
|
155
552
|
}
|
|
156
553
|
}
|
|
157
554
|
}, [persistKey]);
|
|
158
|
-
const applyStreamEvent = useCallback((proto, msgId) => {
|
|
159
|
-
if (proto.type === "navigate") {
|
|
160
|
-
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
setMessages((prev) => {
|
|
164
|
-
const idx = prev.findIndex((m) => m.id === msgId);
|
|
165
|
-
if (idx === -1) return prev;
|
|
166
|
-
const existing = prev[idx];
|
|
167
|
-
const msg = { id: existing.id, role: existing.role, parts: [...existing.parts] };
|
|
168
|
-
switch (proto.type) {
|
|
169
|
-
case "text-delta": {
|
|
170
|
-
const textIdx = msg.parts.findIndex((p) => p.type === "text");
|
|
171
|
-
if (textIdx === -1) {
|
|
172
|
-
msg.parts.push({ type: "text", text: proto.delta });
|
|
173
|
-
} else {
|
|
174
|
-
const p = msg.parts[textIdx];
|
|
175
|
-
msg.parts[textIdx] = { type: "text", text: p.text + proto.delta };
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
case "reasoning-delta": {
|
|
180
|
-
const rIdx = msg.parts.findIndex((p) => p.type === "reasoning");
|
|
181
|
-
if (rIdx === -1) {
|
|
182
|
-
msg.parts.unshift({ type: "reasoning", text: proto.delta });
|
|
183
|
-
} else {
|
|
184
|
-
const p = msg.parts[rIdx];
|
|
185
|
-
msg.parts[rIdx] = { type: "reasoning", text: p.text + proto.delta };
|
|
186
|
-
}
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case "tool-input-available": {
|
|
190
|
-
msg.parts.push({
|
|
191
|
-
type: "tool",
|
|
192
|
-
toolCallId: proto.toolCallId,
|
|
193
|
-
toolName: proto.toolName,
|
|
194
|
-
input: proto.input ?? {},
|
|
195
|
-
status: "running"
|
|
196
|
-
});
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
case "tool-output-available": {
|
|
200
|
-
const tIdx = msg.parts.findIndex(
|
|
201
|
-
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
202
|
-
);
|
|
203
|
-
if (tIdx !== -1) {
|
|
204
|
-
msg.parts[tIdx] = { ...msg.parts[tIdx], status: "done", output: proto.output };
|
|
205
|
-
}
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
case "tool-output-error": {
|
|
209
|
-
const tIdx = msg.parts.findIndex(
|
|
210
|
-
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
211
|
-
);
|
|
212
|
-
if (tIdx !== -1) {
|
|
213
|
-
msg.parts[tIdx] = { ...msg.parts[tIdx], status: "error", errorText: proto.errorText };
|
|
214
|
-
}
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
case "picker": {
|
|
218
|
-
msg.parts.push({
|
|
219
|
-
type: "picker",
|
|
220
|
-
pickerId: proto.pickerId,
|
|
221
|
-
paramName: proto.paramName,
|
|
222
|
-
toolName: proto.toolName,
|
|
223
|
-
label: proto.label,
|
|
224
|
-
options: proto.options
|
|
225
|
-
});
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
case "plan-created": {
|
|
229
|
-
msg.parts.push({
|
|
230
|
-
type: "plan",
|
|
231
|
-
planId: proto.planId,
|
|
232
|
-
goal: proto.goal,
|
|
233
|
-
steps: proto.steps.map((s) => ({ ...s, status: "pending" }))
|
|
234
|
-
});
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
case "plan-step-update": {
|
|
238
|
-
const pIdx = msg.parts.findIndex(
|
|
239
|
-
(p) => p.type === "plan" && p.planId === proto.planId
|
|
240
|
-
);
|
|
241
|
-
if (pIdx !== -1) {
|
|
242
|
-
const prev2 = msg.parts[pIdx];
|
|
243
|
-
msg.parts[pIdx] = {
|
|
244
|
-
...prev2,
|
|
245
|
-
steps: prev2.steps.map(
|
|
246
|
-
(s) => s.index === proto.stepIndex ? { ...s, status: proto.status, ...proto.error ? { error: proto.error } : {} } : s
|
|
247
|
-
)
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
const copy = [...prev];
|
|
254
|
-
copy[idx] = msg;
|
|
255
|
-
return copy;
|
|
256
|
-
});
|
|
257
|
-
}, []);
|
|
258
|
-
const fetchAndStream = useCallback(async (opts) => {
|
|
259
|
-
const { input: userInput, msgId, extraMetadata, attachments } = opts;
|
|
260
|
-
const isPrivate = Boolean(workspaceId);
|
|
261
|
-
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
262
|
-
const url = isPrivate ? `${API_URL}/api/threads/${threadId}/stream` : `${API_URL}/api/chat/stream`;
|
|
263
|
-
const res = await fetch(url, {
|
|
264
|
-
method: "POST",
|
|
265
|
-
headers: {
|
|
266
|
-
"Content-Type": "application/json",
|
|
267
|
-
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
268
|
-
},
|
|
269
|
-
body: JSON.stringify({
|
|
270
|
-
input: userInput,
|
|
271
|
-
agentId,
|
|
272
|
-
...isPrivate ? { workspaceId, ...playgroundOverrides ? { playgroundOverrides } : {} } : { threadId },
|
|
273
|
-
source,
|
|
274
|
-
...attachments?.length ? { attachments } : {},
|
|
275
|
-
...userContext?.userName ? { userName: userContext.userName } : {},
|
|
276
|
-
...userContext?.userEmail ? { userEmail: userContext.userEmail } : {},
|
|
277
|
-
userMetadata: {
|
|
278
|
-
...userContext?.metadata ?? {},
|
|
279
|
-
...userContext?.pageContext ? { pageContext: userContext.pageContext } : {},
|
|
280
|
-
headers: {
|
|
281
|
-
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
282
|
-
...userContext?.headers ?? {}
|
|
283
|
-
},
|
|
284
|
-
...extraMetadata ?? {}
|
|
285
|
-
}
|
|
286
|
-
})
|
|
287
|
-
});
|
|
288
|
-
if (!res.ok) {
|
|
289
|
-
const errText = await res.text().catch(() => "");
|
|
290
|
-
throw new Error(errText || `API error ${res.status}`);
|
|
291
|
-
}
|
|
292
|
-
if (!res.body) throw new Error("No stream body");
|
|
293
|
-
await consumeStream(res.body, (proto) => applyStreamEvent(proto, msgId));
|
|
294
|
-
}, [agentId, workspaceId, source, threadId, userContext, playgroundOverrides, applyStreamEvent]);
|
|
295
555
|
const pendingAttachmentsRef = useRef([]);
|
|
296
556
|
const send = useCallback(
|
|
297
557
|
async (text) => {
|
|
558
|
+
if (customBackend) {
|
|
559
|
+
const content = (text ?? input).trim();
|
|
560
|
+
const attachments2 = pendingAttachmentsRef.current.length > 0 ? [...pendingAttachmentsRef.current] : void 0;
|
|
561
|
+
pendingAttachmentsRef.current = [];
|
|
562
|
+
if (!content && !attachments2?.length || customBackend.streaming)
|
|
563
|
+
return;
|
|
564
|
+
setInput("");
|
|
565
|
+
await customBackend.send(content, attachments2);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
298
568
|
const userInput = (text ?? input).trim();
|
|
299
569
|
if (!userInput || streaming) return;
|
|
300
570
|
setInput("");
|
|
@@ -313,16 +583,32 @@ function useChat({
|
|
|
313
583
|
setStreaming(true);
|
|
314
584
|
const assistantMsgId = newId();
|
|
315
585
|
streamingMsgIdRef.current = assistantMsgId;
|
|
316
|
-
setMessages((prev) => [
|
|
586
|
+
setMessages((prev) => [
|
|
587
|
+
...prev,
|
|
588
|
+
{ id: assistantMsgId, role: "assistant", parts: [] }
|
|
589
|
+
]);
|
|
317
590
|
try {
|
|
318
|
-
await fetchAndStream({
|
|
591
|
+
await fetchAndStream({
|
|
592
|
+
input: userInput,
|
|
593
|
+
msgId: assistantMsgId,
|
|
594
|
+
attachments
|
|
595
|
+
});
|
|
319
596
|
} catch {
|
|
320
597
|
setMessages((prev) => {
|
|
321
598
|
const idx = prev.findIndex((m) => m.id === assistantMsgId);
|
|
322
599
|
if (idx === -1) return prev;
|
|
323
600
|
const copy = [...prev];
|
|
324
601
|
const err = copy[idx];
|
|
325
|
-
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
|
+
};
|
|
326
612
|
return copy;
|
|
327
613
|
});
|
|
328
614
|
}
|
|
@@ -338,19 +624,27 @@ function useChat({
|
|
|
338
624
|
(prev) => prev.map((msg) => ({
|
|
339
625
|
...msg,
|
|
340
626
|
parts: msg.parts.map(
|
|
341
|
-
(part) => part.type === "picker" && part.pickerId === pickerId ? {
|
|
627
|
+
(part) => part.type === "picker" && part.pickerId === pickerId ? {
|
|
628
|
+
...part,
|
|
629
|
+
selectedValue: value
|
|
630
|
+
} : part
|
|
342
631
|
)
|
|
343
632
|
}))
|
|
344
633
|
);
|
|
345
634
|
setStreaming(true);
|
|
346
635
|
const assistantMsgId = newId();
|
|
347
636
|
streamingMsgIdRef.current = assistantMsgId;
|
|
348
|
-
setMessages((prev) => [
|
|
637
|
+
setMessages((prev) => [
|
|
638
|
+
...prev,
|
|
639
|
+
{ id: assistantMsgId, role: "assistant", parts: [] }
|
|
640
|
+
]);
|
|
349
641
|
try {
|
|
350
642
|
await fetchAndStream({
|
|
351
643
|
input: label,
|
|
352
644
|
msgId: assistantMsgId,
|
|
353
|
-
extraMetadata: {
|
|
645
|
+
extraMetadata: {
|
|
646
|
+
__pickerSelection: { pickerId, paramName, value, label }
|
|
647
|
+
}
|
|
354
648
|
});
|
|
355
649
|
} catch {
|
|
356
650
|
setMessages((prev) => {
|
|
@@ -358,7 +652,16 @@ function useChat({
|
|
|
358
652
|
if (idx === -1) return prev;
|
|
359
653
|
const copy = [...prev];
|
|
360
654
|
const err = copy[idx];
|
|
361
|
-
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
|
+
};
|
|
362
665
|
return copy;
|
|
363
666
|
});
|
|
364
667
|
}
|
|
@@ -383,7 +686,20 @@ function useChat({
|
|
|
383
686
|
});
|
|
384
687
|
await send(lastText);
|
|
385
688
|
}, [streaming, messages, send]);
|
|
386
|
-
return {
|
|
689
|
+
return {
|
|
690
|
+
messages: customBackend ? customBackend.messages : messages,
|
|
691
|
+
streaming: customBackend ? customBackend.streaming : streaming,
|
|
692
|
+
input,
|
|
693
|
+
setInput,
|
|
694
|
+
threadId,
|
|
695
|
+
send,
|
|
696
|
+
queueAttachments,
|
|
697
|
+
regenerate,
|
|
698
|
+
reset: customBackend?.reset ?? reset,
|
|
699
|
+
selectPickerOption,
|
|
700
|
+
debugTraces,
|
|
701
|
+
voiceCall
|
|
702
|
+
};
|
|
387
703
|
}
|
|
388
704
|
function getPreferredMimeType() {
|
|
389
705
|
if (typeof MediaRecorder === "undefined") return "";
|
|
@@ -402,7 +718,12 @@ function mimeTypeToExtension(mimeType) {
|
|
|
402
718
|
return "webm";
|
|
403
719
|
}
|
|
404
720
|
var DEFAULT_API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
405
|
-
function useVoice({
|
|
721
|
+
function useVoice({
|
|
722
|
+
agentId,
|
|
723
|
+
apiUrl,
|
|
724
|
+
onTranscript,
|
|
725
|
+
onError
|
|
726
|
+
}) {
|
|
406
727
|
const [voiceState, setVoiceState] = useState("idle");
|
|
407
728
|
const recorderRef = useRef(null);
|
|
408
729
|
const chunksRef = useRef([]);
|
|
@@ -418,10 +739,14 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
418
739
|
const form = new FormData();
|
|
419
740
|
form.append("audio", blob, `recording.${ext}`);
|
|
420
741
|
form.append("agentId", agentId);
|
|
421
|
-
const res = await fetch(`${base}/api/chat/transcribe`, {
|
|
742
|
+
const res = await fetch(`${base}/api/chat/transcribe`, {
|
|
743
|
+
method: "POST",
|
|
744
|
+
body: form
|
|
745
|
+
});
|
|
422
746
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
423
747
|
const data = await res.json();
|
|
424
|
-
if (!data.text?.trim())
|
|
748
|
+
if (!data.text?.trim())
|
|
749
|
+
throw new Error(data.error ?? "Empty transcript");
|
|
425
750
|
onTranscript(data.text.trim());
|
|
426
751
|
setVoiceState("idle");
|
|
427
752
|
} catch (err) {
|
|
@@ -439,14 +764,19 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
439
764
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
440
765
|
streamRef.current = stream;
|
|
441
766
|
const mimeType = getPreferredMimeType();
|
|
442
|
-
const recorder = new MediaRecorder(
|
|
767
|
+
const recorder = new MediaRecorder(
|
|
768
|
+
stream,
|
|
769
|
+
mimeType ? { mimeType } : void 0
|
|
770
|
+
);
|
|
443
771
|
chunksRef.current = [];
|
|
444
772
|
recorder.ondataavailable = (e) => {
|
|
445
773
|
if (e.data.size > 0) chunksRef.current.push(e.data);
|
|
446
774
|
};
|
|
447
775
|
recorder.onstop = async () => {
|
|
448
776
|
stream.getTracks().forEach((t) => t.stop());
|
|
449
|
-
const blob = new Blob(chunksRef.current, {
|
|
777
|
+
const blob = new Blob(chunksRef.current, {
|
|
778
|
+
type: mimeType || "audio/webm"
|
|
779
|
+
});
|
|
450
780
|
if (blob.size === 0) {
|
|
451
781
|
onError?.("Recording was empty \u2014 please try again.");
|
|
452
782
|
setVoiceState("idle");
|
|
@@ -472,7 +802,8 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
472
802
|
useEffect(() => {
|
|
473
803
|
return () => {
|
|
474
804
|
if (errorTimerRef.current) clearTimeout(errorTimerRef.current);
|
|
475
|
-
if (recorderRef.current?.state === "recording")
|
|
805
|
+
if (recorderRef.current?.state === "recording")
|
|
806
|
+
recorderRef.current.stop();
|
|
476
807
|
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
477
808
|
};
|
|
478
809
|
}, []);
|
|
@@ -495,7 +826,10 @@ function useAttachments({
|
|
|
495
826
|
form.append("file", file);
|
|
496
827
|
form.append("agentId", agentId);
|
|
497
828
|
try {
|
|
498
|
-
const res = await fetch(`${base}/api/chat/upload`, {
|
|
829
|
+
const res = await fetch(`${base}/api/chat/upload`, {
|
|
830
|
+
method: "POST",
|
|
831
|
+
body: form
|
|
832
|
+
});
|
|
499
833
|
if (!res.ok) {
|
|
500
834
|
const data = await res.json().catch(() => ({}));
|
|
501
835
|
setAttachments(
|
|
@@ -511,7 +845,9 @@ function useAttachments({
|
|
|
511
845
|
}
|
|
512
846
|
const payload = await res.json();
|
|
513
847
|
setAttachments(
|
|
514
|
-
(prev) => prev.map(
|
|
848
|
+
(prev) => prev.map(
|
|
849
|
+
(a) => a.id === id ? { ...a, status: "ready", payload } : a
|
|
850
|
+
)
|
|
515
851
|
);
|
|
516
852
|
} catch (err) {
|
|
517
853
|
const msg = err instanceof Error ? err.message : "Upload failed";
|
|
@@ -555,16 +891,13 @@ function useAttachments({
|
|
|
555
891
|
return { attachments, attach, remove, clear, isUploading, readyPayloads };
|
|
556
892
|
}
|
|
557
893
|
function DefaultIcon() {
|
|
558
|
-
return /* @__PURE__ */
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
"
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
)
|
|
567
|
-
] });
|
|
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
|
+
) });
|
|
568
901
|
}
|
|
569
902
|
function ExpandIcon() {
|
|
570
903
|
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 11, height: 11 }, children: /* @__PURE__ */ jsx(
|
|
@@ -590,9 +923,58 @@ function MinimizeIcon() {
|
|
|
590
923
|
}
|
|
591
924
|
) });
|
|
592
925
|
}
|
|
593
|
-
var Avatar = ({
|
|
594
|
-
|
|
595
|
-
|
|
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
|
+
);
|
|
596
978
|
function ChatHeader({
|
|
597
979
|
title,
|
|
598
980
|
profilePicture,
|
|
@@ -601,22 +983,39 @@ function ChatHeader({
|
|
|
601
983
|
onReset,
|
|
602
984
|
onClose,
|
|
603
985
|
onExpand,
|
|
604
|
-
expanded
|
|
986
|
+
expanded,
|
|
987
|
+
onCall,
|
|
988
|
+
isCallLoading
|
|
605
989
|
}) {
|
|
606
990
|
return /* @__PURE__ */ jsxs(
|
|
607
991
|
"header",
|
|
608
992
|
{
|
|
609
|
-
className: "ww-flex ww-items-center ww-justify-between ww-px-4 ww-py-3 ww-shrink-0",
|
|
610
|
-
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
|
+
},
|
|
611
999
|
children: [
|
|
612
1000
|
/* @__PURE__ */ jsxs("div", { className: "ww-flex ww-items-center ww-gap-2.5 ww-min-w-0", children: [
|
|
613
|
-
/* @__PURE__ */ jsx(
|
|
614
|
-
|
|
1001
|
+
/* @__PURE__ */ jsx(
|
|
1002
|
+
Avatar,
|
|
615
1003
|
{
|
|
616
|
-
style: {
|
|
617
|
-
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
|
+
)
|
|
618
1017
|
}
|
|
619
|
-
)
|
|
1018
|
+
),
|
|
620
1019
|
/* @__PURE__ */ jsxs("div", { className: "ww-min-w-0", children: [
|
|
621
1020
|
/* @__PURE__ */ jsx("p", { className: "ww-font-semibold ww-text-sm ww-truncate ww-leading-tight", children: title }),
|
|
622
1021
|
/* @__PURE__ */ jsx("p", { className: "ww-text-[10px] ww-opacity-70 ww-leading-tight", children: "AI Assistant" })
|
|
@@ -632,13 +1031,64 @@ function ChatHeader({
|
|
|
632
1031
|
children: expanded ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(ExpandIcon, {})
|
|
633
1032
|
}
|
|
634
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
|
+
),
|
|
635
1079
|
/* @__PURE__ */ jsx(
|
|
636
1080
|
"button",
|
|
637
1081
|
{
|
|
638
1082
|
onClick: onReset,
|
|
639
1083
|
className: "ww-rounded-full ww-p-1.5 ww-transition-colors hover:ww-bg-white/10",
|
|
640
1084
|
title: "New conversation",
|
|
641
|
-
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
|
+
)
|
|
642
1092
|
}
|
|
643
1093
|
),
|
|
644
1094
|
onClose && /* @__PURE__ */ jsx(
|
|
@@ -662,8 +1112,10 @@ function formatBytes(bytes) {
|
|
|
662
1112
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
663
1113
|
}
|
|
664
1114
|
function ChipLeading({ a }) {
|
|
665
|
-
if (a.status === "uploading")
|
|
666
|
-
|
|
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" });
|
|
667
1119
|
const thumbSrc = a.payload?.url ?? a.payload?.base64;
|
|
668
1120
|
if (a.mimeType.startsWith("image/") && thumbSrc) {
|
|
669
1121
|
return /* @__PURE__ */ jsx(
|
|
@@ -675,14 +1127,19 @@ function ChipLeading({ a }) {
|
|
|
675
1127
|
}
|
|
676
1128
|
);
|
|
677
1129
|
}
|
|
678
|
-
if (a.mimeType.startsWith("image/"))
|
|
679
|
-
|
|
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" });
|
|
680
1134
|
if (a.mimeType.includes("csv") || a.mimeType.includes("spreadsheet") || a.name.endsWith(".csv")) {
|
|
681
1135
|
return /* @__PURE__ */ jsx(FileSpreadsheet, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-text-emerald-500" });
|
|
682
1136
|
}
|
|
683
1137
|
return /* @__PURE__ */ jsx(FileText, { className: "ww-h-3 ww-w-3 ww-shrink-0" });
|
|
684
1138
|
}
|
|
685
|
-
function AttachmentChips({
|
|
1139
|
+
function AttachmentChips({
|
|
1140
|
+
attachments,
|
|
1141
|
+
onRemove
|
|
1142
|
+
}) {
|
|
686
1143
|
if (attachments.length === 0) return null;
|
|
687
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(
|
|
688
1145
|
"div",
|
|
@@ -710,41 +1167,49 @@ function AttachmentChips({ attachments, onRemove }) {
|
|
|
710
1167
|
a.id
|
|
711
1168
|
)) });
|
|
712
1169
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
function SentAttachments({ attachments, contrastColor }) {
|
|
1170
|
+
function SentAttachments({
|
|
1171
|
+
attachments,
|
|
1172
|
+
contrastColor
|
|
1173
|
+
}) {
|
|
718
1174
|
const images = attachments.filter((a) => a.contentType === "image");
|
|
719
1175
|
const files = attachments.filter((a) => a.contentType !== "image");
|
|
720
1176
|
const isDark = contrastColor === "#ffffff" || contrastColor === "#fff";
|
|
721
1177
|
return /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-gap-1.5 ww-w-full", children: [
|
|
722
|
-
images.length > 0 && /* @__PURE__ */ jsx(
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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
|
+
),
|
|
748
1213
|
files.length > 0 && /* @__PURE__ */ jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1", children: files.map((f) => /* @__PURE__ */ jsxs(
|
|
749
1214
|
"div",
|
|
750
1215
|
{
|
|
@@ -762,16 +1227,24 @@ function SentAttachments({ attachments, contrastColor }) {
|
|
|
762
1227
|
] });
|
|
763
1228
|
}
|
|
764
1229
|
function PlanStepIcon({ status }) {
|
|
765
|
-
if (status === "executing")
|
|
766
|
-
|
|
767
|
-
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" });
|
|
768
1236
|
return /* @__PURE__ */ jsx("div", { className: "ww-h-3 ww-w-3 ww-rounded-full ww-border-2 ww-border-muted-foreground/30" });
|
|
769
1237
|
}
|
|
770
|
-
function PlanCard({
|
|
1238
|
+
function PlanCard({
|
|
1239
|
+
part,
|
|
1240
|
+
onSend,
|
|
1241
|
+
disabled
|
|
1242
|
+
}) {
|
|
771
1243
|
const successCount = part.steps.filter((s) => s.status === "success").length;
|
|
772
1244
|
const hasExecuting = part.steps.some((s) => s.status === "executing");
|
|
773
1245
|
const allDone = successCount === part.steps.length && part.steps.length > 0;
|
|
774
1246
|
const anyFailed = part.steps.some((s) => s.status === "failed");
|
|
1247
|
+
const allPending = part.steps.length > 0 && part.steps.every((s) => s.status === "pending");
|
|
775
1248
|
return /* @__PURE__ */ jsxs("div", { className: "ww-rounded-xl ww-border ww-bg-background ww-overflow-hidden ww-text-xs ww-w-full ww-shadow-sm", children: [
|
|
776
1249
|
/* @__PURE__ */ jsxs("div", { className: "ww-flex ww-items-center ww-gap-2 ww-px-3 ww-py-2 ww-bg-muted/50 ww-border-b", children: [
|
|
777
1250
|
hasExecuting ? /* @__PURE__ */ jsx(Loader2, { className: "ww-h-3.5 ww-w-3.5 ww-shrink-0 ww-animate-spin ww-text-primary/80" }) : allDone ? /* @__PURE__ */ jsx(CheckCircle2, { className: "ww-h-3.5 ww-w-3.5 ww-shrink-0 ww-text-emerald-500" }) : anyFailed ? /* @__PURE__ */ jsx(AlertCircle, { className: "ww-h-3.5 ww-w-3.5 ww-shrink-0 ww-text-destructive" }) : /* @__PURE__ */ jsx(Zap, { className: "ww-h-3.5 ww-w-3.5 ww-shrink-0 ww-text-primary/70" }),
|
|
@@ -812,7 +1285,37 @@ function PlanCard({ part }) {
|
|
|
812
1285
|
]
|
|
813
1286
|
},
|
|
814
1287
|
step.index
|
|
815
|
-
)) })
|
|
1288
|
+
)) }),
|
|
1289
|
+
allPending && onSend && /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-gap-2 ww-px-3 ww-py-2.5 ww-border-t", children: [
|
|
1290
|
+
/* @__PURE__ */ jsxs(
|
|
1291
|
+
"button",
|
|
1292
|
+
{
|
|
1293
|
+
onClick: () => onSend("s\xED, proceder"),
|
|
1294
|
+
disabled,
|
|
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",
|
|
1296
|
+
style: {
|
|
1297
|
+
backgroundColor: "var(--primary, #18181b)",
|
|
1298
|
+
color: "var(--primary-foreground, #fff)"
|
|
1299
|
+
},
|
|
1300
|
+
children: [
|
|
1301
|
+
/* @__PURE__ */ jsx(Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
1302
|
+
"Proceder"
|
|
1303
|
+
]
|
|
1304
|
+
}
|
|
1305
|
+
),
|
|
1306
|
+
/* @__PURE__ */ jsxs(
|
|
1307
|
+
"button",
|
|
1308
|
+
{
|
|
1309
|
+
onClick: () => onSend("cancelar"),
|
|
1310
|
+
disabled,
|
|
1311
|
+
className: "ww-flex ww-items-center ww-justify-center ww-gap-1.5 ww-rounded-lg ww-px-3 ww-py-1.5 ww-text-xs ww-font-medium ww-bg-muted ww-text-muted-foreground ww-transition-opacity hover:ww-opacity-80 active:ww-scale-[0.98] disabled:ww-opacity-50 disabled:ww-pointer-events-none",
|
|
1312
|
+
children: [
|
|
1313
|
+
/* @__PURE__ */ jsx(X, { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
1314
|
+
"Cancelar"
|
|
1315
|
+
]
|
|
1316
|
+
}
|
|
1317
|
+
)
|
|
1318
|
+
] })
|
|
816
1319
|
] });
|
|
817
1320
|
}
|
|
818
1321
|
function ThinkingDots() {
|
|
@@ -875,7 +1378,15 @@ function ReasoningBlock({ text }) {
|
|
|
875
1378
|
children: [
|
|
876
1379
|
/* @__PURE__ */ jsx(Zap, { className: "ww-h-3 ww-w-3" }),
|
|
877
1380
|
/* @__PURE__ */ jsx("span", { children: "Reasoning" }),
|
|
878
|
-
/* @__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
|
+
)
|
|
879
1390
|
]
|
|
880
1391
|
}
|
|
881
1392
|
),
|
|
@@ -897,98 +1408,292 @@ function PickerSelector({
|
|
|
897
1408
|
}, [part.options, query]);
|
|
898
1409
|
const isConsumed = !!part.selectedValue;
|
|
899
1410
|
const handleClick = (opt) => {
|
|
900
|
-
if (!disabled && !isConsumed)
|
|
1411
|
+
if (!disabled && !isConsumed)
|
|
1412
|
+
onSelect(part.pickerId, part.paramName, opt.value, opt.label);
|
|
901
1413
|
};
|
|
902
|
-
return /* @__PURE__ */ jsxs(
|
|
903
|
-
"
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
"
|
|
911
|
-
{
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
"
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
"
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
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",
|
|
970
1526
|
{
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
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",
|
|
1548
|
+
{
|
|
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
|
+
);
|
|
991
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
|
+
);
|
|
992
1697
|
function MessageBubble({
|
|
993
1698
|
message,
|
|
994
1699
|
userColor,
|
|
@@ -996,14 +1701,21 @@ function MessageBubble({
|
|
|
996
1701
|
profilePicture,
|
|
997
1702
|
isStreaming,
|
|
998
1703
|
showThinking = true,
|
|
999
|
-
onPickerSelect
|
|
1704
|
+
onPickerSelect,
|
|
1705
|
+
onSend
|
|
1000
1706
|
}) {
|
|
1001
1707
|
const isUser = message.role === "user";
|
|
1002
1708
|
const textPart = message.parts.find((p) => p.type === "text");
|
|
1003
1709
|
const reasoningPart = message.parts.find((p) => p.type === "reasoning");
|
|
1004
|
-
const toolParts = message.parts.filter(
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
+
);
|
|
1007
1719
|
const contrastColor = getContrastColor(userColor);
|
|
1008
1720
|
if (isUser) {
|
|
1009
1721
|
return /* @__PURE__ */ jsx("div", { className: "ww-flex ww-justify-end", children: /* @__PURE__ */ jsxs(
|
|
@@ -1012,19 +1724,55 @@ function MessageBubble({
|
|
|
1012
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",
|
|
1013
1725
|
style: { backgroundColor: userColor, color: contrastColor },
|
|
1014
1726
|
children: [
|
|
1015
|
-
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
|
+
),
|
|
1016
1734
|
textPart?.text && /* @__PURE__ */ jsx("span", { children: textPart.text })
|
|
1017
1735
|
]
|
|
1018
1736
|
}
|
|
1019
1737
|
) });
|
|
1020
1738
|
}
|
|
1021
1739
|
const visibleToolParts = showThinking ? toolParts : [];
|
|
1022
|
-
const isEmpty = !textPart?.text && visibleToolParts.length === 0 && pickerParts.length === 0;
|
|
1740
|
+
const isEmpty = !textPart?.text && visibleToolParts.length === 0 && pickerParts.length === 0 && planParts.length === 0;
|
|
1023
1741
|
return /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start", children: [
|
|
1024
|
-
/* @__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
|
+
),
|
|
1025
1765
|
/* @__PURE__ */ jsxs("div", { className: "ww-flex ww-flex-col ww-gap-1.5 ww-min-w-0 ww-max-w-[82%]", children: [
|
|
1026
1766
|
showThinking && reasoningPart && /* @__PURE__ */ jsx(ReasoningBlock, { text: reasoningPart.text }),
|
|
1027
|
-
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
|
+
)),
|
|
1028
1776
|
visibleToolParts.map((t) => /* @__PURE__ */ jsx(ToolCallBadge, { part: t }, t.toolCallId)),
|
|
1029
1777
|
pickerParts.map((p) => /* @__PURE__ */ jsx(
|
|
1030
1778
|
PickerSelector,
|
|
@@ -1037,40 +1785,39 @@ function MessageBubble({
|
|
|
1037
1785
|
p.pickerId
|
|
1038
1786
|
)),
|
|
1039
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: [
|
|
1040
|
-
/* @__PURE__ */ jsx(
|
|
1041
|
-
ReactMarkdown,
|
|
1042
|
-
{
|
|
1043
|
-
remarkPlugins: [remarkGfm],
|
|
1044
|
-
components: {
|
|
1045
|
-
p: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "4px 0" }, children }),
|
|
1046
|
-
h1: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "6px 0", fontWeight: 700, fontSize: "1em" }, children }),
|
|
1047
|
-
h2: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "6px 0", fontWeight: 700, fontSize: "1em" }, children }),
|
|
1048
|
-
h3: ({ children }) => /* @__PURE__ */ jsx("p", { style: { margin: "6px 0", fontWeight: 600, fontSize: "0.95em" }, children }),
|
|
1049
|
-
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1050
|
-
ol: ({ children }) => /* @__PURE__ */ jsx("ol", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1051
|
-
li: ({ children }) => /* @__PURE__ */ jsx("li", { style: { margin: "2px 0" }, children }),
|
|
1052
|
-
strong: ({ children }) => /* @__PURE__ */ jsx("strong", { style: { fontWeight: 600 }, children }),
|
|
1053
|
-
code: ({ children }) => /* @__PURE__ */ jsx("code", { style: { fontSize: "0.85em", backgroundColor: "rgba(0,0,0,0.07)", borderRadius: 4, padding: "1px 5px", fontFamily: "monospace" }, children }),
|
|
1054
|
-
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 }),
|
|
1055
|
-
a: ({ href, children }) => /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "underline", opacity: 0.75 }, children }),
|
|
1056
|
-
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 }) }),
|
|
1057
|
-
thead: ({ children }) => /* @__PURE__ */ jsx("thead", { style: { backgroundColor: "rgba(0,0,0,0.04)" }, children }),
|
|
1058
|
-
tbody: ({ children }) => /* @__PURE__ */ jsx("tbody", { children }),
|
|
1059
|
-
tr: ({ children }) => /* @__PURE__ */ jsx("tr", { style: { borderBottom: "1px solid rgba(0,0,0,0.07)" }, children }),
|
|
1060
|
-
th: ({ children }) => /* @__PURE__ */ jsx("th", { style: { padding: "6px 10px", textAlign: "left", fontWeight: 600, whiteSpace: "nowrap" }, children }),
|
|
1061
|
-
td: ({ children }) => /* @__PURE__ */ jsx("td", { style: { padding: "5px 10px", verticalAlign: "top" }, children })
|
|
1062
|
-
},
|
|
1063
|
-
children: textPart.text
|
|
1064
|
-
}
|
|
1065
|
-
),
|
|
1788
|
+
/* @__PURE__ */ jsx(MarkdownContent, { text: textPart.text }),
|
|
1066
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" })
|
|
1067
1790
|
] }) : null
|
|
1068
1791
|
] })
|
|
1069
1792
|
] });
|
|
1070
1793
|
}
|
|
1071
|
-
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
|
+
);
|
|
1072
1807
|
var AvatarImage3 = AvatarPrimitive.Image;
|
|
1073
|
-
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
|
+
);
|
|
1074
1821
|
function ChatMessages({
|
|
1075
1822
|
messages,
|
|
1076
1823
|
streaming,
|
|
@@ -1084,14 +1831,15 @@ function ChatMessages({
|
|
|
1084
1831
|
onPickerSelect
|
|
1085
1832
|
}) {
|
|
1086
1833
|
const bottomRef = useRef(null);
|
|
1834
|
+
const greetText = initialMessages[0];
|
|
1087
1835
|
const showGreeting = messages.length === 0;
|
|
1088
1836
|
useEffect(() => {
|
|
1089
1837
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1090
|
-
}, [messages]);
|
|
1838
|
+
}, [messages, streaming]);
|
|
1091
1839
|
return /* @__PURE__ */ jsxs("div", { className: "ww-flex-1 ww-flex ww-flex-col ww-overflow-y-auto ww-overscroll-contain", children: [
|
|
1092
|
-
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: [
|
|
1093
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() }) }),
|
|
1094
|
-
/* @__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 })
|
|
1095
1843
|
] }),
|
|
1096
1844
|
showGreeting && /* @__PURE__ */ jsx("div", { className: "ww-flex-1" }),
|
|
1097
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(
|
|
@@ -1103,10 +1851,47 @@ function ChatMessages({
|
|
|
1103
1851
|
profilePicture,
|
|
1104
1852
|
isStreaming: streaming && i === messages.length - 1 && msg.role === "assistant",
|
|
1105
1853
|
showThinking,
|
|
1106
|
-
onPickerSelect
|
|
1854
|
+
onPickerSelect,
|
|
1855
|
+
onSend: i === messages.length - 1 ? onSuggest : void 0
|
|
1107
1856
|
},
|
|
1108
1857
|
msg.id
|
|
1109
1858
|
)) }),
|
|
1859
|
+
streaming && messages.length > 0 && messages[messages.length - 1]?.role !== "assistant" && /* @__PURE__ */ jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start ww-px-4 ww-pb-2", children: [
|
|
1860
|
+
/* @__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() }) }),
|
|
1861
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
1862
|
+
@keyframes wDotBounce {
|
|
1863
|
+
0%, 80%, 100% { transform: translateY(0) scale(1); opacity: 0.35; }
|
|
1864
|
+
40% { transform: translateY(-6px) scale(1.15); opacity: 1; }
|
|
1865
|
+
}
|
|
1866
|
+
` }),
|
|
1867
|
+
/* @__PURE__ */ jsx(
|
|
1868
|
+
"div",
|
|
1869
|
+
{
|
|
1870
|
+
className: "ww-bg-muted",
|
|
1871
|
+
style: {
|
|
1872
|
+
display: "inline-flex",
|
|
1873
|
+
alignItems: "center",
|
|
1874
|
+
gap: 6,
|
|
1875
|
+
borderRadius: "18px 18px 18px 4px",
|
|
1876
|
+
padding: "13px 18px"
|
|
1877
|
+
},
|
|
1878
|
+
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
|
|
1879
|
+
"span",
|
|
1880
|
+
{
|
|
1881
|
+
style: {
|
|
1882
|
+
display: "block",
|
|
1883
|
+
width: 7,
|
|
1884
|
+
height: 7,
|
|
1885
|
+
borderRadius: "50%",
|
|
1886
|
+
backgroundColor: "currentColor",
|
|
1887
|
+
animation: `wDotBounce 1.2s cubic-bezier(0.4,0,0.2,1) ${i * 0.16}s infinite`
|
|
1888
|
+
}
|
|
1889
|
+
},
|
|
1890
|
+
i
|
|
1891
|
+
))
|
|
1892
|
+
}
|
|
1893
|
+
)
|
|
1894
|
+
] }),
|
|
1110
1895
|
showGreeting && suggestedMessages.length > 0 && /* @__PURE__ */ jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-2 ww-px-4 ww-pb-4", children: suggestedMessages.map((msg, i) => /* @__PURE__ */ jsx(
|
|
1111
1896
|
"button",
|
|
1112
1897
|
{
|
|
@@ -1173,7 +1958,13 @@ function ChatInput({
|
|
|
1173
1958
|
}
|
|
1174
1959
|
),
|
|
1175
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: [
|
|
1176
|
-
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
|
+
) }),
|
|
1177
1968
|
hasAttachments && /* @__PURE__ */ jsx(
|
|
1178
1969
|
"input",
|
|
1179
1970
|
{
|
|
@@ -1263,7 +2054,10 @@ function ChatInput({
|
|
|
1263
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",
|
|
1264
2055
|
hasText || streaming ? "ww-opacity-100 ww-shadow-sm" : "ww-opacity-30"
|
|
1265
2056
|
),
|
|
1266
|
-
style: hasText || streaming ? {
|
|
2057
|
+
style: hasText || streaming ? {
|
|
2058
|
+
backgroundColor: accentColor,
|
|
2059
|
+
color: getContrastColor(accentColor)
|
|
2060
|
+
} : { backgroundColor: "transparent", color: "currentColor" },
|
|
1267
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" })
|
|
1268
2062
|
}
|
|
1269
2063
|
)
|
|
@@ -1271,6 +2065,126 @@ function ChatInput({
|
|
|
1271
2065
|
] })
|
|
1272
2066
|
] });
|
|
1273
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
|
+
}
|
|
1274
2188
|
function ChatWidget({
|
|
1275
2189
|
agentId,
|
|
1276
2190
|
workspaceId,
|
|
@@ -1296,13 +2210,27 @@ function ChatWidget({
|
|
|
1296
2210
|
enableVoice = false,
|
|
1297
2211
|
voiceAutoSend = false,
|
|
1298
2212
|
enableAttachments = false,
|
|
2213
|
+
customBackend,
|
|
1299
2214
|
className,
|
|
1300
2215
|
onClose,
|
|
1301
2216
|
onReset,
|
|
1302
2217
|
onExpand,
|
|
1303
|
-
expanded
|
|
2218
|
+
expanded,
|
|
2219
|
+
embedded = false,
|
|
2220
|
+
envId,
|
|
2221
|
+
onDebugTrace
|
|
1304
2222
|
}) {
|
|
1305
|
-
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
|
+
});
|
|
1306
2234
|
const voice = useVoice({
|
|
1307
2235
|
agentId,
|
|
1308
2236
|
onTranscript: (text) => {
|
|
@@ -1314,29 +2242,47 @@ function ChatWidget({
|
|
|
1314
2242
|
}
|
|
1315
2243
|
});
|
|
1316
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]);
|
|
1317
2254
|
const [isDragOver, setIsDragOver] = useState(false);
|
|
1318
|
-
const handleDragOver = useCallback(
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
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();
|
|
1329
2280
|
setIsDragOver(false);
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
e.stopPropagation();
|
|
1336
|
-
setIsDragOver(false);
|
|
1337
|
-
const files = e.dataTransfer.files;
|
|
1338
|
-
if (files.length > 0) attachmentHook.attach(files);
|
|
1339
|
-
}, [enableAttachments, attachmentHook]);
|
|
2281
|
+
const files = e.dataTransfer.files;
|
|
2282
|
+
if (files.length > 0) attachmentHook.attach(files);
|
|
2283
|
+
},
|
|
2284
|
+
[enableAttachments, attachmentHook]
|
|
2285
|
+
);
|
|
1340
2286
|
const handleSend = () => {
|
|
1341
2287
|
const payloads = attachmentHook.readyPayloads;
|
|
1342
2288
|
if (payloads.length > 0) {
|
|
@@ -1355,6 +2301,7 @@ function ChatWidget({
|
|
|
1355
2301
|
};
|
|
1356
2302
|
const isDark = theme === "dark";
|
|
1357
2303
|
const cssVars = {
|
|
2304
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
1358
2305
|
colorScheme: theme,
|
|
1359
2306
|
// Inline style has higher specificity than any host-site stylesheet,
|
|
1360
2307
|
// so background-color set here cannot be overridden by host CSS.
|
|
@@ -1377,7 +2324,8 @@ function ChatWidget({
|
|
|
1377
2324
|
"div",
|
|
1378
2325
|
{
|
|
1379
2326
|
className: cn(
|
|
1380
|
-
"wallavi-widget ww-flex ww-flex-col ww-overflow-hidden ww-
|
|
2327
|
+
"wallavi-widget ww-flex ww-flex-col ww-overflow-hidden ww-bg-background ww-h-full ww-relative ww-overscroll-none",
|
|
2328
|
+
!embedded && "ww-rounded-2xl ww-border ww-shadow-xl",
|
|
1381
2329
|
isDragOver && "ww-ring-2 ww-ring-inset ww-ring-primary/60",
|
|
1382
2330
|
className
|
|
1383
2331
|
),
|
|
@@ -1402,7 +2350,32 @@ function ChatWidget({
|
|
|
1402
2350
|
onReset: handleReset,
|
|
1403
2351
|
onClose: hideCloseButton ? void 0 : onClose,
|
|
1404
2352
|
onExpand,
|
|
1405
|
-
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
|
|
2365
|
+
}
|
|
2366
|
+
),
|
|
2367
|
+
customBackend?.mode === "human" && /* @__PURE__ */ jsxs(
|
|
2368
|
+
"div",
|
|
2369
|
+
{
|
|
2370
|
+
className: "ww-shrink-0 ww-flex ww-items-center ww-gap-2 ww-px-4 ww-py-1.5 ww-border-b",
|
|
2371
|
+
style: { backgroundColor: `${userMessageColor}0d` },
|
|
2372
|
+
children: [
|
|
2373
|
+
/* @__PURE__ */ jsxs("span", { className: "ww-relative ww-flex ww-h-2 ww-w-2 ww-shrink-0", children: [
|
|
2374
|
+
/* @__PURE__ */ jsx("span", { className: "ww-animate-ping ww-absolute ww-inline-flex ww-h-full ww-w-full ww-rounded-full ww-bg-emerald-400 ww-opacity-75" }),
|
|
2375
|
+
/* @__PURE__ */ jsx("span", { className: "ww-relative ww-inline-flex ww-rounded-full ww-h-2 ww-w-2 ww-bg-emerald-500" })
|
|
2376
|
+
] }),
|
|
2377
|
+
/* @__PURE__ */ jsx("span", { className: "ww-text-xs ww-font-medium ww-text-foreground/60", children: "Hablando con un agente" })
|
|
2378
|
+
]
|
|
1406
2379
|
}
|
|
1407
2380
|
),
|
|
1408
2381
|
/* @__PURE__ */ jsx(
|
|
@@ -1420,6 +2393,99 @@ function ChatWidget({
|
|
|
1420
2393
|
onPickerSelect: chat.selectPickerOption
|
|
1421
2394
|
}
|
|
1422
2395
|
),
|
|
2396
|
+
customBackend?.footerAction && /* @__PURE__ */ jsx("div", { className: "ww-shrink-0 ww-px-3 ww-py-1.5 ww-border-t ww-bg-background", children: /* @__PURE__ */ jsxs(
|
|
2397
|
+
"button",
|
|
2398
|
+
{
|
|
2399
|
+
onClick: () => void customBackend.footerAction.onClick(),
|
|
2400
|
+
disabled: customBackend.footerAction.loading,
|
|
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
|
+
},
|
|
2410
|
+
className: [
|
|
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",
|
|
2412
|
+
"hover:ww-opacity-85 active:ww-scale-[0.98] disabled:ww-opacity-50 disabled:ww-pointer-events-none",
|
|
2413
|
+
customBackend.footerAction.icon === "human" ? "" : "ww-border"
|
|
2414
|
+
].join(" "),
|
|
2415
|
+
children: [
|
|
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
|
+
),
|
|
2472
|
+
/* @__PURE__ */ jsx("span", { className: "ww-flex-1 ww-text-left ww-truncate", children: customBackend.footerAction.label }),
|
|
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
|
+
)
|
|
2486
|
+
]
|
|
2487
|
+
}
|
|
2488
|
+
) }),
|
|
1423
2489
|
/* @__PURE__ */ jsx(
|
|
1424
2490
|
ChatInput,
|
|
1425
2491
|
{
|
|
@@ -1444,7 +2510,7 @@ function ChatWidget({
|
|
|
1444
2510
|
} : {}
|
|
1445
2511
|
}
|
|
1446
2512
|
),
|
|
1447
|
-
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: [
|
|
1448
2514
|
/* @__PURE__ */ jsxs(
|
|
1449
2515
|
"a",
|
|
1450
2516
|
{
|
|
@@ -1494,19 +2560,27 @@ function useAutoConfig(agentId, enabled) {
|
|
|
1494
2560
|
if (cancelled) return;
|
|
1495
2561
|
const cfg = body?.data ?? {};
|
|
1496
2562
|
const remote = {};
|
|
1497
|
-
if (cfg.profilePicture != null)
|
|
1498
|
-
|
|
2563
|
+
if (cfg.profilePicture != null)
|
|
2564
|
+
remote.profilePicture = cfg.profilePicture;
|
|
2565
|
+
if (cfg.displayName != null)
|
|
2566
|
+
remote.displayName = cfg.displayName;
|
|
1499
2567
|
if (cfg.theme) remote.theme = cfg.theme;
|
|
1500
|
-
if (cfg.userMessageColor)
|
|
2568
|
+
if (cfg.userMessageColor)
|
|
2569
|
+
remote.userMessageColor = cfg.userMessageColor;
|
|
1501
2570
|
if (Array.isArray(cfg.initialMessages) && cfg.initialMessages.length > 0)
|
|
1502
2571
|
remote.initialMessages = cfg.initialMessages;
|
|
1503
2572
|
if (Array.isArray(cfg.suggestedMessages))
|
|
1504
2573
|
remote.suggestedMessages = cfg.suggestedMessages;
|
|
1505
|
-
if (cfg.messagePlaceholder != null)
|
|
2574
|
+
if (cfg.messagePlaceholder != null)
|
|
2575
|
+
remote.messagePlaceholder = cfg.messagePlaceholder;
|
|
1506
2576
|
if (cfg.watermark != null) remote.watermark = cfg.watermark;
|
|
1507
2577
|
if (cfg.footer != null) remote.footer = cfg.footer;
|
|
1508
|
-
if (cfg.showThinking != null)
|
|
1509
|
-
|
|
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;
|
|
1510
2584
|
setResult({
|
|
1511
2585
|
remoteConfig: remote,
|
|
1512
2586
|
bubbleIconUrl: cfg.chatIcon || cfg.profilePicture || void 0,
|
|
@@ -1527,9 +2601,391 @@ function useAutoConfig(agentId, enabled) {
|
|
|
1527
2601
|
}, [agentId, enabled]);
|
|
1528
2602
|
return result;
|
|
1529
2603
|
}
|
|
2604
|
+
function toWidgetMsg(m) {
|
|
2605
|
+
return {
|
|
2606
|
+
id: m.id,
|
|
2607
|
+
role: m.role === "customer" ? "user" : "assistant",
|
|
2608
|
+
parts: [{ type: "text", text: m.content }],
|
|
2609
|
+
attachments: m.metadata?.attachments ?? void 0
|
|
2610
|
+
};
|
|
2611
|
+
}
|
|
2612
|
+
function useSupportChat({
|
|
2613
|
+
inboxToken,
|
|
2614
|
+
apiBase = "https://app.wallavi.com",
|
|
2615
|
+
requestHumanLabel = "Hablar con un agente",
|
|
2616
|
+
returnToAiLabel
|
|
2617
|
+
}) {
|
|
2618
|
+
const enabled = Boolean(inboxToken) && inboxToken !== "__disabled__";
|
|
2619
|
+
const STORAGE_KEY = `wlv_support_${inboxToken}`;
|
|
2620
|
+
const base = apiBase.replace(/\/$/, "");
|
|
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
|
+
});
|
|
2631
|
+
const [rawMessages, setRawMessages] = useState([]);
|
|
2632
|
+
const [sending, setSending] = useState(false);
|
|
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
|
+
});
|
|
2643
|
+
const [agentTyping, setAgentTyping] = useState(false);
|
|
2644
|
+
const [requestingHuman, setRequestingHuman] = useState(false);
|
|
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);
|
|
2651
|
+
const typingTimerRef = useRef(null);
|
|
2652
|
+
useEffect(() => {
|
|
2653
|
+
if (!enabled) return;
|
|
2654
|
+
try {
|
|
2655
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
2656
|
+
if (saved) JSON.parse(saved);
|
|
2657
|
+
} catch {
|
|
2658
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
2659
|
+
setSession(null);
|
|
2660
|
+
setIsAiMode(false);
|
|
2661
|
+
}
|
|
2662
|
+
}, [STORAGE_KEY, enabled]);
|
|
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
|
+
);
|
|
2679
|
+
useEffect(() => {
|
|
2680
|
+
if (!enabled || !session) return;
|
|
2681
|
+
void loadMessages(session);
|
|
2682
|
+
let ablyClient = null;
|
|
2683
|
+
const setupAbly = async () => {
|
|
2684
|
+
try {
|
|
2685
|
+
const res = await fetch(
|
|
2686
|
+
`${base}/api/support-chat/${session.conversationId}/ably-token`,
|
|
2687
|
+
{
|
|
2688
|
+
headers: { "x-visitor-token": session.visitorToken }
|
|
2689
|
+
}
|
|
2690
|
+
);
|
|
2691
|
+
if (!res.ok) return;
|
|
2692
|
+
const { tokenRequest, channel: channelName } = await res.json();
|
|
2693
|
+
const AblyLib = (await import('ably')).default;
|
|
2694
|
+
ablyClient = new AblyLib.Realtime({
|
|
2695
|
+
authCallback: (_, cb) => cb(null, tokenRequest)
|
|
2696
|
+
});
|
|
2697
|
+
const ch = ablyClient.channels.get(channelName);
|
|
2698
|
+
ch.subscribe((msg) => {
|
|
2699
|
+
const event = { type: msg.name, ...msg.data };
|
|
2700
|
+
if (event.type === "message.created" && event.message) {
|
|
2701
|
+
setRawMessages((prev) => {
|
|
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
|
+
];
|
|
2708
|
+
});
|
|
2709
|
+
} else if (event.type === "agent.typing") {
|
|
2710
|
+
setAgentTyping(!!event.isTyping);
|
|
2711
|
+
if (event.isTyping) {
|
|
2712
|
+
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
2713
|
+
typingTimerRef.current = setTimeout(
|
|
2714
|
+
() => setAgentTyping(false),
|
|
2715
|
+
6e3
|
|
2716
|
+
);
|
|
2717
|
+
} else {
|
|
2718
|
+
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
2719
|
+
}
|
|
2720
|
+
} else if (event.type === "mode.changed") {
|
|
2721
|
+
const newIsAi = event.mode === "auto";
|
|
2722
|
+
setIsAiMode(newIsAi);
|
|
2723
|
+
setSession((s) => {
|
|
2724
|
+
if (s)
|
|
2725
|
+
localStorage.setItem(
|
|
2726
|
+
STORAGE_KEY,
|
|
2727
|
+
JSON.stringify({ session: s, isAiMode: newIsAi })
|
|
2728
|
+
);
|
|
2729
|
+
return s;
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
});
|
|
2733
|
+
} catch {
|
|
2734
|
+
}
|
|
2735
|
+
};
|
|
2736
|
+
void setupAbly();
|
|
2737
|
+
const pollId = setInterval(() => void loadMessages(session), 3e4);
|
|
2738
|
+
return () => {
|
|
2739
|
+
if (ablyClient)
|
|
2740
|
+
try {
|
|
2741
|
+
ablyClient.close();
|
|
2742
|
+
} catch {
|
|
2743
|
+
}
|
|
2744
|
+
clearInterval(pollId);
|
|
2745
|
+
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
2746
|
+
};
|
|
2747
|
+
}, [session, STORAGE_KEY, base, loadMessages]);
|
|
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
|
|
2761
|
+
}
|
|
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
|
+
})
|
|
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 {
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
setSending(false);
|
|
2830
|
+
},
|
|
2831
|
+
[session, sending, inboxToken, base, STORAGE_KEY]
|
|
2832
|
+
);
|
|
2833
|
+
const requestHuman = useCallback(async () => {
|
|
2834
|
+
if (!session || !isAiMode || requestingHuman) return;
|
|
2835
|
+
setRequestingHuman(true);
|
|
2836
|
+
try {
|
|
2837
|
+
await fetch(`${base}/api/support-chat/${session.conversationId}/mode`, {
|
|
2838
|
+
method: "PATCH",
|
|
2839
|
+
headers: {
|
|
2840
|
+
"Content-Type": "application/json",
|
|
2841
|
+
"x-visitor-token": session.visitorToken
|
|
2842
|
+
},
|
|
2843
|
+
body: JSON.stringify({ mode: "human" })
|
|
2844
|
+
});
|
|
2845
|
+
setIsAiMode(false);
|
|
2846
|
+
localStorage.setItem(
|
|
2847
|
+
STORAGE_KEY,
|
|
2848
|
+
JSON.stringify({ session, isAiMode: false })
|
|
2849
|
+
);
|
|
2850
|
+
} catch {
|
|
2851
|
+
}
|
|
2852
|
+
setRequestingHuman(false);
|
|
2853
|
+
}, [session, isAiMode, requestingHuman, base, STORAGE_KEY]);
|
|
2854
|
+
const returnToAi = useCallback(async () => {
|
|
2855
|
+
if (!session || isAiMode || returningToAi) return;
|
|
2856
|
+
setReturningToAi(true);
|
|
2857
|
+
try {
|
|
2858
|
+
await fetch(`${base}/api/support-chat/${session.conversationId}/mode`, {
|
|
2859
|
+
method: "PATCH",
|
|
2860
|
+
headers: {
|
|
2861
|
+
"Content-Type": "application/json",
|
|
2862
|
+
"x-visitor-token": session.visitorToken
|
|
2863
|
+
},
|
|
2864
|
+
body: JSON.stringify({ mode: "auto" })
|
|
2865
|
+
});
|
|
2866
|
+
setIsAiMode(true);
|
|
2867
|
+
localStorage.setItem(
|
|
2868
|
+
STORAGE_KEY,
|
|
2869
|
+
JSON.stringify({ session, isAiMode: true })
|
|
2870
|
+
);
|
|
2871
|
+
} catch {
|
|
2872
|
+
}
|
|
2873
|
+
setReturningToAi(false);
|
|
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
|
+
}, []);
|
|
2901
|
+
const reset = useCallback(() => {
|
|
2902
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
2903
|
+
setSession(null);
|
|
2904
|
+
setRawMessages([]);
|
|
2905
|
+
setIsAiMode(false);
|
|
2906
|
+
setAgentTyping(false);
|
|
2907
|
+
setRequestingHuman(false);
|
|
2908
|
+
setReturningToAi(false);
|
|
2909
|
+
stopVoiceCall();
|
|
2910
|
+
}, [STORAGE_KEY, stopVoiceCall]);
|
|
2911
|
+
const messages = useMemo(
|
|
2912
|
+
() => rawMessages.filter((m) => m.role !== "system").map(toWidgetMsg),
|
|
2913
|
+
[rawMessages]
|
|
2914
|
+
);
|
|
2915
|
+
const footerAction = useMemo(() => {
|
|
2916
|
+
if (isAiMode) {
|
|
2917
|
+
return {
|
|
2918
|
+
label: requestHumanLabel,
|
|
2919
|
+
sublabel: "Te conectamos con un agente disponible",
|
|
2920
|
+
icon: "human",
|
|
2921
|
+
onClick: requestHuman,
|
|
2922
|
+
loading: requestingHuman
|
|
2923
|
+
};
|
|
2924
|
+
}
|
|
2925
|
+
if (!isAiMode && session && returnToAiLabel) {
|
|
2926
|
+
return {
|
|
2927
|
+
label: returnToAiLabel,
|
|
2928
|
+
sublabel: "Respuesta instant\xE1nea con inteligencia artificial",
|
|
2929
|
+
icon: "ai",
|
|
2930
|
+
onClick: returnToAi,
|
|
2931
|
+
loading: returningToAi
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
return void 0;
|
|
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
|
+
);
|
|
2981
|
+
}
|
|
1530
2982
|
var KEY_EXPANDED = "wallavi_bubble_expanded";
|
|
1531
2983
|
var KEY_DISMISSED = "wallavi_bubble_dismissed";
|
|
1532
2984
|
function BubbleWidget({
|
|
2985
|
+
inboxToken,
|
|
2986
|
+
supportApiBase,
|
|
2987
|
+
requestHumanLabel,
|
|
2988
|
+
returnToAiLabel,
|
|
1533
2989
|
position: positionProp,
|
|
1534
2990
|
width: widthProp,
|
|
1535
2991
|
height: heightProp,
|
|
@@ -1547,33 +3003,47 @@ function BubbleWidget({
|
|
|
1547
3003
|
onOpenChange,
|
|
1548
3004
|
...chatProps
|
|
1549
3005
|
}) {
|
|
3006
|
+
const supportBackend = useSupportChat(
|
|
3007
|
+
inboxToken ? {
|
|
3008
|
+
inboxToken,
|
|
3009
|
+
apiBase: supportApiBase,
|
|
3010
|
+
requestHumanLabel,
|
|
3011
|
+
returnToAiLabel
|
|
3012
|
+
} : { inboxToken: "__disabled__", apiBase: supportApiBase }
|
|
3013
|
+
);
|
|
1550
3014
|
const isControlled = isOpenProp !== void 0;
|
|
1551
3015
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
1552
3016
|
const open = isControlled ? isOpenProp : internalOpen;
|
|
1553
|
-
const setOpen = useCallback(
|
|
1554
|
-
|
|
1555
|
-
if (
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
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
|
+
}
|
|
1561
3030
|
} else {
|
|
1562
|
-
|
|
1563
|
-
onOpenChange?.(
|
|
3031
|
+
const next = typeof valueOrUpdater === "function" ? valueOrUpdater(open) : valueOrUpdater;
|
|
3032
|
+
onOpenChange?.(next);
|
|
1564
3033
|
}
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
}
|
|
1569
|
-
}, [isControlled, open, onOpenChange]);
|
|
3034
|
+
},
|
|
3035
|
+
[isControlled, open, onOpenChange]
|
|
3036
|
+
);
|
|
1570
3037
|
const [expanded, setExpanded] = useState(false);
|
|
1571
3038
|
const panelRef = useRef(null);
|
|
1572
3039
|
const autoOpenedRef = useRef(false);
|
|
1573
3040
|
useEffect(() => {
|
|
1574
3041
|
if (localStorage.getItem(KEY_EXPANDED) === "true") setExpanded(true);
|
|
1575
3042
|
}, []);
|
|
1576
|
-
const remote = useAutoConfig(
|
|
3043
|
+
const remote = useAutoConfig(
|
|
3044
|
+
inboxToken ? "" : chatProps.agentId ?? "",
|
|
3045
|
+
!inboxToken && autoConfig
|
|
3046
|
+
);
|
|
1577
3047
|
const resolvedPosition = positionProp ?? remote.position;
|
|
1578
3048
|
const resolvedBubbleIcon = bubbleIconUrlProp ?? remote.bubbleIconUrl;
|
|
1579
3049
|
const resolvedAutoOpen = autoOpenProp || remote.autoOpen;
|
|
@@ -1587,8 +3057,8 @@ function BubbleWidget({
|
|
|
1587
3057
|
const mergedConfig = {
|
|
1588
3058
|
...remote.remoteConfig,
|
|
1589
3059
|
...definedChatProps,
|
|
1590
|
-
agentId: chatProps.agentId,
|
|
1591
|
-
agentName: chatProps.agentName
|
|
3060
|
+
agentId: chatProps.agentId ?? "",
|
|
3061
|
+
agentName: chatProps.agentName ?? ""
|
|
1592
3062
|
};
|
|
1593
3063
|
const setOpenRef = useRef(setOpen);
|
|
1594
3064
|
useEffect(() => {
|
|
@@ -1605,7 +3075,7 @@ function BubbleWidget({
|
|
|
1605
3075
|
useEffect(() => {
|
|
1606
3076
|
if (!resolvedKeyboardShortcut) return;
|
|
1607
3077
|
const onKey = (e) => {
|
|
1608
|
-
if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
|
|
3078
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === shortcutKey.toLowerCase()) {
|
|
1609
3079
|
e.preventDefault();
|
|
1610
3080
|
setOpenRef.current((v) => !v);
|
|
1611
3081
|
}
|
|
@@ -1624,7 +3094,10 @@ function BubbleWidget({
|
|
|
1624
3094
|
const handleClose = () => {
|
|
1625
3095
|
setOpen(false);
|
|
1626
3096
|
if (!isControlled) {
|
|
1627
|
-
localStorage.setItem(
|
|
3097
|
+
localStorage.setItem(
|
|
3098
|
+
KEY_DISMISSED,
|
|
3099
|
+
String(Date.now() + 24 * 60 * 60 * 1e3)
|
|
3100
|
+
);
|
|
1628
3101
|
}
|
|
1629
3102
|
};
|
|
1630
3103
|
const toggleExpanded = () => setExpanded((v) => {
|
|
@@ -1633,7 +3106,10 @@ function BubbleWidget({
|
|
|
1633
3106
|
return next;
|
|
1634
3107
|
});
|
|
1635
3108
|
const isLeft = resolvedPosition === "bottom-left";
|
|
1636
|
-
const panelWidth = expanded ? Math.min(
|
|
3109
|
+
const panelWidth = expanded ? Math.min(
|
|
3110
|
+
expandedWidth,
|
|
3111
|
+
typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth
|
|
3112
|
+
) : resolvedWidth;
|
|
1637
3113
|
const panelHeight = expanded ? expandedHeight : resolvedHeight;
|
|
1638
3114
|
return /* @__PURE__ */ jsxs(
|
|
1639
3115
|
"div",
|
|
@@ -1664,6 +3140,8 @@ function BubbleWidget({
|
|
|
1664
3140
|
ChatWidget,
|
|
1665
3141
|
{
|
|
1666
3142
|
...mergedConfig,
|
|
3143
|
+
agentId: inboxToken ? "support" : chatProps.agentId ?? "",
|
|
3144
|
+
customBackend: inboxToken ? supportBackend : mergedConfig.customBackend,
|
|
1667
3145
|
onClose: handleClose,
|
|
1668
3146
|
onExpand: toggleExpanded,
|
|
1669
3147
|
expanded,
|
|
@@ -1689,15 +3167,20 @@ function BubbleWidget({
|
|
|
1689
3167
|
alignItems: "center",
|
|
1690
3168
|
justifyContent: "center",
|
|
1691
3169
|
transition: "transform 0.2s ease, box-shadow 0.2s ease",
|
|
1692
|
-
background: open ? "
|
|
1693
|
-
color: open ? "
|
|
3170
|
+
background: open ? "#19191c" : "#ffffff",
|
|
3171
|
+
color: open ? "#ffffff" : "#19191c"
|
|
1694
3172
|
},
|
|
1695
3173
|
children: open ? /* @__PURE__ */ jsx(X, { style: { width: 20, height: 20 } }) : resolvedBubbleIcon ? /* @__PURE__ */ jsx(
|
|
1696
3174
|
"img",
|
|
1697
3175
|
{
|
|
1698
3176
|
src: resolvedBubbleIcon,
|
|
1699
3177
|
alt: "",
|
|
1700
|
-
style: {
|
|
3178
|
+
style: {
|
|
3179
|
+
width: "100%",
|
|
3180
|
+
height: "100%",
|
|
3181
|
+
objectFit: "cover",
|
|
3182
|
+
display: "block"
|
|
3183
|
+
}
|
|
1701
3184
|
}
|
|
1702
3185
|
) : /* @__PURE__ */ jsx(DefaultIcon, {})
|
|
1703
3186
|
}
|
|
@@ -1707,4 +3190,4 @@ function BubbleWidget({
|
|
|
1707
3190
|
);
|
|
1708
3191
|
}
|
|
1709
3192
|
|
|
1710
|
-
export { BubbleWidget, ChatWidget, formatToolName, getContrastColor, useAttachments, useChat, useVoice };
|
|
3193
|
+
export { BubbleWidget, ChatWidget, PlanCard, ReasoningBlock, ToolCallBadge, formatToolName, getContrastColor, useAttachments, useChat, useSupportChat, useVoice };
|