@usecrow/ui 0.1.0 → 0.1.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.js CHANGED
@@ -1,203 +1,1200 @@
1
- import { createContext, useRef, useEffect, useMemo, useContext, useState, useCallback } from 'react';
2
- import { CrowClient } from '@usecrow/client';
1
+ import React3, { createContext, forwardRef, useRef, useCallback, useEffect, useContext, useState, useMemo, useLayoutEffect } from 'react';
2
+ import { motion, AnimatePresence } from 'framer-motion';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { clsx } from 'clsx';
4
+ import { Square, ArrowUp, ChevronDown, Check, MessageCircle, Plus, History, ChevronUp, Brain, ChevronRight, Loader2, X } from 'lucide-react';
5
+ import ReactMarkdown from 'react-markdown';
6
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
7
+ import { CrowClient } from '@usecrow/client';
5
8
 
6
- var CrowContext = createContext(null);
7
- function CrowProvider({
8
- children,
9
+ // src/styles/inject.ts
10
+ var STYLE_ID = "crow-ui-styles";
11
+ var CSS_CONTENT = `*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }
12
+
13
+ /*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.crow-pointer-events-none{pointer-events:none}.crow-pointer-events-auto{pointer-events:auto}.crow-fixed{position:fixed}.crow-absolute{position:absolute}.crow-relative{position:relative}.crow-sticky{position:sticky}.crow-bottom-0{bottom:0}.crow-bottom-full{bottom:100%}.crow-left-0{left:0}.crow-right-0{right:0}.crow-top-0{top:0}.crow-z-50{z-index:50}.crow-z-\\[999999\\]{z-index:999999}.crow-m-0{margin:0}.crow-my-1{margin-top:.25rem}.crow-mb-1,.crow-my-1{margin-bottom:.25rem}.crow-mb-2{margin-bottom:.5rem}.crow-mb-3{margin-bottom:.75rem}.crow-ml-0{margin-left:0}.crow-ml-0\\.5{margin-left:.125rem}.crow-ml-2{margin-left:.5rem}.crow-ml-4{margin-left:1rem}.crow-mt-0{margin-top:0}.crow-mt-0\\.5{margin-top:.125rem}.crow-mt-1{margin-top:.25rem}.crow-mt-2{margin-top:.5rem}.crow-mt-auto{margin-top:auto}.crow-inline-block{display:inline-block}.crow-flex{display:flex}.crow-inline-flex{display:inline-flex}.crow-h-10{height:2.5rem}.crow-h-12{height:3rem}.crow-h-2{height:.5rem}.crow-h-3{height:.75rem}.crow-h-3\\.5{height:.875rem}.crow-h-4{height:1rem}.crow-h-7{height:1.75rem}.crow-h-8{height:2rem}.crow-h-full{height:100%}.crow-max-h-32{max-height:8rem}.crow-max-h-\\[200px\\]{max-height:200px}.crow-min-h-0{min-height:0}.crow-min-h-\\[32px\\]{min-height:32px}.crow-w-0{width:0}.crow-w-0\\.5{width:.125rem}.crow-w-2{width:.5rem}.crow-w-3{width:.75rem}.crow-w-3\\.5{width:.875rem}.crow-w-4{width:1rem}.crow-w-7{width:1.75rem}.crow-w-8{width:2rem}.crow-w-full{width:100%}.crow-min-w-0{min-width:0}.crow-min-w-\\[180px\\]{min-width:180px}.crow-max-w-\\[80\\%\\]{max-width:80%}.crow-max-w-\\[90\\%\\]{max-width:90%}.crow-max-w-full{max-width:100%}.crow-flex-1{flex:1 1 0%}.crow-flex-shrink-0{flex-shrink:0}.crow-rotate-180{--tw-rotate:180deg}.crow-rotate-180,.crow-scale-100{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))}.crow-scale-100{--tw-scale-x:1;--tw-scale-y:1}.crow-scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;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))}.crow-animate-fade-in{animation:crow-fadeIn .2s ease-out}.crow-animate-pulse{animation:crow-pulse 2s cubic-bezier(.4,0,.6,1) infinite}.crow-animate-slide-up{animation:crow-slideUp .3s ease-out}@keyframes crow-spin{to{transform:rotate(1turn)}}.crow-animate-spin{animation:crow-spin 1s linear infinite}.crow-cursor-default{cursor:default}.crow-cursor-not-allowed{cursor:not-allowed}.crow-cursor-pointer{cursor:pointer}.crow-select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.crow-resize-none{resize:none}.crow-list-decimal{list-style-type:decimal}.crow-list-disc{list-style-type:disc}.crow-flex-row{flex-direction:row}.crow-flex-col{flex-direction:column}.crow-items-start{align-items:flex-start}.crow-items-end{align-items:flex-end}.crow-items-center{align-items:center}.crow-justify-start{justify-content:flex-start}.crow-justify-end{justify-content:flex-end}.crow-justify-center{justify-content:center}.crow-justify-between{justify-content:space-between}.crow-gap-1{gap:.25rem}.crow-gap-1\\.5{gap:.375rem}.crow-gap-2{gap:.5rem}.crow-gap-3{gap:.75rem}.crow-gap-4{gap:1rem}.crow-gap-6{gap:1.5rem}.crow-space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.crow-space-y-1\\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.crow-space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.crow-space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.crow-space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.crow-overflow-hidden{overflow:hidden}.crow-overflow-visible{overflow:visible}.crow-overflow-x-auto{overflow-x:auto}.crow-overflow-y-auto{overflow-y:auto}.crow-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crow-whitespace-pre-wrap{white-space:pre-wrap}.crow-break-words{overflow-wrap:break-word}.crow-rounded{border-radius:.25rem}.crow-rounded-2xl{border-radius:1rem}.crow-rounded-3xl{border-radius:1.5rem}.crow-rounded-full{border-radius:9999px}.crow-rounded-lg{border-radius:.5rem}.crow-rounded-md{border-radius:.375rem}.crow-rounded-xl{border-radius:.75rem}.crow-border{border-width:1px}.crow-border-b{border-bottom-width:1px}.crow-border-l{border-left-width:1px}.crow-border-l-2{border-left-width:2px}.crow-border-r{border-right-width:1px}.crow-border-t{border-top-width:1px}.crow-border-none{border-style:none}.crow-border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.crow-border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.crow-border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.crow-border-red-500{--tw-border-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity,1))}.crow-bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.crow-bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.crow-bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.crow-bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.crow-bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity,1))}.crow-bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.crow-bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.crow-bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}.crow-bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.crow-bg-transparent{background-color:transparent}.crow-bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.crow-p-0{padding:0}.crow-p-1{padding:.25rem}.crow-p-1\\.5{padding:.375rem}.crow-p-2{padding:.5rem}.crow-p-3{padding:.75rem}.crow-p-4{padding:1rem}.crow-p-6{padding:1.5rem}.crow-px-1{padding-left:.25rem;padding-right:.25rem}.crow-px-2{padding-left:.5rem;padding-right:.5rem}.crow-px-3{padding-left:.75rem;padding-right:.75rem}.crow-px-4{padding-left:1rem;padding-right:1rem}.crow-px-6{padding-left:1.5rem;padding-right:1.5rem}.crow-py-0{padding-top:0;padding-bottom:0}.crow-py-0\\.5{padding-top:.125rem;padding-bottom:.125rem}.crow-py-1{padding-top:.25rem;padding-bottom:.25rem}.crow-py-1\\.5{padding-top:.375rem;padding-bottom:.375rem}.crow-py-2{padding-top:.5rem;padding-bottom:.5rem}.crow-py-3{padding-top:.75rem;padding-bottom:.75rem}.crow-py-6{padding-top:1.5rem;padding-bottom:1.5rem}.crow-py-8{padding-top:2rem;padding-bottom:2rem}.crow-pb-2{padding-bottom:.5rem}.crow-pl-3{padding-left:.75rem}.crow-pl-4{padding-left:1rem}.crow-pl-5{padding-left:1.25rem}.crow-pr-4{padding-right:1rem}.crow-pt-1{padding-top:.25rem}.crow-text-left{text-align:left}.crow-text-center{text-align:center}.crow-text-right{text-align:right}.crow-align-text-bottom{vertical-align:text-bottom}.crow-font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.crow-text-base{font-size:1rem;line-height:1.5rem}.crow-text-lg{font-size:1.125rem;line-height:1.75rem}.crow-text-sm{font-size:.875rem;line-height:1.25rem}.crow-text-xs{font-size:.75rem;line-height:1rem}.crow-font-bold{font-weight:700}.crow-font-medium{font-weight:500}.crow-font-semibold{font-weight:600}.crow-uppercase{text-transform:uppercase}.crow-leading-relaxed{line-height:1.625}.crow-tracking-wide{letter-spacing:.025em}.crow-text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.crow-text-blue-300{--tw-text-opacity:1;color:rgb(147 197 253/var(--tw-text-opacity,1))}.crow-text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.crow-text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.crow-text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.crow-text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.crow-text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.crow-text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.crow-text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.crow-text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.crow-text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.crow-text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.crow-underline{text-decoration-line:underline}.crow-opacity-0{opacity:0}.crow-opacity-100{opacity:1}.crow-opacity-50{opacity:.5}.crow-opacity-60{opacity:.6}.crow-shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.crow-shadow-2xl,.crow-shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.crow-shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.crow-shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.crow-backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.crow-backdrop-blur-md,.crow-backdrop-blur-sm{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)}.crow-backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.crow-transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.crow-transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.crow-transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.crow-transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.crow-transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.crow-duration-150{transition-duration:.15s}.crow-duration-200{transition-duration:.2s}.crow-duration-300{transition-duration:.3s}.crow-duration-500{transition-duration:.5s}.crow-ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.crow-animate-fade-in{animation:crow-fadeIn .2s ease-out}.crow-animate-slide-up{animation:crow-slideUp .3s ease-out}.crow-animate-pulse{animation:crow-pulse 1.5s ease-in-out infinite}.crow-animation-delay-100{animation-delay:.1s}.crow-animation-delay-200{animation-delay:.2s}@keyframes crow-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes crow-slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes crow-pulse{0%,to{opacity:1}50%{opacity:.4}}.crow-overflow-y-auto::-webkit-scrollbar{width:6px}.crow-overflow-y-auto::-webkit-scrollbar-track{background:transparent}.crow-overflow-y-auto::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:3px}.crow-overflow-y-auto::-webkit-scrollbar-thumb:hover{background-color:#9ca3af}.crow-focus-visible\\:crow-outline-none:focus-visible{outline:none}.crow-focus-visible\\:crow-ring-2:focus-visible{box-shadow:0 0 0 2px var(--crow-primary,#6366f1)}:root{--crow-primary:#6366f1;--crow-primary-dark:#4f46e5;--crow-secondary:#f1f5f9;--crow-accent:#10b981}@media (prefers-color-scheme:dark){:root{--crow-primary:#818cf8;--crow-primary-dark:#6366f1}}.placeholder\\:crow-text-gray-500::-moz-placeholder{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.placeholder\\:crow-text-gray-500::placeholder{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.last\\:crow-mb-0:last-child{margin-bottom:0}.last\\:crow-border-0:last-child{border-width:0}.hover\\:crow-scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1;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))}.hover\\:crow-bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\\:crow-bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.hover\\:crow-bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.hover\\:crow-bg-white\\/80:hover{background-color:hsla(0,0%,100%,.8)}.hover\\:crow-text-blue-300:hover{--tw-text-opacity:1;color:rgb(147 197 253/var(--tw-text-opacity,1))}.hover\\:crow-text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.hover\\:crow-text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.hover\\:crow-opacity-100:hover{opacity:1}.focus\\:crow-outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\\:crow-ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\\:crow-ring-0:focus,.focus\\:crow-ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\\:crow-ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\\:crow-ring-offset-2:focus{--tw-ring-offset-width:2px}.focus-visible\\:crow-outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:crow-ring-0:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.disabled\\:crow-pointer-events-none:disabled{pointer-events:none}.disabled\\:crow-cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:crow-opacity-50:disabled{opacity:.5}`;
14
+ var injected = false;
15
+ function injectStyles() {
16
+ if (injected || typeof document === "undefined") return;
17
+ if (document.getElementById(STYLE_ID)) {
18
+ injected = true;
19
+ return;
20
+ }
21
+ const style = document.createElement("style");
22
+ style.id = STYLE_ID;
23
+ style.textContent = CSS_CONTENT;
24
+ document.head.appendChild(style);
25
+ injected = true;
26
+ }
27
+ injectStyles();
28
+
29
+ // src/utils.ts
30
+ var cn = (...classes) => classes.filter(Boolean).join(" ");
31
+ var formatTime = (date) => date.toLocaleTimeString("en-US", {
32
+ hour: "numeric",
33
+ minute: "2-digit"
34
+ });
35
+ var formatConversationDate = (dateStr) => {
36
+ const date = new Date(dateStr);
37
+ const now = /* @__PURE__ */ new Date();
38
+ const diffDays = Math.floor(
39
+ (now.getTime() - date.getTime()) / (1e3 * 60 * 60 * 24)
40
+ );
41
+ if (diffDays === 0) return "Today";
42
+ if (diffDays === 1) return "Yesterday";
43
+ if (diffDays < 7) return `${diffDays} days ago`;
44
+ return date.toLocaleDateString();
45
+ };
46
+ var generateMessageId = (prefix) => `${prefix}-${Date.now()}`;
47
+
48
+ // src/constants.ts
49
+ var AVAILABLE_MODELS = [
50
+ { id: "gpt-4o", name: "GPT-4o", provider: "OpenAI" },
51
+ { id: "gpt-5-mini", name: "GPT-5 Mini", provider: "OpenAI" },
52
+ { id: "gpt-5.2", name: "GPT-5.2", provider: "OpenAI" },
53
+ { id: "gpt-5.2-pro", name: "GPT-5.2 Pro", provider: "OpenAI" },
54
+ { id: "claude-haiku-4-5-20251001", name: "Haiku 4.5", provider: "Anthropic" },
55
+ { id: "claude-sonnet-4-5-20250929", name: "Sonnet 4.5", provider: "Anthropic" },
56
+ { id: "claude-opus-4-5-20251203", name: "Opus 4.5", provider: "Anthropic" }
57
+ ];
58
+ var DEFAULT_MODEL = "claude-sonnet-4-5-20250929";
59
+ var DEFAULT_WELCOME_MESSAGE = "Hi! How can I help you today?";
60
+ var MESSAGES_CONTAINER_ID = "crow-messages-container";
61
+
62
+ // src/hooks/useChat.ts
63
+ var getConversationStorageKey = (productId) => `crow_conv_${productId}`;
64
+ function useChat({
9
65
  productId,
10
- apiUrl,
11
- model
66
+ apiUrl = "",
67
+ onVerificationStatus,
68
+ onConversationId,
69
+ onWorkflowEvent,
70
+ onToolCall,
71
+ onRestoredConversation
12
72
  }) {
13
- const clientRef = useRef(null);
14
- if (!clientRef.current) {
15
- clientRef.current = new CrowClient({ productId, apiUrl, model });
16
- }
17
- const client = clientRef.current;
73
+ const [messages, setMessages] = useState([
74
+ {
75
+ id: "welcome",
76
+ content: DEFAULT_WELCOME_MESSAGE,
77
+ isBot: true,
78
+ timestamp: /* @__PURE__ */ new Date()
79
+ }
80
+ ]);
81
+ const [isLoading, setIsLoading] = useState(false);
82
+ const [activeToolCalls, setActiveToolCalls] = useState([]);
83
+ const [conversationId, setConversationId] = useState(() => {
84
+ try {
85
+ return localStorage.getItem(getConversationStorageKey(productId));
86
+ } catch {
87
+ return null;
88
+ }
89
+ });
90
+ const [selectedModel, setSelectedModel] = useState(DEFAULT_MODEL);
91
+ const abortControllerRef = useRef(null);
92
+ const hasRestoredRef = useRef(false);
18
93
  useEffect(() => {
19
- return () => {
20
- client.destroy();
21
- };
22
- }, [client]);
23
- const value = useMemo(() => ({ client }), [client]);
24
- return /* @__PURE__ */ jsx(CrowContext.Provider, { value, children });
94
+ if (conversationId && onRestoredConversation && !hasRestoredRef.current) {
95
+ hasRestoredRef.current = true;
96
+ onRestoredConversation(conversationId);
97
+ }
98
+ }, []);
99
+ const streamFromBackend = useCallback(
100
+ async (message, botMsgId) => {
101
+ let accumulatedText = "";
102
+ let firstChunk = true;
103
+ abortControllerRef.current = new AbortController();
104
+ try {
105
+ const identityToken = window.__crow_identity_token;
106
+ const response = await fetch(`${apiUrl}/api/chat/message`, {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ body: JSON.stringify({
110
+ product_id: productId,
111
+ message,
112
+ conversation_id: conversationId,
113
+ identity_token: identityToken,
114
+ model: selectedModel
115
+ }),
116
+ signal: abortControllerRef.current.signal
117
+ });
118
+ if (!response.ok) {
119
+ throw new Error(`HTTP error! status: ${response.status}`);
120
+ }
121
+ const reader = response.body?.getReader();
122
+ const decoder = new TextDecoder();
123
+ if (reader) {
124
+ while (true) {
125
+ const { done, value } = await reader.read();
126
+ if (done) break;
127
+ const chunk = decoder.decode(value);
128
+ const lines = chunk.split("\n");
129
+ for (const line of lines) {
130
+ if (line.startsWith("data: ")) {
131
+ const data = line.slice(6).trim();
132
+ if (data === "[DONE]") {
133
+ setIsLoading(false);
134
+ return;
135
+ }
136
+ try {
137
+ const parsed = JSON.parse(data);
138
+ switch (parsed.type) {
139
+ case "verification_status":
140
+ onVerificationStatus?.(parsed.is_verified === true);
141
+ break;
142
+ case "conversation_id":
143
+ if (parsed.conversation_id) {
144
+ setConversationId(parsed.conversation_id);
145
+ try {
146
+ localStorage.setItem(
147
+ getConversationStorageKey(productId),
148
+ parsed.conversation_id
149
+ );
150
+ } catch {
151
+ }
152
+ onConversationId?.(parsed.conversation_id);
153
+ }
154
+ break;
155
+ case "thinking":
156
+ if (parsed.status === "complete") {
157
+ setMessages(
158
+ (prev) => prev.map(
159
+ (msg) => msg.id === botMsgId ? { ...msg, thinkingComplete: true } : msg
160
+ )
161
+ );
162
+ }
163
+ break;
164
+ case "thinking_token":
165
+ if (parsed.content) {
166
+ setMessages(
167
+ (prev) => prev.map(
168
+ (msg) => msg.id === botMsgId ? { ...msg, thinking: (msg.thinking || "") + parsed.content } : msg
169
+ )
170
+ );
171
+ }
172
+ break;
173
+ case "content":
174
+ if (firstChunk) firstChunk = false;
175
+ accumulatedText += parsed.content;
176
+ setMessages(
177
+ (prev) => prev.map(
178
+ (msg) => msg.id === botMsgId ? { ...msg, content: accumulatedText } : msg
179
+ )
180
+ );
181
+ break;
182
+ case "citations":
183
+ if (parsed.citations) {
184
+ setMessages(
185
+ (prev) => prev.map(
186
+ (msg) => msg.id === botMsgId ? { ...msg, citations: parsed.citations } : msg
187
+ )
188
+ );
189
+ }
190
+ break;
191
+ case "error":
192
+ if (parsed.message) {
193
+ setMessages(
194
+ (prev) => prev.map(
195
+ (msg) => msg.id === botMsgId ? { ...msg, content: parsed.message } : msg
196
+ )
197
+ );
198
+ }
199
+ break;
200
+ case "tool_call_start":
201
+ onToolCall?.({
202
+ type: "start",
203
+ toolName: parsed.tool_name,
204
+ arguments: parsed.arguments
205
+ });
206
+ setActiveToolCalls((prev) => [
207
+ ...prev,
208
+ {
209
+ id: `tool-${Date.now()}`,
210
+ name: parsed.tool_name,
211
+ arguments: parsed.arguments || {},
212
+ status: "executing",
213
+ timestamp: /* @__PURE__ */ new Date()
214
+ }
215
+ ]);
216
+ break;
217
+ case "tool_call_complete":
218
+ onToolCall?.({
219
+ type: "complete",
220
+ toolName: parsed.tool_name,
221
+ success: parsed.success
222
+ });
223
+ setActiveToolCalls(
224
+ (prev) => prev.map(
225
+ (tool) => tool.name === parsed.tool_name ? { ...tool, status: parsed.success ? "complete" : "error" } : tool
226
+ )
227
+ );
228
+ break;
229
+ case "client_tool_call":
230
+ onToolCall?.({
231
+ type: "client_call",
232
+ toolName: parsed.tool_name,
233
+ arguments: parsed.arguments
234
+ });
235
+ break;
236
+ case "workflow_started":
237
+ onWorkflowEvent?.({
238
+ type: "started",
239
+ name: parsed.name,
240
+ todos: parsed.todos
241
+ });
242
+ break;
243
+ case "todo_updated":
244
+ onWorkflowEvent?.({
245
+ type: "todo_updated",
246
+ todoId: parsed.id,
247
+ todoStatus: parsed.status
248
+ });
249
+ break;
250
+ case "workflow_ended":
251
+ onWorkflowEvent?.({ type: "ended" });
252
+ break;
253
+ case "workflow_complete_prompt":
254
+ onWorkflowEvent?.({ type: "complete_prompt" });
255
+ break;
256
+ }
257
+ } catch (e) {
258
+ console.error("[Crow] Parse error:", e);
259
+ }
260
+ }
261
+ }
262
+ }
263
+ }
264
+ } catch (error) {
265
+ if (error instanceof Error && error.name === "AbortError") {
266
+ if (accumulatedText) {
267
+ setMessages(
268
+ (prev) => prev.map(
269
+ (msg) => msg.id === botMsgId ? { ...msg, content: accumulatedText } : msg
270
+ )
271
+ );
272
+ } else {
273
+ setMessages((prev) => prev.filter((msg) => msg.id !== botMsgId));
274
+ }
275
+ return;
276
+ }
277
+ console.error("[Crow] Error:", error);
278
+ setMessages(
279
+ (prev) => prev.map(
280
+ (msg) => msg.id === botMsgId ? { ...msg, content: "Sorry, I encountered an error. Please try again." } : msg
281
+ )
282
+ );
283
+ } finally {
284
+ setIsLoading(false);
285
+ abortControllerRef.current = null;
286
+ }
287
+ },
288
+ [apiUrl, productId, conversationId, selectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall]
289
+ );
290
+ const sendMessage = useCallback(
291
+ (content) => {
292
+ if (!content.trim()) {
293
+ return { userMsgId: "", botMsgId: "" };
294
+ }
295
+ setActiveToolCalls([]);
296
+ const userMsgId = generateMessageId("user");
297
+ const botMsgId = generateMessageId("bot");
298
+ setMessages((prev) => [
299
+ ...prev,
300
+ {
301
+ id: userMsgId,
302
+ content,
303
+ isBot: false,
304
+ timestamp: /* @__PURE__ */ new Date()
305
+ }
306
+ ]);
307
+ setIsLoading(true);
308
+ setMessages((prev) => [
309
+ ...prev,
310
+ {
311
+ id: botMsgId,
312
+ content: "Thinking...",
313
+ isBot: true,
314
+ timestamp: /* @__PURE__ */ new Date()
315
+ }
316
+ ]);
317
+ streamFromBackend(content, botMsgId);
318
+ return { userMsgId, botMsgId };
319
+ },
320
+ [streamFromBackend]
321
+ );
322
+ const stopGeneration = useCallback(() => {
323
+ if (abortControllerRef.current) {
324
+ abortControllerRef.current.abort();
325
+ setIsLoading(false);
326
+ }
327
+ }, []);
328
+ const resetMessages = useCallback(() => {
329
+ setMessages([
330
+ {
331
+ id: "welcome",
332
+ content: DEFAULT_WELCOME_MESSAGE,
333
+ isBot: true,
334
+ timestamp: /* @__PURE__ */ new Date()
335
+ }
336
+ ]);
337
+ setConversationId(null);
338
+ try {
339
+ localStorage.removeItem(getConversationStorageKey(productId));
340
+ } catch {
341
+ }
342
+ }, [productId]);
343
+ const loadMessages = useCallback((historyMessages) => {
344
+ setMessages(historyMessages);
345
+ }, []);
346
+ return {
347
+ messages,
348
+ isLoading,
349
+ activeToolCalls,
350
+ conversationId,
351
+ selectedModel,
352
+ setSelectedModel,
353
+ setConversationId,
354
+ sendMessage,
355
+ stopGeneration,
356
+ resetMessages,
357
+ loadMessages
358
+ };
25
359
  }
