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