@wallavi/widget 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +80 -4
- package/dist/index.d.ts +80 -4
- package/dist/index.js +1680 -545
- package/dist/index.mjs +1679 -547
- package/dist/styles.css +1 -0
- package/package.json +11 -8
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@ var AvatarPrimitive = require('@radix-ui/react-avatar');
|
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
var ReactMarkdownLib = require('react-markdown');
|
|
10
10
|
var remarkGfm = require('remark-gfm');
|
|
11
|
+
var componentsReact = require('@livekit/components-react');
|
|
12
|
+
require('@livekit/components-styles');
|
|
11
13
|
|
|
12
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
15
|
|
|
@@ -56,11 +58,11 @@ function styleInject(css, { insertAt } = {}) {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
// src/styles.css
|
|
59
|
-
styleInject(".ww-pointer-events-none {\n pointer-events: none;\n}\n.ww-absolute {\n position: absolute;\n}\n.ww-relative {\n position: relative;\n}\n.ww-inset-0 {\n inset: 0px;\n}\n.ww-left-2\\.5 {\n left: 0.625rem;\n}\n.ww-top-1\\/2 {\n top: 50%;\n}\n.ww-z-50 {\n z-index: 50;\n}\n.ww-mb-1 {\n margin-bottom: 0.25rem;\n}\n.ww-mb-2 {\n margin-bottom: 0.5rem;\n}\n.ww-ml-0\\.5 {\n margin-left: 0.125rem;\n}\n.ww-mt-0\\.5 {\n margin-top: 0.125rem;\n}\n.ww-mt-1 {\n margin-top: 0.25rem;\n}\n.ww-block {\n display: block;\n}\n.ww-inline-block {\n display: inline-block;\n}\n.ww-flex {\n display: flex;\n}\n.ww-inline-flex {\n display: inline-flex;\n}\n.ww-grid {\n display: grid;\n}\n.ww-hidden {\n display: none;\n}\n.ww-h-10 {\n height: 2.5rem;\n}\n.ww-h-2 {\n height: 0.5rem;\n}\n.ww-h-2\\.5 {\n height: 0.625rem;\n}\n.ww-h-20 {\n height: 5rem;\n}\n.ww-h-3 {\n height: 0.75rem;\n}\n.ww-h-3\\.5 {\n height: 0.875rem;\n}\n.ww-h-4 {\n height: 1rem;\n}\n.ww-h-6 {\n height: 1.5rem;\n}\n.ww-h-7 {\n height: 1.75rem;\n}\n.ww-h-8 {\n height: 2rem;\n}\n.ww-h-full {\n height: 100%;\n}\n.ww-max-h-32 {\n max-height: 8rem;\n}\n.ww-max-h-48 {\n max-height: 12rem;\n}\n.ww-max-h-\\[168px\\] {\n max-height: 168px;\n}\n.ww-max-h-\\[180px\\] {\n max-height: 180px;\n}\n.ww-w-0\\.5 {\n width: 0.125rem;\n}\n.ww-w-10 {\n width: 2.5rem;\n}\n.ww-w-2 {\n width: 0.5rem;\n}\n.ww-w-2\\.5 {\n width: 0.625rem;\n}\n.ww-w-20 {\n width: 5rem;\n}\n.ww-w-3 {\n width: 0.75rem;\n}\n.ww-w-3\\.5 {\n width: 0.875rem;\n}\n.ww-w-4 {\n width: 1rem;\n}\n.ww-w-6 {\n width: 1.5rem;\n}\n.ww-w-7 {\n width: 1.75rem;\n}\n.ww-w-8 {\n width: 2rem;\n}\n.ww-w-fit {\n width: -moz-fit-content;\n width: fit-content;\n}\n.ww-w-full {\n width: 100%;\n}\n.ww-min-w-0 {\n min-width: 0px;\n}\n.ww-max-w-\\[120px\\] {\n max-width: 120px;\n}\n.ww-max-w-\\[200px\\] {\n max-width: 200px;\n}\n.ww-max-w-\\[78\\%\\] {\n max-width: 78%;\n}\n.ww-max-w-\\[82\\%\\] {\n max-width: 82%;\n}\n.ww-max-w-none {\n max-width: none;\n}\n.ww-flex-1 {\n flex: 1 1 0%;\n}\n.ww-shrink-0 {\n flex-shrink: 0;\n}\n.ww-rotate-180 {\n --tw-rotate: 180deg;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n@keyframes ww-ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n.ww-animate-ping {\n animation: ww-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\n}\n@keyframes ww-pulse {\n 50% {\n opacity: .5;\n }\n}\n.ww-animate-pulse {\n animation: ww-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n@keyframes ww-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.ww-animate-spin {\n animation: ww-spin 1s linear infinite;\n}\n.ww-cursor-default {\n cursor: default;\n}\n.ww-cursor-pointer {\n cursor: pointer;\n}\n.ww-select-none {\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.ww-resize-none {\n resize: none;\n}\n.ww-grid-cols-2 {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.ww-flex-col {\n flex-direction: column;\n}\n.ww-flex-wrap {\n flex-wrap: wrap;\n}\n.ww-items-start {\n align-items: flex-start;\n}\n.ww-items-end {\n align-items: flex-end;\n}\n.ww-items-center {\n align-items: center;\n}\n.ww-justify-end {\n justify-content: flex-end;\n}\n.ww-justify-center {\n justify-content: center;\n}\n.ww-justify-between {\n justify-content: space-between;\n}\n.ww-gap-0\\.5 {\n gap: 0.125rem;\n}\n.ww-gap-1 {\n gap: 0.25rem;\n}\n.ww-gap-1\\.5 {\n gap: 0.375rem;\n}\n.ww-gap-2 {\n gap: 0.5rem;\n}\n.ww-gap-2\\.5 {\n gap: 0.625rem;\n}\n.ww-gap-4 {\n gap: 1rem;\n}\n.ww-divide-y > :not([hidden]) ~ :not([hidden]) {\n --tw-divide-y-reverse: 0;\n border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));\n border-bottom-width: calc(1px * var(--tw-divide-y-reverse));\n}\n.ww-divide-border\\/40 > :not([hidden]) ~ :not([hidden]) {\n border-color: hsl(var(--border) / 0.4);\n}\n.ww-overflow-hidden {\n overflow: hidden;\n}\n.ww-overflow-y-auto {\n overflow-y: auto;\n}\n.ww-overscroll-contain {\n overscroll-behavior: contain;\n}\n.ww-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ww-whitespace-pre-wrap {\n white-space: pre-wrap;\n}\n.ww-rounded {\n border-radius: 0.25rem;\n}\n.ww-rounded-2xl {\n border-radius: 1rem;\n}\n.ww-rounded-full {\n border-radius: 9999px;\n}\n.ww-rounded-lg {\n border-radius: var(--radius);\n}\n.ww-rounded-xl {\n border-radius: 0.75rem;\n}\n.ww-rounded-tl-none {\n border-top-left-radius: 0px;\n}\n.ww-rounded-tl-sm {\n border-top-left-radius: calc(var(--radius) - 4px);\n}\n.ww-rounded-tr-sm {\n border-top-right-radius: calc(var(--radius) - 4px);\n}\n.ww-border {\n border-width: 1px;\n}\n.ww-border-2 {\n border-width: 2px;\n}\n.ww-border-b {\n border-bottom-width: 1px;\n}\n.ww-border-l-2 {\n border-left-width: 2px;\n}\n.ww-border-t {\n border-top-width: 1px;\n}\n.ww-border-background {\n border-color: hsl(var(--background));\n}\n.ww-border-black\\/10 {\n border-color: rgb(0 0 0 / 0.1);\n}\n.ww-border-border {\n border-color: hsl(var(--border));\n}\n.ww-border-border\\/30 {\n border-color: hsl(var(--border) / 0.3);\n}\n.ww-border-border\\/40 {\n border-color: hsl(var(--border) / 0.4);\n}\n.ww-border-border\\/50 {\n border-color: hsl(var(--border) / 0.5);\n}\n.ww-border-border\\/60 {\n border-color: hsl(var(--border) / 0.6);\n}\n.ww-border-border\\/70 {\n border-color: hsl(var(--border) / 0.7);\n}\n.ww-border-muted {\n border-color: hsl(var(--muted));\n}\n.ww-border-muted-foreground\\/30 {\n border-color: hsl(var(--muted-foreground) / 0.3);\n}\n.ww-border-red-200 {\n --tw-border-opacity: 1;\n border-color: rgb(254 202 202 / var(--tw-border-opacity, 1));\n}\n.ww-border-white\\/20 {\n border-color: rgb(255 255 255 / 0.2);\n}\n.ww-bg-background {\n background-color: hsl(var(--background));\n}\n.ww-bg-background\\/20 {\n background-color: hsl(var(--background) / 0.2);\n}\n.ww-bg-background\\/40 {\n background-color: hsl(var(--background) / 0.4);\n}\n.ww-bg-background\\/50 {\n background-color: hsl(var(--background) / 0.5);\n}\n.ww-bg-background\\/90 {\n background-color: hsl(var(--background) / 0.9);\n}\n.ww-bg-black\\/10 {\n background-color: rgb(0 0 0 / 0.1);\n}\n.ww-bg-emerald-400 {\n --tw-bg-opacity: 1;\n background-color: rgb(52 211 153 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-emerald-500 {\n --tw-bg-opacity: 1;\n background-color: rgb(16 185 129 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-foreground {\n background-color: hsl(var(--foreground));\n}\n.ww-bg-foreground\\/60 {\n background-color: hsl(var(--foreground) / 0.6);\n}\n.ww-bg-muted {\n background-color: hsl(var(--muted));\n}\n.ww-bg-muted-foreground\\/10 {\n background-color: hsl(var(--muted-foreground) / 0.1);\n}\n.ww-bg-muted\\/50 {\n background-color: hsl(var(--muted) / 0.5);\n}\n.ww-bg-muted\\/60 {\n background-color: hsl(var(--muted) / 0.6);\n}\n.ww-bg-primary {\n background-color: hsl(var(--primary));\n}\n.ww-bg-primary\\/5 {\n background-color: hsl(var(--primary) / 0.05);\n}\n.ww-bg-red-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 242 242 / var(--tw-bg-opacity, 1));\n}\n.ww-bg-transparent {\n background-color: transparent;\n}\n.ww-bg-white\\/10 {\n background-color: rgb(255 255 255 / 0.1);\n}\n.ww-bg-white\\/15 {\n background-color: rgb(255 255 255 / 0.15);\n}\n.ww-fill-current {\n fill: currentColor;\n}\n.ww-object-cover {\n -o-object-fit: cover;\n object-fit: cover;\n}\n.ww-p-0\\.5 {\n padding: 0.125rem;\n}\n.ww-p-1\\.5 {\n padding: 0.375rem;\n}\n.ww-p-3 {\n padding: 0.75rem;\n}\n.ww-px-1 {\n padding-left: 0.25rem;\n padding-right: 0.25rem;\n}\n.ww-px-2 {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n}\n.ww-px-2\\.5 {\n padding-left: 0.625rem;\n padding-right: 0.625rem;\n}\n.ww-px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.ww-px-3\\.5 {\n padding-left: 0.875rem;\n padding-right: 0.875rem;\n}\n.ww-px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.ww-py-0\\.5 {\n padding-top: 0.125rem;\n padding-bottom: 0.125rem;\n}\n.ww-py-1 {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n}\n.ww-py-1\\.5 {\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n}\n.ww-py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.ww-py-2\\.5 {\n padding-top: 0.625rem;\n padding-bottom: 0.625rem;\n}\n.ww-py-3 {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n}\n.ww-py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.ww-pb-1\\.5 {\n padding-bottom: 0.375rem;\n}\n.ww-pb-2 {\n padding-bottom: 0.5rem;\n}\n.ww-pb-4 {\n padding-bottom: 1rem;\n}\n.ww-pl-2 {\n padding-left: 0.5rem;\n}\n.ww-pl-7 {\n padding-left: 1.75rem;\n}\n.ww-pr-0\\.5 {\n padding-right: 0.125rem;\n}\n.ww-pr-3 {\n padding-right: 0.75rem;\n}\n.ww-pt-2 {\n padding-top: 0.5rem;\n}\n.ww-pt-5 {\n padding-top: 1.25rem;\n}\n.ww-text-left {\n text-align: left;\n}\n.ww-text-center {\n text-align: center;\n}\n.ww-align-middle {\n vertical-align: middle;\n}\n.ww-text-\\[10\\.5px\\] {\n font-size: 10.5px;\n}\n.ww-text-\\[10px\\] {\n font-size: 10px;\n}\n.ww-text-\\[11px\\] {\n font-size: 11px;\n}\n.ww-text-\\[12\\.5px\\] {\n font-size: 12.5px;\n}\n.ww-text-\\[12px\\] {\n font-size: 12px;\n}\n.ww-text-\\[8px\\] {\n font-size: 8px;\n}\n.ww-text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.ww-text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.ww-font-medium {\n font-weight: 500;\n}\n.ww-font-semibold {\n font-weight: 600;\n}\n.ww-uppercase {\n text-transform: uppercase;\n}\n.ww-leading-none {\n line-height: 1;\n}\n.ww-leading-relaxed {\n line-height: 1.625;\n}\n.ww-leading-snug {\n line-height: 1.375;\n}\n.ww-leading-tight {\n line-height: 1.25;\n}\n.ww-tracking-widest {\n letter-spacing: 0.1em;\n}\n.ww-text-background {\n color: hsl(var(--background));\n}\n.ww-text-black\\/40 {\n color: rgb(0 0 0 / 0.4);\n}\n.ww-text-black\\/60 {\n color: rgb(0 0 0 / 0.6);\n}\n.ww-text-destructive {\n color: hsl(var(--destructive));\n}\n.ww-text-destructive\\/70 {\n color: hsl(var(--destructive) / 0.7);\n}\n.ww-text-emerald-500 {\n --tw-text-opacity: 1;\n color: rgb(16 185 129 / var(--tw-text-opacity, 1));\n}\n.ww-text-foreground {\n color: hsl(var(--foreground));\n}\n.ww-text-foreground\\/60 {\n color: hsl(var(--foreground) / 0.6);\n}\n.ww-text-foreground\\/70 {\n color: hsl(var(--foreground) / 0.7);\n}\n.ww-text-foreground\\/80 {\n color: hsl(var(--foreground) / 0.8);\n}\n.ww-text-muted-foreground {\n color: hsl(var(--muted-foreground));\n}\n.ww-text-muted-foreground\\/40 {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.ww-text-muted-foreground\\/50 {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.ww-text-muted-foreground\\/70 {\n color: hsl(var(--muted-foreground) / 0.7);\n}\n.ww-text-muted-foreground\\/80 {\n color: hsl(var(--muted-foreground) / 0.8);\n}\n.ww-text-primary {\n color: hsl(var(--primary));\n}\n.ww-text-primary-foreground {\n color: hsl(var(--primary-foreground));\n}\n.ww-text-primary\\/70 {\n color: hsl(var(--primary) / 0.7);\n}\n.ww-text-primary\\/80 {\n color: hsl(var(--primary) / 0.8);\n}\n.ww-text-red-400 {\n --tw-text-opacity: 1;\n color: rgb(248 113 113 / var(--tw-text-opacity, 1));\n}\n.ww-text-red-500 {\n --tw-text-opacity: 1;\n color: rgb(239 68 68 / var(--tw-text-opacity, 1));\n}\n.ww-text-red-600 {\n --tw-text-opacity: 1;\n color: rgb(220 38 38 / var(--tw-text-opacity, 1));\n}\n.ww-text-white\\/60 {\n color: rgb(255 255 255 / 0.6);\n}\n.ww-text-white\\/80 {\n color: rgb(255 255 255 / 0.8);\n}\n.ww-line-through {\n text-decoration-line: line-through;\n}\n.ww-no-underline {\n text-decoration-line: none;\n}\n.ww-decoration-foreground\\/20 {\n text-decoration-color: hsl(var(--foreground) / 0.2);\n}\n.ww-opacity-100 {\n opacity: 1;\n}\n.ww-opacity-25 {\n opacity: 0.25;\n}\n.ww-opacity-30 {\n opacity: 0.3;\n}\n.ww-opacity-35 {\n opacity: 0.35;\n}\n.ww-opacity-40 {\n opacity: 0.4;\n}\n.ww-opacity-60 {\n opacity: 0.6;\n}\n.ww-opacity-70 {\n opacity: 0.7;\n}\n.ww-opacity-75 {\n opacity: 0.75;\n}\n.ww-opacity-80 {\n opacity: 0.8;\n}\n.ww-shadow-2xl {\n --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-sm {\n --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-shadow-xl {\n --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);\n box-shadow:\n var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000),\n var(--tw-shadow);\n}\n.ww-outline-none {\n outline: 2px solid transparent;\n outline-offset: 2px;\n}\n.ww-ring-2 {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.ww-ring-inset {\n --tw-ring-inset: inset;\n}\n.ww-ring-primary\\/60 {\n --tw-ring-color: hsl(var(--primary) / 0.6);\n}\n.ww-backdrop-blur-sm {\n --tw-backdrop-blur: blur(4px);\n backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);\n}\n.ww-transition-all {\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-colors {\n transition-property:\n color,\n background-color,\n border-color,\n text-decoration-color,\n fill,\n stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-opacity {\n transition-property: opacity;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-shadow {\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-transition-transform {\n transition-property: transform;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.ww-duration-100 {\n transition-duration: 100ms;\n}\n.ww-duration-150 {\n transition-duration: 150ms;\n}\n.ww-duration-200 {\n transition-duration: 200ms;\n}\n@keyframes enter {\n from {\n opacity: var(--tw-enter-opacity, 1);\n transform: translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0));\n }\n}\n@keyframes exit {\n to {\n opacity: var(--tw-exit-opacity, 1);\n transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));\n }\n}\n.ww-duration-100 {\n animation-duration: 100ms;\n}\n.ww-duration-150 {\n animation-duration: 150ms;\n}\n.ww-duration-200 {\n animation-duration: 200ms;\n}\n.wallavi-widget *,\n.wallavi-widget *::before,\n.wallavi-widget *::after {\n box-sizing: border-box;\n border-width: 0;\n border-style: solid;\n}\n.wallavi-widget button {\n -moz-appearance: none;\n appearance: none;\n -webkit-appearance: none;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n.wallavi-widget textarea,\n.wallavi-widget input,\n.wallavi-widget select {\n font-family: inherit;\n font-size: inherit;\n}\n.wallavi-widget img,\n.wallavi-widget video {\n max-width: 100%;\n height: auto;\n}\n.placeholder\\:ww-text-muted-foreground\\/40::-moz-placeholder {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.placeholder\\:ww-text-muted-foreground\\/40::placeholder {\n color: hsl(var(--muted-foreground) / 0.4);\n}\n.placeholder\\:ww-text-muted-foreground\\/50::-moz-placeholder {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.placeholder\\:ww-text-muted-foreground\\/50::placeholder {\n color: hsl(var(--muted-foreground) / 0.5);\n}\n.focus-within\\:ww-ring-1:focus-within {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.focus-within\\:ww-ring-ring\\/40:focus-within {\n --tw-ring-color: hsl(var(--ring) / 0.4);\n}\n.hover\\:ww-border-foreground\\/25:hover {\n border-color: hsl(var(--foreground) / 0.25);\n}\n.hover\\:ww-border-foreground\\/30:hover {\n border-color: hsl(var(--foreground) / 0.3);\n}\n.hover\\:ww-bg-background:hover {\n background-color: hsl(var(--background));\n}\n.hover\\:ww-bg-foreground\\/10:hover {\n background-color: hsl(var(--foreground) / 0.1);\n}\n.hover\\:ww-bg-muted:hover {\n background-color: hsl(var(--muted));\n}\n.hover\\:ww-bg-white\\/10:hover {\n background-color: rgb(255 255 255 / 0.1);\n}\n.hover\\:ww-text-foreground:hover {\n color: hsl(var(--foreground));\n}\n.hover\\:ww-opacity-80:hover {\n opacity: 0.8;\n}\n.hover\\:ww-opacity-85:hover {\n opacity: 0.85;\n}\n.focus\\:ww-ring-1:focus {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow:\n var(--tw-ring-offset-shadow),\n var(--tw-ring-shadow),\n var(--tw-shadow, 0 0 #0000);\n}\n.focus\\:ww-ring-ring\\/40:focus {\n --tw-ring-color: hsl(var(--ring) / 0.4);\n}\n.active\\:ww-scale-\\[0\\.98\\]:active {\n --tw-scale-x: 0.98;\n --tw-scale-y: 0.98;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.disabled\\:ww-pointer-events-none:disabled {\n pointer-events: none;\n}\n.disabled\\:ww-opacity-40:disabled {\n opacity: 0.4;\n}\n.disabled\\:ww-opacity-50:disabled {\n opacity: 0.5;\n}\n.dark\\:ww-border-red-800:is(.ww-dark *) {\n --tw-border-opacity: 1;\n border-color: rgb(153 27 27 / var(--tw-border-opacity, 1));\n}\n.dark\\:ww-bg-red-950:is(.ww-dark *) {\n --tw-bg-opacity: 1;\n background-color: rgb(69 10 10 / var(--tw-bg-opacity, 1));\n}\n.dark\\:ww-text-red-400:is(.ww-dark *) {\n --tw-text-opacity: 1;\n color: rgb(248 113 113 / var(--tw-text-opacity, 1));\n}\n");
|
|
61
|
+
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");
|
|
60
62
|
var twMerge = tailwindMerge.extendTailwindMerge({ prefix: "ww-" });
|
|
61
63
|
var cn = (...inputs) => twMerge(clsx.clsx(inputs));
|
|
62
64
|
|
|
63
|
-
// src/types.ts
|
|
65
|
+
// src/lib/types.ts
|
|
64
66
|
function getContrastColor(hex) {
|
|
65
67
|
const clean = hex.replace("#", "");
|
|
66
68
|
if (clean.length < 6) return "#ffffff";
|
|
@@ -72,15 +74,16 @@ function getContrastColor(hex) {
|
|
|
72
74
|
function formatToolName(name) {
|
|
73
75
|
return name.replace(/([A-Z])/g, " $1").replace(/_/g, " ").trim();
|
|
74
76
|
}
|
|
77
|
+
|
|
78
|
+
// src/core/stream-protocol.ts
|
|
75
79
|
var STREAM_DELIMITER = "\u03B6\u236E";
|
|
76
80
|
async function consumeStream(body, handler) {
|
|
77
81
|
const reader = body.getReader();
|
|
78
82
|
const decoder = new TextDecoder();
|
|
79
83
|
let buffer = "";
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
buffer += decoder.decode(value, { stream: true });
|
|
84
|
+
let textAccumulator = "";
|
|
85
|
+
let eventCount = 0;
|
|
86
|
+
const processBuffer = () => {
|
|
84
87
|
const chunks = buffer.split(STREAM_DELIMITER);
|
|
85
88
|
buffer = chunks.pop() ?? "";
|
|
86
89
|
for (const chunk of chunks) {
|
|
@@ -88,19 +91,220 @@ async function consumeStream(body, handler) {
|
|
|
88
91
|
if (!raw) continue;
|
|
89
92
|
try {
|
|
90
93
|
const parsed = JSON.parse(raw);
|
|
91
|
-
|
|
94
|
+
const proto = parsed.data?.uiMessageProtocol;
|
|
95
|
+
if (proto) {
|
|
96
|
+
eventCount++;
|
|
97
|
+
if (proto.type === "text-delta") {
|
|
98
|
+
textAccumulator += proto.delta ?? "";
|
|
99
|
+
}
|
|
100
|
+
handler(proto);
|
|
101
|
+
}
|
|
92
102
|
} catch {
|
|
93
103
|
}
|
|
94
104
|
}
|
|
105
|
+
};
|
|
106
|
+
while (true) {
|
|
107
|
+
const { done, value } = await reader.read();
|
|
108
|
+
if (done) break;
|
|
109
|
+
buffer += decoder.decode(value, { stream: true });
|
|
110
|
+
processBuffer();
|
|
111
|
+
}
|
|
112
|
+
if (buffer.trim()) {
|
|
113
|
+
buffer += STREAM_DELIMITER;
|
|
114
|
+
processBuffer();
|
|
95
115
|
}
|
|
116
|
+
return { textAccumulator, eventCount };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/core/chat-reducer.ts
|
|
120
|
+
function applyUiEventToMessages(prev, proto, msgId) {
|
|
121
|
+
let idx = prev.findIndex((m) => m.id === msgId);
|
|
122
|
+
if (idx === -1) {
|
|
123
|
+
if (proto.type === "finish" || proto.type === "debug-trace" || proto.type === "step-start" || proto.type === "step-end" || proto.type === "navigate" || proto.type === "suggestions") {
|
|
124
|
+
return prev;
|
|
125
|
+
}
|
|
126
|
+
prev = [...prev, { id: msgId, role: "assistant", parts: [] }];
|
|
127
|
+
idx = prev.length - 1;
|
|
128
|
+
}
|
|
129
|
+
const existing = prev[idx];
|
|
130
|
+
const msg = {
|
|
131
|
+
id: existing.id,
|
|
132
|
+
role: existing.role,
|
|
133
|
+
parts: [...existing.parts]
|
|
134
|
+
};
|
|
135
|
+
switch (proto.type) {
|
|
136
|
+
case "text-delta": {
|
|
137
|
+
const textIdx = msg.parts.findIndex((p) => p.type === "text");
|
|
138
|
+
if (textIdx === -1) {
|
|
139
|
+
msg.parts.push({ type: "text", text: proto.delta });
|
|
140
|
+
} else {
|
|
141
|
+
const p = msg.parts[textIdx];
|
|
142
|
+
msg.parts[textIdx] = { type: "text", text: p.text + proto.delta };
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case "reasoning-delta": {
|
|
147
|
+
const rIdx = msg.parts.findIndex((p) => p.type === "reasoning");
|
|
148
|
+
if (rIdx === -1) {
|
|
149
|
+
msg.parts.unshift({ type: "reasoning", text: proto.delta });
|
|
150
|
+
} else {
|
|
151
|
+
const p = msg.parts[rIdx];
|
|
152
|
+
msg.parts[rIdx] = {
|
|
153
|
+
type: "reasoning",
|
|
154
|
+
text: p.text + proto.delta
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case "tool-input-available": {
|
|
160
|
+
msg.parts.push({
|
|
161
|
+
type: "tool",
|
|
162
|
+
toolCallId: proto.toolCallId,
|
|
163
|
+
toolName: proto.toolName,
|
|
164
|
+
input: proto.input ?? {},
|
|
165
|
+
status: "running"
|
|
166
|
+
});
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case "tool-output-available": {
|
|
170
|
+
const tIdx = msg.parts.findIndex(
|
|
171
|
+
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
172
|
+
);
|
|
173
|
+
if (tIdx !== -1) {
|
|
174
|
+
msg.parts[tIdx] = {
|
|
175
|
+
...msg.parts[tIdx],
|
|
176
|
+
status: "done",
|
|
177
|
+
output: proto.output
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "tool-output-error": {
|
|
183
|
+
const tIdx = msg.parts.findIndex(
|
|
184
|
+
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
185
|
+
);
|
|
186
|
+
if (tIdx !== -1) {
|
|
187
|
+
msg.parts[tIdx] = {
|
|
188
|
+
...msg.parts[tIdx],
|
|
189
|
+
status: "error",
|
|
190
|
+
errorText: proto.errorText
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
case "picker": {
|
|
196
|
+
const safeOptions = (proto.options ?? []).map((o) => ({
|
|
197
|
+
value: typeof o.value === "string" ? o.value : JSON.stringify(o.value ?? ""),
|
|
198
|
+
label: typeof o.label === "string" ? o.label : JSON.stringify(o.label ?? "")
|
|
199
|
+
}));
|
|
200
|
+
msg.parts.push({
|
|
201
|
+
type: "picker",
|
|
202
|
+
pickerId: proto.pickerId,
|
|
203
|
+
paramName: proto.paramName,
|
|
204
|
+
toolName: proto.toolName,
|
|
205
|
+
label: typeof proto.label === "string" ? proto.label : String(proto.label),
|
|
206
|
+
options: safeOptions
|
|
207
|
+
});
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
case "plan-created": {
|
|
211
|
+
msg.parts.push({
|
|
212
|
+
type: "plan",
|
|
213
|
+
planId: proto.planId,
|
|
214
|
+
goal: proto.goal,
|
|
215
|
+
steps: proto.steps.map((s) => ({
|
|
216
|
+
...s,
|
|
217
|
+
status: "pending"
|
|
218
|
+
}))
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case "plan-step-update": {
|
|
223
|
+
const pIdx = msg.parts.findIndex(
|
|
224
|
+
(p) => p.type === "plan" && p.planId === proto.planId
|
|
225
|
+
);
|
|
226
|
+
if (pIdx !== -1) {
|
|
227
|
+
const prevPlan = msg.parts[pIdx];
|
|
228
|
+
msg.parts[pIdx] = {
|
|
229
|
+
...prevPlan,
|
|
230
|
+
steps: prevPlan.steps.map(
|
|
231
|
+
(s) => s.index === proto.stepIndex ? {
|
|
232
|
+
...s,
|
|
233
|
+
status: proto.status,
|
|
234
|
+
...proto.error ? { error: proto.error } : {}
|
|
235
|
+
} : s
|
|
236
|
+
)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const copy = [...prev];
|
|
243
|
+
copy[idx] = msg;
|
|
244
|
+
return copy;
|
|
96
245
|
}
|
|
97
246
|
var API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
247
|
+
function useVoiceCall({
|
|
248
|
+
agentId,
|
|
249
|
+
threadId,
|
|
250
|
+
workspaceId,
|
|
251
|
+
customBackend
|
|
252
|
+
}) {
|
|
253
|
+
const [active, setActive] = react.useState(false);
|
|
254
|
+
const [token, setToken] = react.useState(null);
|
|
255
|
+
const [serverUrl, setServerUrl] = react.useState(null);
|
|
256
|
+
const [loading, setLoading] = react.useState(false);
|
|
257
|
+
const [error, setError] = react.useState(null);
|
|
258
|
+
const start = react.useCallback(async () => {
|
|
259
|
+
if (customBackend) return;
|
|
260
|
+
setLoading(true);
|
|
261
|
+
setError(null);
|
|
262
|
+
try {
|
|
263
|
+
const isPrivate = Boolean(workspaceId);
|
|
264
|
+
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)}`;
|
|
265
|
+
const res = await fetch(url, {
|
|
266
|
+
headers: isPrivate && typeof window !== "undefined" ? (
|
|
267
|
+
// @ts-ignore
|
|
268
|
+
{
|
|
269
|
+
Authorization: `Bearer ${await window.Clerk?.session?.getToken()}`
|
|
270
|
+
}
|
|
271
|
+
) : {}
|
|
272
|
+
});
|
|
273
|
+
const data = await res.json();
|
|
274
|
+
if (!res.ok) throw new Error(data.error || "Failed to start call");
|
|
275
|
+
setToken(data.token);
|
|
276
|
+
setServerUrl(data.url);
|
|
277
|
+
setActive(true);
|
|
278
|
+
} catch (err) {
|
|
279
|
+
setError(err.message);
|
|
280
|
+
}
|
|
281
|
+
setLoading(false);
|
|
282
|
+
}, [agentId, threadId, workspaceId, customBackend]);
|
|
283
|
+
const stop = react.useCallback(() => {
|
|
284
|
+
setActive(false);
|
|
285
|
+
setToken(null);
|
|
286
|
+
setServerUrl(null);
|
|
287
|
+
}, []);
|
|
288
|
+
return customBackend?.voiceCall ?? {
|
|
289
|
+
active,
|
|
290
|
+
token,
|
|
291
|
+
serverUrl,
|
|
292
|
+
start,
|
|
293
|
+
stop,
|
|
294
|
+
loading,
|
|
295
|
+
error
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/hooks/use-chat.ts
|
|
300
|
+
var API_URL2 = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
98
301
|
function newId() {
|
|
99
302
|
return Math.random().toString(36).slice(2, 10);
|
|
100
303
|
}
|
|
101
304
|
function useChat({
|
|
102
305
|
agentId,
|
|
103
306
|
workspaceId = "",
|
|
307
|
+
envId,
|
|
104
308
|
source = "playground",
|
|
105
309
|
userContext,
|
|
106
310
|
persist = false,
|
|
@@ -108,7 +312,8 @@ function useChat({
|
|
|
108
312
|
playgroundOverrides,
|
|
109
313
|
customBackend
|
|
110
314
|
}) {
|
|
111
|
-
const
|
|
315
|
+
const userId = userContext?.userId;
|
|
316
|
+
const persistKey = persist ? userId ? `wallavi_${agentId}_${userId}` : `wallavi_${agentId}` : null;
|
|
112
317
|
const onNavigateRef = react.useRef(onNavigate);
|
|
113
318
|
react.useEffect(() => {
|
|
114
319
|
onNavigateRef.current = onNavigate;
|
|
@@ -132,6 +337,119 @@ function useChat({
|
|
|
132
337
|
return crypto.randomUUID();
|
|
133
338
|
});
|
|
134
339
|
const streamingMsgIdRef = react.useRef(null);
|
|
340
|
+
const [debugTraces, setDebugTraces] = react.useState([]);
|
|
341
|
+
const initializedThreadsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
342
|
+
const messagesRef = react.useRef(messages);
|
|
343
|
+
react.useEffect(() => {
|
|
344
|
+
messagesRef.current = messages;
|
|
345
|
+
}, [messages]);
|
|
346
|
+
const applyStreamEvent = react.useCallback(
|
|
347
|
+
(proto, msgId) => {
|
|
348
|
+
if (proto.type === "navigate") {
|
|
349
|
+
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (proto.type === "debug-trace") {
|
|
353
|
+
setDebugTraces((prev) => [
|
|
354
|
+
...prev,
|
|
355
|
+
proto.trace
|
|
356
|
+
]);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
setMessages((prev) => applyUiEventToMessages(prev, proto, msgId));
|
|
360
|
+
},
|
|
361
|
+
[]
|
|
362
|
+
);
|
|
363
|
+
const fetchAndStream = react.useCallback(
|
|
364
|
+
async (opts) => {
|
|
365
|
+
const { input: userInput, msgId, extraMetadata, attachments } = opts;
|
|
366
|
+
const isPrivate = Boolean(workspaceId);
|
|
367
|
+
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
368
|
+
const url = isPrivate ? `${API_URL2}/api/threads/${threadId}/stream` : `${API_URL2}/api/chat/stream`;
|
|
369
|
+
const res = await fetch(url, {
|
|
370
|
+
method: "POST",
|
|
371
|
+
headers: {
|
|
372
|
+
"Content-Type": "application/json",
|
|
373
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
374
|
+
},
|
|
375
|
+
body: JSON.stringify({
|
|
376
|
+
input: userInput,
|
|
377
|
+
agentId,
|
|
378
|
+
...isPrivate ? {
|
|
379
|
+
workspaceId,
|
|
380
|
+
...playgroundOverrides ? { playgroundOverrides } : {},
|
|
381
|
+
...envId ? { envId } : {}
|
|
382
|
+
} : { threadId },
|
|
383
|
+
source,
|
|
384
|
+
...attachments?.length ? { attachments } : {},
|
|
385
|
+
...userContext?.userName ? { userName: userContext.userName } : {},
|
|
386
|
+
...userContext?.userEmail ? { userEmail: userContext.userEmail } : {},
|
|
387
|
+
userMetadata: {
|
|
388
|
+
...userContext?.metadata ?? {},
|
|
389
|
+
...userContext?.pageContext ? { pageContext: userContext.pageContext } : {},
|
|
390
|
+
headers: {
|
|
391
|
+
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
392
|
+
...userContext?.headers ?? {},
|
|
393
|
+
...userContext?.metadata?.headers ?? {}
|
|
394
|
+
},
|
|
395
|
+
...extraMetadata ?? {}
|
|
396
|
+
}
|
|
397
|
+
})
|
|
398
|
+
});
|
|
399
|
+
if (!res.ok) {
|
|
400
|
+
const errText = await res.text().catch(() => "");
|
|
401
|
+
throw new Error(errText || `API error ${res.status}`);
|
|
402
|
+
}
|
|
403
|
+
if (!res.body) throw new Error("No stream body");
|
|
404
|
+
const { textAccumulator, eventCount } = await consumeStream(
|
|
405
|
+
res.body,
|
|
406
|
+
(proto) => applyStreamEvent(proto, msgId)
|
|
407
|
+
);
|
|
408
|
+
if (textAccumulator) {
|
|
409
|
+
setMessages((prev) => {
|
|
410
|
+
const idx = prev.findIndex((m) => m.id === msgId);
|
|
411
|
+
if (idx === -1) {
|
|
412
|
+
return [
|
|
413
|
+
...prev,
|
|
414
|
+
{
|
|
415
|
+
id: msgId,
|
|
416
|
+
role: "assistant",
|
|
417
|
+
parts: [{ type: "text", text: textAccumulator }]
|
|
418
|
+
}
|
|
419
|
+
];
|
|
420
|
+
}
|
|
421
|
+
const existing = prev[idx];
|
|
422
|
+
const textPart = existing.parts.find((p) => p.type === "text");
|
|
423
|
+
if (!textPart?.text || textPart.text.length < textAccumulator.length) {
|
|
424
|
+
const copy = [...prev];
|
|
425
|
+
const parts = [
|
|
426
|
+
...existing.parts.filter((p) => p.type !== "text"),
|
|
427
|
+
{ type: "text", text: textAccumulator }
|
|
428
|
+
];
|
|
429
|
+
copy[idx] = { ...existing, parts };
|
|
430
|
+
return copy;
|
|
431
|
+
}
|
|
432
|
+
return prev;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
[
|
|
437
|
+
agentId,
|
|
438
|
+
workspaceId,
|
|
439
|
+
envId,
|
|
440
|
+
source,
|
|
441
|
+
threadId,
|
|
442
|
+
userContext,
|
|
443
|
+
playgroundOverrides,
|
|
444
|
+
applyStreamEvent
|
|
445
|
+
]
|
|
446
|
+
);
|
|
447
|
+
const voiceCall = useVoiceCall({
|
|
448
|
+
agentId,
|
|
449
|
+
threadId,
|
|
450
|
+
workspaceId,
|
|
451
|
+
customBackend
|
|
452
|
+
});
|
|
135
453
|
react.useEffect(() => {
|
|
136
454
|
if (customBackend || !persistKey) return;
|
|
137
455
|
try {
|
|
@@ -148,30 +466,108 @@ function useChat({
|
|
|
148
466
|
}, [customBackend, persistKey, threadId]);
|
|
149
467
|
react.useEffect(() => {
|
|
150
468
|
if (customBackend || !persistKey || typeof window === "undefined") return;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
})).filter((m) => m.parts.length > 0);
|
|
165
|
-
if (restored.length > 0) setMessages(restored);
|
|
166
|
-
} catch {
|
|
469
|
+
const savedTid = localStorage.getItem(`${persistKey}_tid`);
|
|
470
|
+
if (savedTid) {
|
|
471
|
+
if (savedTid !== threadId) {
|
|
472
|
+
setThreadId(savedTid);
|
|
473
|
+
const savedMsgs = sessionStorage.getItem(`${persistKey}_msgs`);
|
|
474
|
+
if (savedMsgs) {
|
|
475
|
+
try {
|
|
476
|
+
setMessages(JSON.parse(savedMsgs));
|
|
477
|
+
} catch {
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
setMessages([]);
|
|
481
|
+
}
|
|
167
482
|
}
|
|
168
|
-
}
|
|
169
|
-
|
|
483
|
+
} else {
|
|
484
|
+
const newTid = crypto.randomUUID();
|
|
485
|
+
setThreadId(newTid);
|
|
486
|
+
setMessages([]);
|
|
487
|
+
localStorage.setItem(`${persistKey}_tid`, newTid);
|
|
488
|
+
}
|
|
489
|
+
}, [customBackend, persistKey]);
|
|
490
|
+
react.useEffect(() => {
|
|
491
|
+
if (customBackend || typeof window === "undefined") return;
|
|
492
|
+
if (initializedThreadsRef.current.has(threadId)) return;
|
|
493
|
+
initializedThreadsRef.current.add(threadId);
|
|
494
|
+
if (persistKey) {
|
|
495
|
+
if (messagesRef.current.length > 0) return;
|
|
496
|
+
void (async () => {
|
|
497
|
+
try {
|
|
498
|
+
const isPrivate = Boolean(workspaceId);
|
|
499
|
+
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
500
|
+
const url = isPrivate ? `${API_URL2}/api/threads/${threadId}/messages` : `${API_URL2}/api/chat/messages?agentId=${encodeURIComponent(agentId)}&threadId=${encodeURIComponent(threadId)}`;
|
|
501
|
+
const res = await fetch(url, {
|
|
502
|
+
headers: {
|
|
503
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
if (!res.ok) return;
|
|
507
|
+
const { data } = await res.json();
|
|
508
|
+
if (!data?.length) {
|
|
509
|
+
try {
|
|
510
|
+
fetchAndStream({
|
|
511
|
+
input: "__INIT__",
|
|
512
|
+
msgId: "init",
|
|
513
|
+
extraMetadata: { isSilentInit: true }
|
|
514
|
+
});
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const restored = data.map((m) => ({
|
|
520
|
+
id: m.id,
|
|
521
|
+
role: m.role,
|
|
522
|
+
parts: m.parts.filter((p) => p?.type).map((p) => {
|
|
523
|
+
if (p.type === "picker" && Array.isArray(p.options)) {
|
|
524
|
+
return {
|
|
525
|
+
...p,
|
|
526
|
+
label: typeof p.label === "string" ? p.label : String(p.label ?? ""),
|
|
527
|
+
options: p.options.map((o) => ({
|
|
528
|
+
...o,
|
|
529
|
+
value: typeof o.value === "string" ? o.value : JSON.stringify(o.value ?? ""),
|
|
530
|
+
label: typeof o.label === "string" ? o.label : JSON.stringify(o.label ?? "")
|
|
531
|
+
}))
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
return p;
|
|
535
|
+
})
|
|
536
|
+
})).filter((m) => m.parts.length > 0);
|
|
537
|
+
if (restored.length > 0) {
|
|
538
|
+
setMessages(restored);
|
|
539
|
+
} else {
|
|
540
|
+
try {
|
|
541
|
+
fetchAndStream({
|
|
542
|
+
input: "__INIT__",
|
|
543
|
+
msgId: "init",
|
|
544
|
+
extraMetadata: { isSilentInit: true }
|
|
545
|
+
});
|
|
546
|
+
} catch {
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} catch {
|
|
550
|
+
}
|
|
551
|
+
})();
|
|
552
|
+
} else {
|
|
553
|
+
if (messagesRef.current.length === 0) {
|
|
554
|
+
try {
|
|
555
|
+
fetchAndStream({
|
|
556
|
+
input: "__INIT__",
|
|
557
|
+
msgId: "init",
|
|
558
|
+
extraMetadata: { isSilentInit: true }
|
|
559
|
+
});
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}, [threadId, agentId, workspaceId, envId, persistKey, fetchAndStream]);
|
|
170
565
|
const reset = react.useCallback(() => {
|
|
171
566
|
setMessages([]);
|
|
172
567
|
setInput("");
|
|
173
568
|
setStreaming(false);
|
|
174
569
|
setThreadId(crypto.randomUUID());
|
|
570
|
+
setDebugTraces([]);
|
|
175
571
|
streamingMsgIdRef.current = null;
|
|
176
572
|
if (persistKey) {
|
|
177
573
|
try {
|
|
@@ -182,143 +578,6 @@ function useChat({
|
|
|
182
578
|
}
|
|
183
579
|
}
|
|
184
580
|
}, [persistKey]);
|
|
185
|
-
const applyStreamEvent = react.useCallback((proto, msgId) => {
|
|
186
|
-
if (proto.type === "navigate") {
|
|
187
|
-
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
setMessages((prev) => {
|
|
191
|
-
const idx = prev.findIndex((m) => m.id === msgId);
|
|
192
|
-
if (idx === -1) return prev;
|
|
193
|
-
const existing = prev[idx];
|
|
194
|
-
const msg = { id: existing.id, role: existing.role, parts: [...existing.parts] };
|
|
195
|
-
switch (proto.type) {
|
|
196
|
-
case "text-delta": {
|
|
197
|
-
const textIdx = msg.parts.findIndex((p) => p.type === "text");
|
|
198
|
-
if (textIdx === -1) {
|
|
199
|
-
msg.parts.push({ type: "text", text: proto.delta });
|
|
200
|
-
} else {
|
|
201
|
-
const p = msg.parts[textIdx];
|
|
202
|
-
msg.parts[textIdx] = { type: "text", text: p.text + proto.delta };
|
|
203
|
-
}
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
case "reasoning-delta": {
|
|
207
|
-
const rIdx = msg.parts.findIndex((p) => p.type === "reasoning");
|
|
208
|
-
if (rIdx === -1) {
|
|
209
|
-
msg.parts.unshift({ type: "reasoning", text: proto.delta });
|
|
210
|
-
} else {
|
|
211
|
-
const p = msg.parts[rIdx];
|
|
212
|
-
msg.parts[rIdx] = { type: "reasoning", text: p.text + proto.delta };
|
|
213
|
-
}
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
case "tool-input-available": {
|
|
217
|
-
msg.parts.push({
|
|
218
|
-
type: "tool",
|
|
219
|
-
toolCallId: proto.toolCallId,
|
|
220
|
-
toolName: proto.toolName,
|
|
221
|
-
input: proto.input ?? {},
|
|
222
|
-
status: "running"
|
|
223
|
-
});
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case "tool-output-available": {
|
|
227
|
-
const tIdx = msg.parts.findIndex(
|
|
228
|
-
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
229
|
-
);
|
|
230
|
-
if (tIdx !== -1) {
|
|
231
|
-
msg.parts[tIdx] = { ...msg.parts[tIdx], status: "done", output: proto.output };
|
|
232
|
-
}
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
case "tool-output-error": {
|
|
236
|
-
const tIdx = msg.parts.findIndex(
|
|
237
|
-
(p) => p.type === "tool" && p.toolCallId === proto.toolCallId
|
|
238
|
-
);
|
|
239
|
-
if (tIdx !== -1) {
|
|
240
|
-
msg.parts[tIdx] = { ...msg.parts[tIdx], status: "error", errorText: proto.errorText };
|
|
241
|
-
}
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
case "picker": {
|
|
245
|
-
msg.parts.push({
|
|
246
|
-
type: "picker",
|
|
247
|
-
pickerId: proto.pickerId,
|
|
248
|
-
paramName: proto.paramName,
|
|
249
|
-
toolName: proto.toolName,
|
|
250
|
-
label: proto.label,
|
|
251
|
-
options: proto.options
|
|
252
|
-
});
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
case "plan-created": {
|
|
256
|
-
msg.parts.push({
|
|
257
|
-
type: "plan",
|
|
258
|
-
planId: proto.planId,
|
|
259
|
-
goal: proto.goal,
|
|
260
|
-
steps: proto.steps.map((s) => ({ ...s, status: "pending" }))
|
|
261
|
-
});
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
case "plan-step-update": {
|
|
265
|
-
const pIdx = msg.parts.findIndex(
|
|
266
|
-
(p) => p.type === "plan" && p.planId === proto.planId
|
|
267
|
-
);
|
|
268
|
-
if (pIdx !== -1) {
|
|
269
|
-
const prev2 = msg.parts[pIdx];
|
|
270
|
-
msg.parts[pIdx] = {
|
|
271
|
-
...prev2,
|
|
272
|
-
steps: prev2.steps.map(
|
|
273
|
-
(s) => s.index === proto.stepIndex ? { ...s, status: proto.status, ...proto.error ? { error: proto.error } : {} } : s
|
|
274
|
-
)
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
const copy = [...prev];
|
|
281
|
-
copy[idx] = msg;
|
|
282
|
-
return copy;
|
|
283
|
-
});
|
|
284
|
-
}, []);
|
|
285
|
-
const fetchAndStream = react.useCallback(async (opts) => {
|
|
286
|
-
const { input: userInput, msgId, extraMetadata, attachments } = opts;
|
|
287
|
-
const isPrivate = Boolean(workspaceId);
|
|
288
|
-
const token = isPrivate && typeof window !== "undefined" ? await window.Clerk?.session?.getToken() : null;
|
|
289
|
-
const url = isPrivate ? `${API_URL}/api/threads/${threadId}/stream` : `${API_URL}/api/chat/stream`;
|
|
290
|
-
const res = await fetch(url, {
|
|
291
|
-
method: "POST",
|
|
292
|
-
headers: {
|
|
293
|
-
"Content-Type": "application/json",
|
|
294
|
-
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
295
|
-
},
|
|
296
|
-
body: JSON.stringify({
|
|
297
|
-
input: userInput,
|
|
298
|
-
agentId,
|
|
299
|
-
...isPrivate ? { workspaceId, ...playgroundOverrides ? { playgroundOverrides } : {} } : { threadId },
|
|
300
|
-
source,
|
|
301
|
-
...attachments?.length ? { attachments } : {},
|
|
302
|
-
...userContext?.userName ? { userName: userContext.userName } : {},
|
|
303
|
-
...userContext?.userEmail ? { userEmail: userContext.userEmail } : {},
|
|
304
|
-
userMetadata: {
|
|
305
|
-
...userContext?.metadata ?? {},
|
|
306
|
-
...userContext?.pageContext ? { pageContext: userContext.pageContext } : {},
|
|
307
|
-
headers: {
|
|
308
|
-
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
309
|
-
...userContext?.headers ?? {}
|
|
310
|
-
},
|
|
311
|
-
...extraMetadata ?? {}
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
});
|
|
315
|
-
if (!res.ok) {
|
|
316
|
-
const errText = await res.text().catch(() => "");
|
|
317
|
-
throw new Error(errText || `API error ${res.status}`);
|
|
318
|
-
}
|
|
319
|
-
if (!res.body) throw new Error("No stream body");
|
|
320
|
-
await consumeStream(res.body, (proto) => applyStreamEvent(proto, msgId));
|
|
321
|
-
}, [agentId, workspaceId, source, threadId, userContext, playgroundOverrides, applyStreamEvent]);
|
|
322
581
|
const pendingAttachmentsRef = react.useRef([]);
|
|
323
582
|
const send = react.useCallback(
|
|
324
583
|
async (text) => {
|
|
@@ -326,7 +585,8 @@ function useChat({
|
|
|
326
585
|
const content = (text ?? input).trim();
|
|
327
586
|
const attachments2 = pendingAttachmentsRef.current.length > 0 ? [...pendingAttachmentsRef.current] : void 0;
|
|
328
587
|
pendingAttachmentsRef.current = [];
|
|
329
|
-
if (!content && !attachments2?.length || customBackend.streaming)
|
|
588
|
+
if (!content && !attachments2?.length || customBackend.streaming)
|
|
589
|
+
return;
|
|
330
590
|
setInput("");
|
|
331
591
|
await customBackend.send(content, attachments2);
|
|
332
592
|
return;
|
|
@@ -349,16 +609,32 @@ function useChat({
|
|
|
349
609
|
setStreaming(true);
|
|
350
610
|
const assistantMsgId = newId();
|
|
351
611
|
streamingMsgIdRef.current = assistantMsgId;
|
|
352
|
-
setMessages((prev) => [
|
|
612
|
+
setMessages((prev) => [
|
|
613
|
+
...prev,
|
|
614
|
+
{ id: assistantMsgId, role: "assistant", parts: [] }
|
|
615
|
+
]);
|
|
353
616
|
try {
|
|
354
|
-
await fetchAndStream({
|
|
617
|
+
await fetchAndStream({
|
|
618
|
+
input: userInput,
|
|
619
|
+
msgId: assistantMsgId,
|
|
620
|
+
attachments
|
|
621
|
+
});
|
|
355
622
|
} catch {
|
|
356
623
|
setMessages((prev) => {
|
|
357
624
|
const idx = prev.findIndex((m) => m.id === assistantMsgId);
|
|
358
625
|
if (idx === -1) return prev;
|
|
359
626
|
const copy = [...prev];
|
|
360
627
|
const err = copy[idx];
|
|
361
|
-
copy[idx] = {
|
|
628
|
+
copy[idx] = {
|
|
629
|
+
id: err.id,
|
|
630
|
+
role: err.role,
|
|
631
|
+
parts: [
|
|
632
|
+
{
|
|
633
|
+
type: "text",
|
|
634
|
+
text: "Sorry, something went wrong. Please try again."
|
|
635
|
+
}
|
|
636
|
+
]
|
|
637
|
+
};
|
|
362
638
|
return copy;
|
|
363
639
|
});
|
|
364
640
|
}
|
|
@@ -374,19 +650,27 @@ function useChat({
|
|
|
374
650
|
(prev) => prev.map((msg) => ({
|
|
375
651
|
...msg,
|
|
376
652
|
parts: msg.parts.map(
|
|
377
|
-
(part) => part.type === "picker" && part.pickerId === pickerId ? {
|
|
653
|
+
(part) => part.type === "picker" && part.pickerId === pickerId ? {
|
|
654
|
+
...part,
|
|
655
|
+
selectedValue: value
|
|
656
|
+
} : part
|
|
378
657
|
)
|
|
379
658
|
}))
|
|
380
659
|
);
|
|
381
660
|
setStreaming(true);
|
|
382
661
|
const assistantMsgId = newId();
|
|
383
662
|
streamingMsgIdRef.current = assistantMsgId;
|
|
384
|
-
setMessages((prev) => [
|
|
663
|
+
setMessages((prev) => [
|
|
664
|
+
...prev,
|
|
665
|
+
{ id: assistantMsgId, role: "assistant", parts: [] }
|
|
666
|
+
]);
|
|
385
667
|
try {
|
|
386
668
|
await fetchAndStream({
|
|
387
669
|
input: label,
|
|
388
670
|
msgId: assistantMsgId,
|
|
389
|
-
extraMetadata: {
|
|
671
|
+
extraMetadata: {
|
|
672
|
+
__pickerSelection: { pickerId, paramName, value, label }
|
|
673
|
+
}
|
|
390
674
|
});
|
|
391
675
|
} catch {
|
|
392
676
|
setMessages((prev) => {
|
|
@@ -394,7 +678,16 @@ function useChat({
|
|
|
394
678
|
if (idx === -1) return prev;
|
|
395
679
|
const copy = [...prev];
|
|
396
680
|
const err = copy[idx];
|
|
397
|
-
copy[idx] = {
|
|
681
|
+
copy[idx] = {
|
|
682
|
+
id: err.id,
|
|
683
|
+
role: err.role,
|
|
684
|
+
parts: [
|
|
685
|
+
{
|
|
686
|
+
type: "text",
|
|
687
|
+
text: "Sorry, something went wrong. Please try again."
|
|
688
|
+
}
|
|
689
|
+
]
|
|
690
|
+
};
|
|
398
691
|
return copy;
|
|
399
692
|
});
|
|
400
693
|
}
|
|
@@ -429,7 +722,9 @@ function useChat({
|
|
|
429
722
|
queueAttachments,
|
|
430
723
|
regenerate,
|
|
431
724
|
reset: customBackend?.reset ?? reset,
|
|
432
|
-
selectPickerOption
|
|
725
|
+
selectPickerOption,
|
|
726
|
+
debugTraces,
|
|
727
|
+
voiceCall
|
|
433
728
|
};
|
|
434
729
|
}
|
|
435
730
|
function getPreferredMimeType() {
|
|
@@ -449,7 +744,12 @@ function mimeTypeToExtension(mimeType) {
|
|
|
449
744
|
return "webm";
|
|
450
745
|
}
|
|
451
746
|
var DEFAULT_API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://wallavi-production.up.railway.app";
|
|
452
|
-
function useVoice({
|
|
747
|
+
function useVoice({
|
|
748
|
+
agentId,
|
|
749
|
+
apiUrl,
|
|
750
|
+
onTranscript,
|
|
751
|
+
onError
|
|
752
|
+
}) {
|
|
453
753
|
const [voiceState, setVoiceState] = react.useState("idle");
|
|
454
754
|
const recorderRef = react.useRef(null);
|
|
455
755
|
const chunksRef = react.useRef([]);
|
|
@@ -465,10 +765,14 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
465
765
|
const form = new FormData();
|
|
466
766
|
form.append("audio", blob, `recording.${ext}`);
|
|
467
767
|
form.append("agentId", agentId);
|
|
468
|
-
const res = await fetch(`${base}/api/chat/transcribe`, {
|
|
768
|
+
const res = await fetch(`${base}/api/chat/transcribe`, {
|
|
769
|
+
method: "POST",
|
|
770
|
+
body: form
|
|
771
|
+
});
|
|
469
772
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
470
773
|
const data = await res.json();
|
|
471
|
-
if (!data.text?.trim())
|
|
774
|
+
if (!data.text?.trim())
|
|
775
|
+
throw new Error(data.error ?? "Empty transcript");
|
|
472
776
|
onTranscript(data.text.trim());
|
|
473
777
|
setVoiceState("idle");
|
|
474
778
|
} catch (err) {
|
|
@@ -486,14 +790,19 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
486
790
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
487
791
|
streamRef.current = stream;
|
|
488
792
|
const mimeType = getPreferredMimeType();
|
|
489
|
-
const recorder = new MediaRecorder(
|
|
793
|
+
const recorder = new MediaRecorder(
|
|
794
|
+
stream,
|
|
795
|
+
mimeType ? { mimeType } : void 0
|
|
796
|
+
);
|
|
490
797
|
chunksRef.current = [];
|
|
491
798
|
recorder.ondataavailable = (e) => {
|
|
492
799
|
if (e.data.size > 0) chunksRef.current.push(e.data);
|
|
493
800
|
};
|
|
494
801
|
recorder.onstop = async () => {
|
|
495
802
|
stream.getTracks().forEach((t) => t.stop());
|
|
496
|
-
const blob = new Blob(chunksRef.current, {
|
|
803
|
+
const blob = new Blob(chunksRef.current, {
|
|
804
|
+
type: mimeType || "audio/webm"
|
|
805
|
+
});
|
|
497
806
|
if (blob.size === 0) {
|
|
498
807
|
onError?.("Recording was empty \u2014 please try again.");
|
|
499
808
|
setVoiceState("idle");
|
|
@@ -519,7 +828,8 @@ function useVoice({ agentId, apiUrl, onTranscript, onError }) {
|
|
|
519
828
|
react.useEffect(() => {
|
|
520
829
|
return () => {
|
|
521
830
|
if (errorTimerRef.current) clearTimeout(errorTimerRef.current);
|
|
522
|
-
if (recorderRef.current?.state === "recording")
|
|
831
|
+
if (recorderRef.current?.state === "recording")
|
|
832
|
+
recorderRef.current.stop();
|
|
523
833
|
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
524
834
|
};
|
|
525
835
|
}, []);
|
|
@@ -542,7 +852,10 @@ function useAttachments({
|
|
|
542
852
|
form.append("file", file);
|
|
543
853
|
form.append("agentId", agentId);
|
|
544
854
|
try {
|
|
545
|
-
const res = await fetch(`${base}/api/chat/upload`, {
|
|
855
|
+
const res = await fetch(`${base}/api/chat/upload`, {
|
|
856
|
+
method: "POST",
|
|
857
|
+
body: form
|
|
858
|
+
});
|
|
546
859
|
if (!res.ok) {
|
|
547
860
|
const data = await res.json().catch(() => ({}));
|
|
548
861
|
setAttachments(
|
|
@@ -558,7 +871,9 @@ function useAttachments({
|
|
|
558
871
|
}
|
|
559
872
|
const payload = await res.json();
|
|
560
873
|
setAttachments(
|
|
561
|
-
(prev) => prev.map(
|
|
874
|
+
(prev) => prev.map(
|
|
875
|
+
(a) => a.id === id ? { ...a, status: "ready", payload } : a
|
|
876
|
+
)
|
|
562
877
|
);
|
|
563
878
|
} catch (err) {
|
|
564
879
|
const msg = err instanceof Error ? err.message : "Upload failed";
|
|
@@ -602,16 +917,13 @@ function useAttachments({
|
|
|
602
917
|
return { attachments, attach, remove, clear, isUploading, readyPayloads };
|
|
603
918
|
}
|
|
604
919
|
function DefaultIcon() {
|
|
605
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
"
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
)
|
|
614
|
-
] });
|
|
920
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 26, height: 26 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
921
|
+
"path",
|
|
922
|
+
{
|
|
923
|
+
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",
|
|
924
|
+
fill: "currentColor"
|
|
925
|
+
}
|
|
926
|
+
) });
|
|
615
927
|
}
|
|
616
928
|
function ExpandIcon() {
|
|
617
929
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", style: { width: 11, height: 11 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -637,9 +949,58 @@ function MinimizeIcon() {
|
|
|
637
949
|
}
|
|
638
950
|
) });
|
|
639
951
|
}
|
|
640
|
-
var Avatar = ({
|
|
641
|
-
|
|
642
|
-
|
|
952
|
+
var Avatar = ({
|
|
953
|
+
style,
|
|
954
|
+
...p
|
|
955
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
956
|
+
AvatarPrimitive__namespace.Root,
|
|
957
|
+
{
|
|
958
|
+
style: {
|
|
959
|
+
position: "relative",
|
|
960
|
+
display: "flex",
|
|
961
|
+
flexShrink: 0,
|
|
962
|
+
overflow: "hidden",
|
|
963
|
+
borderRadius: "9999px",
|
|
964
|
+
...style
|
|
965
|
+
},
|
|
966
|
+
...p
|
|
967
|
+
}
|
|
968
|
+
);
|
|
969
|
+
var AvatarImage = ({
|
|
970
|
+
style,
|
|
971
|
+
...p
|
|
972
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
973
|
+
AvatarPrimitive__namespace.Image,
|
|
974
|
+
{
|
|
975
|
+
style: {
|
|
976
|
+
position: "absolute",
|
|
977
|
+
inset: 0,
|
|
978
|
+
width: "100%",
|
|
979
|
+
height: "100%",
|
|
980
|
+
objectFit: "cover",
|
|
981
|
+
...style
|
|
982
|
+
},
|
|
983
|
+
...p
|
|
984
|
+
}
|
|
985
|
+
);
|
|
986
|
+
var AvatarFallback = ({
|
|
987
|
+
style,
|
|
988
|
+
...p
|
|
989
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
990
|
+
AvatarPrimitive__namespace.Fallback,
|
|
991
|
+
{
|
|
992
|
+
style: {
|
|
993
|
+
display: "flex",
|
|
994
|
+
width: "100%",
|
|
995
|
+
height: "100%",
|
|
996
|
+
alignItems: "center",
|
|
997
|
+
justifyContent: "center",
|
|
998
|
+
borderRadius: "9999px",
|
|
999
|
+
...style
|
|
1000
|
+
},
|
|
1001
|
+
...p
|
|
1002
|
+
}
|
|
1003
|
+
);
|
|
643
1004
|
function ChatHeader({
|
|
644
1005
|
title,
|
|
645
1006
|
profilePicture,
|
|
@@ -648,22 +1009,39 @@ function ChatHeader({
|
|
|
648
1009
|
onReset,
|
|
649
1010
|
onClose,
|
|
650
1011
|
onExpand,
|
|
651
|
-
expanded
|
|
1012
|
+
expanded,
|
|
1013
|
+
onCall,
|
|
1014
|
+
isCallLoading
|
|
652
1015
|
}) {
|
|
653
1016
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
654
1017
|
"header",
|
|
655
1018
|
{
|
|
656
|
-
className: "ww-flex ww-items-center ww-justify-between ww-px-4 ww-py-3 ww-shrink-0",
|
|
657
|
-
style: {
|
|
1019
|
+
className: "ww-flex ww-items-center ww-justify-between ww-px-4 ww-py-3 ww-shrink-0 ww-touch-none",
|
|
1020
|
+
style: {
|
|
1021
|
+
backgroundColor: headerBg,
|
|
1022
|
+
color: headerText,
|
|
1023
|
+
borderBottom: `1px solid ${headerText}18`
|
|
1024
|
+
},
|
|
658
1025
|
children: [
|
|
659
1026
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-items-center ww-gap-2.5 ww-min-w-0", children: [
|
|
660
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
661
|
-
|
|
1027
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
|
+
Avatar,
|
|
662
1029
|
{
|
|
663
|
-
style: {
|
|
664
|
-
children:
|
|
1030
|
+
style: { width: 32, height: 32, border: `2px solid ${headerText}30` },
|
|
1031
|
+
children: profilePicture ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: profilePicture, alt: title }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1032
|
+
AvatarFallback,
|
|
1033
|
+
{
|
|
1034
|
+
style: {
|
|
1035
|
+
backgroundColor: `${headerText}20`,
|
|
1036
|
+
color: headerText,
|
|
1037
|
+
fontSize: 11,
|
|
1038
|
+
fontWeight: 700
|
|
1039
|
+
},
|
|
1040
|
+
children: title.slice(0, 2).toUpperCase()
|
|
1041
|
+
}
|
|
1042
|
+
)
|
|
665
1043
|
}
|
|
666
|
-
)
|
|
1044
|
+
),
|
|
667
1045
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-min-w-0", children: [
|
|
668
1046
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "ww-font-semibold ww-text-sm ww-truncate ww-leading-tight", children: title }),
|
|
669
1047
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "ww-text-[10px] ww-opacity-70 ww-leading-tight", children: "AI Assistant" })
|
|
@@ -679,13 +1057,64 @@ function ChatHeader({
|
|
|
679
1057
|
children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ExpandIcon, {})
|
|
680
1058
|
}
|
|
681
1059
|
),
|
|
1060
|
+
onCall && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1061
|
+
"button",
|
|
1062
|
+
{
|
|
1063
|
+
onClick: onCall,
|
|
1064
|
+
disabled: isCallLoading,
|
|
1065
|
+
className: "ww-rounded-full ww-p-1.5 ww-transition-colors hover:ww-bg-white/10 disabled:ww-opacity-50",
|
|
1066
|
+
title: "Voice Call",
|
|
1067
|
+
children: isCallLoading ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1068
|
+
"svg",
|
|
1069
|
+
{
|
|
1070
|
+
className: "ww-animate-spin ww-h-3.5 ww-w-3.5",
|
|
1071
|
+
viewBox: "0 0 24 24",
|
|
1072
|
+
fill: "none",
|
|
1073
|
+
style: { color: headerText },
|
|
1074
|
+
children: [
|
|
1075
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1076
|
+
"circle",
|
|
1077
|
+
{
|
|
1078
|
+
className: "ww-opacity-25",
|
|
1079
|
+
cx: "12",
|
|
1080
|
+
cy: "12",
|
|
1081
|
+
r: "10",
|
|
1082
|
+
stroke: "currentColor",
|
|
1083
|
+
strokeWidth: "4"
|
|
1084
|
+
}
|
|
1085
|
+
),
|
|
1086
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1087
|
+
"path",
|
|
1088
|
+
{
|
|
1089
|
+
className: "ww-opacity-75",
|
|
1090
|
+
fill: "currentColor",
|
|
1091
|
+
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"
|
|
1092
|
+
}
|
|
1093
|
+
)
|
|
1094
|
+
]
|
|
1095
|
+
}
|
|
1096
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1097
|
+
lucideReact.Phone,
|
|
1098
|
+
{
|
|
1099
|
+
className: "ww-h-3.5 ww-w-3.5",
|
|
1100
|
+
style: { color: headerText }
|
|
1101
|
+
}
|
|
1102
|
+
)
|
|
1103
|
+
}
|
|
1104
|
+
),
|
|
682
1105
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
683
1106
|
"button",
|
|
684
1107
|
{
|
|
685
1108
|
onClick: onReset,
|
|
686
1109
|
className: "ww-rounded-full ww-p-1.5 ww-transition-colors hover:ww-bg-white/10",
|
|
687
1110
|
title: "New conversation",
|
|
688
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1111
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1112
|
+
lucideReact.RotateCcw,
|
|
1113
|
+
{
|
|
1114
|
+
className: "ww-h-3.5 ww-w-3.5",
|
|
1115
|
+
style: { color: headerText }
|
|
1116
|
+
}
|
|
1117
|
+
)
|
|
689
1118
|
}
|
|
690
1119
|
),
|
|
691
1120
|
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -709,8 +1138,10 @@ function formatBytes(bytes) {
|
|
|
709
1138
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
710
1139
|
}
|
|
711
1140
|
function ChipLeading({ a }) {
|
|
712
|
-
if (a.status === "uploading")
|
|
713
|
-
|
|
1141
|
+
if (a.status === "uploading")
|
|
1142
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-animate-spin" });
|
|
1143
|
+
if (a.status === "error")
|
|
1144
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "ww-h-3 ww-w-3 ww-shrink-0" });
|
|
714
1145
|
const thumbSrc = a.payload?.url ?? a.payload?.base64;
|
|
715
1146
|
if (a.mimeType.startsWith("image/") && thumbSrc) {
|
|
716
1147
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -722,14 +1153,19 @@ function ChipLeading({ a }) {
|
|
|
722
1153
|
}
|
|
723
1154
|
);
|
|
724
1155
|
}
|
|
725
|
-
if (a.mimeType.startsWith("image/"))
|
|
726
|
-
|
|
1156
|
+
if (a.mimeType.startsWith("image/"))
|
|
1157
|
+
return /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("span", { className: "ww-text-[8px] ww-font-semibold ww-text-muted-foreground/50", children: "IMG" }) });
|
|
1158
|
+
if (a.mimeType === "application/pdf")
|
|
1159
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-text-red-400" });
|
|
727
1160
|
if (a.mimeType.includes("csv") || a.mimeType.includes("spreadsheet") || a.name.endsWith(".csv")) {
|
|
728
1161
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSpreadsheet, { className: "ww-h-3 ww-w-3 ww-shrink-0 ww-text-emerald-500" });
|
|
729
1162
|
}
|
|
730
1163
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "ww-h-3 ww-w-3 ww-shrink-0" });
|
|
731
1164
|
}
|
|
732
|
-
function AttachmentChips({
|
|
1165
|
+
function AttachmentChips({
|
|
1166
|
+
attachments,
|
|
1167
|
+
onRemove
|
|
1168
|
+
}) {
|
|
733
1169
|
if (attachments.length === 0) return null;
|
|
734
1170
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1.5 ww-px-1 ww-pb-1.5", children: attachments.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
735
1171
|
"div",
|
|
@@ -757,41 +1193,49 @@ function AttachmentChips({ attachments, onRemove }) {
|
|
|
757
1193
|
a.id
|
|
758
1194
|
)) });
|
|
759
1195
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
function SentAttachments({ attachments, contrastColor }) {
|
|
1196
|
+
function SentAttachments({
|
|
1197
|
+
attachments,
|
|
1198
|
+
contrastColor
|
|
1199
|
+
}) {
|
|
765
1200
|
const images = attachments.filter((a) => a.contentType === "image");
|
|
766
1201
|
const files = attachments.filter((a) => a.contentType !== "image");
|
|
767
1202
|
const isDark = contrastColor === "#ffffff" || contrastColor === "#fff";
|
|
768
1203
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-flex-col ww-gap-1.5 ww-w-full", children: [
|
|
769
|
-
images.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1204
|
+
images.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1205
|
+
"div",
|
|
1206
|
+
{
|
|
1207
|
+
className: cn(
|
|
1208
|
+
"ww-flex ww-gap-1.5 ww-flex-wrap",
|
|
1209
|
+
images.length === 1 && ""
|
|
1210
|
+
),
|
|
1211
|
+
children: images.map((img) => {
|
|
1212
|
+
const src = img.url ?? img.base64;
|
|
1213
|
+
return src ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1214
|
+
"img",
|
|
1215
|
+
{
|
|
1216
|
+
src,
|
|
1217
|
+
alt: img.name,
|
|
1218
|
+
className: cn(
|
|
1219
|
+
"ww-rounded-xl ww-object-cover ww-border",
|
|
1220
|
+
images.length === 1 ? "ww-w-full ww-max-h-48" : "ww-h-20 ww-w-20",
|
|
1221
|
+
isDark ? "ww-border-white/20" : "ww-border-black/10"
|
|
1222
|
+
)
|
|
1223
|
+
},
|
|
1224
|
+
img.id
|
|
1225
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1226
|
+
"div",
|
|
1227
|
+
{
|
|
1228
|
+
className: cn(
|
|
1229
|
+
"ww-h-20 ww-w-20 ww-rounded-xl ww-flex ww-items-center ww-justify-center ww-text-[10px] ww-font-medium",
|
|
1230
|
+
isDark ? "ww-bg-white/10 ww-text-white/60" : "ww-bg-black/10 ww-text-black/40"
|
|
1231
|
+
),
|
|
1232
|
+
children: "IMG"
|
|
1233
|
+
},
|
|
1234
|
+
img.id
|
|
1235
|
+
);
|
|
1236
|
+
})
|
|
1237
|
+
}
|
|
1238
|
+
),
|
|
795
1239
|
files.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1", children: files.map((f) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
796
1240
|
"div",
|
|
797
1241
|
{
|
|
@@ -809,12 +1253,19 @@ function SentAttachments({ attachments, contrastColor }) {
|
|
|
809
1253
|
] });
|
|
810
1254
|
}
|
|
811
1255
|
function PlanStepIcon({ status }) {
|
|
812
|
-
if (status === "executing")
|
|
813
|
-
|
|
814
|
-
if (status === "
|
|
1256
|
+
if (status === "executing")
|
|
1257
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "ww-h-3 ww-w-3 ww-animate-spin ww-text-primary" });
|
|
1258
|
+
if (status === "success")
|
|
1259
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "ww-h-3 ww-w-3 ww-text-emerald-500" });
|
|
1260
|
+
if (status === "failed")
|
|
1261
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "ww-h-3 ww-w-3 ww-text-destructive" });
|
|
815
1262
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-h-3 ww-w-3 ww-rounded-full ww-border-2 ww-border-muted-foreground/30" });
|
|
816
1263
|
}
|
|
817
|
-
function PlanCard({
|
|
1264
|
+
function PlanCard({
|
|
1265
|
+
part,
|
|
1266
|
+
onSend,
|
|
1267
|
+
disabled
|
|
1268
|
+
}) {
|
|
818
1269
|
const successCount = part.steps.filter((s) => s.status === "success").length;
|
|
819
1270
|
const hasExecuting = part.steps.some((s) => s.status === "executing");
|
|
820
1271
|
const allDone = successCount === part.steps.length && part.steps.length > 0;
|
|
@@ -868,7 +1319,10 @@ function PlanCard({ part, onSend, disabled }) {
|
|
|
868
1319
|
onClick: () => onSend("s\xED, proceder"),
|
|
869
1320
|
disabled,
|
|
870
1321
|
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",
|
|
871
|
-
style: {
|
|
1322
|
+
style: {
|
|
1323
|
+
backgroundColor: "var(--primary, #18181b)",
|
|
1324
|
+
color: "var(--primary-foreground, #fff)"
|
|
1325
|
+
},
|
|
872
1326
|
children: [
|
|
873
1327
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
874
1328
|
"Proceder"
|
|
@@ -950,7 +1404,15 @@ function ReasoningBlock({ text }) {
|
|
|
950
1404
|
children: [
|
|
951
1405
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { className: "ww-h-3 ww-w-3" }),
|
|
952
1406
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reasoning" }),
|
|
953
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1407
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1408
|
+
lucideReact.ChevronDown,
|
|
1409
|
+
{
|
|
1410
|
+
className: cn(
|
|
1411
|
+
"ww-h-3 ww-w-3 ww-transition-transform",
|
|
1412
|
+
open && "ww-rotate-180"
|
|
1413
|
+
)
|
|
1414
|
+
}
|
|
1415
|
+
)
|
|
954
1416
|
]
|
|
955
1417
|
}
|
|
956
1418
|
),
|
|
@@ -972,98 +1434,292 @@ function PickerSelector({
|
|
|
972
1434
|
}, [part.options, query]);
|
|
973
1435
|
const isConsumed = !!part.selectedValue;
|
|
974
1436
|
const handleClick = (opt) => {
|
|
975
|
-
if (!disabled && !isConsumed)
|
|
1437
|
+
if (!disabled && !isConsumed)
|
|
1438
|
+
onSelect(part.pickerId, part.paramName, opt.value, opt.label);
|
|
976
1439
|
};
|
|
977
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
978
|
-
"
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
"
|
|
986
|
-
{
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
"
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
"
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1440
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1441
|
+
"div",
|
|
1442
|
+
{
|
|
1443
|
+
className: cn(
|
|
1444
|
+
"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",
|
|
1445
|
+
"ww-border-border/50"
|
|
1446
|
+
),
|
|
1447
|
+
children: [
|
|
1448
|
+
/* @__PURE__ */ jsxRuntime.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 }),
|
|
1449
|
+
mode === "list" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-relative", children: [
|
|
1450
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.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" }),
|
|
1451
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1452
|
+
"input",
|
|
1453
|
+
{
|
|
1454
|
+
type: "text",
|
|
1455
|
+
value: query,
|
|
1456
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1457
|
+
placeholder: "Search\u2026",
|
|
1458
|
+
disabled: disabled || isConsumed,
|
|
1459
|
+
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"
|
|
1460
|
+
}
|
|
1461
|
+
)
|
|
1462
|
+
] }),
|
|
1463
|
+
mode === "pills" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex ww-flex-wrap ww-gap-1.5", children: part.options.map((opt, i) => {
|
|
1464
|
+
const sel = part.selectedValue === opt.value;
|
|
1465
|
+
const faded = isConsumed && !sel;
|
|
1466
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1467
|
+
"button",
|
|
1468
|
+
{
|
|
1469
|
+
disabled: disabled || isConsumed,
|
|
1470
|
+
onClick: () => handleClick(opt),
|
|
1471
|
+
className: cn(
|
|
1472
|
+
"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",
|
|
1473
|
+
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",
|
|
1474
|
+
disabled && !isConsumed && "ww-opacity-60 ww-pointer-events-none"
|
|
1475
|
+
),
|
|
1476
|
+
children: [
|
|
1477
|
+
sel && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
1478
|
+
opt.label
|
|
1479
|
+
]
|
|
1480
|
+
},
|
|
1481
|
+
`${opt.value}-${i}`
|
|
1482
|
+
);
|
|
1483
|
+
}) }),
|
|
1484
|
+
mode === "grid" && /* @__PURE__ */ jsxRuntime.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) => {
|
|
1485
|
+
const sel = part.selectedValue === opt.value;
|
|
1486
|
+
const faded = isConsumed && !sel;
|
|
1487
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1488
|
+
"button",
|
|
1489
|
+
{
|
|
1490
|
+
disabled: disabled || isConsumed,
|
|
1491
|
+
onClick: () => handleClick(opt),
|
|
1492
|
+
className: cn(
|
|
1493
|
+
"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",
|
|
1494
|
+
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",
|
|
1495
|
+
disabled && !isConsumed && "ww-opacity-60 ww-pointer-events-none"
|
|
1496
|
+
),
|
|
1497
|
+
children: [
|
|
1498
|
+
sel ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ww-h-3 ww-w-3 ww-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ww-h-3 ww-w-3 ww-shrink-0" }),
|
|
1499
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ww-truncate", children: opt.label })
|
|
1500
|
+
]
|
|
1501
|
+
},
|
|
1502
|
+
`${opt.value}-${i}`
|
|
1503
|
+
);
|
|
1504
|
+
}) }),
|
|
1505
|
+
mode === "list" && /* @__PURE__ */ jsxRuntime.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: [
|
|
1506
|
+
filtered.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ww-py-3 ww-text-center ww-text-xs ww-text-muted-foreground/50", children: "No results" }),
|
|
1507
|
+
filtered.map((opt, i) => {
|
|
1508
|
+
const sel = part.selectedValue === opt.value;
|
|
1509
|
+
const faded = isConsumed && !sel;
|
|
1510
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1511
|
+
"button",
|
|
1512
|
+
{
|
|
1513
|
+
disabled: disabled || isConsumed,
|
|
1514
|
+
onClick: () => handleClick(opt),
|
|
1515
|
+
className: cn(
|
|
1516
|
+
"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",
|
|
1517
|
+
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",
|
|
1518
|
+
disabled && !isConsumed && "ww-opacity-60 ww-pointer-events-none"
|
|
1519
|
+
),
|
|
1520
|
+
children: [
|
|
1521
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1522
|
+
"span",
|
|
1523
|
+
{
|
|
1524
|
+
className: cn(
|
|
1525
|
+
"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]",
|
|
1526
|
+
sel ? "ww-border-background ww-bg-background/20" : "ww-border-border/50"
|
|
1527
|
+
),
|
|
1528
|
+
children: sel && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ww-h-2.5 ww-w-2.5" })
|
|
1529
|
+
}
|
|
1530
|
+
),
|
|
1531
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ww-truncate", children: opt.label })
|
|
1532
|
+
]
|
|
1533
|
+
},
|
|
1534
|
+
`${opt.value}-${i}`
|
|
1535
|
+
);
|
|
1536
|
+
})
|
|
1537
|
+
] })
|
|
1538
|
+
]
|
|
1539
|
+
}
|
|
1540
|
+
);
|
|
1541
|
+
}
|
|
1542
|
+
var ReactMarkdown = ReactMarkdownLib__default.default;
|
|
1543
|
+
function MarkdownContent({ text }) {
|
|
1544
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1545
|
+
ReactMarkdown,
|
|
1546
|
+
{
|
|
1547
|
+
remarkPlugins: [remarkGfm__default.default],
|
|
1548
|
+
components: {
|
|
1549
|
+
p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0" }, children }),
|
|
1550
|
+
h1: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1551
|
+
"p",
|
|
1552
|
+
{
|
|
1553
|
+
style: {
|
|
1554
|
+
margin: "6px 0",
|
|
1555
|
+
fontWeight: 700,
|
|
1556
|
+
fontSize: "1em"
|
|
1557
|
+
},
|
|
1558
|
+
children
|
|
1559
|
+
}
|
|
1560
|
+
),
|
|
1561
|
+
h2: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1562
|
+
"p",
|
|
1563
|
+
{
|
|
1564
|
+
style: {
|
|
1565
|
+
margin: "6px 0",
|
|
1566
|
+
fontWeight: 700,
|
|
1567
|
+
fontSize: "1em"
|
|
1568
|
+
},
|
|
1569
|
+
children
|
|
1570
|
+
}
|
|
1571
|
+
),
|
|
1572
|
+
h3: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1573
|
+
"p",
|
|
1045
1574
|
{
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
"
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1575
|
+
style: {
|
|
1576
|
+
margin: "6px 0",
|
|
1577
|
+
fontWeight: 600,
|
|
1578
|
+
fontSize: "0.95em"
|
|
1579
|
+
},
|
|
1580
|
+
children
|
|
1581
|
+
}
|
|
1582
|
+
),
|
|
1583
|
+
ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1584
|
+
ol: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1585
|
+
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { style: { margin: "2px 0" }, children }),
|
|
1586
|
+
strong: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontWeight: 600 }, children }),
|
|
1587
|
+
code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1588
|
+
"code",
|
|
1589
|
+
{
|
|
1590
|
+
style: {
|
|
1591
|
+
fontSize: "0.85em",
|
|
1592
|
+
backgroundColor: "rgba(0,0,0,0.07)",
|
|
1593
|
+
borderRadius: 4,
|
|
1594
|
+
padding: "1px 5px",
|
|
1595
|
+
fontFamily: "monospace"
|
|
1596
|
+
},
|
|
1597
|
+
children
|
|
1598
|
+
}
|
|
1599
|
+
),
|
|
1600
|
+
pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1601
|
+
"pre",
|
|
1602
|
+
{
|
|
1603
|
+
style: {
|
|
1604
|
+
overflowX: "auto",
|
|
1605
|
+
margin: "6px 0",
|
|
1606
|
+
padding: "8px 10px",
|
|
1607
|
+
backgroundColor: "rgba(0,0,0,0.06)",
|
|
1608
|
+
borderRadius: 8,
|
|
1609
|
+
fontSize: "0.82em",
|
|
1610
|
+
fontFamily: "monospace"
|
|
1611
|
+
},
|
|
1612
|
+
children
|
|
1613
|
+
}
|
|
1614
|
+
),
|
|
1615
|
+
a: ({
|
|
1616
|
+
href,
|
|
1617
|
+
children
|
|
1618
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1619
|
+
"a",
|
|
1620
|
+
{
|
|
1621
|
+
href,
|
|
1622
|
+
target: "_blank",
|
|
1623
|
+
rel: "noopener noreferrer",
|
|
1624
|
+
style: { textDecoration: "underline", opacity: 0.75 },
|
|
1625
|
+
children
|
|
1626
|
+
}
|
|
1627
|
+
),
|
|
1628
|
+
table: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1629
|
+
"div",
|
|
1630
|
+
{
|
|
1631
|
+
style: {
|
|
1632
|
+
overflowX: "auto",
|
|
1633
|
+
margin: "6px 0",
|
|
1634
|
+
borderRadius: 8,
|
|
1635
|
+
border: "1px solid rgba(0,0,0,0.1)"
|
|
1636
|
+
},
|
|
1637
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1638
|
+
"table",
|
|
1639
|
+
{
|
|
1640
|
+
style: {
|
|
1641
|
+
borderCollapse: "collapse",
|
|
1642
|
+
minWidth: "100%",
|
|
1643
|
+
fontSize: "0.82em"
|
|
1644
|
+
},
|
|
1645
|
+
children
|
|
1646
|
+
}
|
|
1647
|
+
)
|
|
1648
|
+
}
|
|
1649
|
+
),
|
|
1650
|
+
thead: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("thead", { style: { backgroundColor: "rgba(0,0,0,0.04)" }, children }),
|
|
1651
|
+
tbody: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { children }),
|
|
1652
|
+
tr: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("tr", { style: { borderBottom: "1px solid rgba(0,0,0,0.07)" }, children }),
|
|
1653
|
+
th: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1654
|
+
"th",
|
|
1655
|
+
{
|
|
1656
|
+
style: {
|
|
1657
|
+
padding: "6px 10px",
|
|
1658
|
+
textAlign: "left",
|
|
1659
|
+
fontWeight: 600,
|
|
1660
|
+
whiteSpace: "nowrap"
|
|
1661
|
+
},
|
|
1662
|
+
children
|
|
1663
|
+
}
|
|
1664
|
+
),
|
|
1665
|
+
td: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "5px 10px", verticalAlign: "top" }, children })
|
|
1666
|
+
},
|
|
1667
|
+
children: text
|
|
1668
|
+
}
|
|
1669
|
+
);
|
|
1066
1670
|
}
|
|
1671
|
+
var Avatar2 = ({
|
|
1672
|
+
style,
|
|
1673
|
+
...p
|
|
1674
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1675
|
+
AvatarPrimitive__namespace.Root,
|
|
1676
|
+
{
|
|
1677
|
+
style: {
|
|
1678
|
+
position: "relative",
|
|
1679
|
+
display: "flex",
|
|
1680
|
+
flexShrink: 0,
|
|
1681
|
+
overflow: "hidden",
|
|
1682
|
+
borderRadius: "9999px",
|
|
1683
|
+
...style
|
|
1684
|
+
},
|
|
1685
|
+
...p
|
|
1686
|
+
}
|
|
1687
|
+
);
|
|
1688
|
+
var AvatarImage2 = ({
|
|
1689
|
+
style,
|
|
1690
|
+
...p
|
|
1691
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1692
|
+
AvatarPrimitive__namespace.Image,
|
|
1693
|
+
{
|
|
1694
|
+
style: {
|
|
1695
|
+
position: "absolute",
|
|
1696
|
+
inset: 0,
|
|
1697
|
+
width: "100%",
|
|
1698
|
+
height: "100%",
|
|
1699
|
+
objectFit: "cover",
|
|
1700
|
+
...style
|
|
1701
|
+
},
|
|
1702
|
+
...p
|
|
1703
|
+
}
|
|
1704
|
+
);
|
|
1705
|
+
var AvatarFallback2 = ({
|
|
1706
|
+
style,
|
|
1707
|
+
...p
|
|
1708
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1709
|
+
AvatarPrimitive__namespace.Fallback,
|
|
1710
|
+
{
|
|
1711
|
+
style: {
|
|
1712
|
+
display: "flex",
|
|
1713
|
+
width: "100%",
|
|
1714
|
+
height: "100%",
|
|
1715
|
+
alignItems: "center",
|
|
1716
|
+
justifyContent: "center",
|
|
1717
|
+
borderRadius: "9999px",
|
|
1718
|
+
...style
|
|
1719
|
+
},
|
|
1720
|
+
...p
|
|
1721
|
+
}
|
|
1722
|
+
);
|
|
1067
1723
|
function MessageBubble({
|
|
1068
1724
|
message,
|
|
1069
1725
|
userColor,
|
|
@@ -1077,9 +1733,15 @@ function MessageBubble({
|
|
|
1077
1733
|
const isUser = message.role === "user";
|
|
1078
1734
|
const textPart = message.parts.find((p) => p.type === "text");
|
|
1079
1735
|
const reasoningPart = message.parts.find((p) => p.type === "reasoning");
|
|
1080
|
-
const toolParts = message.parts.filter(
|
|
1081
|
-
|
|
1082
|
-
|
|
1736
|
+
const toolParts = message.parts.filter(
|
|
1737
|
+
(p) => p.type === "tool"
|
|
1738
|
+
);
|
|
1739
|
+
const pickerParts = message.parts.filter(
|
|
1740
|
+
(p) => p.type === "picker"
|
|
1741
|
+
);
|
|
1742
|
+
const planParts = message.parts.filter(
|
|
1743
|
+
(p) => p.type === "plan"
|
|
1744
|
+
);
|
|
1083
1745
|
const contrastColor = getContrastColor(userColor);
|
|
1084
1746
|
if (isUser) {
|
|
1085
1747
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex ww-justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1088,7 +1750,13 @@ function MessageBubble({
|
|
|
1088
1750
|
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",
|
|
1089
1751
|
style: { backgroundColor: userColor, color: contrastColor },
|
|
1090
1752
|
children: [
|
|
1091
|
-
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1753
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1754
|
+
SentAttachments,
|
|
1755
|
+
{
|
|
1756
|
+
attachments: message.attachments,
|
|
1757
|
+
contrastColor
|
|
1758
|
+
}
|
|
1759
|
+
),
|
|
1092
1760
|
textPart?.text && /* @__PURE__ */ jsxRuntime.jsx("span", { children: textPart.text })
|
|
1093
1761
|
]
|
|
1094
1762
|
}
|
|
@@ -1097,10 +1765,40 @@ function MessageBubble({
|
|
|
1097
1765
|
const visibleToolParts = showThinking ? toolParts : [];
|
|
1098
1766
|
const isEmpty = !textPart?.text && visibleToolParts.length === 0 && pickerParts.length === 0 && planParts.length === 0;
|
|
1099
1767
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start", children: [
|
|
1100
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1768
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1769
|
+
Avatar2,
|
|
1770
|
+
{
|
|
1771
|
+
style: {
|
|
1772
|
+
width: 28,
|
|
1773
|
+
height: 28,
|
|
1774
|
+
marginTop: 2,
|
|
1775
|
+
border: "1px solid rgba(0,0,0,0.08)"
|
|
1776
|
+
},
|
|
1777
|
+
children: profilePicture ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage2, { src: profilePicture, alt: agentName }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1778
|
+
AvatarFallback2,
|
|
1779
|
+
{
|
|
1780
|
+
style: {
|
|
1781
|
+
fontSize: 10,
|
|
1782
|
+
fontWeight: 600,
|
|
1783
|
+
backgroundColor: "var(--primary, #19191c)",
|
|
1784
|
+
color: "var(--primary-foreground, #fff)"
|
|
1785
|
+
},
|
|
1786
|
+
children: agentName.slice(0, 2).toUpperCase()
|
|
1787
|
+
}
|
|
1788
|
+
)
|
|
1789
|
+
}
|
|
1790
|
+
),
|
|
1101
1791
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-flex-col ww-gap-1.5 ww-min-w-0 ww-max-w-[82%]", children: [
|
|
1102
1792
|
showThinking && reasoningPart && /* @__PURE__ */ jsxRuntime.jsx(ReasoningBlock, { text: reasoningPart.text }),
|
|
1103
|
-
planParts.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1793
|
+
planParts.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1794
|
+
PlanCard,
|
|
1795
|
+
{
|
|
1796
|
+
part: p,
|
|
1797
|
+
onSend,
|
|
1798
|
+
disabled: isStreaming
|
|
1799
|
+
},
|
|
1800
|
+
p.planId
|
|
1801
|
+
)),
|
|
1104
1802
|
visibleToolParts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallBadge, { part: t }, t.toolCallId)),
|
|
1105
1803
|
pickerParts.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1106
1804
|
PickerSelector,
|
|
@@ -1113,40 +1811,39 @@ function MessageBubble({
|
|
|
1113
1811
|
p.pickerId
|
|
1114
1812
|
)),
|
|
1115
1813
|
isEmpty && isStreaming ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingDots, {}) : textPart?.text ? /* @__PURE__ */ jsxRuntime.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: [
|
|
1116
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1117
|
-
ReactMarkdown,
|
|
1118
|
-
{
|
|
1119
|
-
remarkPlugins: [remarkGfm__default.default],
|
|
1120
|
-
components: {
|
|
1121
|
-
p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0" }, children }),
|
|
1122
|
-
h1: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "6px 0", fontWeight: 700, fontSize: "1em" }, children }),
|
|
1123
|
-
h2: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "6px 0", fontWeight: 700, fontSize: "1em" }, children }),
|
|
1124
|
-
h3: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "6px 0", fontWeight: 600, fontSize: "0.95em" }, children }),
|
|
1125
|
-
ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1126
|
-
ol: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { style: { margin: "4px 0", paddingLeft: 16 }, children }),
|
|
1127
|
-
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { style: { margin: "2px 0" }, children }),
|
|
1128
|
-
strong: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontWeight: 600 }, children }),
|
|
1129
|
-
code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("code", { style: { fontSize: "0.85em", backgroundColor: "rgba(0,0,0,0.07)", borderRadius: 4, padding: "1px 5px", fontFamily: "monospace" }, children }),
|
|
1130
|
-
pre: ({ children }) => /* @__PURE__ */ jsxRuntime.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 }),
|
|
1131
|
-
a: ({ href, children }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "underline", opacity: 0.75 }, children }),
|
|
1132
|
-
table: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto", margin: "6px 0", borderRadius: 8, border: "1px solid rgba(0,0,0,0.1)" }, children: /* @__PURE__ */ jsxRuntime.jsx("table", { style: { borderCollapse: "collapse", minWidth: "100%", fontSize: "0.82em" }, children }) }),
|
|
1133
|
-
thead: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("thead", { style: { backgroundColor: "rgba(0,0,0,0.04)" }, children }),
|
|
1134
|
-
tbody: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { children }),
|
|
1135
|
-
tr: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("tr", { style: { borderBottom: "1px solid rgba(0,0,0,0.07)" }, children }),
|
|
1136
|
-
th: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("th", { style: { padding: "6px 10px", textAlign: "left", fontWeight: 600, whiteSpace: "nowrap" }, children }),
|
|
1137
|
-
td: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "5px 10px", verticalAlign: "top" }, children })
|
|
1138
|
-
},
|
|
1139
|
-
children: textPart.text
|
|
1140
|
-
}
|
|
1141
|
-
),
|
|
1814
|
+
/* @__PURE__ */ jsxRuntime.jsx(MarkdownContent, { text: textPart.text }),
|
|
1142
1815
|
isStreaming && /* @__PURE__ */ jsxRuntime.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" })
|
|
1143
1816
|
] }) : null
|
|
1144
1817
|
] })
|
|
1145
1818
|
] });
|
|
1146
1819
|
}
|
|
1147
|
-
var Avatar3 = ({
|
|
1820
|
+
var Avatar3 = ({
|
|
1821
|
+
className,
|
|
1822
|
+
...p
|
|
1823
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1824
|
+
AvatarPrimitive__namespace.Root,
|
|
1825
|
+
{
|
|
1826
|
+
className: [
|
|
1827
|
+
"ww-relative ww-flex ww-h-10 ww-w-10 ww-shrink-0 ww-overflow-hidden ww-rounded-full",
|
|
1828
|
+
className
|
|
1829
|
+
].filter(Boolean).join(" "),
|
|
1830
|
+
...p
|
|
1831
|
+
}
|
|
1832
|
+
);
|
|
1148
1833
|
var AvatarImage3 = AvatarPrimitive__namespace.Image;
|
|
1149
|
-
var AvatarFallback3 = ({
|
|
1834
|
+
var AvatarFallback3 = ({
|
|
1835
|
+
className,
|
|
1836
|
+
...p
|
|
1837
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1838
|
+
AvatarPrimitive__namespace.Fallback,
|
|
1839
|
+
{
|
|
1840
|
+
className: [
|
|
1841
|
+
"ww-flex ww-h-full ww-w-full ww-items-center ww-justify-center ww-rounded-full ww-bg-muted",
|
|
1842
|
+
className
|
|
1843
|
+
].filter(Boolean).join(" "),
|
|
1844
|
+
...p
|
|
1845
|
+
}
|
|
1846
|
+
);
|
|
1150
1847
|
function ChatMessages({
|
|
1151
1848
|
messages,
|
|
1152
1849
|
streaming,
|
|
@@ -1160,14 +1857,15 @@ function ChatMessages({
|
|
|
1160
1857
|
onPickerSelect
|
|
1161
1858
|
}) {
|
|
1162
1859
|
const bottomRef = react.useRef(null);
|
|
1860
|
+
const greetText = initialMessages[0];
|
|
1163
1861
|
const showGreeting = messages.length === 0;
|
|
1164
1862
|
react.useEffect(() => {
|
|
1165
1863
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1166
1864
|
}, [messages, streaming]);
|
|
1167
1865
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex-1 ww-flex ww-flex-col ww-overflow-y-auto ww-overscroll-contain", children: [
|
|
1168
|
-
showGreeting && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start ww-px-4 ww-pt-5", children: [
|
|
1866
|
+
showGreeting && greetText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-gap-2.5 ww-items-start ww-px-4 ww-pt-5", children: [
|
|
1169
1867
|
/* @__PURE__ */ jsxRuntime.jsx(Avatar3, { className: "ww-h-7 ww-w-7 ww-shrink-0 ww-mt-0.5 ww-border", children: profilePicture ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage3, { src: profilePicture, alt: agentName }) : /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback3, { className: "ww-text-[10px] ww-font-semibold ww-bg-primary ww-text-primary-foreground", children: agentName.slice(0, 2).toUpperCase() }) }),
|
|
1170
|
-
/* @__PURE__ */ jsxRuntime.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:
|
|
1868
|
+
/* @__PURE__ */ jsxRuntime.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 })
|
|
1171
1869
|
] }),
|
|
1172
1870
|
showGreeting && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex-1" }),
|
|
1173
1871
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex ww-flex-col ww-gap-4 ww-px-4 ww-py-4", children: messages.map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1196,7 +1894,13 @@ function ChatMessages({
|
|
|
1196
1894
|
"div",
|
|
1197
1895
|
{
|
|
1198
1896
|
className: "ww-bg-muted",
|
|
1199
|
-
style: {
|
|
1897
|
+
style: {
|
|
1898
|
+
display: "inline-flex",
|
|
1899
|
+
alignItems: "center",
|
|
1900
|
+
gap: 6,
|
|
1901
|
+
borderRadius: "18px 18px 18px 4px",
|
|
1902
|
+
padding: "13px 18px"
|
|
1903
|
+
},
|
|
1200
1904
|
children: [0, 1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1201
1905
|
"span",
|
|
1202
1906
|
{
|
|
@@ -1280,7 +1984,13 @@ function ChatInput({
|
|
|
1280
1984
|
}
|
|
1281
1985
|
),
|
|
1282
1986
|
/* @__PURE__ */ jsxRuntime.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: [
|
|
1283
|
-
hasAttachments && attachments && attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-px-2 ww-pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1987
|
+
hasAttachments && attachments && attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-px-2 ww-pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1988
|
+
AttachmentChips,
|
|
1989
|
+
{
|
|
1990
|
+
attachments,
|
|
1991
|
+
onRemove: (id) => onRemoveAttachment?.(id)
|
|
1992
|
+
}
|
|
1993
|
+
) }),
|
|
1284
1994
|
hasAttachments && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1285
1995
|
"input",
|
|
1286
1996
|
{
|
|
@@ -1370,7 +2080,10 @@ function ChatInput({
|
|
|
1370
2080
|
"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",
|
|
1371
2081
|
hasText || streaming ? "ww-opacity-100 ww-shadow-sm" : "ww-opacity-30"
|
|
1372
2082
|
),
|
|
1373
|
-
style: hasText || streaming ? {
|
|
2083
|
+
style: hasText || streaming ? {
|
|
2084
|
+
backgroundColor: accentColor,
|
|
2085
|
+
color: getContrastColor(accentColor)
|
|
2086
|
+
} : { backgroundColor: "transparent", color: "currentColor" },
|
|
1374
2087
|
children: streaming ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "ww-h-3.5 ww-w-3.5 ww-animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "ww-h-3.5 ww-w-3.5" })
|
|
1375
2088
|
}
|
|
1376
2089
|
)
|
|
@@ -1378,6 +2091,126 @@ function ChatInput({
|
|
|
1378
2091
|
] })
|
|
1379
2092
|
] });
|
|
1380
2093
|
}
|
|
2094
|
+
function CustomControlBar({ onClose }) {
|
|
2095
|
+
const { localParticipant, isMicrophoneEnabled } = componentsReact.useLocalParticipant();
|
|
2096
|
+
const room = componentsReact.useRoomContext();
|
|
2097
|
+
const toggleMic = async () => {
|
|
2098
|
+
if (isMicrophoneEnabled) {
|
|
2099
|
+
await localParticipant.setMicrophoneEnabled(false);
|
|
2100
|
+
} else {
|
|
2101
|
+
await localParticipant.setMicrophoneEnabled(true);
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
const disconnect = () => {
|
|
2105
|
+
room.disconnect();
|
|
2106
|
+
onClose();
|
|
2107
|
+
};
|
|
2108
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-items-center ww-justify-center ww-gap-6", children: [
|
|
2109
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2110
|
+
"button",
|
|
2111
|
+
{
|
|
2112
|
+
onClick: toggleMic,
|
|
2113
|
+
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"}`,
|
|
2114
|
+
title: isMicrophoneEnabled ? "Silenciar micr\xF3fono" : "Activar micr\xF3fono",
|
|
2115
|
+
children: isMicrophoneEnabled ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "ww-w-6 ww-h-6" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { className: "ww-w-6 ww-h-6" })
|
|
2116
|
+
}
|
|
2117
|
+
),
|
|
2118
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2119
|
+
"button",
|
|
2120
|
+
{
|
|
2121
|
+
onClick: disconnect,
|
|
2122
|
+
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",
|
|
2123
|
+
style: { backgroundColor: "#ef4444" },
|
|
2124
|
+
title: "Desconectar",
|
|
2125
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { className: "ww-w-6 ww-h-6" })
|
|
2126
|
+
}
|
|
2127
|
+
)
|
|
2128
|
+
] });
|
|
2129
|
+
}
|
|
2130
|
+
function ChatGPTOrb() {
|
|
2131
|
+
const { state, audioTrack } = componentsReact.useVoiceAssistant();
|
|
2132
|
+
const isSpeaking = state === "speaking";
|
|
2133
|
+
const isListening = state === "listening";
|
|
2134
|
+
const getGradient = () => {
|
|
2135
|
+
if (isSpeaking) {
|
|
2136
|
+
return "linear-gradient(135deg, rgba(59, 130, 246, 0.9), rgba(147, 51, 234, 0.9))";
|
|
2137
|
+
} else if (isListening) {
|
|
2138
|
+
return "linear-gradient(135deg, rgba(16, 185, 129, 0.85), rgba(20, 184, 166, 0.85))";
|
|
2139
|
+
}
|
|
2140
|
+
return "linear-gradient(135deg, rgba(25, 25, 28, 0.8), rgba(25, 25, 28, 0.95))";
|
|
2141
|
+
};
|
|
2142
|
+
const getGlow = () => {
|
|
2143
|
+
if (isSpeaking) return "ww-bg-purple-500/30 ww-animate-ping";
|
|
2144
|
+
if (isListening) return "ww-bg-emerald-500/20 ww-animate-pulse";
|
|
2145
|
+
return "ww-bg-transparent ww-scale-90";
|
|
2146
|
+
};
|
|
2147
|
+
const getRing = () => {
|
|
2148
|
+
if (isSpeaking) return "ww-bg-purple-500/20 ww-scale-110";
|
|
2149
|
+
if (isListening) return "ww-bg-emerald-500/10 ww-scale-105";
|
|
2150
|
+
return "ww-bg-foreground/5 ww-scale-100";
|
|
2151
|
+
};
|
|
2152
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-relative ww-w-48 ww-h-48 ww-flex ww-items-center ww-justify-center", children: [
|
|
2153
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2154
|
+
"div",
|
|
2155
|
+
{
|
|
2156
|
+
className: `ww-absolute ww-inset-0 ww-rounded-full ww-transition-all ww-duration-1000 ${getGlow()}`
|
|
2157
|
+
}
|
|
2158
|
+
),
|
|
2159
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2160
|
+
"div",
|
|
2161
|
+
{
|
|
2162
|
+
className: `ww-absolute ww-inset-4 ww-rounded-full ww-transition-all ww-duration-500 ${getRing()}`
|
|
2163
|
+
}
|
|
2164
|
+
),
|
|
2165
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2166
|
+
"div",
|
|
2167
|
+
{
|
|
2168
|
+
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",
|
|
2169
|
+
style: {
|
|
2170
|
+
background: getGradient(),
|
|
2171
|
+
transform: isSpeaking ? "scale(1.05)" : "scale(1)"
|
|
2172
|
+
},
|
|
2173
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-opacity-90 ww-flex ww-items-center ww-justify-center ww-w-full ww-h-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2174
|
+
componentsReact.BarVisualizer,
|
|
2175
|
+
{
|
|
2176
|
+
state,
|
|
2177
|
+
barCount: 5,
|
|
2178
|
+
trackRef: audioTrack,
|
|
2179
|
+
options: { minHeight: 6 },
|
|
2180
|
+
style: { color: "rgba(255, 255, 255, 0.95)" }
|
|
2181
|
+
}
|
|
2182
|
+
) })
|
|
2183
|
+
}
|
|
2184
|
+
)
|
|
2185
|
+
] });
|
|
2186
|
+
}
|
|
2187
|
+
function AssistantVisualizer({ onClose }) {
|
|
2188
|
+
const { state } = componentsReact.useVoiceAssistant();
|
|
2189
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-flex ww-flex-col ww-items-center ww-justify-center ww-h-full ww-w-full", children: [
|
|
2190
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ww-flex-1 ww-flex ww-items-center ww-justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ChatGPTOrb, {}) }),
|
|
2191
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-h-40 ww-flex ww-flex-col ww-items-center ww-justify-center ww-gap-8 ww-mb-12", children: [
|
|
2192
|
+
/* @__PURE__ */ jsxRuntime.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" }),
|
|
2193
|
+
/* @__PURE__ */ jsxRuntime.jsx(CustomControlBar, { onClose })
|
|
2194
|
+
] })
|
|
2195
|
+
] });
|
|
2196
|
+
}
|
|
2197
|
+
function VoiceOverlay({ token, serverUrl, onClose }) {
|
|
2198
|
+
return /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs(
|
|
2199
|
+
componentsReact.LiveKitRoom,
|
|
2200
|
+
{
|
|
2201
|
+
token,
|
|
2202
|
+
serverUrl,
|
|
2203
|
+
connect: true,
|
|
2204
|
+
audio: true,
|
|
2205
|
+
video: false,
|
|
2206
|
+
className: "ww-flex-1",
|
|
2207
|
+
children: [
|
|
2208
|
+
/* @__PURE__ */ jsxRuntime.jsx(componentsReact.RoomAudioRenderer, {}),
|
|
2209
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssistantVisualizer, { onClose })
|
|
2210
|
+
]
|
|
2211
|
+
}
|
|
2212
|
+
) });
|
|
2213
|
+
}
|
|
1381
2214
|
function ChatWidget({
|
|
1382
2215
|
agentId,
|
|
1383
2216
|
workspaceId,
|
|
@@ -1409,9 +2242,21 @@ function ChatWidget({
|
|
|
1409
2242
|
onReset,
|
|
1410
2243
|
onExpand,
|
|
1411
2244
|
expanded,
|
|
1412
|
-
embedded = false
|
|
2245
|
+
embedded = false,
|
|
2246
|
+
envId,
|
|
2247
|
+
onDebugTrace
|
|
1413
2248
|
}) {
|
|
1414
|
-
const chat = useChat({
|
|
2249
|
+
const chat = useChat({
|
|
2250
|
+
agentId,
|
|
2251
|
+
workspaceId,
|
|
2252
|
+
envId,
|
|
2253
|
+
source,
|
|
2254
|
+
userContext,
|
|
2255
|
+
persist,
|
|
2256
|
+
onNavigate,
|
|
2257
|
+
playgroundOverrides,
|
|
2258
|
+
customBackend
|
|
2259
|
+
});
|
|
1415
2260
|
const voice = useVoice({
|
|
1416
2261
|
agentId,
|
|
1417
2262
|
onTranscript: (text) => {
|
|
@@ -1423,29 +2268,47 @@ function ChatWidget({
|
|
|
1423
2268
|
}
|
|
1424
2269
|
});
|
|
1425
2270
|
const attachmentHook = useAttachments({ agentId });
|
|
2271
|
+
const debugTraceLenRef = react.useRef(0);
|
|
2272
|
+
react.useEffect(() => {
|
|
2273
|
+
if (!onDebugTrace || chat.debugTraces.length <= debugTraceLenRef.current)
|
|
2274
|
+
return;
|
|
2275
|
+
for (let i = debugTraceLenRef.current; i < chat.debugTraces.length; i++) {
|
|
2276
|
+
onDebugTrace(chat.debugTraces[i]);
|
|
2277
|
+
}
|
|
2278
|
+
debugTraceLenRef.current = chat.debugTraces.length;
|
|
2279
|
+
}, [chat.debugTraces, onDebugTrace]);
|
|
1426
2280
|
const [isDragOver, setIsDragOver] = react.useState(false);
|
|
1427
|
-
const handleDragOver = react.useCallback(
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
2281
|
+
const handleDragOver = react.useCallback(
|
|
2282
|
+
(e) => {
|
|
2283
|
+
if (!enableAttachments) return;
|
|
2284
|
+
e.preventDefault();
|
|
2285
|
+
e.stopPropagation();
|
|
2286
|
+
if (e.dataTransfer.types.includes("Files")) setIsDragOver(true);
|
|
2287
|
+
},
|
|
2288
|
+
[enableAttachments]
|
|
2289
|
+
);
|
|
2290
|
+
const handleDragLeave = react.useCallback(
|
|
2291
|
+
(e) => {
|
|
2292
|
+
if (!enableAttachments) return;
|
|
2293
|
+
e.preventDefault();
|
|
2294
|
+
e.stopPropagation();
|
|
2295
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
2296
|
+
setIsDragOver(false);
|
|
2297
|
+
}
|
|
2298
|
+
},
|
|
2299
|
+
[enableAttachments]
|
|
2300
|
+
);
|
|
2301
|
+
const handleDrop = react.useCallback(
|
|
2302
|
+
(e) => {
|
|
2303
|
+
if (!enableAttachments) return;
|
|
2304
|
+
e.preventDefault();
|
|
2305
|
+
e.stopPropagation();
|
|
1438
2306
|
setIsDragOver(false);
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
e.stopPropagation();
|
|
1445
|
-
setIsDragOver(false);
|
|
1446
|
-
const files = e.dataTransfer.files;
|
|
1447
|
-
if (files.length > 0) attachmentHook.attach(files);
|
|
1448
|
-
}, [enableAttachments, attachmentHook]);
|
|
2307
|
+
const files = e.dataTransfer.files;
|
|
2308
|
+
if (files.length > 0) attachmentHook.attach(files);
|
|
2309
|
+
},
|
|
2310
|
+
[enableAttachments, attachmentHook]
|
|
2311
|
+
);
|
|
1449
2312
|
const handleSend = () => {
|
|
1450
2313
|
const payloads = attachmentHook.readyPayloads;
|
|
1451
2314
|
if (payloads.length > 0) {
|
|
@@ -1487,7 +2350,7 @@ function ChatWidget({
|
|
|
1487
2350
|
"div",
|
|
1488
2351
|
{
|
|
1489
2352
|
className: cn(
|
|
1490
|
-
"wallavi-widget ww-flex ww-flex-col ww-overflow-hidden ww-bg-background ww-h-full ww-relative",
|
|
2353
|
+
"wallavi-widget ww-flex ww-flex-col ww-overflow-hidden ww-bg-background ww-h-full ww-relative ww-overscroll-none",
|
|
1491
2354
|
!embedded && "ww-rounded-2xl ww-border ww-shadow-xl",
|
|
1492
2355
|
isDragOver && "ww-ring-2 ww-ring-inset ww-ring-primary/60",
|
|
1493
2356
|
className
|
|
@@ -1513,7 +2376,18 @@ function ChatWidget({
|
|
|
1513
2376
|
onReset: handleReset,
|
|
1514
2377
|
onClose: hideCloseButton ? void 0 : onClose,
|
|
1515
2378
|
onExpand,
|
|
1516
|
-
expanded
|
|
2379
|
+
expanded,
|
|
2380
|
+
onCall: enableVoice && chat.voiceCall ? () => chat.voiceCall?.start() : void 0,
|
|
2381
|
+
isCallLoading: chat.voiceCall?.loading
|
|
2382
|
+
}
|
|
2383
|
+
),
|
|
2384
|
+
chat.voiceCall?.active && chat.voiceCall.token && chat.voiceCall.serverUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2385
|
+
VoiceOverlay,
|
|
2386
|
+
{
|
|
2387
|
+
token: chat.voiceCall.token,
|
|
2388
|
+
serverUrl: chat.voiceCall.serverUrl,
|
|
2389
|
+
onClose: chat.voiceCall.stop,
|
|
2390
|
+
accentColor: userMessageColor
|
|
1517
2391
|
}
|
|
1518
2392
|
),
|
|
1519
2393
|
customBackend?.mode === "human" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1550,22 +2424,91 @@ function ChatWidget({
|
|
|
1550
2424
|
{
|
|
1551
2425
|
onClick: () => void customBackend.footerAction.onClick(),
|
|
1552
2426
|
disabled: customBackend.footerAction.loading,
|
|
1553
|
-
style: customBackend.footerAction.icon === "human" ? {
|
|
2427
|
+
style: customBackend.footerAction.icon === "human" ? {
|
|
2428
|
+
backgroundColor: userMessageColor,
|
|
2429
|
+
color: "#ffffff",
|
|
2430
|
+
boxShadow: `0 2px 12px ${userMessageColor}55`
|
|
2431
|
+
} : {
|
|
2432
|
+
borderColor: `${userMessageColor}35`,
|
|
2433
|
+
backgroundColor: `${userMessageColor}0d`,
|
|
2434
|
+
color: userMessageColor
|
|
2435
|
+
},
|
|
1554
2436
|
className: [
|
|
1555
2437
|
"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",
|
|
1556
2438
|
"hover:ww-opacity-85 active:ww-scale-[0.98] disabled:ww-opacity-50 disabled:ww-pointer-events-none",
|
|
1557
2439
|
customBackend.footerAction.icon === "human" ? "" : "ww-border"
|
|
1558
2440
|
].join(" "),
|
|
1559
2441
|
children: [
|
|
1560
|
-
customBackend.footerAction.loading ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
2442
|
+
customBackend.footerAction.loading ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2443
|
+
"svg",
|
|
2444
|
+
{
|
|
2445
|
+
className: "ww-animate-spin ww-w-3.5 ww-h-3.5 ww-shrink-0",
|
|
2446
|
+
viewBox: "0 0 24 24",
|
|
2447
|
+
fill: "none",
|
|
2448
|
+
children: [
|
|
2449
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2450
|
+
"circle",
|
|
2451
|
+
{
|
|
2452
|
+
className: "ww-opacity-25",
|
|
2453
|
+
cx: "12",
|
|
2454
|
+
cy: "12",
|
|
2455
|
+
r: "10",
|
|
2456
|
+
stroke: "currentColor",
|
|
2457
|
+
strokeWidth: "3"
|
|
2458
|
+
}
|
|
2459
|
+
),
|
|
2460
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2461
|
+
"path",
|
|
2462
|
+
{
|
|
2463
|
+
className: "ww-opacity-75",
|
|
2464
|
+
fill: "currentColor",
|
|
2465
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
2466
|
+
}
|
|
2467
|
+
)
|
|
2468
|
+
]
|
|
2469
|
+
}
|
|
2470
|
+
) : customBackend.footerAction.icon === "ai" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2471
|
+
"svg",
|
|
2472
|
+
{
|
|
2473
|
+
className: "ww-w-3.5 ww-h-3.5 ww-shrink-0",
|
|
2474
|
+
viewBox: "0 0 24 24",
|
|
2475
|
+
fill: "none",
|
|
2476
|
+
stroke: "currentColor",
|
|
2477
|
+
strokeWidth: "2",
|
|
2478
|
+
strokeLinecap: "round",
|
|
2479
|
+
strokeLinejoin: "round",
|
|
2480
|
+
children: /* @__PURE__ */ jsxRuntime.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" })
|
|
2481
|
+
}
|
|
2482
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2483
|
+
"svg",
|
|
2484
|
+
{
|
|
2485
|
+
className: "ww-w-3.5 ww-h-3.5 ww-shrink-0",
|
|
2486
|
+
viewBox: "0 0 24 24",
|
|
2487
|
+
fill: "none",
|
|
2488
|
+
stroke: "currentColor",
|
|
2489
|
+
strokeWidth: "2",
|
|
2490
|
+
strokeLinecap: "round",
|
|
2491
|
+
strokeLinejoin: "round",
|
|
2492
|
+
children: [
|
|
2493
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 18v-6a9 9 0 0 1 18 0v6" }),
|
|
2494
|
+
/* @__PURE__ */ jsxRuntime.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" })
|
|
2495
|
+
]
|
|
2496
|
+
}
|
|
2497
|
+
),
|
|
1567
2498
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ww-flex-1 ww-text-left ww-truncate", children: customBackend.footerAction.label }),
|
|
1568
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2499
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2500
|
+
"svg",
|
|
2501
|
+
{
|
|
2502
|
+
className: "ww-shrink-0 ww-w-3 ww-h-3 ww-opacity-60",
|
|
2503
|
+
viewBox: "0 0 24 24",
|
|
2504
|
+
fill: "none",
|
|
2505
|
+
stroke: "currentColor",
|
|
2506
|
+
strokeWidth: "2.5",
|
|
2507
|
+
strokeLinecap: "round",
|
|
2508
|
+
strokeLinejoin: "round",
|
|
2509
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 18l6-6-6-6" })
|
|
2510
|
+
}
|
|
2511
|
+
)
|
|
1569
2512
|
]
|
|
1570
2513
|
}
|
|
1571
2514
|
) }),
|
|
@@ -1593,7 +2536,7 @@ function ChatWidget({
|
|
|
1593
2536
|
} : {}
|
|
1594
2537
|
}
|
|
1595
2538
|
),
|
|
1596
|
-
watermark && /* @__PURE__ */ jsxRuntime.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: [
|
|
2539
|
+
watermark && /* @__PURE__ */ jsxRuntime.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: [
|
|
1597
2540
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1598
2541
|
"a",
|
|
1599
2542
|
{
|
|
@@ -1643,19 +2586,27 @@ function useAutoConfig(agentId, enabled) {
|
|
|
1643
2586
|
if (cancelled) return;
|
|
1644
2587
|
const cfg = body?.data ?? {};
|
|
1645
2588
|
const remote = {};
|
|
1646
|
-
if (cfg.profilePicture != null)
|
|
1647
|
-
|
|
2589
|
+
if (cfg.profilePicture != null)
|
|
2590
|
+
remote.profilePicture = cfg.profilePicture;
|
|
2591
|
+
if (cfg.displayName != null)
|
|
2592
|
+
remote.displayName = cfg.displayName;
|
|
1648
2593
|
if (cfg.theme) remote.theme = cfg.theme;
|
|
1649
|
-
if (cfg.userMessageColor)
|
|
2594
|
+
if (cfg.userMessageColor)
|
|
2595
|
+
remote.userMessageColor = cfg.userMessageColor;
|
|
1650
2596
|
if (Array.isArray(cfg.initialMessages) && cfg.initialMessages.length > 0)
|
|
1651
2597
|
remote.initialMessages = cfg.initialMessages;
|
|
1652
2598
|
if (Array.isArray(cfg.suggestedMessages))
|
|
1653
2599
|
remote.suggestedMessages = cfg.suggestedMessages;
|
|
1654
|
-
if (cfg.messagePlaceholder != null)
|
|
2600
|
+
if (cfg.messagePlaceholder != null)
|
|
2601
|
+
remote.messagePlaceholder = cfg.messagePlaceholder;
|
|
1655
2602
|
if (cfg.watermark != null) remote.watermark = cfg.watermark;
|
|
1656
2603
|
if (cfg.footer != null) remote.footer = cfg.footer;
|
|
1657
|
-
if (cfg.showThinking != null)
|
|
1658
|
-
|
|
2604
|
+
if (cfg.showThinking != null)
|
|
2605
|
+
remote.showThinking = cfg.showThinking;
|
|
2606
|
+
if (cfg.regenerateMessage != null)
|
|
2607
|
+
remote.regenerateMessage = cfg.regenerateMessage;
|
|
2608
|
+
if (cfg.enableVoice != null)
|
|
2609
|
+
remote.enableVoice = cfg.enableVoice;
|
|
1659
2610
|
setResult({
|
|
1660
2611
|
remoteConfig: remote,
|
|
1661
2612
|
bubbleIconUrl: cfg.chatIcon || cfg.profilePicture || void 0,
|
|
@@ -1693,63 +2644,102 @@ function useSupportChat({
|
|
|
1693
2644
|
const enabled = Boolean(inboxToken) && inboxToken !== "__disabled__";
|
|
1694
2645
|
const STORAGE_KEY = `wlv_support_${inboxToken}`;
|
|
1695
2646
|
const base = apiBase.replace(/\/$/, "");
|
|
1696
|
-
const [session, setSession] = react.useState(
|
|
2647
|
+
const [session, setSession] = react.useState(() => {
|
|
2648
|
+
if (typeof window === "undefined") return null;
|
|
2649
|
+
try {
|
|
2650
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
2651
|
+
if (saved)
|
|
2652
|
+
return JSON.parse(saved).session ?? null;
|
|
2653
|
+
} catch {
|
|
2654
|
+
}
|
|
2655
|
+
return null;
|
|
2656
|
+
});
|
|
1697
2657
|
const [rawMessages, setRawMessages] = react.useState([]);
|
|
1698
2658
|
const [sending, setSending] = react.useState(false);
|
|
1699
|
-
const [isAiMode, setIsAiMode] = react.useState(
|
|
2659
|
+
const [isAiMode, setIsAiMode] = react.useState(() => {
|
|
2660
|
+
if (typeof window === "undefined") return false;
|
|
2661
|
+
try {
|
|
2662
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
2663
|
+
if (saved)
|
|
2664
|
+
return JSON.parse(saved).isAiMode ?? false;
|
|
2665
|
+
} catch {
|
|
2666
|
+
}
|
|
2667
|
+
return false;
|
|
2668
|
+
});
|
|
1700
2669
|
const [agentTyping, setAgentTyping] = react.useState(false);
|
|
1701
2670
|
const [requestingHuman, setRequestingHuman] = react.useState(false);
|
|
1702
2671
|
const [returningToAi, setReturningToAi] = react.useState(false);
|
|
2672
|
+
const [voiceActive, setVoiceActive] = react.useState(false);
|
|
2673
|
+
const [voiceToken, setVoiceToken] = react.useState(null);
|
|
2674
|
+
const [voiceServerUrl, setVoiceServerUrl] = react.useState(null);
|
|
2675
|
+
const [voiceLoading, setVoiceLoading] = react.useState(false);
|
|
2676
|
+
const [voiceError, setVoiceError] = react.useState(null);
|
|
1703
2677
|
const typingTimerRef = react.useRef(null);
|
|
1704
2678
|
react.useEffect(() => {
|
|
1705
2679
|
if (!enabled) return;
|
|
1706
2680
|
try {
|
|
1707
2681
|
const saved = localStorage.getItem(STORAGE_KEY);
|
|
1708
|
-
if (saved)
|
|
1709
|
-
const { session: s, isAiMode: ai } = JSON.parse(saved);
|
|
1710
|
-
setSession(s);
|
|
1711
|
-
setIsAiMode(ai ?? false);
|
|
1712
|
-
}
|
|
2682
|
+
if (saved) JSON.parse(saved);
|
|
1713
2683
|
} catch {
|
|
1714
2684
|
localStorage.removeItem(STORAGE_KEY);
|
|
2685
|
+
setSession(null);
|
|
2686
|
+
setIsAiMode(false);
|
|
1715
2687
|
}
|
|
1716
2688
|
}, [STORAGE_KEY, enabled]);
|
|
1717
|
-
const loadMessages = react.useCallback(
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
2689
|
+
const loadMessages = react.useCallback(
|
|
2690
|
+
async (sess) => {
|
|
2691
|
+
try {
|
|
2692
|
+
const res = await fetch(
|
|
2693
|
+
`${base}/api/support-chat/${sess.conversationId}/messages`,
|
|
2694
|
+
{
|
|
2695
|
+
headers: { "x-visitor-token": sess.visitorToken }
|
|
2696
|
+
}
|
|
2697
|
+
);
|
|
2698
|
+
const data = await res.json();
|
|
2699
|
+
if (Array.isArray(data.data)) setRawMessages(data.data);
|
|
2700
|
+
} catch {
|
|
2701
|
+
}
|
|
2702
|
+
},
|
|
2703
|
+
[base]
|
|
2704
|
+
);
|
|
1727
2705
|
react.useEffect(() => {
|
|
1728
2706
|
if (!enabled || !session) return;
|
|
1729
2707
|
void loadMessages(session);
|
|
1730
2708
|
let ablyClient = null;
|
|
1731
2709
|
const setupAbly = async () => {
|
|
1732
2710
|
try {
|
|
1733
|
-
const res = await fetch(
|
|
1734
|
-
|
|
1735
|
-
|
|
2711
|
+
const res = await fetch(
|
|
2712
|
+
`${base}/api/support-chat/${session.conversationId}/ably-token`,
|
|
2713
|
+
{
|
|
2714
|
+
headers: { "x-visitor-token": session.visitorToken }
|
|
2715
|
+
}
|
|
2716
|
+
);
|
|
1736
2717
|
if (!res.ok) return;
|
|
1737
2718
|
const { tokenRequest, channel: channelName } = await res.json();
|
|
1738
2719
|
const AblyLib = (await import('ably')).default;
|
|
1739
|
-
ablyClient = new AblyLib.Realtime({
|
|
2720
|
+
ablyClient = new AblyLib.Realtime({
|
|
2721
|
+
authCallback: (_, cb) => cb(null, tokenRequest)
|
|
2722
|
+
});
|
|
1740
2723
|
const ch = ablyClient.channels.get(channelName);
|
|
1741
2724
|
ch.subscribe((msg) => {
|
|
1742
2725
|
const event = { type: msg.name, ...msg.data };
|
|
1743
2726
|
if (event.type === "message.created" && event.message) {
|
|
1744
2727
|
setRawMessages((prev) => {
|
|
1745
|
-
if (prev.some((m) => m.id === event.message.id))
|
|
1746
|
-
|
|
2728
|
+
if (prev.some((m) => m.id === event.message.id))
|
|
2729
|
+
return prev;
|
|
2730
|
+
return [
|
|
2731
|
+
...prev.filter((m) => !m.id.startsWith("tmp_")),
|
|
2732
|
+
event.message
|
|
2733
|
+
];
|
|
1747
2734
|
});
|
|
1748
2735
|
} else if (event.type === "agent.typing") {
|
|
1749
2736
|
setAgentTyping(!!event.isTyping);
|
|
1750
2737
|
if (event.isTyping) {
|
|
1751
2738
|
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
1752
|
-
typingTimerRef.current = setTimeout(
|
|
2739
|
+
typingTimerRef.current = setTimeout(
|
|
2740
|
+
() => setAgentTyping(false),
|
|
2741
|
+
6e3
|
|
2742
|
+
);
|
|
1753
2743
|
} else {
|
|
1754
2744
|
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
1755
2745
|
}
|
|
@@ -1757,7 +2747,11 @@ function useSupportChat({
|
|
|
1757
2747
|
const newIsAi = event.mode === "auto";
|
|
1758
2748
|
setIsAiMode(newIsAi);
|
|
1759
2749
|
setSession((s) => {
|
|
1760
|
-
if (s)
|
|
2750
|
+
if (s)
|
|
2751
|
+
localStorage.setItem(
|
|
2752
|
+
STORAGE_KEY,
|
|
2753
|
+
JSON.stringify({ session: s, isAiMode: newIsAi })
|
|
2754
|
+
);
|
|
1761
2755
|
return s;
|
|
1762
2756
|
});
|
|
1763
2757
|
}
|
|
@@ -1768,84 +2762,117 @@ function useSupportChat({
|
|
|
1768
2762
|
void setupAbly();
|
|
1769
2763
|
const pollId = setInterval(() => void loadMessages(session), 3e4);
|
|
1770
2764
|
return () => {
|
|
1771
|
-
if (ablyClient)
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
2765
|
+
if (ablyClient)
|
|
2766
|
+
try {
|
|
2767
|
+
ablyClient.close();
|
|
2768
|
+
} catch {
|
|
2769
|
+
}
|
|
1775
2770
|
clearInterval(pollId);
|
|
1776
2771
|
if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
|
|
1777
2772
|
};
|
|
1778
2773
|
}, [session, STORAGE_KEY, base, loadMessages]);
|
|
1779
|
-
const send = react.useCallback(
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
attachments
|
|
1792
|
-
})
|
|
1793
|
-
});
|
|
1794
|
-
const data = await res.json();
|
|
1795
|
-
if (data.data) {
|
|
1796
|
-
const sess = {
|
|
1797
|
-
conversationId: data.data.conversationId,
|
|
1798
|
-
visitorToken: data.data.visitorToken
|
|
1799
|
-
};
|
|
1800
|
-
const ai = data.data.isAiMode ?? false;
|
|
1801
|
-
localStorage.setItem(STORAGE_KEY, JSON.stringify({ session: sess, isAiMode: ai }));
|
|
1802
|
-
setSession(sess);
|
|
1803
|
-
setIsAiMode(ai);
|
|
1804
|
-
if (Array.isArray(data.data.messages)) {
|
|
1805
|
-
setRawMessages(data.data.messages);
|
|
2774
|
+
const send = react.useCallback(
|
|
2775
|
+
async (text, attachments) => {
|
|
2776
|
+
if (!text.trim() && !attachments?.length) return;
|
|
2777
|
+
if (sending) return;
|
|
2778
|
+
setSending(true);
|
|
2779
|
+
if (!session) {
|
|
2780
|
+
setRawMessages([
|
|
2781
|
+
{
|
|
2782
|
+
id: `tmp_${Date.now()}`,
|
|
2783
|
+
role: "customer",
|
|
2784
|
+
content: text || `[${attachments?.length ?? 0} archivo(s)]`,
|
|
2785
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2786
|
+
metadata: attachments?.length ? { attachments } : void 0
|
|
1806
2787
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
}]);
|
|
1818
|
-
try {
|
|
1819
|
-
const body = { content: text };
|
|
1820
|
-
if (attachments?.length) body.attachments = attachments;
|
|
1821
|
-
const res = await fetch(`${base}/api/support-chat/${session.conversationId}/messages`, {
|
|
1822
|
-
method: "POST",
|
|
1823
|
-
headers: { "Content-Type": "application/json", "x-visitor-token": session.visitorToken },
|
|
1824
|
-
body: JSON.stringify(body)
|
|
1825
|
-
});
|
|
1826
|
-
const data = await res.json();
|
|
1827
|
-
if (data.data?.aiReply) {
|
|
1828
|
-
setRawMessages((prev) => {
|
|
1829
|
-
const withoutTemp = prev.filter((m) => !m.id.startsWith("tmp_"));
|
|
1830
|
-
return [...withoutTemp, data.data.aiReply];
|
|
2788
|
+
]);
|
|
2789
|
+
try {
|
|
2790
|
+
const res = await fetch(`${base}/api/support-chat/start`, {
|
|
2791
|
+
method: "POST",
|
|
2792
|
+
headers: { "Content-Type": "application/json" },
|
|
2793
|
+
body: JSON.stringify({
|
|
2794
|
+
inboxToken,
|
|
2795
|
+
message: text || `[${attachments.length} archivo(s)]`,
|
|
2796
|
+
attachments
|
|
2797
|
+
})
|
|
1831
2798
|
});
|
|
2799
|
+
const data = await res.json();
|
|
2800
|
+
if (data.data) {
|
|
2801
|
+
const sess = {
|
|
2802
|
+
conversationId: data.data.conversationId,
|
|
2803
|
+
visitorToken: data.data.visitorToken
|
|
2804
|
+
};
|
|
2805
|
+
const ai = data.data.isAiMode ?? false;
|
|
2806
|
+
localStorage.setItem(
|
|
2807
|
+
STORAGE_KEY,
|
|
2808
|
+
JSON.stringify({ session: sess, isAiMode: ai })
|
|
2809
|
+
);
|
|
2810
|
+
setSession(sess);
|
|
2811
|
+
setIsAiMode(ai);
|
|
2812
|
+
if (Array.isArray(data.data.messages)) {
|
|
2813
|
+
setRawMessages(data.data.messages);
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
} catch {
|
|
2817
|
+
}
|
|
2818
|
+
} else {
|
|
2819
|
+
setRawMessages((prev) => [
|
|
2820
|
+
...prev,
|
|
2821
|
+
{
|
|
2822
|
+
id: `tmp_${Date.now()}`,
|
|
2823
|
+
role: "customer",
|
|
2824
|
+
content: text || `[${attachments.length} archivo(s)]`,
|
|
2825
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2826
|
+
metadata: attachments?.length ? { attachments } : void 0
|
|
2827
|
+
}
|
|
2828
|
+
]);
|
|
2829
|
+
try {
|
|
2830
|
+
const body = { content: text };
|
|
2831
|
+
if (attachments?.length) body.attachments = attachments;
|
|
2832
|
+
const res = await fetch(
|
|
2833
|
+
`${base}/api/support-chat/${session.conversationId}/messages`,
|
|
2834
|
+
{
|
|
2835
|
+
method: "POST",
|
|
2836
|
+
headers: {
|
|
2837
|
+
"Content-Type": "application/json",
|
|
2838
|
+
"x-visitor-token": session.visitorToken
|
|
2839
|
+
},
|
|
2840
|
+
body: JSON.stringify(body)
|
|
2841
|
+
}
|
|
2842
|
+
);
|
|
2843
|
+
const data = await res.json();
|
|
2844
|
+
if (data.data?.aiReply) {
|
|
2845
|
+
setRawMessages((prev) => {
|
|
2846
|
+
const withoutTemp = prev.filter((m) => !m.id.startsWith("tmp_"));
|
|
2847
|
+
if (withoutTemp.some((m) => m.id === data.data.aiReply.id))
|
|
2848
|
+
return withoutTemp;
|
|
2849
|
+
return [...withoutTemp, data.data.aiReply];
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
} catch {
|
|
1832
2853
|
}
|
|
1833
|
-
} catch {
|
|
1834
2854
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
2855
|
+
setSending(false);
|
|
2856
|
+
},
|
|
2857
|
+
[session, sending, inboxToken, base, STORAGE_KEY]
|
|
2858
|
+
);
|
|
1838
2859
|
const requestHuman = react.useCallback(async () => {
|
|
1839
2860
|
if (!session || !isAiMode || requestingHuman) return;
|
|
1840
2861
|
setRequestingHuman(true);
|
|
1841
2862
|
try {
|
|
1842
2863
|
await fetch(`${base}/api/support-chat/${session.conversationId}/mode`, {
|
|
1843
2864
|
method: "PATCH",
|
|
1844
|
-
headers: {
|
|
2865
|
+
headers: {
|
|
2866
|
+
"Content-Type": "application/json",
|
|
2867
|
+
"x-visitor-token": session.visitorToken
|
|
2868
|
+
},
|
|
1845
2869
|
body: JSON.stringify({ mode: "human" })
|
|
1846
2870
|
});
|
|
1847
2871
|
setIsAiMode(false);
|
|
1848
|
-
localStorage.setItem(
|
|
2872
|
+
localStorage.setItem(
|
|
2873
|
+
STORAGE_KEY,
|
|
2874
|
+
JSON.stringify({ session, isAiMode: false })
|
|
2875
|
+
);
|
|
1849
2876
|
} catch {
|
|
1850
2877
|
}
|
|
1851
2878
|
setRequestingHuman(false);
|
|
@@ -1856,15 +2883,47 @@ function useSupportChat({
|
|
|
1856
2883
|
try {
|
|
1857
2884
|
await fetch(`${base}/api/support-chat/${session.conversationId}/mode`, {
|
|
1858
2885
|
method: "PATCH",
|
|
1859
|
-
headers: {
|
|
2886
|
+
headers: {
|
|
2887
|
+
"Content-Type": "application/json",
|
|
2888
|
+
"x-visitor-token": session.visitorToken
|
|
2889
|
+
},
|
|
1860
2890
|
body: JSON.stringify({ mode: "auto" })
|
|
1861
2891
|
});
|
|
1862
2892
|
setIsAiMode(true);
|
|
1863
|
-
localStorage.setItem(
|
|
2893
|
+
localStorage.setItem(
|
|
2894
|
+
STORAGE_KEY,
|
|
2895
|
+
JSON.stringify({ session, isAiMode: true })
|
|
2896
|
+
);
|
|
1864
2897
|
} catch {
|
|
1865
2898
|
}
|
|
1866
2899
|
setReturningToAi(false);
|
|
1867
2900
|
}, [session, isAiMode, returningToAi, base, STORAGE_KEY]);
|
|
2901
|
+
const startVoiceCall = react.useCallback(async () => {
|
|
2902
|
+
if (!session || !isAiMode) return;
|
|
2903
|
+
setVoiceLoading(true);
|
|
2904
|
+
setVoiceError(null);
|
|
2905
|
+
try {
|
|
2906
|
+
const res = await fetch(
|
|
2907
|
+
`${base}/api/support-chat/${session.conversationId}/livekit-token`,
|
|
2908
|
+
{
|
|
2909
|
+
headers: { "x-visitor-token": session.visitorToken }
|
|
2910
|
+
}
|
|
2911
|
+
);
|
|
2912
|
+
const data = await res.json();
|
|
2913
|
+
if (!res.ok) throw new Error(data.error || "Failed to start call");
|
|
2914
|
+
setVoiceToken(data.token);
|
|
2915
|
+
setVoiceServerUrl(data.url);
|
|
2916
|
+
setVoiceActive(true);
|
|
2917
|
+
} catch (err) {
|
|
2918
|
+
setVoiceError(err.message);
|
|
2919
|
+
}
|
|
2920
|
+
setVoiceLoading(false);
|
|
2921
|
+
}, [session, isAiMode, base]);
|
|
2922
|
+
const stopVoiceCall = react.useCallback(() => {
|
|
2923
|
+
setVoiceActive(false);
|
|
2924
|
+
setVoiceToken(null);
|
|
2925
|
+
setVoiceServerUrl(null);
|
|
2926
|
+
}, []);
|
|
1868
2927
|
const reset = react.useCallback(() => {
|
|
1869
2928
|
localStorage.removeItem(STORAGE_KEY);
|
|
1870
2929
|
setSession(null);
|
|
@@ -1873,28 +2932,78 @@ function useSupportChat({
|
|
|
1873
2932
|
setAgentTyping(false);
|
|
1874
2933
|
setRequestingHuman(false);
|
|
1875
2934
|
setReturningToAi(false);
|
|
1876
|
-
|
|
2935
|
+
stopVoiceCall();
|
|
2936
|
+
}, [STORAGE_KEY, stopVoiceCall]);
|
|
1877
2937
|
const messages = react.useMemo(
|
|
1878
2938
|
() => rawMessages.filter((m) => m.role !== "system").map(toWidgetMsg),
|
|
1879
2939
|
[rawMessages]
|
|
1880
2940
|
);
|
|
1881
2941
|
const footerAction = react.useMemo(() => {
|
|
1882
2942
|
if (isAiMode) {
|
|
1883
|
-
return {
|
|
2943
|
+
return {
|
|
2944
|
+
label: requestHumanLabel,
|
|
2945
|
+
sublabel: "Te conectamos con un agente disponible",
|
|
2946
|
+
icon: "human",
|
|
2947
|
+
onClick: requestHuman,
|
|
2948
|
+
loading: requestingHuman
|
|
2949
|
+
};
|
|
1884
2950
|
}
|
|
1885
2951
|
if (!isAiMode && session && returnToAiLabel) {
|
|
1886
|
-
return {
|
|
2952
|
+
return {
|
|
2953
|
+
label: returnToAiLabel,
|
|
2954
|
+
sublabel: "Respuesta instant\xE1nea con inteligencia artificial",
|
|
2955
|
+
icon: "ai",
|
|
2956
|
+
onClick: returnToAi,
|
|
2957
|
+
loading: returningToAi
|
|
2958
|
+
};
|
|
1887
2959
|
}
|
|
1888
2960
|
return void 0;
|
|
1889
|
-
}, [
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2961
|
+
}, [
|
|
2962
|
+
isAiMode,
|
|
2963
|
+
session,
|
|
2964
|
+
requestHumanLabel,
|
|
2965
|
+
requestHuman,
|
|
2966
|
+
requestingHuman,
|
|
2967
|
+
returnToAiLabel,
|
|
2968
|
+
returnToAi,
|
|
2969
|
+
returningToAi
|
|
2970
|
+
]);
|
|
2971
|
+
return react.useMemo(
|
|
2972
|
+
() => ({
|
|
2973
|
+
messages,
|
|
2974
|
+
streaming: sending || agentTyping,
|
|
2975
|
+
send,
|
|
2976
|
+
reset,
|
|
2977
|
+
mode: isAiMode || !session ? "ai" : "human",
|
|
2978
|
+
...footerAction ? { footerAction } : {},
|
|
2979
|
+
voiceCall: isAiMode && session ? {
|
|
2980
|
+
active: voiceActive,
|
|
2981
|
+
token: voiceToken,
|
|
2982
|
+
serverUrl: voiceServerUrl,
|
|
2983
|
+
start: startVoiceCall,
|
|
2984
|
+
stop: stopVoiceCall,
|
|
2985
|
+
loading: voiceLoading,
|
|
2986
|
+
error: voiceError
|
|
2987
|
+
} : void 0
|
|
2988
|
+
}),
|
|
2989
|
+
[
|
|
2990
|
+
messages,
|
|
2991
|
+
sending,
|
|
2992
|
+
agentTyping,
|
|
2993
|
+
send,
|
|
2994
|
+
reset,
|
|
2995
|
+
isAiMode,
|
|
2996
|
+
footerAction,
|
|
2997
|
+
voiceActive,
|
|
2998
|
+
voiceToken,
|
|
2999
|
+
voiceServerUrl,
|
|
3000
|
+
startVoiceCall,
|
|
3001
|
+
stopVoiceCall,
|
|
3002
|
+
voiceLoading,
|
|
3003
|
+
voiceError,
|
|
3004
|
+
session
|
|
3005
|
+
]
|
|
3006
|
+
);
|
|
1898
3007
|
}
|
|
1899
3008
|
var KEY_EXPANDED = "wallavi_bubble_expanded";
|
|
1900
3009
|
var KEY_DISMISSED = "wallavi_bubble_dismissed";
|
|
@@ -1921,50 +3030,62 @@ function BubbleWidget({
|
|
|
1921
3030
|
...chatProps
|
|
1922
3031
|
}) {
|
|
1923
3032
|
const supportBackend = useSupportChat(
|
|
1924
|
-
inboxToken ? {
|
|
3033
|
+
inboxToken ? {
|
|
3034
|
+
inboxToken,
|
|
3035
|
+
apiBase: supportApiBase,
|
|
3036
|
+
requestHumanLabel,
|
|
3037
|
+
returnToAiLabel
|
|
3038
|
+
} : { inboxToken: "__disabled__", apiBase: supportApiBase }
|
|
1925
3039
|
);
|
|
1926
3040
|
const isControlled = isOpenProp !== void 0;
|
|
1927
3041
|
const [internalOpen, setInternalOpen] = react.useState(false);
|
|
1928
3042
|
const open = isControlled ? isOpenProp : internalOpen;
|
|
1929
|
-
const setOpen = react.useCallback(
|
|
1930
|
-
|
|
1931
|
-
if (
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
3043
|
+
const setOpen = react.useCallback(
|
|
3044
|
+
(valueOrUpdater) => {
|
|
3045
|
+
if (!isControlled) {
|
|
3046
|
+
if (typeof valueOrUpdater === "function") {
|
|
3047
|
+
setInternalOpen((prev) => {
|
|
3048
|
+
const next = valueOrUpdater(prev);
|
|
3049
|
+
onOpenChange?.(next);
|
|
3050
|
+
return next;
|
|
3051
|
+
});
|
|
3052
|
+
} else {
|
|
3053
|
+
setInternalOpen(valueOrUpdater);
|
|
3054
|
+
onOpenChange?.(valueOrUpdater);
|
|
3055
|
+
}
|
|
1937
3056
|
} else {
|
|
1938
|
-
|
|
1939
|
-
onOpenChange?.(
|
|
3057
|
+
const next = typeof valueOrUpdater === "function" ? valueOrUpdater(open) : valueOrUpdater;
|
|
3058
|
+
onOpenChange?.(next);
|
|
1940
3059
|
}
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
}
|
|
1945
|
-
}, [isControlled, open, onOpenChange]);
|
|
3060
|
+
},
|
|
3061
|
+
[isControlled, open, onOpenChange]
|
|
3062
|
+
);
|
|
1946
3063
|
const [expanded, setExpanded] = react.useState(false);
|
|
1947
3064
|
const panelRef = react.useRef(null);
|
|
1948
3065
|
const autoOpenedRef = react.useRef(false);
|
|
1949
3066
|
react.useEffect(() => {
|
|
1950
3067
|
if (localStorage.getItem(KEY_EXPANDED) === "true") setExpanded(true);
|
|
1951
3068
|
}, []);
|
|
1952
|
-
const remote = useAutoConfig(
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
const
|
|
1957
|
-
const
|
|
1958
|
-
const
|
|
1959
|
-
const
|
|
3069
|
+
const remote = useAutoConfig(
|
|
3070
|
+
inboxToken ? "" : chatProps.agentId ?? "",
|
|
3071
|
+
!inboxToken && autoConfig
|
|
3072
|
+
);
|
|
3073
|
+
const resolvedPosition = remote.position ?? positionProp;
|
|
3074
|
+
const resolvedBubbleIcon = remote.bubbleIconUrl ?? bubbleIconUrlProp;
|
|
3075
|
+
const resolvedAutoOpen = remote.autoOpen || autoOpenProp;
|
|
3076
|
+
const resolvedKeyboardShortcut = remote.keyboardShortcut || keyboardShortcutProp;
|
|
3077
|
+
const resolvedBubbleSize = remote.bubbleSize ?? bubbleSizeProp;
|
|
3078
|
+
const resolvedWidth = remote.panelWidth ?? widthProp;
|
|
3079
|
+
const resolvedHeight = remote.panelHeight ?? heightProp;
|
|
1960
3080
|
const definedChatProps = Object.fromEntries(
|
|
1961
3081
|
Object.entries(chatProps).filter(([, v]) => v !== void 0)
|
|
1962
3082
|
);
|
|
1963
3083
|
const mergedConfig = {
|
|
1964
|
-
...remote.remoteConfig,
|
|
1965
3084
|
...definedChatProps,
|
|
3085
|
+
...remote.remoteConfig,
|
|
1966
3086
|
agentId: chatProps.agentId ?? "",
|
|
1967
|
-
agentName: chatProps.agentName ?? ""
|
|
3087
|
+
agentName: remote.remoteConfig.agentName ?? chatProps.agentName ?? "Asistente",
|
|
3088
|
+
source: chatProps.source ?? remote.remoteConfig.source ?? "web"
|
|
1968
3089
|
};
|
|
1969
3090
|
const setOpenRef = react.useRef(setOpen);
|
|
1970
3091
|
react.useEffect(() => {
|
|
@@ -1981,7 +3102,7 @@ function BubbleWidget({
|
|
|
1981
3102
|
react.useEffect(() => {
|
|
1982
3103
|
if (!resolvedKeyboardShortcut) return;
|
|
1983
3104
|
const onKey = (e) => {
|
|
1984
|
-
if ((e.metaKey || e.ctrlKey) && e.key === shortcutKey) {
|
|
3105
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === shortcutKey.toLowerCase()) {
|
|
1985
3106
|
e.preventDefault();
|
|
1986
3107
|
setOpenRef.current((v) => !v);
|
|
1987
3108
|
}
|
|
@@ -2000,7 +3121,10 @@ function BubbleWidget({
|
|
|
2000
3121
|
const handleClose = () => {
|
|
2001
3122
|
setOpen(false);
|
|
2002
3123
|
if (!isControlled) {
|
|
2003
|
-
localStorage.setItem(
|
|
3124
|
+
localStorage.setItem(
|
|
3125
|
+
KEY_DISMISSED,
|
|
3126
|
+
String(Date.now() + 24 * 60 * 60 * 1e3)
|
|
3127
|
+
);
|
|
2004
3128
|
}
|
|
2005
3129
|
};
|
|
2006
3130
|
const toggleExpanded = () => setExpanded((v) => {
|
|
@@ -2009,7 +3133,10 @@ function BubbleWidget({
|
|
|
2009
3133
|
return next;
|
|
2010
3134
|
});
|
|
2011
3135
|
const isLeft = resolvedPosition === "bottom-left";
|
|
2012
|
-
const panelWidth = expanded ? Math.min(
|
|
3136
|
+
const panelWidth = expanded ? Math.min(
|
|
3137
|
+
expandedWidth,
|
|
3138
|
+
typeof window !== "undefined" ? window.innerWidth - 40 : expandedWidth
|
|
3139
|
+
) : resolvedWidth;
|
|
2013
3140
|
const panelHeight = expanded ? expandedHeight : resolvedHeight;
|
|
2014
3141
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2015
3142
|
"div",
|
|
@@ -2067,15 +3194,20 @@ function BubbleWidget({
|
|
|
2067
3194
|
alignItems: "center",
|
|
2068
3195
|
justifyContent: "center",
|
|
2069
3196
|
transition: "transform 0.2s ease, box-shadow 0.2s ease",
|
|
2070
|
-
background: open ? "
|
|
2071
|
-
color: open ? "
|
|
3197
|
+
background: open ? "#19191c" : "#ffffff",
|
|
3198
|
+
color: open ? "#ffffff" : "#19191c"
|
|
2072
3199
|
},
|
|
2073
3200
|
children: open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { style: { width: 20, height: 20 } }) : resolvedBubbleIcon ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2074
3201
|
"img",
|
|
2075
3202
|
{
|
|
2076
3203
|
src: resolvedBubbleIcon,
|
|
2077
3204
|
alt: "",
|
|
2078
|
-
style: {
|
|
3205
|
+
style: {
|
|
3206
|
+
width: "100%",
|
|
3207
|
+
height: "100%",
|
|
3208
|
+
objectFit: "cover",
|
|
3209
|
+
display: "block"
|
|
3210
|
+
}
|
|
2079
3211
|
}
|
|
2080
3212
|
) : /* @__PURE__ */ jsxRuntime.jsx(DefaultIcon, {})
|
|
2081
3213
|
}
|
|
@@ -2087,6 +3219,9 @@ function BubbleWidget({
|
|
|
2087
3219
|
|
|
2088
3220
|
exports.BubbleWidget = BubbleWidget;
|
|
2089
3221
|
exports.ChatWidget = ChatWidget;
|
|
3222
|
+
exports.PlanCard = PlanCard;
|
|
3223
|
+
exports.ReasoningBlock = ReasoningBlock;
|
|
3224
|
+
exports.ToolCallBadge = ToolCallBadge;
|
|
2090
3225
|
exports.formatToolName = formatToolName;
|
|
2091
3226
|
exports.getContrastColor = getContrastColor;
|
|
2092
3227
|
exports.useAttachments = useAttachments;
|