26
- function useCrowClient() {
27
- const context = useContext(CrowContext);
28
- if (!context) {
29
- throw new Error("useCrowClient must be used within a CrowProvider");
30
- }
31
- return context.client;
360
+ function useConversations({ productId, apiUrl = "" }) {
361
+ const [conversations, setConversations] = useState([]);
362
+ const [isLoadingHistory, setIsLoadingHistory] = useState(false);
363
+ const loadConversations = useCallback(async () => {
364
+ const token = window.__crow_identity_token;
365
+ if (!token) return;
366
+ try {
367
+ const res = await fetch(
368
+ `${apiUrl}/api/chat/conversations?product_id=${productId}&identity_token=${encodeURIComponent(token)}`
369
+ );
370
+ if (res.ok) {
371
+ const data = await res.json();
372
+ setConversations(data.conversations || []);
373
+ }
374
+ } catch (error) {
375
+ console.error("[Crow] Failed to load conversations:", error);
376
+ }
377
+ }, [apiUrl, productId]);
378
+ const loadConversationHistory = useCallback(
379
+ async (conversationId) => {
380
+ const token = window.__crow_identity_token;
381
+ if (!token) return [];
382
+ setIsLoadingHistory(true);
383
+ try {
384
+ const res = await fetch(
385
+ `${apiUrl}/api/chat/conversations/${conversationId}/history?product_id=${productId}&identity_token=${encodeURIComponent(token)}`
386
+ );
387
+ if (res.ok) {
388
+ const data = await res.json();
389
+ const historyMessages = data.messages || [];
390
+ return historyMessages.map(
391
+ (msg, idx) => ({
392
+ id: `history-${idx}`,
393
+ content: msg.content,
394
+ isBot: msg.role === "assistant",
395
+ timestamp: /* @__PURE__ */ new Date()
396
+ })
397
+ );
398
+ }
399
+ } catch (error) {
400
+ console.error("[Crow] Error loading conversation history:", error);
401
+ } finally {
402
+ setIsLoadingHistory(false);
403
+ }
404
+ return [];
405
+ },
406
+ [apiUrl, productId]
407
+ );
408
+ const loadAnonymousConversationHistory = useCallback(
409
+ async (conversationId) => {
410
+ setIsLoadingHistory(true);
411
+ try {
412
+ const res = await fetch(
413
+ `${apiUrl}/api/chat/conversations/${conversationId}/history/anonymous?product_id=${productId}`
414
+ );
415
+ if (res.ok) {
416
+ const data = await res.json();
417
+ const historyMessages = data.messages || [];
418
+ return historyMessages.map(
419
+ (msg, idx) => ({
420
+ id: `history-${idx}`,
421
+ content: msg.content,
422
+ isBot: msg.role === "assistant",
423
+ timestamp: /* @__PURE__ */ new Date()
424
+ })
425
+ );
426
+ }
427
+ } catch (error) {
428
+ console.error("[Crow] Error loading anonymous conversation history:", error);
429
+ } finally {
430
+ setIsLoadingHistory(false);
431
+ }
432
+ return [];
433
+ },
434
+ [apiUrl, productId]
435
+ );
436
+ return {
437
+ conversations,
438
+ isLoadingHistory,
439
+ loadConversations,
440
+ loadConversationHistory,
441
+ loadAnonymousConversationHistory
442
+ };
32
443
  }
33
- function useCrowClientOptional() {
34
- const context = useContext(CrowContext);
35
- return context?.client ?? null;
444
+ function useWorkflow({
445
+ productId,
446
+ apiUrl = "",
447
+ conversationId,
448
+ selectedModel,
449
+ onMessage
450
+ }) {
451
+ const [activeWorkflow, setActiveWorkflow] = useState(null);
452
+ const abortControllerRef = useRef(null);
453
+ const startWorkflow = useCallback((name, todos) => {
454
+ setActiveWorkflow({ name, todos });
455
+ }, []);
456
+ const updateTodo = useCallback((todoId, status) => {
457
+ setActiveWorkflow((prev) => {
458
+ if (!prev) return null;
459
+ return {
460
+ ...prev,
461
+ todos: prev.todos.map(
462
+ (todo) => todo.id === todoId ? { ...todo, status } : todo
463
+ )
464
+ };
465
+ });
466
+ }, []);
467
+ const markComplete = useCallback(() => {
468
+ setActiveWorkflow((prev) => {
469
+ if (!prev) return null;
470
+ return { ...prev, isComplete: true };
471
+ });
472
+ }, []);
473
+ const endWorkflow = useCallback((delay = 0) => {
474
+ if (delay > 0) {
475
+ setTimeout(() => setActiveWorkflow(null), delay);
476
+ } else {
477
+ setActiveWorkflow(null);
478
+ }
479
+ }, []);
480
+ const exitWorkflow = useCallback(async () => {
481
+ abortControllerRef.current = new AbortController();
482
+ try {
483
+ const identityToken = window.__crow_identity_token;
484
+ const response = await fetch(`${apiUrl}/api/chat/message`, {
485
+ method: "POST",
486
+ headers: { "Content-Type": "application/json" },
487
+ body: JSON.stringify({
488
+ product_id: productId,
489
+ message: "[EXIT_WORKFLOW]",
490
+ conversation_id: conversationId,
491
+ identity_token: identityToken,
492
+ model: selectedModel
493
+ }),
494
+ signal: abortControllerRef.current.signal
495
+ });
496
+ if (!response.ok) return;
497
+ const reader = response.body?.getReader();
498
+ const decoder = new TextDecoder();
499
+ if (reader) {
500
+ while (true) {
501
+ const { done, value } = await reader.read();
502
+ if (done) break;
503
+ const chunk = decoder.decode(value);
504
+ const lines = chunk.split("\n");
505
+ for (const line of lines) {
506
+ if (line.startsWith("data: ")) {
507
+ const data = line.slice(6).trim();
508
+ if (data === "[DONE]") return;
509
+ try {
510
+ const parsed = JSON.parse(data);
511
+ if (parsed.type === "workflow_ended") {
512
+ setActiveWorkflow(null);
513
+ }
514
+ if (parsed.type === "content" && parsed.content) {
515
+ onMessage?.(parsed.content);
516
+ }
517
+ } catch {
518
+ }
519
+ }
520
+ }
521
+ }
522
+ }
523
+ } catch (error) {
524
+ console.error("[Crow] Exit workflow error:", error);
525
+ } finally {
526
+ abortControllerRef.current = null;
527
+ }
528
+ }, [apiUrl, productId, conversationId, selectedModel, onMessage]);
529
+ return {
530
+ activeWorkflow,
531
+ startWorkflow,
532
+ updateTodo,
533
+ markComplete,
534
+ endWorkflow,
535
+ exitWorkflow
536
+ };
36
537
  }
37
- function useChat({ client, onStreamEvent }) {
38
- const [messages, setMessages] = useState(client.messages);
39
- const [isLoading, setIsLoading] = useState(client.isLoading);
40
- const onStreamEventRef = useRef(onStreamEvent);
538
+ function useCrowAPI({ onIdentified, onReset } = {}) {
539
+ const onIdentifiedRef = useRef(onIdentified);
540
+ const onResetRef = useRef(onReset);
541
+ const hasCalledInitialRef = useRef(false);
41
542
  useEffect(() => {
42
- onStreamEventRef.current = onStreamEvent;
543
+ onIdentifiedRef.current = onIdentified;
544
+ onResetRef.current = onReset;
43
545
  });
44
546
  useEffect(() => {
45
- const unsubMessages = client.onMessages(setMessages);
46
- const unsubLoading = client.onLoading(setIsLoading);
47
- setMessages(client.messages);
48
- setIsLoading(client.isLoading);
547
+ window.crow = function(command, options) {
548
+ const opts = options;
549
+ switch (command) {
550
+ case "identify":
551
+ if (!opts?.token) {
552
+ console.error("[Crow] identify() requires a token");
553
+ return;
554
+ }
555
+ window.__crow_identity_token = opts.token;
556
+ const { token, ...metadata } = opts;
557
+ window.__crow_public_metadata = metadata;
558
+ console.log("[Crow] User identified");
559
+ window.dispatchEvent(
560
+ new CustomEvent("crow:identified", { detail: { token, metadata } })
561
+ );
562
+ break;
563
+ case "resetUser":
564
+ window.__crow_identity_token = void 0;
565
+ window.__crow_public_metadata = void 0;
566
+ console.log("[Crow] User reset");
567
+ window.dispatchEvent(new CustomEvent("crow:reset"));
568
+ break;
569
+ case "registerTools":
570
+ if (!opts || typeof opts !== "object") {
571
+ console.error("[Crow] registerTools() requires an object");
572
+ return;
573
+ }
574
+ if (!window.__crow_client_tools) {
575
+ window.__crow_client_tools = {};
576
+ }
577
+ for (const [toolName, handler] of Object.entries(opts)) {
578
+ if (typeof handler === "function") {
579
+ window.__crow_client_tools[toolName] = handler;
580
+ console.log(`[Crow] Registered tool: ${toolName}`);
581
+ }
582
+ }
583
+ break;
584
+ case "runJourney":
585
+ if (!opts?.journeyId) {
586
+ console.error("[Crow] runJourney() requires a journeyId");
587
+ return;
588
+ }
589
+ window.dispatchEvent(
590
+ new CustomEvent("crow:runJourney", {
591
+ detail: { journeyId: opts.journeyId, inputs: opts.inputs || {} }
592
+ })
593
+ );
594
+ break;
595
+ default:
596
+ console.warn(`[Crow] Unknown command: ${command}`);
597
+ }
598
+ };
599
+ console.log("[Crow] API ready");
600
+ const handleIdentified = () => onIdentifiedRef.current?.();
601
+ const handleReset = () => onResetRef.current?.();
602
+ window.addEventListener("crow:identified", handleIdentified);
603
+ window.addEventListener("crow:reset", handleReset);
604
+ if (window.__crow_identity_token && !hasCalledInitialRef.current) {
605
+ hasCalledInitialRef.current = true;
606
+ onIdentifiedRef.current?.();
607
+ }
49
608
  return () => {
50
- unsubMessages();
51
- unsubLoading();
609
+ window.removeEventListener("crow:identified", handleIdentified);
610
+ window.removeEventListener("crow:reset", handleReset);
52
611
  };
53
- }, [client]);
54
- const sendMessage = useCallback(
55
- async (content) => {
56
- for await (const event of client.sendMessage(content)) {
57
- onStreamEventRef.current?.(event);
612
+ }, []);
613
+ const executeClientTool = useCallback(
614
+ async (toolName, args) => {
615
+ const handler = window.__crow_client_tools?.[toolName];
616
+ if (handler) {
617
+ try {
618
+ return await handler(args);
619
+ } catch (err) {
620
+ console.error(`[Crow] Client tool error: ${toolName}`, err);
621
+ return { status: "error", error: String(err) };
622
+ }
58
623
  }
624
+ console.warn(`[Crow] No handler for: ${toolName}`);
625
+ return { status: "error", error: "No handler registered" };
59
626
  },
60
- [client]
627
+ []
61
628
  );
62
- const stop = useCallback(() => {
63
- client.stop();
64
- }, [client]);
65
- const clearMessages = useCallback(() => {
66
- client.clearMessages();
67
- }, [client]);
629
+ return { executeClientTool };
630
+ }
631
+
632
+ // src/styles/defaults.ts
633
+ var DEFAULT_WIDGET_STYLES = {
634
+ // ═══════════════════════════════════════════════════════════
635
+ // COLORS
636
+ // ═══════════════════════════════════════════════════════════
637
+ colors: {
638
+ // Primary accent
639
+ primary: "#000000",
640
+ // Widget container
641
+ background: "rgba(255, 255, 255, 0.95)",
642
+ border: "#d1d5db",
643
+ text: "#111827",
644
+ // Bot messages
645
+ botBubble: "#000000",
646
+ botText: "#ffffff",
647
+ // User messages
648
+ userBubble: "#ffffff",
649
+ userText: "#000000",
650
+ userBorder: "#000000",
651
+ // Floating chat bubble
652
+ bubbleBackground: "#ffffff",
653
+ bubbleBorder: "#d1d5db",
654
+ bubbleIcon: "#111827",
655
+ // Messages container
656
+ messagesBackground: "rgba(255, 255, 255, 0.5)"
657
+ },
658
+ // ═══════════════════════════════════════════════════════════
659
+ // TYPOGRAPHY
660
+ // ═══════════════════════════════════════════════════════════
661
+ typography: {
662
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
663
+ fontSize: 14,
664
+ headerFontSize: 16
665
+ },
666
+ // ═══════════════════════════════════════════════════════════
667
+ // ANIMATIONS
668
+ // ═══════════════════════════════════════════════════════════
669
+ animations: {
670
+ duration: 0.3,
671
+ easing: "easeInOut"
672
+ },
673
+ // ═══════════════════════════════════════════════════════════
674
+ // DIMENSIONS
675
+ // ═══════════════════════════════════════════════════════════
676
+ dimensions: {
677
+ width: 400,
678
+ maxHeight: 600,
679
+ previewHeight: 700,
680
+ messagesMaxHeight: 350,
681
+ borderRadius: 24,
682
+ padding: 20
683
+ },
684
+ // ═══════════════════════════════════════════════════════════
685
+ // POSITIONING (floating widget only)
686
+ // ═══════════════════════════════════════════════════════════
687
+ position: {
688
+ right: 16,
689
+ bottom: 80,
690
+ bubbleRight: 16,
691
+ bubbleBottom: 16
692
+ },
693
+ // ═══════════════════════════════════════════════════════════
694
+ // CHAT BUBBLE (floating button)
695
+ // ═══════════════════════════════════════════════════════════
696
+ bubble: {
697
+ size: 48,
698
+ iconSize: 24
699
+ },
700
+ // ═══════════════════════════════════════════════════════════
701
+ // SHADOWS
702
+ // ═══════════════════════════════════════════════════════════
703
+ shadows: {
704
+ widget: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
705
+ bubble: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
706
+ },
707
+ // ═══════════════════════════════════════════════════════════
708
+ // BRANDING
709
+ // ═══════════════════════════════════════════════════════════
710
+ branding: {
711
+ showPoweredBy: true,
712
+ poweredByText: "Powered by Crow",
713
+ showLogo: true,
714
+ logoUrl: "/static/crow.png"
715
+ }
716
+ };
717
+ var DEFAULT_COPILOT_STYLES = {
718
+ // ═══════════════════════════════════════════════════════════
719
+ // COLORS (same as widget by default)
720
+ // ═══════════════════════════════════════════════════════════
721
+ colors: {
722
+ primary: "#000000",
723
+ background: "rgba(255, 255, 255, 0.95)",
724
+ border: "#d1d5db",
725
+ text: "#111827",
726
+ botBubble: "#000000",
727
+ botText: "#ffffff",
728
+ userBubble: "#ffffff",
729
+ userText: "#000000",
730
+ userBorder: "#000000",
731
+ bubbleBackground: "#ffffff",
732
+ bubbleBorder: "#d1d5db",
733
+ bubbleIcon: "#111827",
734
+ messagesBackground: "rgba(255, 255, 255, 0.5)"
735
+ },
736
+ // ═══════════════════════════════════════════════════════════
737
+ // TYPOGRAPHY
738
+ // ═══════════════════════════════════════════════════════════
739
+ typography: {
740
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
741
+ fontSize: 14,
742
+ headerFontSize: 16
743
+ },
744
+ // ═══════════════════════════════════════════════════════════
745
+ // ANIMATIONS
746
+ // ═══════════════════════════════════════════════════════════
747
+ animations: {
748
+ duration: 0.3,
749
+ easing: "easeInOut"
750
+ },
751
+ // ═══════════════════════════════════════════════════════════
752
+ // DIMENSIONS
753
+ // ═══════════════════════════════════════════════════════════
754
+ dimensions: {
755
+ width: 400,
756
+ headerHeight: 56,
757
+ borderRadius: 16,
758
+ padding: 16
759
+ },
760
+ // ═══════════════════════════════════════════════════════════
761
+ // POSITIONING
762
+ // ═══════════════════════════════════════════════════════════
763
+ position: {
764
+ side: "right"
765
+ },
766
+ // ═══════════════════════════════════════════════════════════
767
+ // BRANDING
768
+ // ═══════════════════════════════════════════════════════════
769
+ branding: {
770
+ showPoweredBy: true,
771
+ poweredByText: "Powered by Crow"
772
+ }
773
+ };
774
+
775
+ // src/styles/utils.ts
776
+ function deepMerge(target, source) {
777
+ if (!source) return target;
778
+ const result = { ...target };
779
+ for (const key of Object.keys(source)) {
780
+ const sourceValue = source[key];
781
+ const targetValue = target[key];
782
+ if (sourceValue !== void 0 && sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && typeof targetValue === "object" && !Array.isArray(targetValue)) {
783
+ result[key] = deepMerge(
784
+ targetValue,
785
+ sourceValue
786
+ );
787
+ } else if (sourceValue !== void 0) {
788
+ result[key] = sourceValue;
789
+ }
790
+ }
791
+ return result;
792
+ }
793
+ function mergeWidgetStyles(dbStyles, propStyles) {
794
+ let result = { ...DEFAULT_WIDGET_STYLES };
795
+ if (dbStyles) {
796
+ result = {
797
+ colors: deepMerge(result.colors, dbStyles.colors),
798
+ typography: deepMerge(result.typography, dbStyles.typography),
799
+ animations: deepMerge(result.animations, dbStyles.animations),
800
+ dimensions: deepMerge(result.dimensions, dbStyles.dimensions),
801
+ position: deepMerge(result.position, dbStyles.position),
802
+ bubble: deepMerge(result.bubble, dbStyles.bubble),
803
+ shadows: deepMerge(result.shadows, dbStyles.shadows),
804
+ branding: deepMerge(result.branding, dbStyles.branding)
805
+ };
806
+ }
807
+ if (propStyles) {
808
+ result = {
809
+ colors: deepMerge(result.colors, propStyles.colors),
810
+ typography: deepMerge(result.typography, propStyles.typography),
811
+ animations: deepMerge(result.animations, propStyles.animations),
812
+ dimensions: deepMerge(result.dimensions, propStyles.dimensions),
813
+ position: deepMerge(result.position, propStyles.position),
814
+ bubble: deepMerge(result.bubble, propStyles.bubble),
815
+ shadows: deepMerge(result.shadows, propStyles.shadows),
816
+ branding: deepMerge(result.branding, propStyles.branding)
817
+ };
818
+ }
819
+ return result;
820
+ }
821
+ function mergeCopilotStyles(dbStyles, propStyles) {
822
+ let result = { ...DEFAULT_COPILOT_STYLES };
823
+ if (dbStyles) {
824
+ result = {
825
+ colors: deepMerge(result.colors, dbStyles.colors),
826
+ typography: deepMerge(result.typography, dbStyles.typography),
827
+ animations: deepMerge(result.animations, dbStyles.animations),
828
+ dimensions: deepMerge(result.dimensions, dbStyles.dimensions),
829
+ position: deepMerge(result.position, dbStyles.position),
830
+ branding: deepMerge(result.branding, dbStyles.branding)
831
+ };
832
+ }
833
+ if (propStyles) {
834
+ result = {
835
+ colors: deepMerge(result.colors, propStyles.colors),
836
+ typography: deepMerge(result.typography, propStyles.typography),
837
+ animations: deepMerge(result.animations, propStyles.animations),
838
+ dimensions: deepMerge(result.dimensions, propStyles.dimensions),
839
+ position: deepMerge(result.position, propStyles.position),
840
+ branding: deepMerge(result.branding, propStyles.branding)
841
+ };
842
+ }
843
+ return result;
844
+ }
845
+ function stylesToCSSVariables(styles2) {
68
846
  return {
69
- messages,
847
+ // Colors
848
+ "--crow-color-primary": styles2.colors.primary,
849
+ "--crow-color-background": styles2.colors.background,
850
+ "--crow-color-text": styles2.colors.text,
851
+ "--crow-color-border": styles2.colors.border,
852
+ "--crow-color-bot-bubble": styles2.colors.botBubble,
853
+ "--crow-color-bot-text": styles2.colors.botText,
854
+ "--crow-color-user-bubble": styles2.colors.userBubble,
855
+ "--crow-color-user-text": styles2.colors.userText,
856
+ "--crow-color-user-border": styles2.colors.userBorder,
857
+ "--crow-color-messages-bg": styles2.colors.messagesBackground,
858
+ // Typography
859
+ "--crow-font-family": styles2.typography.fontFamily,
860
+ "--crow-font-size": `${styles2.typography.fontSize}px`,
861
+ "--crow-header-font-size": `${styles2.typography.headerFontSize}px`,
862
+ // Animations
863
+ "--crow-animation-duration": `${styles2.animations.duration}s`,
864
+ "--crow-animation-easing": styles2.animations.easing
865
+ };
866
+ }
867
+
868
+ // src/hooks/useWidgetStyles.ts
869
+ var styleCache = /* @__PURE__ */ new Map();
870
+ async function fetchWidgetConfig(productId, apiUrl) {
871
+ const baseUrl = apiUrl || "";
872
+ const url = `${baseUrl}/api/products/${productId}/widget-config`;
873
+ const response = await fetch(url);
874
+ if (!response.ok) {
875
+ throw new Error(`Failed to fetch widget config: ${response.status} ${response.statusText}`);
876
+ }
877
+ return response.json();
878
+ }
879
+ function useWidgetStyles({
880
+ productId,
881
+ apiUrl,
882
+ propStyles,
883
+ skip = false,
884
+ cacheKey
885
+ }) {
886
+ const key = cacheKey || productId;
887
+ const [isLoading, setIsLoading] = useState(!skip && !styleCache.has(key));
888
+ const [error, setError] = useState(null);
889
+ const [dbStyles, setDbStyles] = useState(
890
+ styleCache.get(key)?.widgetStyles
891
+ );
892
+ const [agentName, setAgentName] = useState(
893
+ styleCache.get(key)?.agentName || "Assistant"
894
+ );
895
+ const hasFetchedRef = useRef(false);
896
+ const fetchStyles = async () => {
897
+ if (skip) return;
898
+ setIsLoading(true);
899
+ setError(null);
900
+ try {
901
+ const config = await fetchWidgetConfig(productId, apiUrl);
902
+ styleCache.set(key, config);
903
+ setDbStyles(config.widgetStyles);
904
+ setAgentName(config.agentName || "Assistant");
905
+ } catch (err) {
906
+ console.error("[CrowWidget] Failed to fetch styles:", err);
907
+ setError(err instanceof Error ? err : new Error(String(err)));
908
+ } finally {
909
+ setIsLoading(false);
910
+ }
911
+ };
912
+ useEffect(() => {
913
+ if (skip || hasFetchedRef.current) return;
914
+ const cached = styleCache.get(key);
915
+ if (cached) {
916
+ setDbStyles(cached.widgetStyles);
917
+ setAgentName(cached.agentName || "Assistant");
918
+ setIsLoading(false);
919
+ return;
920
+ }
921
+ hasFetchedRef.current = true;
922
+ fetchStyles();
923
+ }, [productId, apiUrl, skip, key]);
924
+ const styles2 = mergeWidgetStyles(dbStyles, propStyles);
925
+ return {
926
+ styles: styles2,
70
927
  isLoading,
71
- sendMessage,
72
- stop,
73
- clearMessages
928
+ error,
929
+ agentName,
930
+ refetch: fetchStyles
74
931
  };
75
932
  }
76
- function ChatBubble({ isOpen, onClick, className }) {
933
+ function useCopilotStyles({
934
+ productId,
935
+ apiUrl,
936
+ propStyles,
937
+ skip = false,
938
+ cacheKey
939
+ }) {
940
+ const key = cacheKey || productId;
941
+ const [isLoading, setIsLoading] = useState(!skip && !styleCache.has(key));
942
+ const [error, setError] = useState(null);
943
+ const [dbStyles, setDbStyles] = useState(
944
+ styleCache.get(key)?.copilotStyles
945
+ );
946
+ const [agentName, setAgentName] = useState(
947
+ styleCache.get(key)?.agentName || "Assistant"
948
+ );
949
+ const hasFetchedRef = useRef(false);
950
+ const fetchStyles = async () => {
951
+ if (skip) return;
952
+ setIsLoading(true);
953
+ setError(null);
954
+ try {
955
+ const config = await fetchWidgetConfig(productId, apiUrl);
956
+ styleCache.set(key, config);
957
+ setDbStyles(config.copilotStyles);
958
+ setAgentName(config.agentName || "Assistant");
959
+ } catch (err) {
960
+ console.error("[CrowCopilot] Failed to fetch styles:", err);
961
+ setError(err instanceof Error ? err : new Error(String(err)));
962
+ } finally {
963
+ setIsLoading(false);
964
+ }
965
+ };
966
+ useEffect(() => {
967
+ if (skip || hasFetchedRef.current) return;
968
+ const cached = styleCache.get(key);
969
+ if (cached) {
970
+ setDbStyles(cached.copilotStyles);
971
+ setAgentName(cached.agentName || "Assistant");
972
+ setIsLoading(false);
973
+ return;
974
+ }
975
+ hasFetchedRef.current = true;
976
+ fetchStyles();
977
+ }, [productId, apiUrl, skip, key]);
978
+ const styles2 = mergeCopilotStyles(dbStyles, propStyles);
979
+ return {
980
+ styles: styles2,
981
+ isLoading,
982
+ error,
983
+ agentName,
984
+ refetch: fetchStyles
985
+ };
986
+ }
987
+ function clearStyleCache(productId) {
988
+ if (productId) {
989
+ styleCache.delete(productId);
990
+ } else {
991
+ styleCache.clear();
992
+ }
993
+ }
994
+ function usePreviewWidgetStyles(previewStyles) {
995
+ return {
996
+ styles: mergeWidgetStyles(void 0, previewStyles)
997
+ };
998
+ }
999
+ function usePreviewCopilotStyles(previewStyles) {
1000
+ return {
1001
+ styles: mergeCopilotStyles(void 0, previewStyles)
1002
+ };
1003
+ }
1004
+ var WidgetStyleContext = createContext(null);
1005
+ function WidgetStyleProvider({
1006
+ children,
1007
+ styles: styles2,
1008
+ agentName = "Assistant",
1009
+ isLoading = false,
1010
+ variant = "floating"
1011
+ }) {
1012
+ const value = useMemo(
1013
+ () => ({ styles: styles2, agentName, isLoading, variant }),
1014
+ [styles2, agentName, isLoading, variant]
1015
+ );
1016
+ return /* @__PURE__ */ jsx(WidgetStyleContext.Provider, { value, children });
1017
+ }
1018
+ function useWidgetStyleContext() {
1019
+ const context = useContext(WidgetStyleContext);
1020
+ if (!context) {
1021
+ throw new Error(
1022
+ "useWidgetStyleContext must be used within a WidgetStyleProvider. Make sure your component is wrapped with CrowWidget or WidgetStyleProvider."
1023
+ );
1024
+ }
1025
+ return context;
1026
+ }
1027
+ function useWidgetStyles2() {
1028
+ const context = useContext(WidgetStyleContext);
1029
+ return context?.styles ?? DEFAULT_WIDGET_STYLES;
1030
+ }
1031
+ var CopilotStyleContext = createContext(null);
1032
+ function CopilotStyleProvider({
1033
+ children,
1034
+ styles: styles2,
1035
+ agentName = "Assistant",
1036
+ isLoading = false
1037
+ }) {
1038
+ const value = useMemo(
1039
+ () => ({ styles: styles2, agentName, isLoading }),
1040
+ [styles2, agentName, isLoading]
1041
+ );
1042
+ return /* @__PURE__ */ jsx(CopilotStyleContext.Provider, { value, children });
1043
+ }
1044
+ function useCopilotStyleContext() {
1045
+ const context = useContext(CopilotStyleContext);
1046
+ if (!context) {
1047
+ throw new Error(
1048
+ "useCopilotStyleContext must be used within a CopilotStyleProvider. Make sure your component is wrapped with CrowCopilot or CopilotStyleProvider."
1049
+ );
1050
+ }
1051
+ return context;
1052
+ }
1053
+ function useCopilotStyles2() {
1054
+ const context = useContext(CopilotStyleContext);
1055
+ return context?.styles ?? DEFAULT_COPILOT_STYLES;
1056
+ }
1057
+ function ChatBubble({ isExpanded, onClick }) {
1058
+ const { styles: styles2 } = useWidgetStyleContext();
77
1059
  return /* @__PURE__ */ jsx(
78
1060
  "button",
79
1061
  {
80
1062
  onClick,
81
- className: clsx(
82
- "crow-fixed crow-z-[999999] crow-rounded-full",
83
- "crow-w-14 crow-h-14 crow-flex crow-items-center crow-justify-center",
84
- "crow-bg-crow-primary hover:crow-bg-crow-primary-dark",
85
- "crow-shadow-lg hover:crow-shadow-xl crow-transition-all crow-duration-300",
86
- "hover:crow-scale-110",
87
- className
88
- ),
1063
+ className: "crow-fixed crow-z-[999999] crow-rounded-full crow-flex crow-items-center crow-justify-center crow-shadow-2xl hover:crow-scale-110 crow-transition-all crow-duration-500 crow-border crow-backdrop-blur-md",
89
1064
  style: {
90
- right: "20px",
91
- bottom: "20px"
1065
+ width: styles2.bubble.size,
1066
+ height: styles2.bubble.size,
1067
+ right: styles2.position.bubbleRight,
1068
+ bottom: styles2.position.bubbleBottom,
1069
+ background: styles2.colors.bubbleBackground,
1070
+ borderColor: styles2.colors.bubbleBorder,
1071
+ boxShadow: styles2.shadows.bubble,
1072
+ color: styles2.colors.bubbleIcon
92
1073
  },
93
- "aria-label": isOpen ? "Close chat" : "Open chat",
94
- children: isOpen ? /* @__PURE__ */ jsx(
95
- "svg",
96
- {
97
- className: "crow-w-6 crow-h-6 crow-text-white",
98
- fill: "none",
99
- stroke: "currentColor",
100
- viewBox: "0 0 24 24",
101
- children: /* @__PURE__ */ jsx(
102
- "path",
103
- {
104
- strokeLinecap: "round",
105
- strokeLinejoin: "round",
106
- strokeWidth: 2,
107
- d: "M19 9l-7 7-7-7"
108
- }
109
- )
110
- }
111
- ) : /* @__PURE__ */ jsx(
112
- "svg",
113
- {
114
- className: "crow-w-6 crow-h-6 crow-text-white",
115
- fill: "none",
116
- stroke: "currentColor",
117
- viewBox: "0 0 24 24",
118
- children: /* @__PURE__ */ jsx(
119
- "path",
120
- {
121
- strokeLinecap: "round",
122
- strokeLinejoin: "round",
123
- strokeWidth: 2,
124
- d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
125
- }
126
- )
127
- }
128
- )
1074
+ "aria-label": isExpanded ? "Close Chat" : "Open Chat",
1075
+ children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { size: styles2.bubble.iconSize, strokeWidth: 2 }) : /* @__PURE__ */ jsx(MessageCircle, { size: styles2.bubble.iconSize, strokeWidth: 2 })
129
1076
  }
130
1077
  );
131
1078
  }
1079
+ var GlassCard = forwardRef(
1080
+ ({ className, children, ...props }, ref) => {
1081
+ return /* @__PURE__ */ jsx(
1082
+ "div",
1083
+ {
1084
+ ref,
1085
+ className: cn(
1086
+ "crow-border crow-flex crow-flex-col crow-gap-6 crow-rounded-2xl crow-py-6 crow-backdrop-blur-md",
1087
+ className
1088
+ ),
1089
+ style: { background: "rgba(255, 255, 255, 0.3)", borderColor: "rgba(229, 231, 235, 0.3)", ...props.style },
1090
+ ...props,
1091
+ children
1092
+ }
1093
+ );
1094
+ }
1095
+ );
1096
+ GlassCard.displayName = "GlassCard";
1097
+ var WidgetShell = forwardRef(
1098
+ ({ children, className }, ref) => {
1099
+ const { styles: styles2, variant } = useWidgetStyleContext();
1100
+ const baseStyle = {
1101
+ borderRadius: styles2.dimensions.borderRadius,
1102
+ padding: styles2.dimensions.padding,
1103
+ background: styles2.colors.background,
1104
+ borderColor: styles2.colors.border,
1105
+ color: styles2.colors.text,
1106
+ boxShadow: styles2.shadows.widget,
1107
+ fontFamily: styles2.typography.fontFamily,
1108
+ fontSize: styles2.typography.fontSize
1109
+ };
1110
+ if (variant === "embedded") {
1111
+ return /* @__PURE__ */ jsx(
1112
+ GlassCard,
1113
+ {
1114
+ ref,
1115
+ className: `crow-flex crow-flex-col crow-shadow-2xl crow-gap-3 crow-w-full crow-h-full ${className ?? ""}`,
1116
+ style: {
1117
+ ...baseStyle,
1118
+ maxWidth: styles2.dimensions.width,
1119
+ maxHeight: styles2.dimensions.previewHeight
1120
+ },
1121
+ children
1122
+ }
1123
+ );
1124
+ }
1125
+ return /* @__PURE__ */ jsx(
1126
+ GlassCard,
1127
+ {
1128
+ ref,
1129
+ className: `crow-fixed crow-z-[999999] crow-shadow-2xl crow-gap-3 crow-transition-all crow-duration-500 crow-flex crow-flex-col ${className ?? ""}`,
1130
+ style: {
1131
+ ...baseStyle,
1132
+ width: `min(${styles2.dimensions.width}px, calc(100vw - 32px))`,
1133
+ height: `min(${styles2.dimensions.maxHeight}px, calc(100vh - 120px))`,
1134
+ right: styles2.position.right,
1135
+ bottom: styles2.position.bottom
1136
+ },
1137
+ children
1138
+ }
1139
+ );
1140
+ }
1141
+ );
1142
+ WidgetShell.displayName = "WidgetShell";
132
1143
  function WidgetHeader({
133
- title = "Chat",
1144
+ isVerifiedUser,
1145
+ showConversationList,
134
1146
  onNewChat,
135
- onClose,
136
- showNewChat = true,
137
- showClose = false,
138
- className
1147
+ onToggleHistory,
1148
+ showMinimize = false,
1149
+ isMinimized = false,
1150
+ onToggleMinimize
139
1151
  }) {
1152
+ const { agentName, styles: styles2 } = useWidgetStyleContext();
140
1153
  return /* @__PURE__ */ jsxs(
141
1154
  "div",
142
1155
  {
143
- className: clsx(
144
- "crow-flex crow-items-center crow-justify-between crow-px-4 crow-py-3",
145
- "crow-border-b crow-border-gray-200 crow-bg-white",
146
- className
147
- ),
1156
+ className: "crow-flex crow-items-center crow-justify-between crow-mb-3 crow-pb-2 crow-border-b",
1157
+ style: { borderColor: styles2.colors.border },
148
1158
  children: [
149
- /* @__PURE__ */ jsx("h2", { className: "crow-font-semibold crow-text-gray-900", children: title }),
150
- /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-2", children: [
151
- showNewChat && onNewChat && /* @__PURE__ */ jsx(
1159
+ /* @__PURE__ */ jsx("div", { className: "crow-flex crow-items-center crow-gap-2", children: /* @__PURE__ */ jsx(
1160
+ "span",
1161
+ {
1162
+ className: "crow-text-sm crow-font-semibold",
1163
+ style: {
1164
+ color: styles2.colors.text,
1165
+ fontSize: styles2.typography.headerFontSize
1166
+ },
1167
+ children: agentName
1168
+ }
1169
+ ) }),
1170
+ /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-1", children: [
1171
+ /* @__PURE__ */ jsx(
152
1172
  "button",
153
1173
  {
154
1174
  onClick: onNewChat,
155
- className: "crow-p-1.5 crow-rounded-lg crow-text-gray-500 hover:crow-bg-gray-100 hover:crow-text-gray-700 crow-transition-colors",
156
- "aria-label": "New chat",
157
- children: /* @__PURE__ */ jsx(
158
- "svg",
159
- {
160
- className: "crow-w-5 crow-h-5",
161
- fill: "none",
162
- stroke: "currentColor",
163
- viewBox: "0 0 24 24",
164
- children: /* @__PURE__ */ jsx(
165
- "path",
166
- {
167
- strokeLinecap: "round",
168
- strokeLinejoin: "round",
169
- strokeWidth: 2,
170
- d: "M12 4v16m8-8H4"
171
- }
172
- )
173
- }
174
- )
1175
+ className: "crow-p-1.5 hover:crow-bg-gray-200 crow-rounded crow-transition-colors",
1176
+ "aria-label": "New Chat",
1177
+ title: "New Chat",
1178
+ children: /* @__PURE__ */ jsx(Plus, { size: 18, className: "crow-text-gray-700" })
175
1179
  }
176
1180
  ),
177
- showClose && onClose && /* @__PURE__ */ jsx(
1181
+ isVerifiedUser && /* @__PURE__ */ jsx(
178
1182
  "button",
179
1183
  {
180
- onClick: onClose,
181
- className: "crow-p-1.5 crow-rounded-lg crow-text-gray-500 hover:crow-bg-gray-100 hover:crow-text-gray-700 crow-transition-colors",
182
- "aria-label": "Close",
183
- children: /* @__PURE__ */ jsx(
184
- "svg",
185
- {
186
- className: "crow-w-5 crow-h-5",
187
- fill: "none",
188
- stroke: "currentColor",
189
- viewBox: "0 0 24 24",
190
- children: /* @__PURE__ */ jsx(
191
- "path",
192
- {
193
- strokeLinecap: "round",
194
- strokeLinejoin: "round",
195
- strokeWidth: 2,
196
- d: "M6 18L18 6M6 6l12 12"
197
- }
198
- )
199
- }
200
- )
1184
+ onClick: onToggleHistory,
1185
+ className: `crow-p-1.5 hover:crow-bg-gray-200 crow-rounded crow-transition-colors ${showConversationList ? "crow-bg-gray-200" : ""}`,
1186
+ "aria-label": "Conversation History",
1187
+ title: "Conversation History",
1188
+ children: /* @__PURE__ */ jsx(History, { size: 18, className: "crow-text-gray-700" })
1189
+ }
1190
+ ),
1191
+ showMinimize && onToggleMinimize && /* @__PURE__ */ jsx(
1192
+ "button",
1193
+ {
1194
+ onClick: onToggleMinimize,
1195
+ className: "crow-p-1 hover:crow-bg-gray-200 crow-rounded crow-transition-colors",
1196
+ "aria-label": isMinimized ? "Expand" : "Minimize",
1197
+ children: isMinimized ? /* @__PURE__ */ jsx(ChevronUp, { size: 18, className: "crow-text-gray-900" }) : /* @__PURE__ */ jsx(ChevronDown, { size: 18, className: "crow-text-gray-900" })
201
1198
  }
202
1199
  )
203
1200
  ] })
@@ -205,420 +1202,1403 @@ function WidgetHeader({
205
1202
  }
206
1203
  );
207
1204
  }
208
- function formatTime(date) {
209
- return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
1205
+ function StreamingText({
1206
+ content,
1207
+ isStreaming = false
1208
+ }) {
1209
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1210
+ /* @__PURE__ */ jsx(
1211
+ ReactMarkdown,
1212
+ {
1213
+ components: {
1214
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "crow-font-bold", children }),
1215
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "crow-list-disc crow-pl-5 crow-my-1", children }),
1216
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "crow-list-decimal crow-pl-5 crow-my-1", children }),
1217
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { children }),
1218
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "crow-mb-1 last:crow-mb-0", children }),
1219
+ a: ({ href, children }) => /* @__PURE__ */ jsx(
1220
+ "a",
1221
+ {
1222
+ href,
1223
+ className: "crow-underline hover:crow-text-blue-300",
1224
+ target: "_blank",
1225
+ rel: "noopener noreferrer",
1226
+ children
1227
+ }
1228
+ ),
1229
+ code: ({ className, children, ...props }) => {
1230
+ const isInline = !className;
1231
+ return isInline ? /* @__PURE__ */ jsx(
1232
+ "code",
1233
+ {
1234
+ className: "crow-bg-gray-100 crow-px-1 crow-py-0.5 crow-rounded crow-text-sm",
1235
+ ...props,
1236
+ children
1237
+ }
1238
+ ) : /* @__PURE__ */ jsx("code", { className, ...props, children });
1239
+ },
1240
+ pre: ({ children }) => /* @__PURE__ */ jsx("pre", { className: "crow-bg-gray-100 crow-p-2 crow-rounded crow-my-1 crow-overflow-x-auto crow-text-sm", children })
1241
+ },
1242
+ children: content
1243
+ }
1244
+ ),
1245
+ isStreaming && /* @__PURE__ */ jsx(
1246
+ "span",
1247
+ {
1248
+ className: "crow-inline-block crow-w-0.5 crow-h-4 crow-ml-0.5 crow-align-text-bottom",
1249
+ style: {
1250
+ backgroundColor: "currentColor",
1251
+ animation: "cursor-blink 1s ease-in-out infinite"
1252
+ },
1253
+ "aria-hidden": "true"
1254
+ }
1255
+ ),
1256
+ /* @__PURE__ */ jsx("style", { children: `
1257
+ @keyframes cursor-blink {
1258
+ 0%, 100% { opacity: 1; }
1259
+ 50% { opacity: 0; }
1260
+ }
1261
+ ` })
1262
+ ] });
1263
+ }
1264
+ function ThinkingIndicator() {
1265
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1266
+ /* @__PURE__ */ jsx(
1267
+ "span",
1268
+ {
1269
+ className: "crow-inline-block crow-font-medium",
1270
+ style: {
1271
+ background: "linear-gradient(90deg, rgba(255,255,255,0.4) 0%, rgba(255,255,255,1) 50%, rgba(255,255,255,0.4) 100%)",
1272
+ backgroundSize: "200% 100%",
1273
+ WebkitBackgroundClip: "text",
1274
+ backgroundClip: "text",
1275
+ WebkitTextFillColor: "transparent",
1276
+ animation: "shimmer 1.5s ease-in-out infinite"
1277
+ },
1278
+ children: "Thinking..."
1279
+ }
1280
+ ),
1281
+ /* @__PURE__ */ jsx("style", { children: `
1282
+ @keyframes shimmer {
1283
+ 0% { background-position: 100% 0; }
1284
+ 100% { background-position: -100% 0; }
1285
+ }
1286
+ ` })
1287
+ ] });
1288
+ }
1289
+ function LoadingHistory() {
1290
+ return /* @__PURE__ */ jsx(
1291
+ motion.div,
1292
+ {
1293
+ initial: { opacity: 0, y: 10 },
1294
+ animate: { opacity: 1, y: 0 },
1295
+ className: "crow-flex crow-justify-center crow-items-center crow-py-8",
1296
+ children: /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-flex-col crow-items-center crow-gap-3", children: [
1297
+ /* @__PURE__ */ jsx("div", { className: "crow-flex crow-gap-1", children: [0, 0.15, 0.3].map((delay, i) => /* @__PURE__ */ jsx(
1298
+ motion.div,
1299
+ {
1300
+ className: "crow-w-2 crow-h-2 crow-bg-gray-400 crow-rounded-full",
1301
+ animate: { y: [0, -8, 0] },
1302
+ transition: { duration: 0.6, repeat: Infinity, delay }
1303
+ },
1304
+ i
1305
+ )) }),
1306
+ /* @__PURE__ */ jsx("span", { className: "crow-text-sm crow-text-gray-500", children: "Loading conversation..." })
1307
+ ] })
1308
+ }
1309
+ );
1310
+ }
1311
+ var THINKING_MESSAGES = [
1312
+ "Pondering",
1313
+ "Analyzing",
1314
+ "Reasoning",
1315
+ "Considering",
1316
+ "Processing",
1317
+ "Evaluating",
1318
+ "Thinking",
1319
+ "Exploring",
1320
+ "Connecting",
1321
+ "Synthesizing"
1322
+ ];
1323
+ function getRandomThinkingMessage() {
1324
+ const idx = Math.floor(Math.random() * THINKING_MESSAGES.length);
1325
+ return THINKING_MESSAGES[idx] + "...";
1326
+ }
1327
+ function ShimmeringContent({ children }) {
1328
+ return /* @__PURE__ */ jsxs(
1329
+ "span",
1330
+ {
1331
+ className: "crow-inline-block",
1332
+ style: {
1333
+ background: "linear-gradient(90deg, rgba(100,100,100,0.6) 0%, rgba(100,100,100,1) 50%, rgba(100,100,100,0.6) 100%)",
1334
+ backgroundSize: "200% 100%",
1335
+ WebkitBackgroundClip: "text",
1336
+ backgroundClip: "text",
1337
+ WebkitTextFillColor: "transparent",
1338
+ animation: "shimmer 1.5s ease-in-out infinite"
1339
+ },
1340
+ children: [
1341
+ children,
1342
+ /* @__PURE__ */ jsx("style", { children: `
1343
+ @keyframes shimmer {
1344
+ 0% { background-position: 100% 0; }
1345
+ 100% { background-position: -100% 0; }
1346
+ }
1347
+ ` })
1348
+ ]
1349
+ }
1350
+ );
1351
+ }
1352
+ function ReasoningTrace({ thinking, isComplete, toolCalls = [], isWaiting = false }) {
1353
+ const hasThinking = !!thinking && thinking.trim().length > 0;
1354
+ const hasToolCalls = toolCalls.length > 0;
1355
+ if (!isWaiting && !hasThinking && !hasToolCalls) return null;
1356
+ return /* @__PURE__ */ jsx("div", { className: "crow-flex crow-justify-start crow-mb-2", children: /* @__PURE__ */ jsxs("div", { className: "crow-max-w-[90%] crow-space-y-1.5", children: [
1357
+ isWaiting && !hasThinking && /* @__PURE__ */ jsx(WaitingIndicator, {}),
1358
+ hasThinking && /* @__PURE__ */ jsx(ThinkingBlock, { thinking, isComplete }),
1359
+ toolCalls.map((tool) => /* @__PURE__ */ jsx(ToolCallBlock, { toolCall: tool }, tool.id))
1360
+ ] }) });
1361
+ }
1362
+ function WaitingIndicator() {
1363
+ return /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-1.5 crow-text-xs crow-text-gray-500", children: [
1364
+ /* @__PURE__ */ jsx("div", { className: "crow-flex crow-items-center crow-justify-center crow-w-4 crow-h-4", children: /* @__PURE__ */ jsx(ShimmeringContent, { children: /* @__PURE__ */ jsx(Brain, { className: "crow-w-3.5 crow-h-3.5" }) }) }),
1365
+ /* @__PURE__ */ jsx("span", { className: "crow-font-medium", children: /* @__PURE__ */ jsx(ShimmeringContent, { children: getRandomThinkingMessage() }) })
1366
+ ] });
1367
+ }
1368
+ function ThinkingBlock({ thinking, isComplete }) {
1369
+ const [isExpanded, setIsExpanded] = useState(!isComplete);
1370
+ useLayoutEffect(() => {
1371
+ setIsExpanded(!isComplete);
1372
+ }, [isComplete]);
1373
+ const isInProgress = !isComplete;
1374
+ return /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-flex-col crow-gap-1 crow-text-xs", children: [
1375
+ /* @__PURE__ */ jsxs(
1376
+ "button",
1377
+ {
1378
+ onClick: () => setIsExpanded(!isExpanded),
1379
+ className: `crow-flex crow-items-center crow-gap-1.5 crow-select-none crow-transition-colors ${isInProgress ? "crow-text-gray-500" : "crow-text-gray-600 hover:crow-text-gray-800"} crow-cursor-pointer`,
1380
+ children: [
1381
+ /* @__PURE__ */ jsx("div", { className: "crow-flex crow-items-center crow-justify-center crow-w-4 crow-h-4", children: isInProgress ? /* @__PURE__ */ jsx(ShimmeringContent, { children: /* @__PURE__ */ jsx(Brain, { className: "crow-w-3.5 crow-h-3.5" }) }) : /* @__PURE__ */ jsx(Brain, { className: "crow-w-3.5 crow-h-3.5" }) }),
1382
+ /* @__PURE__ */ jsx("span", { className: "crow-font-medium", children: isInProgress ? /* @__PURE__ */ jsx(ShimmeringContent, { children: getRandomThinkingMessage() }) : "Thought" }),
1383
+ /* @__PURE__ */ jsx(
1384
+ motion.div,
1385
+ {
1386
+ animate: { rotate: isExpanded ? 90 : 0 },
1387
+ transition: { duration: 0.15 },
1388
+ className: "crow-flex-shrink-0",
1389
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "crow-w-3 crow-h-3" })
1390
+ }
1391
+ ),
1392
+ isComplete && /* @__PURE__ */ jsx(Check, { className: "crow-w-3 crow-h-3 crow-text-green-500" })
1393
+ ]
1394
+ }
1395
+ ),
1396
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isExpanded && /* @__PURE__ */ jsx(
1397
+ motion.div,
1398
+ {
1399
+ initial: { height: 0, opacity: 0 },
1400
+ animate: { height: "auto", opacity: 1 },
1401
+ exit: { height: 0, opacity: 0 },
1402
+ transition: { duration: 0.15 },
1403
+ className: "crow-overflow-hidden",
1404
+ children: /* @__PURE__ */ jsx("div", { className: "crow-border-l-2 crow-border-gray-200 crow-pl-3 crow-ml-2", children: /* @__PURE__ */ jsx(
1405
+ "div",
1406
+ {
1407
+ className: `crow-text-xs crow-leading-relaxed crow-whitespace-pre-wrap ${isComplete ? "crow-text-gray-500" : "crow-text-gray-600"}`,
1408
+ children: thinking
1409
+ }
1410
+ ) })
1411
+ }
1412
+ ) })
1413
+ ] });
1414
+ }
1415
+ function ToolCallBlock({ toolCall }) {
1416
+ const [expanded, setExpanded] = useState(false);
1417
+ const hasArgs = Object.keys(toolCall.arguments || {}).length > 0;
1418
+ const isExecuting = toolCall.status === "executing";
1419
+ const isComplete = toolCall.status === "complete";
1420
+ const isError = toolCall.status === "error";
1421
+ return /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-flex-col crow-gap-1 crow-text-xs", children: [
1422
+ /* @__PURE__ */ jsxs(
1423
+ "button",
1424
+ {
1425
+ onClick: () => hasArgs && setExpanded(!expanded),
1426
+ className: `crow-flex crow-items-center crow-gap-1.5 crow-select-none crow-transition-colors ${hasArgs ? "crow-cursor-pointer hover:crow-text-gray-800" : "crow-cursor-default"} ${isExecuting ? "crow-text-gray-500" : "crow-text-gray-600"}`,
1427
+ disabled: !hasArgs,
1428
+ children: [
1429
+ hasArgs && /* @__PURE__ */ jsx(
1430
+ motion.div,
1431
+ {
1432
+ animate: { rotate: expanded ? 90 : 0 },
1433
+ transition: { duration: 0.15 },
1434
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "crow-w-3 crow-h-3" })
1435
+ }
1436
+ ),
1437
+ isExecuting && /* @__PURE__ */ jsx(Loader2, { className: "crow-w-3 crow-h-3 crow-animate-spin crow-text-blue-500" }),
1438
+ isComplete && /* @__PURE__ */ jsx(Check, { className: "crow-w-3 crow-h-3 crow-text-green-500" }),
1439
+ isError && /* @__PURE__ */ jsx("span", { className: "crow-w-3 crow-h-3 crow-text-red-500", children: "\u2715" }),
1440
+ /* @__PURE__ */ jsx("span", { className: "crow-font-medium", children: toolCall.name }),
1441
+ /* @__PURE__ */ jsxs("span", { className: "crow-text-gray-400", children: [
1442
+ isExecuting && "running...",
1443
+ isComplete && "done",
1444
+ isError && "failed"
1445
+ ] })
1446
+ ]
1447
+ }
1448
+ ),
1449
+ /* @__PURE__ */ jsx(AnimatePresence, { children: expanded && hasArgs && /* @__PURE__ */ jsx(
1450
+ motion.div,
1451
+ {
1452
+ initial: { height: 0, opacity: 0 },
1453
+ animate: { height: "auto", opacity: 1 },
1454
+ exit: { height: 0, opacity: 0 },
1455
+ transition: { duration: 0.15 },
1456
+ className: "crow-overflow-hidden",
1457
+ children: /* @__PURE__ */ jsx("pre", { className: "crow-mt-1 crow-p-2 crow-bg-gray-100 crow-rounded crow-text-xs crow-font-mono crow-text-gray-700 crow-overflow-x-auto crow-max-h-32 crow-overflow-y-auto crow-ml-4", children: JSON.stringify(toolCall.arguments, null, 2) })
1458
+ }
1459
+ ) })
1460
+ ] });
210
1461
  }
211
- function MessageBubble({ message, isStreaming = false }) {
212
- const isUser = message.role === "user";
213
- const isWaiting = !message.content && !isUser;
1462
+ function MessageBubble({
1463
+ message,
1464
+ toolCalls = [],
1465
+ isLoading = false
1466
+ }) {
1467
+ const styles2 = useWidgetStyles2();
1468
+ const isWaiting = message.content === "Thinking..." || message.isBot && isLoading && !message.content;
1469
+ const hasThinking = message.isBot && message.thinking;
1470
+ const hasContent = message.content && message.content !== "Thinking...";
1471
+ const hasToolCalls = toolCalls.length > 0;
1472
+ const showReasoningTrace = message.isBot && (isWaiting || hasThinking || hasToolCalls);
1473
+ const isStreaming = Boolean(message.isBot && isLoading && hasContent);
214
1474
  return /* @__PURE__ */ jsxs(
215
1475
  "div",
216
1476
  {
217
- className: clsx(
218
- "crow-flex crow-flex-col",
219
- isUser ? "crow-items-end" : "crow-items-start"
220
- ),
1477
+ id: message.id,
1478
+ className: `crow-flex crow-flex-col ${message.isBot ? "crow-items-start" : "crow-items-end"}`,
221
1479
  children: [
222
- message.thinking && /* @__PURE__ */ jsx("div", { className: "crow-mb-2 crow-text-xs crow-text-gray-500 crow-bg-gray-100 crow-rounded-lg crow-px-3 crow-py-2 crow-max-w-[80%]", children: /* @__PURE__ */ jsxs("details", { open: !message.thinkingComplete, children: [
223
- /* @__PURE__ */ jsx("summary", { className: "crow-cursor-pointer crow-font-medium", children: message.thinkingComplete ? "Reasoning" : "Thinking..." }),
224
- /* @__PURE__ */ jsx("div", { className: "crow-mt-1 crow-text-gray-600 crow-whitespace-pre-wrap", children: message.thinking })
225
- ] }) }),
226
- isWaiting && /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-1 crow-text-gray-500 crow-text-sm crow-px-3 crow-py-2", children: [
227
- /* @__PURE__ */ jsx("span", { className: "crow-animate-pulse", children: "\u25CF" }),
228
- /* @__PURE__ */ jsx("span", { className: "crow-animate-pulse crow-animation-delay-100", children: "\u25CF" }),
229
- /* @__PURE__ */ jsx("span", { className: "crow-animate-pulse crow-animation-delay-200", children: "\u25CF" })
230
- ] }),
231
- message.content && /* @__PURE__ */ jsxs(
1480
+ showReasoningTrace && /* @__PURE__ */ jsx(
1481
+ ReasoningTrace,
1482
+ {
1483
+ thinking: message.thinking,
1484
+ isComplete: message.thinkingComplete,
1485
+ toolCalls,
1486
+ isWaiting: isWaiting && !hasThinking
1487
+ }
1488
+ ),
1489
+ hasContent && /* @__PURE__ */ jsxs(
232
1490
  "div",
233
1491
  {
234
- className: clsx(
235
- "crow-max-w-[80%] crow-rounded-2xl crow-px-4 crow-py-2 crow-transition-all",
236
- isUser ? "crow-bg-crow-primary crow-text-white" : "crow-bg-gray-100 crow-text-gray-900"
237
- ),
1492
+ className: "crow-max-w-[80%] crow-rounded-2xl crow-px-4 crow-py-2 crow-transition-all crow-duration-150",
1493
+ style: message.isBot ? {
1494
+ background: styles2.colors.botBubble,
1495
+ color: styles2.colors.botText
1496
+ } : {
1497
+ background: styles2.colors.userBubble,
1498
+ color: styles2.colors.userText,
1499
+ border: `1px solid ${styles2.colors.userBorder}`
1500
+ },
238
1501
  children: [
239
- /* @__PURE__ */ jsxs("div", { className: "crow-text-sm crow-whitespace-pre-wrap", children: [
240
- message.content,
241
- isStreaming && /* @__PURE__ */ jsx("span", { className: "crow-inline-block crow-w-1 crow-h-4 crow-ml-0.5 crow-bg-current crow-animate-pulse" })
242
- ] }),
1502
+ /* @__PURE__ */ jsx("div", { className: "crow-text-sm crow-whitespace-pre-wrap", children: message.isBot ? /* @__PURE__ */ jsx(
1503
+ StreamingText,
1504
+ {
1505
+ content: message.content,
1506
+ isStreaming
1507
+ }
1508
+ ) : /* @__PURE__ */ jsx(
1509
+ ReactMarkdown,
1510
+ {
1511
+ components: {
1512
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "crow-font-bold", children }),
1513
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "crow-list-disc crow-pl-5 crow-my-1", children }),
1514
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "crow-list-decimal crow-pl-5 crow-my-1", children }),
1515
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { children }),
1516
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "crow-mb-1 last:crow-mb-0", children }),
1517
+ a: ({ href, children }) => /* @__PURE__ */ jsx(
1518
+ "a",
1519
+ {
1520
+ href,
1521
+ className: "crow-underline hover:crow-text-blue-300",
1522
+ target: "_blank",
1523
+ rel: "noopener noreferrer",
1524
+ children
1525
+ }
1526
+ )
1527
+ },
1528
+ children: message.content
1529
+ }
1530
+ ) }),
243
1531
  /* @__PURE__ */ jsx("div", { className: "crow-text-xs crow-opacity-60 crow-mt-1", children: formatTime(message.timestamp) })
244
1532
  ]
245
1533
  }
246
- ),
247
- message.citations && message.citations.length > 0 && /* @__PURE__ */ jsx("div", { className: "crow-mt-1 crow-flex crow-flex-wrap crow-gap-1", children: message.citations.map((citation, idx) => /* @__PURE__ */ jsx(
248
- "span",
1534
+ )
1535
+ ]
1536
+ }
1537
+ );
1538
+ }
1539
+ function MessageList({
1540
+ messages,
1541
+ activeToolCalls,
1542
+ isLoadingHistory,
1543
+ isGenerating = false
1544
+ }) {
1545
+ if (isLoadingHistory) {
1546
+ return /* @__PURE__ */ jsx(LoadingHistory, {});
1547
+ }
1548
+ const lastBotIndex = messages.reduce(
1549
+ (lastIdx, m, i) => m.isBot ? i : lastIdx,
1550
+ -1
1551
+ );
1552
+ return /* @__PURE__ */ jsx(Fragment, { children: messages.map((msg, index) => /* @__PURE__ */ jsx(
1553
+ MessageBubble,
1554
+ {
1555
+ message: msg,
1556
+ toolCalls: index === lastBotIndex ? activeToolCalls : void 0,
1557
+ isLoading: index === lastBotIndex && isGenerating
1558
+ },
1559
+ msg.id
1560
+ )) });
1561
+ }
1562
+ var MessagesContainer = forwardRef(
1563
+ ({ children, maxHeight }, ref) => {
1564
+ const styles2 = useWidgetStyles2();
1565
+ const internalRef = useRef(null);
1566
+ const lastScrollHeightRef = useRef(0);
1567
+ const isUserScrollingRef = useRef(false);
1568
+ const containerRef = ref || internalRef;
1569
+ const isNearBottom = useCallback(() => {
1570
+ const container = containerRef.current;
1571
+ if (!container) return true;
1572
+ const threshold = 100;
1573
+ return container.scrollHeight - container.scrollTop - container.clientHeight < threshold;
1574
+ }, [containerRef]);
1575
+ const scrollToBottom = useCallback(() => {
1576
+ const container = containerRef.current;
1577
+ if (!container) return;
1578
+ container.scrollTo({
1579
+ top: container.scrollHeight,
1580
+ behavior: "smooth"
1581
+ });
1582
+ }, [containerRef]);
1583
+ useEffect(() => {
1584
+ const container = containerRef.current;
1585
+ if (!container) return;
1586
+ const handleScroll = () => {
1587
+ isUserScrollingRef.current = !isNearBottom();
1588
+ };
1589
+ container.addEventListener("scroll", handleScroll, { passive: true });
1590
+ return () => container.removeEventListener("scroll", handleScroll);
1591
+ }, [containerRef, isNearBottom]);
1592
+ useEffect(() => {
1593
+ const container = containerRef.current;
1594
+ if (!container) return;
1595
+ const currentHeight = container.scrollHeight;
1596
+ const heightChanged = currentHeight !== lastScrollHeightRef.current;
1597
+ if (heightChanged) {
1598
+ lastScrollHeightRef.current = currentHeight;
1599
+ if (!isUserScrollingRef.current || isNearBottom()) {
1600
+ scrollToBottom();
1601
+ }
1602
+ }
1603
+ });
1604
+ return /* @__PURE__ */ jsx(
1605
+ motion.div,
1606
+ {
1607
+ ref: containerRef,
1608
+ id: MESSAGES_CONTAINER_ID,
1609
+ initial: { opacity: 0 },
1610
+ animate: { opacity: 1 },
1611
+ exit: { opacity: 0 },
1612
+ transition: { duration: styles2.animations.duration },
1613
+ className: "crow-relative crow-flex-1 crow-min-h-0 crow-rounded-2xl crow-mb-3 crow-overflow-y-auto crow-p-4 crow-space-y-3 crow-pointer-events-auto",
1614
+ style: {
1615
+ background: styles2.colors.messagesBackground,
1616
+ ...maxHeight && { maxHeight }
1617
+ },
1618
+ children
1619
+ }
1620
+ );
1621
+ }
1622
+ );
1623
+ MessagesContainer.displayName = "MessagesContainer";
1624
+ function ConversationList({
1625
+ conversations,
1626
+ currentConversationId,
1627
+ onSelect,
1628
+ onClose
1629
+ }) {
1630
+ return /* @__PURE__ */ jsxs(
1631
+ motion.div,
1632
+ {
1633
+ initial: { opacity: 0, height: 0 },
1634
+ animate: { opacity: 1, height: "auto" },
1635
+ exit: { opacity: 0, height: 0 },
1636
+ className: "crow-mb-3 crow-rounded-xl crow-bg-gray-50 crow-border crow-border-gray-200",
1637
+ children: [
1638
+ /* @__PURE__ */ jsxs("div", { className: "crow-p-2 crow-border-b crow-border-gray-200 crow-flex crow-justify-between crow-items-center", children: [
1639
+ /* @__PURE__ */ jsx("span", { className: "crow-text-sm crow-font-medium crow-text-gray-700", children: "Recent Conversations" }),
1640
+ /* @__PURE__ */ jsx("button", { onClick: onClose, className: "crow-p-1 hover:crow-bg-gray-200 crow-rounded", children: /* @__PURE__ */ jsx(X, { size: 14, className: "crow-text-gray-500" }) })
1641
+ ] }),
1642
+ /* @__PURE__ */ jsx("div", { className: "crow-max-h-[200px] crow-overflow-y-auto", children: conversations.length === 0 ? /* @__PURE__ */ jsx("div", { className: "crow-p-4 crow-text-center crow-text-sm crow-text-gray-500", children: "No conversations yet" }) : conversations.map((conv) => /* @__PURE__ */ jsxs(
1643
+ "button",
249
1644
  {
250
- className: "crow-text-xs crow-bg-blue-100 crow-text-blue-700 crow-px-2 crow-py-0.5 crow-rounded",
251
- children: citation.filename
1645
+ onClick: () => onSelect(conv.id),
1646
+ className: `crow-w-full crow-p-3 crow-text-left hover:crow-bg-gray-100 crow-transition-colors crow-border-b crow-border-gray-100 last:crow-border-0 ${currentConversationId === conv.id ? "crow-bg-blue-50" : ""}`,
1647
+ children: [
1648
+ /* @__PURE__ */ jsx("div", { className: "crow-text-sm crow-font-medium crow-text-gray-800 crow-truncate", children: conv.name || "Untitled conversation" }),
1649
+ /* @__PURE__ */ jsx("div", { className: "crow-text-xs crow-text-gray-500 crow-mt-0.5", children: formatConversationDate(conv.updated_at) })
1650
+ ]
252
1651
  },
253
- idx
1652
+ conv.id
254
1653
  )) })
255
1654
  ]
256
1655
  }
257
1656
  );
258
1657
  }
259
- function MessageList({ messages, isLoading = false, className }) {
260
- const containerRef = useRef(null);
261
- useEffect(() => {
262
- if (containerRef.current) {
263
- containerRef.current.scrollTop = containerRef.current.scrollHeight;
264
- }
265
- }, [messages]);
1658
+ function WorkflowPanel({ workflow, onExit }) {
266
1659
  return /* @__PURE__ */ jsx(
267
- "div",
1660
+ motion.div,
268
1661
  {
269
- ref: containerRef,
270
- className: `crow-flex-1 crow-overflow-y-auto crow-px-4 crow-py-4 crow-space-y-3 ${className || ""}`,
271
- children: messages.map((message, index) => {
272
- const isLastBotMessage = message.role === "assistant" && index === messages.length - 1;
273
- return /* @__PURE__ */ jsx(
274
- MessageBubble,
1662
+ initial: { opacity: 0, y: -10 },
1663
+ animate: { opacity: 1, y: 0 },
1664
+ exit: { opacity: 0, y: -10 },
1665
+ transition: { duration: 0.3 },
1666
+ className: "crow-mb-3 crow-p-3 crow-rounded-xl crow-bg-gray-50 crow-border crow-border-gray-200",
1667
+ children: /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-justify-between", children: [
1668
+ /* @__PURE__ */ jsx("span", { className: "crow-text-sm crow-font-medium crow-text-gray-900 crow-flex crow-items-center crow-gap-1", children: workflow.name }),
1669
+ /* @__PURE__ */ jsx(
1670
+ "button",
275
1671
  {
276
- message,
277
- isStreaming: isLastBotMessage && isLoading
1672
+ onClick: onExit,
1673
+ className: "crow-text-xs crow-text-gray-500 hover:crow-text-gray-700 crow-underline",
1674
+ children: "Exit"
1675
+ }
1676
+ )
1677
+ ] })
1678
+ }
1679
+ );
1680
+ }
1681
+ function PoweredByBadge({ apiUrl = "" }) {
1682
+ const styles2 = useWidgetStyles2();
1683
+ const branding = styles2.branding;
1684
+ if (!branding.showPoweredBy) return null;
1685
+ const logoUrl = branding.logoUrl?.startsWith("http") ? branding.logoUrl : `${apiUrl}${branding.logoUrl}`;
1686
+ return /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-justify-center crow-gap-1.5 crow-mb-3 crow-text-xs crow-text-gray-400", children: [
1687
+ branding.showLogo && logoUrl && /* @__PURE__ */ jsx(
1688
+ "img",
1689
+ {
1690
+ src: logoUrl,
1691
+ alt: "Crow",
1692
+ width: 14,
1693
+ height: 14,
1694
+ className: "crow-opacity-50"
1695
+ }
1696
+ ),
1697
+ /* @__PURE__ */ jsx("span", { children: branding.poweredByText })
1698
+ ] });
1699
+ }
1700
+ var ModelSelector = ({
1701
+ models,
1702
+ selectedModel,
1703
+ onModelChange,
1704
+ disabled = false
1705
+ }) => {
1706
+ const [isOpen, setIsOpen] = useState(false);
1707
+ const dropdownRef = useRef(null);
1708
+ useEffect(() => {
1709
+ const handleClickOutside = (event) => {
1710
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
1711
+ setIsOpen(false);
1712
+ }
1713
+ };
1714
+ document.addEventListener("mousedown", handleClickOutside);
1715
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1716
+ }, []);
1717
+ const selectedModelData = models.find((m) => m.id === selectedModel);
1718
+ const groupedModels = models.reduce((acc, model) => {
1719
+ if (!acc[model.provider]) acc[model.provider] = [];
1720
+ acc[model.provider].push(model);
1721
+ return acc;
1722
+ }, {});
1723
+ return /* @__PURE__ */ jsxs("div", { className: "crow-relative", ref: dropdownRef, children: [
1724
+ /* @__PURE__ */ jsxs(
1725
+ "button",
1726
+ {
1727
+ type: "button",
1728
+ onClick: () => !disabled && setIsOpen(!isOpen),
1729
+ disabled,
1730
+ className: cn(
1731
+ "crow-flex crow-items-center crow-gap-1 crow-px-2 crow-py-1 crow-rounded-md crow-text-xs",
1732
+ "crow-bg-transparent crow-text-gray-400",
1733
+ "hover:crow-text-gray-700 crow-transition-colors",
1734
+ disabled ? "crow-opacity-50 crow-cursor-not-allowed" : "crow-cursor-pointer"
1735
+ ),
1736
+ children: [
1737
+ /* @__PURE__ */ jsx("span", { children: selectedModelData?.name || "Select Model" }),
1738
+ /* @__PURE__ */ jsx(
1739
+ ChevronDown,
1740
+ {
1741
+ className: cn(
1742
+ "crow-w-3 crow-h-3 crow-transition-transform",
1743
+ isOpen ? "crow-rotate-180" : ""
1744
+ )
1745
+ }
1746
+ )
1747
+ ]
1748
+ }
1749
+ ),
1750
+ isOpen && /* @__PURE__ */ jsx("div", { className: "crow-absolute crow-bottom-full crow-mb-2 crow-left-0 crow-min-w-[180px] crow-bg-white crow-border crow-border-gray-200 crow-rounded-xl crow-shadow-lg crow-z-50 crow-overflow-hidden", children: Object.entries(groupedModels).map(([provider, providerModels]) => /* @__PURE__ */ jsxs("div", { children: [
1751
+ /* @__PURE__ */ jsx("div", { className: "crow-px-3 crow-py-1.5 crow-text-xs crow-font-medium crow-text-gray-400 crow-uppercase crow-tracking-wide crow-bg-gray-50", children: provider }),
1752
+ providerModels.map((model) => /* @__PURE__ */ jsxs(
1753
+ "button",
1754
+ {
1755
+ onClick: () => {
1756
+ onModelChange(model.id);
1757
+ setIsOpen(false);
278
1758
  },
279
- message.id
280
- );
281
- })
282
- }
283
- );
1759
+ className: cn(
1760
+ "crow-w-full crow-flex crow-items-center crow-justify-between crow-px-3 crow-py-1.5 crow-text-sm",
1761
+ "hover:crow-bg-gray-100 crow-transition-colors",
1762
+ model.id === selectedModel ? "crow-text-gray-900" : "crow-text-gray-600"
1763
+ ),
1764
+ children: [
1765
+ /* @__PURE__ */ jsx("span", { children: model.name }),
1766
+ model.id === selectedModel && /* @__PURE__ */ jsx(Check, { className: "crow-w-4 crow-h-4 crow-text-green-500" })
1767
+ ]
1768
+ },
1769
+ model.id
1770
+ ))
1771
+ ] }, provider)) })
1772
+ ] });
1773
+ };
1774
+ var styles = `
1775
+ *:focus-visible {
1776
+ outline-offset: 0 !important;
1777
+ --ring-offset: 0 !important;
1778
+ }
1779
+ textarea::-webkit-scrollbar {
1780
+ width: 6px;
1781
+ }
1782
+ textarea::-webkit-scrollbar-track {
1783
+ background: transparent;
1784
+ }
1785
+ textarea::-webkit-scrollbar-thumb {
1786
+ background-color: #444444;
1787
+ border-radius: 3px;
1788
+ }
1789
+ textarea::-webkit-scrollbar-thumb:hover {
1790
+ background-color: #555555;
1791
+ }
1792
+ `;
1793
+ if (typeof document !== "undefined") {
1794
+ const styleSheet = document.createElement("style");
1795
+ styleSheet.innerText = styles;
1796
+ document.head.appendChild(styleSheet);
284
1797
  }
285
- function PromptInput({
286
- onSend,
287
- onStop,
288
- isLoading = false,
289
- placeholder = "Type your message...",
290
- disabled = false,
291
- className
292
- }) {
293
- const [value, setValue] = useState("");
294
- const textareaRef = useRef(null);
295
- useEffect(() => {
296
- const textarea = textareaRef.current;
297
- if (textarea) {
298
- textarea.style.height = "auto";
299
- textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
300
- }
301
- }, [value]);
302
- const handleSubmit = useCallback(() => {
303
- if (value.trim() && !isLoading) {
304
- onSend(value.trim());
305
- setValue("");
306
- }
307
- }, [value, isLoading, onSend]);
308
- const handleKeyDown = useCallback(
309
- (e) => {
310
- if (e.key === "Enter" && !e.shiftKey) {
311
- e.preventDefault();
312
- handleSubmit();
313
- }
314
- },
315
- [handleSubmit]
316
- );
317
- const hasContent = value.trim().length > 0;
318
- return /* @__PURE__ */ jsxs(
319
- "div",
1798
+ var Textarea = React3.forwardRef(
1799
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1800
+ "textarea",
320
1801
  {
321
- className: clsx(
322
- "crow-flex crow-items-end crow-gap-2 crow-p-3 crow-border-t crow-border-gray-200 crow-bg-white",
1802
+ className: cn(
1803
+ "crow-flex crow-w-full crow-rounded-md crow-border-none crow-bg-transparent crow-px-3 crow-py-1.5 crow-text-base crow-text-gray-900 placeholder:crow-text-gray-500 focus-visible:crow-outline-none focus-visible:crow-ring-0 disabled:crow-cursor-not-allowed disabled:crow-opacity-50 crow-min-h-[32px] crow-resize-none",
323
1804
  className
324
1805
  ),
325
- children: [
326
- /* @__PURE__ */ jsx(
327
- "textarea",
328
- {
329
- ref: textareaRef,
330
- value,
331
- onChange: (e) => setValue(e.target.value),
332
- onKeyDown: handleKeyDown,
333
- placeholder,
334
- disabled: disabled || isLoading,
335
- rows: 1,
336
- className: clsx(
337
- "crow-flex-1 crow-resize-none crow-border crow-border-gray-300 crow-rounded-xl crow-px-4 crow-py-2",
338
- "crow-text-sm crow-text-gray-900 crow-placeholder-gray-500",
339
- "focus:crow-outline-none focus:crow-ring-2 focus:crow-ring-crow-primary focus:crow-border-transparent",
340
- "disabled:crow-bg-gray-50 disabled:crow-cursor-not-allowed"
341
- )
342
- }
1806
+ ref,
1807
+ rows: 1,
1808
+ ...props
1809
+ }
1810
+ )
1811
+ );
1812
+ Textarea.displayName = "Textarea";
1813
+ var TooltipProvider = TooltipPrimitive.Provider;
1814
+ var Tooltip = TooltipPrimitive.Root;
1815
+ var TooltipTrigger = TooltipPrimitive.Trigger;
1816
+ var TooltipContent = React3.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
1817
+ TooltipPrimitive.Content,
1818
+ {
1819
+ ref,
1820
+ sideOffset,
1821
+ className: cn(
1822
+ "crow-z-50 crow-overflow-hidden crow-rounded-md crow-border crow-px-3 crow-py-1.5 crow-text-sm crow-text-white crow-shadow-md",
1823
+ className
1824
+ ),
1825
+ style: { borderColor: "#333333", background: "#1F2023" },
1826
+ ...props
1827
+ }
1828
+ ));
1829
+ TooltipContent.displayName = "TooltipContent";
1830
+ var Button = React3.forwardRef(
1831
+ ({ className, variant = "default", size = "default", ...props }, ref) => {
1832
+ const variantClasses = {
1833
+ default: "crow-bg-white hover:crow-bg-white/80 crow-text-black",
1834
+ outline: "crow-border crow-bg-transparent hover:crow-bg-gray-700",
1835
+ ghost: "crow-bg-transparent hover:crow-bg-gray-700"
1836
+ };
1837
+ const sizeClasses = {
1838
+ default: "crow-h-10 crow-px-4 crow-py-2",
1839
+ sm: "crow-h-8 crow-px-3 crow-text-sm",
1840
+ lg: "crow-h-12 crow-px-6",
1841
+ icon: "crow-h-8 crow-w-8 crow-rounded-full"
1842
+ };
1843
+ return /* @__PURE__ */ jsx(
1844
+ "button",
1845
+ {
1846
+ className: cn(
1847
+ "crow-inline-flex crow-items-center crow-justify-center crow-font-medium crow-transition-colors focus-visible:crow-outline-none disabled:crow-pointer-events-none disabled:crow-opacity-50",
1848
+ variantClasses[variant],
1849
+ sizeClasses[size],
1850
+ className
343
1851
  ),
344
- /* @__PURE__ */ jsx(
345
- "button",
1852
+ ref,
1853
+ ...props
1854
+ }
1855
+ );
1856
+ }
1857
+ );
1858
+ Button.displayName = "Button";
1859
+ var PromptInputContext = React3.createContext({
1860
+ isLoading: false,
1861
+ value: "",
1862
+ setValue: () => {
1863
+ },
1864
+ maxHeight: 240,
1865
+ onSubmit: void 0,
1866
+ disabled: false
1867
+ });
1868
+ function usePromptInput() {
1869
+ const context = React3.useContext(PromptInputContext);
1870
+ if (!context) {
1871
+ throw new Error("usePromptInput must be used within a PromptInput");
1872
+ }
1873
+ return context;
1874
+ }
1875
+ var PromptInput = React3.forwardRef(
1876
+ ({
1877
+ className,
1878
+ isLoading = false,
1879
+ maxHeight = 240,
1880
+ value,
1881
+ onValueChange,
1882
+ onSubmit,
1883
+ children,
1884
+ disabled = false
1885
+ }, ref) => {
1886
+ const [internalValue, setInternalValue] = React3.useState(value || "");
1887
+ const handleChange = (newValue) => {
1888
+ setInternalValue(newValue);
1889
+ onValueChange?.(newValue);
1890
+ };
1891
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(
1892
+ PromptInputContext.Provider,
1893
+ {
1894
+ value: {
1895
+ isLoading,
1896
+ value: value ?? internalValue,
1897
+ setValue: onValueChange ?? handleChange,
1898
+ maxHeight,
1899
+ onSubmit,
1900
+ disabled
1901
+ },
1902
+ children: /* @__PURE__ */ jsx(
1903
+ "div",
346
1904
  {
347
- onClick: isLoading ? onStop : handleSubmit,
348
- disabled: !isLoading && !hasContent,
349
- className: clsx(
350
- "crow-flex-shrink-0 crow-w-10 crow-h-10 crow-rounded-full crow-flex crow-items-center crow-justify-center",
351
- "crow-transition-all crow-duration-200",
352
- isLoading ? "crow-bg-red-500 hover:crow-bg-red-600 crow-text-white" : hasContent ? "crow-bg-crow-primary hover:crow-bg-crow-primary-dark crow-text-white" : "crow-bg-gray-200 crow-text-gray-400 crow-cursor-not-allowed"
1905
+ ref,
1906
+ className: cn(
1907
+ "crow-rounded-3xl crow-border crow-p-1.5 crow-shadow-lg crow-transition-all crow-duration-300",
1908
+ isLoading && "crow-border-red-500",
1909
+ className
353
1910
  ),
354
- "aria-label": isLoading ? "Stop generation" : "Send message",
355
- children: isLoading ? /* @__PURE__ */ jsx("svg", { className: "crow-w-4 crow-h-4", fill: "currentColor", viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx("rect", { width: "10", height: "10", x: "3", y: "3", rx: "1" }) }) : /* @__PURE__ */ jsx("svg", { className: "crow-w-4 crow-h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 12h14M12 5l7 7-7 7" }) })
1911
+ style: { borderColor: isLoading ? void 0 : "#444444", background: "#1F2023" },
1912
+ children
356
1913
  }
357
1914
  )
358
- ]
1915
+ }
1916
+ ) });
1917
+ }
1918
+ );
1919
+ PromptInput.displayName = "PromptInput";
1920
+ var PromptInputTextarea = ({ className, onKeyDown, disableAutosize = false, placeholder, ...props }) => {
1921
+ const { value, setValue, maxHeight, onSubmit, disabled } = usePromptInput();
1922
+ const textareaRef = React3.useRef(null);
1923
+ React3.useEffect(() => {
1924
+ if (disableAutosize || !textareaRef.current) return;
1925
+ textareaRef.current.style.height = "auto";
1926
+ textareaRef.current.style.height = typeof maxHeight === "number" ? `${Math.min(textareaRef.current.scrollHeight, maxHeight)}px` : `min(${textareaRef.current.scrollHeight}px, ${maxHeight})`;
1927
+ }, [value, maxHeight, disableAutosize]);
1928
+ const handleKeyDown = (e) => {
1929
+ if (e.key === "Enter" && !e.shiftKey) {
1930
+ e.preventDefault();
1931
+ onSubmit?.();
1932
+ }
1933
+ onKeyDown?.(e);
1934
+ };
1935
+ return /* @__PURE__ */ jsx(
1936
+ Textarea,
1937
+ {
1938
+ ref: textareaRef,
1939
+ value,
1940
+ onChange: (e) => setValue(e.target.value),
1941
+ onKeyDown: handleKeyDown,
1942
+ className: cn("text-base", className),
1943
+ disabled,
1944
+ placeholder,
1945
+ ...props
359
1946
  }
360
1947
  );
361
- }
1948
+ };
1949
+ var PromptInputActions = ({
1950
+ children,
1951
+ className,
1952
+ ...props
1953
+ }) => /* @__PURE__ */ jsx("div", { className: cn("crow-flex crow-items-center crow-gap-2", className), ...props, children });
1954
+ var PromptInputAction = ({
1955
+ tooltip,
1956
+ children,
1957
+ side = "top",
1958
+ ...props
1959
+ }) => {
1960
+ return /* @__PURE__ */ jsxs(Tooltip, { ...props, children: [
1961
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children }),
1962
+ /* @__PURE__ */ jsx(TooltipContent, { side, children: tooltip })
1963
+ ] });
1964
+ };
1965
+ var PromptInputBox = React3.forwardRef(
1966
+ ({
1967
+ onSend = () => {
1968
+ },
1969
+ onStop,
1970
+ isLoading = false,
1971
+ placeholder = "Type your message here...",
1972
+ className,
1973
+ selectedModel = "gpt-4o",
1974
+ onModelChange,
1975
+ availableModels = []
1976
+ }, ref) => {
1977
+ const [input, setInput] = React3.useState("");
1978
+ const promptBoxRef = React3.useRef(null);
1979
+ const handleSubmit = () => {
1980
+ if (input.trim()) {
1981
+ onSend(input);
1982
+ setInput("");
1983
+ }
1984
+ };
1985
+ const hasContent = input.trim() !== "";
1986
+ return /* @__PURE__ */ jsxs(
1987
+ PromptInput,
1988
+ {
1989
+ value: input,
1990
+ onValueChange: setInput,
1991
+ isLoading,
1992
+ onSubmit: handleSubmit,
1993
+ className: cn(
1994
+ "crow-w-full crow-shadow-lg crow-transition-all crow-duration-300 crow-ease-in-out",
1995
+ className
1996
+ ),
1997
+ disabled: isLoading,
1998
+ ref: ref || promptBoxRef,
1999
+ children: [
2000
+ /* @__PURE__ */ jsx("div", { className: "crow-transition-all crow-duration-300 crow-opacity-100", children: /* @__PURE__ */ jsx(PromptInputTextarea, { placeholder, className: "crow-text-base" }) }),
2001
+ /* @__PURE__ */ jsxs(PromptInputActions, { className: "crow-flex crow-items-center crow-justify-between crow-gap-2 crow-p-0 crow-pt-1", children: [
2002
+ /* @__PURE__ */ jsx("div", { className: "crow-flex crow-items-center", children: availableModels.length > 0 && onModelChange && /* @__PURE__ */ jsx(
2003
+ ModelSelector,
2004
+ {
2005
+ models: availableModels,
2006
+ selectedModel,
2007
+ onModelChange,
2008
+ disabled: isLoading
2009
+ }
2010
+ ) }),
2011
+ /* @__PURE__ */ jsx(
2012
+ PromptInputAction,
2013
+ {
2014
+ tooltip: isLoading ? "Stop generation" : hasContent ? "Send message" : "Type a message",
2015
+ children: /* @__PURE__ */ jsx(
2016
+ Button,
2017
+ {
2018
+ variant: "default",
2019
+ size: "icon",
2020
+ className: cn(
2021
+ "crow-h-7 crow-w-7 crow-rounded-full crow-transition-all crow-duration-200"
2022
+ ),
2023
+ style: {
2024
+ background: isLoading ? "#ef4444" : hasContent ? "#ffffff" : "transparent",
2025
+ color: isLoading ? "#ffffff" : "#1F2023"
2026
+ },
2027
+ onClick: () => {
2028
+ if (isLoading && onStop) {
2029
+ onStop();
2030
+ } else if (hasContent) {
2031
+ handleSubmit();
2032
+ }
2033
+ },
2034
+ children: isLoading ? /* @__PURE__ */ jsx(Square, { className: "crow-h-3.5 crow-w-3.5", style: { fill: "white", color: "white" } }) : /* @__PURE__ */ jsx(ArrowUp, { className: "crow-h-3.5 crow-w-3.5", style: { color: "#1F2023" } })
2035
+ }
2036
+ )
2037
+ }
2038
+ )
2039
+ ] })
2040
+ ]
2041
+ }
2042
+ );
2043
+ }
2044
+ );
2045
+ PromptInputBox.displayName = "PromptInputBox";
362
2046
  function CrowWidget({
363
2047
  productId,
364
- apiUrl,
365
- model,
366
- agentName = "Assistant",
367
- defaultCollapsed = true,
368
- onIdentify,
369
- tools,
370
- className,
371
- zIndex = 999999
2048
+ apiUrl = "",
2049
+ variant = "floating",
2050
+ styles: propStyles,
2051
+ previewMode = false,
2052
+ onReady
372
2053
  }) {
373
- const contextClient = useCrowClientOptional();
374
- const standaloneClientRef = useRef(null);
375
- if (!contextClient && !standaloneClientRef.current) {
376
- standaloneClientRef.current = new CrowClient({ productId, apiUrl, model });
377
- }
378
- const client = contextClient || standaloneClientRef.current;
379
- useEffect(() => {
380
- return () => {
381
- if (standaloneClientRef.current) {
382
- standaloneClientRef.current.destroy();
2054
+ const { styles: styles2, isLoading: isLoadingStyles, agentName } = useWidgetStyles({
2055
+ productId,
2056
+ apiUrl,
2057
+ propStyles,
2058
+ skip: previewMode
2059
+ });
2060
+ const messagesContainerRef = useRef(null);
2061
+ const executeClientToolRef = useRef(null);
2062
+ const [isCollapsed, setIsCollapsed] = useState(variant === "floating");
2063
+ const [showConversationList, setShowConversationList] = useState(false);
2064
+ const [isVerifiedUser, setIsVerifiedUser] = useState(false);
2065
+ const {
2066
+ activeWorkflow,
2067
+ startWorkflow,
2068
+ updateTodo,
2069
+ markComplete,
2070
+ endWorkflow
2071
+ } = useWorkflow({
2072
+ productId,
2073
+ apiUrl,
2074
+ conversationId: null,
2075
+ selectedModel: DEFAULT_MODEL
2076
+ });
2077
+ const conversations = useConversations({ productId, apiUrl });
2078
+ const [shouldRestoreHistory, setShouldRestoreHistory] = useState(false);
2079
+ const hasRestoredHistoryRef = useRef(false);
2080
+ const chat = useChat({
2081
+ productId,
2082
+ apiUrl,
2083
+ onVerificationStatus: (isVerified) => {
2084
+ setIsVerifiedUser(isVerified);
2085
+ },
2086
+ onConversationId: () => {
2087
+ },
2088
+ onWorkflowEvent: (event) => {
2089
+ switch (event.type) {
2090
+ case "started":
2091
+ if (event.name && event.todos) {
2092
+ startWorkflow(event.name, event.todos);
2093
+ }
2094
+ break;
2095
+ case "todo_updated":
2096
+ if (event.todoId && event.todoStatus) {
2097
+ updateTodo(event.todoId, event.todoStatus);
2098
+ }
2099
+ break;
2100
+ case "ended":
2101
+ endWorkflow(2e3);
2102
+ break;
2103
+ case "complete_prompt":
2104
+ markComplete();
2105
+ break;
383
2106
  }
384
- };
385
- }, []);
386
- useEffect(() => {
387
- if (tools) {
388
- client.registerTools(tools);
2107
+ },
2108
+ onToolCall: (event) => {
2109
+ if (event.type === "client_call" && event.toolName) {
2110
+ console.log("[Crow Widget] Executing client tool:", event.toolName, event.arguments);
2111
+ const result = executeClientToolRef.current?.(event.toolName, event.arguments || {});
2112
+ result?.then((r) => console.log("[Crow Widget] Tool result:", r)).catch((e) => console.error("[Crow Widget] Tool error:", e));
2113
+ }
2114
+ },
2115
+ onRestoredConversation: () => {
2116
+ setShouldRestoreHistory(true);
389
2117
  }
390
- }, [client, tools]);
2118
+ });
391
2119
  useEffect(() => {
392
- if (onIdentify) {
393
- onIdentify((options) => client.identify(options));
2120
+ if (shouldRestoreHistory && chat.conversationId && !hasRestoredHistoryRef.current) {
2121
+ hasRestoredHistoryRef.current = true;
2122
+ console.log("[Crow Widget] Restoring conversation history:", chat.conversationId);
2123
+ conversations.loadAnonymousConversationHistory(chat.conversationId).then((historyMessages) => {
2124
+ if (historyMessages.length > 0) {
2125
+ chat.loadMessages(historyMessages);
2126
+ }
2127
+ });
2128
+ }
2129
+ }, [shouldRestoreHistory, chat.conversationId, conversations, chat]);
2130
+ const workflowActions = useWorkflow({
2131
+ productId,
2132
+ apiUrl,
2133
+ conversationId: chat.conversationId,
2134
+ selectedModel: chat.selectedModel,
2135
+ onMessage: (content) => {
2136
+ chat.loadMessages([
2137
+ ...chat.messages,
2138
+ {
2139
+ id: `bot-${Date.now()}`,
2140
+ content,
2141
+ isBot: true,
2142
+ timestamp: /* @__PURE__ */ new Date()
2143
+ }
2144
+ ]);
394
2145
  }
395
- }, [client, onIdentify]);
396
- const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
397
- const { messages, isLoading, sendMessage, stop, clearMessages } = useChat({
398
- client
399
2146
  });
400
- return /* @__PURE__ */ jsxs(Fragment, { children: [
401
- /* @__PURE__ */ jsx(ChatBubble, { isOpen: !isCollapsed, onClick: () => setIsCollapsed(!isCollapsed) }),
402
- !isCollapsed && /* @__PURE__ */ jsxs(
403
- "div",
404
- {
405
- className: clsx(
406
- "crow-fixed crow-flex crow-flex-col",
407
- "crow-bg-white crow-rounded-2xl crow-shadow-2xl",
408
- "crow-border crow-border-gray-200",
409
- "crow-overflow-hidden crow-animate-fade-in",
410
- className
411
- ),
412
- style: {
413
- zIndex,
414
- right: "20px",
415
- bottom: "90px",
416
- width: "380px",
417
- height: "550px",
418
- maxHeight: "calc(100vh - 120px)"
419
- },
420
- children: [
2147
+ const { executeClientTool } = useCrowAPI({
2148
+ onIdentified: async () => {
2149
+ setIsVerifiedUser(true);
2150
+ await conversations.loadConversations();
2151
+ },
2152
+ onReset: () => {
2153
+ setIsVerifiedUser(false);
2154
+ chat.resetMessages();
2155
+ }
2156
+ });
2157
+ executeClientToolRef.current = executeClientTool;
2158
+ useEffect(() => {
2159
+ if (!isLoadingStyles) {
2160
+ onReady?.();
2161
+ }
2162
+ }, [isLoadingStyles, onReady]);
2163
+ const handleSend = (message) => {
2164
+ if (!message.trim()) return;
2165
+ setIsCollapsed(false);
2166
+ chat.sendMessage(message);
2167
+ };
2168
+ const handleNewChat = () => {
2169
+ chat.resetMessages();
2170
+ setShowConversationList(false);
2171
+ };
2172
+ const handleToggleHistory = () => {
2173
+ setShowConversationList(!showConversationList);
2174
+ if (!showConversationList) {
2175
+ conversations.loadConversations();
2176
+ }
2177
+ };
2178
+ const handleSelectConversation = async (convId) => {
2179
+ const historyMessages = await conversations.loadConversationHistory(convId);
2180
+ if (historyMessages.length > 0) {
2181
+ chat.loadMessages(historyMessages);
2182
+ chat.setConversationId(convId);
2183
+ } else {
2184
+ chat.resetMessages();
2185
+ }
2186
+ setShowConversationList(false);
2187
+ };
2188
+ const handleCloseConversationList = () => {
2189
+ setShowConversationList(false);
2190
+ };
2191
+ const handleExitWorkflow = async () => {
2192
+ await workflowActions.exitWorkflow();
2193
+ };
2194
+ const handleBubbleClick = () => {
2195
+ setIsCollapsed(!isCollapsed);
2196
+ };
2197
+ return /* @__PURE__ */ jsxs(
2198
+ WidgetStyleProvider,
2199
+ {
2200
+ styles: styles2,
2201
+ agentName,
2202
+ isLoading: isLoadingStyles,
2203
+ variant,
2204
+ children: [
2205
+ variant === "floating" && /* @__PURE__ */ jsxs(Fragment, { children: [
2206
+ /* @__PURE__ */ jsx(ChatBubble, { isExpanded: !isCollapsed, onClick: handleBubbleClick }),
2207
+ !isCollapsed && /* @__PURE__ */ jsxs(WidgetShell, { children: [
2208
+ /* @__PURE__ */ jsx(
2209
+ WidgetHeader,
2210
+ {
2211
+ isVerifiedUser,
2212
+ showConversationList,
2213
+ onNewChat: handleNewChat,
2214
+ onToggleHistory: handleToggleHistory
2215
+ }
2216
+ ),
2217
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showConversationList && isVerifiedUser && /* @__PURE__ */ jsx(
2218
+ ConversationList,
2219
+ {
2220
+ conversations: conversations.conversations,
2221
+ currentConversationId: chat.conversationId,
2222
+ onSelect: handleSelectConversation,
2223
+ onClose: handleCloseConversationList
2224
+ }
2225
+ ) }),
2226
+ /* @__PURE__ */ jsx(AnimatePresence, { children: activeWorkflow && /* @__PURE__ */ jsx(
2227
+ WorkflowPanel,
2228
+ {
2229
+ workflow: activeWorkflow,
2230
+ onExit: handleExitWorkflow
2231
+ }
2232
+ ) }),
2233
+ /* @__PURE__ */ jsx(AnimatePresence, { children: (chat.messages.length > 0 || conversations.isLoadingHistory) && /* @__PURE__ */ jsx(MessagesContainer, { ref: messagesContainerRef, children: /* @__PURE__ */ jsx(
2234
+ MessageList,
2235
+ {
2236
+ messages: chat.messages,
2237
+ activeToolCalls: chat.activeToolCalls,
2238
+ isLoadingHistory: conversations.isLoadingHistory,
2239
+ isGenerating: chat.isLoading
2240
+ }
2241
+ ) }) }),
2242
+ /* @__PURE__ */ jsxs("div", { className: "crow-mt-auto", children: [
2243
+ /* @__PURE__ */ jsx(PoweredByBadge, { apiUrl }),
2244
+ /* @__PURE__ */ jsx(
2245
+ PromptInputBox,
2246
+ {
2247
+ onSend: handleSend,
2248
+ onStop: chat.stopGeneration,
2249
+ placeholder: "Type your message...",
2250
+ isLoading: chat.isLoading,
2251
+ className: "crow-backdrop-blur-md"
2252
+ }
2253
+ )
2254
+ ] })
2255
+ ] })
2256
+ ] }),
2257
+ variant === "embedded" && /* @__PURE__ */ jsxs(WidgetShell, { children: [
421
2258
  /* @__PURE__ */ jsx(
422
2259
  WidgetHeader,
423
2260
  {
424
- title: agentName,
425
- onNewChat: clearMessages,
426
- showNewChat: true
2261
+ isVerifiedUser,
2262
+ showConversationList,
2263
+ onNewChat: handleNewChat,
2264
+ onToggleHistory: handleToggleHistory
427
2265
  }
428
2266
  ),
429
- /* @__PURE__ */ jsx(
430
- MessageList,
2267
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showConversationList && isVerifiedUser && /* @__PURE__ */ jsx(
2268
+ ConversationList,
431
2269
  {
432
- messages,
433
- isLoading,
434
- className: "crow-flex-1"
2270
+ conversations: conversations.conversations,
2271
+ currentConversationId: chat.conversationId,
2272
+ onSelect: handleSelectConversation,
2273
+ onClose: handleCloseConversationList
435
2274
  }
436
- ),
437
- /* @__PURE__ */ jsx(
438
- PromptInput,
2275
+ ) }),
2276
+ /* @__PURE__ */ jsx(AnimatePresence, { children: activeWorkflow && /* @__PURE__ */ jsx(
2277
+ WorkflowPanel,
439
2278
  {
440
- onSend: sendMessage,
441
- onStop: stop,
442
- isLoading,
443
- placeholder: "Type your message..."
2279
+ workflow: activeWorkflow,
2280
+ onExit: handleExitWorkflow
444
2281
  }
445
- )
446
- ]
447
- }
448
- )
449
- ] });
2282
+ ) }),
2283
+ /* @__PURE__ */ jsx(AnimatePresence, { children: (chat.messages.length > 0 || conversations.isLoadingHistory) && /* @__PURE__ */ jsx(MessagesContainer, { ref: messagesContainerRef, children: /* @__PURE__ */ jsx(
2284
+ MessageList,
2285
+ {
2286
+ messages: chat.messages,
2287
+ activeToolCalls: chat.activeToolCalls,
2288
+ isLoadingHistory: conversations.isLoadingHistory,
2289
+ isGenerating: chat.isLoading
2290
+ }
2291
+ ) }) }),
2292
+ /* @__PURE__ */ jsxs("div", { className: "crow-mt-auto", children: [
2293
+ /* @__PURE__ */ jsx(PoweredByBadge, { apiUrl }),
2294
+ /* @__PURE__ */ jsx(
2295
+ PromptInputBox,
2296
+ {
2297
+ onSend: handleSend,
2298
+ onStop: chat.stopGeneration,
2299
+ placeholder: "Type your message...",
2300
+ isLoading: chat.isLoading,
2301
+ className: "crow-backdrop-blur-md"
2302
+ }
2303
+ )
2304
+ ] })
2305
+ ] })
2306
+ ]
2307
+ }
2308
+ );
450
2309
  }
451
2310
  function CrowCopilot({
452
2311
  productId,
453
- apiUrl,
454
- model,
2312
+ apiUrl = "",
455
2313
  title = "Copilot",
456
2314
  position = "right",
457
2315
  width = 400,
458
2316
  showClose = false,
459
2317
  onClose,
460
- onIdentify,
461
- tools,
462
- className
2318
+ styles: propStyles,
2319
+ previewMode = false,
2320
+ className,
2321
+ onReady
463
2322
  }) {
464
- const contextClient = useCrowClientOptional();
465
- const standaloneClientRef = useRef(null);
466
- if (!contextClient && !standaloneClientRef.current && productId) {
467
- standaloneClientRef.current = new CrowClient({ productId, apiUrl, model });
468
- }
469
- const client = contextClient || standaloneClientRef.current;
470
- if (!client) {
471
- console.error(
472
- "[CrowCopilot] No client available. Either wrap in CrowProvider or provide productId prop."
473
- );
474
- return null;
475
- }
476
- useEffect(() => {
477
- return () => {
478
- if (standaloneClientRef.current) {
479
- standaloneClientRef.current.destroy();
2323
+ const { styles: styles2, isLoading: isLoadingStyles, agentName } = useCopilotStyles({
2324
+ productId,
2325
+ apiUrl,
2326
+ propStyles,
2327
+ skip: previewMode
2328
+ });
2329
+ const messagesContainerRef = useRef(null);
2330
+ const executeClientToolRef = useRef(null);
2331
+ const [showConversationList, setShowConversationList] = useState(false);
2332
+ const [isVerifiedUser, setIsVerifiedUser] = useState(false);
2333
+ const conversations = useConversations({ productId, apiUrl });
2334
+ const [shouldRestoreHistory, setShouldRestoreHistory] = useState(false);
2335
+ const hasRestoredHistoryRef = useRef(false);
2336
+ const chat = useChat({
2337
+ productId,
2338
+ apiUrl,
2339
+ onVerificationStatus: (isVerified) => {
2340
+ setIsVerifiedUser(isVerified);
2341
+ },
2342
+ onConversationId: () => {
2343
+ },
2344
+ onToolCall: (event) => {
2345
+ if (event.type === "client_call" && event.toolName) {
2346
+ console.log("[Crow Copilot] Executing client tool:", event.toolName, event.arguments);
2347
+ const result = executeClientToolRef.current?.(event.toolName, event.arguments || {});
2348
+ result?.then((r) => console.log("[Crow Copilot] Tool result:", r)).catch((e) => console.error("[Crow Copilot] Tool error:", e));
480
2349
  }
481
- };
482
- }, []);
483
- useEffect(() => {
484
- if (tools) {
485
- client.registerTools(tools);
2350
+ },
2351
+ onRestoredConversation: () => {
2352
+ setShouldRestoreHistory(true);
486
2353
  }
487
- }, [client, tools]);
2354
+ });
488
2355
  useEffect(() => {
489
- if (onIdentify) {
490
- onIdentify((options) => client.identify(options));
2356
+ if (shouldRestoreHistory && chat.conversationId && !hasRestoredHistoryRef.current) {
2357
+ hasRestoredHistoryRef.current = true;
2358
+ conversations.loadAnonymousConversationHistory(chat.conversationId).then((historyMessages) => {
2359
+ if (historyMessages.length > 0) {
2360
+ chat.loadMessages(historyMessages);
2361
+ }
2362
+ });
2363
+ }
2364
+ }, [shouldRestoreHistory, chat.conversationId, conversations, chat]);
2365
+ const { executeClientTool } = useCrowAPI({
2366
+ onIdentified: async () => {
2367
+ setIsVerifiedUser(true);
2368
+ await conversations.loadConversations();
2369
+ },
2370
+ onReset: () => {
2371
+ setIsVerifiedUser(false);
2372
+ chat.resetMessages();
491
2373
  }
492
- }, [client, onIdentify]);
493
- const { messages, isLoading, sendMessage, stop, clearMessages } = useChat({
494
- client
495
2374
  });
2375
+ executeClientToolRef.current = executeClientTool;
2376
+ useEffect(() => {
2377
+ if (!isLoadingStyles) {
2378
+ onReady?.();
2379
+ }
2380
+ }, [isLoadingStyles, onReady]);
2381
+ const handleSend = (message) => {
2382
+ if (!message.trim()) return;
2383
+ chat.sendMessage(message);
2384
+ };
2385
+ const handleNewChat = () => {
2386
+ chat.resetMessages();
2387
+ setShowConversationList(false);
2388
+ };
2389
+ const handleToggleHistory = () => {
2390
+ setShowConversationList(!showConversationList);
2391
+ if (!showConversationList) {
2392
+ conversations.loadConversations();
2393
+ }
2394
+ };
2395
+ const handleSelectConversation = async (convId) => {
2396
+ const historyMessages = await conversations.loadConversationHistory(convId);
2397
+ if (historyMessages.length > 0) {
2398
+ chat.loadMessages(historyMessages);
2399
+ chat.setConversationId(convId);
2400
+ } else {
2401
+ chat.resetMessages();
2402
+ }
2403
+ setShowConversationList(false);
2404
+ };
2405
+ const handleCloseConversationList = () => {
2406
+ setShowConversationList(false);
2407
+ };
496
2408
  const widthStyle = typeof width === "number" ? `${width}px` : width;
2409
+ return /* @__PURE__ */ jsx(
2410
+ CopilotStyleProvider,
2411
+ {
2412
+ styles: styles2,
2413
+ agentName: agentName || title,
2414
+ isLoading: isLoadingStyles,
2415
+ children: /* @__PURE__ */ jsxs(
2416
+ "div",
2417
+ {
2418
+ className: `crow-flex crow-flex-col crow-h-full ${position === "left" ? "crow-border-r" : "crow-border-l"} ${className || ""}`,
2419
+ style: {
2420
+ width: widthStyle,
2421
+ fontFamily: styles2.typography.fontFamily,
2422
+ fontSize: styles2.typography.fontSize,
2423
+ background: styles2.colors.background,
2424
+ borderColor: styles2.colors.border
2425
+ },
2426
+ children: [
2427
+ /* @__PURE__ */ jsxs(
2428
+ "div",
2429
+ {
2430
+ className: "crow-flex crow-items-center crow-justify-between crow-px-4 crow-py-3 crow-border-b",
2431
+ style: {
2432
+ height: styles2.dimensions.headerHeight,
2433
+ borderColor: styles2.colors.border
2434
+ },
2435
+ children: [
2436
+ /* @__PURE__ */ jsx(
2437
+ "span",
2438
+ {
2439
+ className: "crow-font-semibold",
2440
+ style: {
2441
+ color: styles2.colors.text,
2442
+ fontSize: styles2.typography.headerFontSize
2443
+ },
2444
+ children: agentName || title
2445
+ }
2446
+ ),
2447
+ /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-1", children: [
2448
+ /* @__PURE__ */ jsx(
2449
+ "button",
2450
+ {
2451
+ onClick: handleNewChat,
2452
+ className: "crow-p-1.5 hover:crow-bg-gray-100 crow-rounded crow-transition-colors",
2453
+ "aria-label": "New Chat",
2454
+ title: "New Chat",
2455
+ children: /* @__PURE__ */ jsx(PlusIcon, { className: "crow-w-4 crow-h-4 crow-text-gray-600" })
2456
+ }
2457
+ ),
2458
+ isVerifiedUser && /* @__PURE__ */ jsx(
2459
+ "button",
2460
+ {
2461
+ onClick: handleToggleHistory,
2462
+ className: `crow-p-1.5 hover:crow-bg-gray-100 crow-rounded crow-transition-colors ${showConversationList ? "crow-bg-gray-100" : ""}`,
2463
+ "aria-label": "Conversation History",
2464
+ title: "Conversation History",
2465
+ children: /* @__PURE__ */ jsx(HistoryIcon, { className: "crow-w-4 crow-h-4 crow-text-gray-600" })
2466
+ }
2467
+ ),
2468
+ showClose && onClose && /* @__PURE__ */ jsx(
2469
+ "button",
2470
+ {
2471
+ onClick: onClose,
2472
+ className: "crow-p-1.5 hover:crow-bg-gray-100 crow-rounded crow-transition-colors",
2473
+ "aria-label": "Close",
2474
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: "crow-w-4 crow-h-4 crow-text-gray-600" })
2475
+ }
2476
+ )
2477
+ ] })
2478
+ ]
2479
+ }
2480
+ ),
2481
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showConversationList && isVerifiedUser && /* @__PURE__ */ jsx(
2482
+ ConversationList,
2483
+ {
2484
+ conversations: conversations.conversations,
2485
+ currentConversationId: chat.conversationId,
2486
+ onSelect: handleSelectConversation,
2487
+ onClose: handleCloseConversationList
2488
+ }
2489
+ ) }),
2490
+ /* @__PURE__ */ jsx(MessagesContainer, { ref: messagesContainerRef, children: /* @__PURE__ */ jsx(
2491
+ MessageList,
2492
+ {
2493
+ messages: chat.messages,
2494
+ activeToolCalls: chat.activeToolCalls,
2495
+ isLoadingHistory: conversations.isLoadingHistory,
2496
+ isGenerating: chat.isLoading
2497
+ }
2498
+ ) }),
2499
+ /* @__PURE__ */ jsxs("div", { className: "crow-p-3 crow-border-t", style: { borderColor: styles2.colors.border }, children: [
2500
+ styles2.branding.showPoweredBy && /* @__PURE__ */ jsx(PoweredByBadge, { apiUrl }),
2501
+ /* @__PURE__ */ jsx(
2502
+ PromptInputBox,
2503
+ {
2504
+ onSend: handleSend,
2505
+ onStop: chat.stopGeneration,
2506
+ placeholder: "Ask anything...",
2507
+ isLoading: chat.isLoading
2508
+ }
2509
+ )
2510
+ ] })
2511
+ ]
2512
+ }
2513
+ )
2514
+ }
2515
+ );
2516
+ }
2517
+ function PlusIcon({ className }) {
497
2518
  return /* @__PURE__ */ jsxs(
498
- "div",
2519
+ "svg",
499
2520
  {
500
- className: clsx(
501
- "crow-flex crow-flex-col crow-h-full",
502
- "crow-bg-white crow-border-gray-200",
503
- position === "left" ? "crow-border-r" : "crow-border-l",
504
- className
505
- ),
506
- style: { width: widthStyle },
2521
+ xmlns: "http://www.w3.org/2000/svg",
2522
+ width: "24",
2523
+ height: "24",
2524
+ viewBox: "0 0 24 24",
2525
+ fill: "none",
2526
+ stroke: "currentColor",
2527
+ strokeWidth: "2",
2528
+ strokeLinecap: "round",
2529
+ strokeLinejoin: "round",
2530
+ className,
507
2531
  children: [
508
- /* @__PURE__ */ jsx(
509
- WidgetHeader,
510
- {
511
- title,
512
- onNewChat: clearMessages,
513
- onClose,
514
- showNewChat: true,
515
- showClose
516
- }
517
- ),
518
- /* @__PURE__ */ jsx(
519
- MessageList,
520
- {
521
- messages,
522
- isLoading,
523
- className: "crow-flex-1"
524
- }
525
- ),
526
- /* @__PURE__ */ jsx(
527
- PromptInput,
528
- {
529
- onSend: sendMessage,
530
- onStop: stop,
531
- isLoading,
532
- placeholder: "Ask anything..."
533
- }
534
- )
2532
+ /* @__PURE__ */ jsx("path", { d: "M5 12h14" }),
2533
+ /* @__PURE__ */ jsx("path", { d: "M12 5v14" })
535
2534
  ]
536
2535
  }
537
2536
  );
538
2537
  }
539
- function useIdentity({ client }) {
540
- const [isIdentified, setIsIdentified] = useState(client.isIdentified());
541
- const [isVerified, setIsVerified] = useState(client.isVerified());
542
- useEffect(() => {
543
- client.on({
544
- onVerificationStatus: (verified) => {
545
- setIsVerified(verified);
546
- }
547
- });
548
- setIsIdentified(client.isIdentified());
549
- setIsVerified(client.isVerified());
550
- }, [client]);
551
- const identify = useCallback(
552
- (options) => {
553
- client.identify(options);
554
- setIsIdentified(true);
555
- },
556
- [client]
2538
+ function HistoryIcon({ className }) {
2539
+ return /* @__PURE__ */ jsxs(
2540
+ "svg",
2541
+ {
2542
+ xmlns: "http://www.w3.org/2000/svg",
2543
+ width: "24",
2544
+ height: "24",
2545
+ viewBox: "0 0 24 24",
2546
+ fill: "none",
2547
+ stroke: "currentColor",
2548
+ strokeWidth: "2",
2549
+ strokeLinecap: "round",
2550
+ strokeLinejoin: "round",
2551
+ className,
2552
+ children: [
2553
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
2554
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
2555
+ /* @__PURE__ */ jsx("path", { d: "M12 7v5l4 2" })
2556
+ ]
2557
+ }
557
2558
  );
558
- const resetUser = useCallback(() => {
559
- client.resetUser();
560
- setIsIdentified(false);
561
- setIsVerified(false);
562
- }, [client]);
563
- return {
564
- isIdentified,
565
- isVerified,
566
- identify,
567
- resetUser
568
- };
569
2559
  }
570
- function useConversations({
571
- client
572
- }) {
573
- const [conversations, setConversations] = useState([]);
574
- const [isLoadingConversations, setIsLoadingConversations] = useState(false);
575
- const [isLoadingHistory, setIsLoadingHistory] = useState(false);
576
- const loadConversations = useCallback(async () => {
577
- setIsLoadingConversations(true);
578
- try {
579
- const convs = await client.getConversations();
580
- setConversations(convs);
581
- } finally {
582
- setIsLoadingConversations(false);
2560
+ function CloseIcon({ className }) {
2561
+ return /* @__PURE__ */ jsxs(
2562
+ "svg",
2563
+ {
2564
+ xmlns: "http://www.w3.org/2000/svg",
2565
+ width: "24",
2566
+ height: "24",
2567
+ viewBox: "0 0 24 24",
2568
+ fill: "none",
2569
+ stroke: "currentColor",
2570
+ strokeWidth: "2",
2571
+ strokeLinecap: "round",
2572
+ strokeLinejoin: "round",
2573
+ className,
2574
+ children: [
2575
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
2576
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
2577
+ ]
583
2578
  }
584
- }, [client]);
585
- const loadHistory = useCallback(
586
- async (conversationId) => {
587
- setIsLoadingHistory(true);
588
- try {
589
- return await client.loadHistory(conversationId);
590
- } finally {
591
- setIsLoadingHistory(false);
592
- }
593
- },
594
- [client]
595
2579
  );
596
- const switchConversation = useCallback(
597
- async (conversationId) => {
598
- setIsLoadingHistory(true);
599
- try {
600
- await client.switchConversation(conversationId);
601
- } finally {
602
- setIsLoadingHistory(false);
603
- }
604
- },
605
- [client]
606
- );
607
- const startNewConversation = useCallback(() => {
608
- client.clearMessages();
2580
+ }
2581
+ var CrowContext = createContext(null);
2582
+ function CrowProvider({
2583
+ children,
2584
+ productId,
2585
+ apiUrl,
2586
+ model
2587
+ }) {
2588
+ const clientRef = useRef(null);
2589
+ if (!clientRef.current) {
2590
+ clientRef.current = new CrowClient({ productId, apiUrl, model });
2591
+ }
2592
+ const client = clientRef.current;
2593
+ useEffect(() => {
2594
+ return () => {
2595
+ client.destroy();
2596
+ };
609
2597
  }, [client]);
610
- return {
611
- conversations,
612
- isLoadingConversations,
613
- isLoadingHistory,
614
- currentConversationId: client.conversationId,
615
- loadConversations,
616
- loadHistory,
617
- switchConversation,
618
- startNewConversation
619
- };
2598
+ const value = useMemo(() => ({ client }), [client]);
2599
+ return /* @__PURE__ */ jsx(CrowContext.Provider, { value, children });
620
2600
  }
621
2601
 
622
- export { ChatBubble, CrowCopilot, CrowProvider, CrowWidget, MessageBubble, MessageList, PromptInput, WidgetHeader, useChat, useConversations, useCrowClient, useCrowClientOptional, useIdentity };
2602
+ export { AVAILABLE_MODELS, ChatBubble, ConversationList, CopilotStyleProvider, CrowCopilot, CrowProvider, CrowWidget, DEFAULT_COPILOT_STYLES, DEFAULT_MODEL, DEFAULT_WELCOME_MESSAGE, DEFAULT_WIDGET_STYLES, GlassCard, LoadingHistory, MESSAGES_CONTAINER_ID, MessageBubble, MessageList, MessagesContainer, ModelSelector, PoweredByBadge, PromptInputBox, ReasoningTrace, StreamingText, ThinkingIndicator, WidgetHeader, WidgetShell, WidgetStyleProvider, WorkflowPanel, clearStyleCache, mergeCopilotStyles, mergeWidgetStyles, stylesToCSSVariables, useChat, useConversations, useCopilotStyleContext, useCopilotStyles, useCopilotStyles2 as useCopilotStylesContext, useCrowAPI, usePreviewCopilotStyles, usePreviewWidgetStyles, useWidgetStyleContext, useWidgetStyles, useWidgetStyles2 as useWidgetStylesContext, useWorkflow };
623
2603
  //# sourceMappingURL=index.js.map
624
2604
  //# sourceMappingURL=index.js.map