@waniwani/sdk 0.1.2 → 0.1.4

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.
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- import{forwardRef as So,useCallback as Ce,useEffect as ut,useImperativeHandle as Eo,useRef as ct,useState as pt}from"react";import{ArrowDownIcon as ht}from"lucide-react";import{useCallback as bt}from"react";import{StickToBottom as Fe,useStickToBottomContext as xt}from"use-stick-to-bottom";import{clsx as mt}from"clsx";import{twMerge as ft}from"tailwind-merge";function i(...e){return ft(mt(e))}import{jsx as gt}from"react/jsx-runtime";var J=({className:e,variant:t="default",size:o="default",type:r="button",...n})=>gt("button",{type:r,className:i("inline-flex cursor-pointer items-center justify-center rounded-md font-medium transition-colors disabled:pointer-events-none disabled:opacity-50",t==="default"&&"bg-primary text-primary-foreground hover:bg-primary/90",t==="outline"&&"border border-border bg-background hover:bg-accent hover:text-accent-foreground",t==="ghost"&&"hover:bg-accent hover:text-accent-foreground",o==="default"&&"h-9 px-4 py-2 text-sm",o==="sm"&&"h-8 px-3 text-xs",o==="icon"&&"size-9",o==="icon-sm"&&"size-7",e),...n});import{jsx as oe}from"react/jsx-runtime";var re=({className:e,...t})=>oe(Fe,{className:i("relative flex-1 overflow-y-hidden",e),initial:"smooth",resize:"smooth",role:"log",...t}),ne=({className:e,...t})=>oe(Fe.Content,{className:i("flex flex-col gap-8 p-4",e),...t}),se=({className:e,...t})=>{let{isAtBottom:o,scrollToBottom:r}=xt(),n=bt(()=>{r()},[r]);return!o&&oe(J,{className:i("absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full",e),onClick:n,size:"icon",variant:"outline",...t,children:oe(ht,{className:"size-4"})})};import{ArrowUpIcon as yt,LoaderIcon as Ct,PaperclipIcon as vt,SquareIcon as Tt,XIcon as wt}from"lucide-react";import{nanoid as Pt}from"nanoid";import{createContext as Mt,useCallback as q,useContext as kt,useEffect as Pe,useMemo as St,useRef as Me,useState as Ue}from"react";import{jsx as O,jsxs as _e}from"react/jsx-runtime";var Et=async e=>{try{let o=await(await fetch(e)).blob();return new Promise(r=>{let n=new FileReader;n.onloadend=()=>r(n.result),n.onerror=()=>r(null),n.readAsDataURL(o)})}catch{return null}},Oe=Mt(null),ze=()=>{let e=kt(Oe);if(!e)throw new Error("usePromptInputAttachments must be used within a PromptInput");return e},ae=({className:e,accept:t,multiple:o,globalDrop:r,maxFiles:n,maxFileSize:s,onSubmit:a,children:l,...f})=>{let p=Me(null),u=Me(null),[d,C]=Ue([]),v=Me(d);Pe(()=>{v.current=d},[d]);let E=q(()=>{p.current?.click()},[]),P=q(x=>{let T=[...x];if(T.length===0)return;let M=h=>s?h.size<=s:!0,N=T.filter(M);C(h=>{let I=typeof n=="number"?Math.max(0,n-h.length):void 0,R=typeof I=="number"?N.slice(0,I):N;return[...h,...R.map(k=>({filename:k.name,id:Pt(),mediaType:k.type,type:"file",url:URL.createObjectURL(k)}))]})},[n,s]),g=q(x=>{C(T=>{let M=T.find(N=>N.id===x);return M?.url&&URL.revokeObjectURL(M.url),T.filter(N=>N.id!==x)})},[]),c=q(()=>{C(x=>{for(let T of x)T.url&&URL.revokeObjectURL(T.url);return[]})},[]);Pe(()=>()=>{for(let x of v.current)x.url&&URL.revokeObjectURL(x.url)},[]);let m=q(x=>{x.currentTarget.files&&P(x.currentTarget.files),x.currentTarget.value=""},[P]);Pe(()=>{if(!r)return;let x=M=>{M.dataTransfer?.types?.includes("Files")&&M.preventDefault()},T=M=>{M.dataTransfer?.types?.includes("Files")&&M.preventDefault(),M.dataTransfer?.files&&M.dataTransfer.files.length>0&&P(M.dataTransfer.files)};return document.addEventListener("dragover",x),document.addEventListener("drop",T),()=>{document.removeEventListener("dragover",x),document.removeEventListener("drop",T)}},[P,r]);let y=q(async x=>{x.preventDefault();let T=x.currentTarget,N=new FormData(T).get("message")||"";T.reset();let h=await Promise.all(d.map(async({id:I,...R})=>{if(R.url?.startsWith("blob:")){let k=await Et(R.url);return{...R,url:k??R.url}}return R}));try{let I=a({files:h,text:N},x);I instanceof Promise&&await I,c()}catch{}},[d,a,c]),D=St(()=>({add:P,clear:c,files:d,openFileDialog:E,remove:g}),[d,P,g,c,E]);return _e(Oe.Provider,{value:D,children:[O("input",{accept:t,"aria-label":"Upload files",className:"hidden",multiple:o,onChange:m,ref:p,title:"Upload files",type:"file"}),O("form",{className:i("flex w-full flex-col rounded-lg border border-border bg-background",e),onSubmit:y,ref:u,...f,children:l})]})};var ie=({onChange:e,onKeyDown:t,className:o,placeholder:r="What would you like to know?",...n})=>{let s=ze(),[a,l]=Ue(!1),f=q(u=>{if(t?.(u),!u.defaultPrevented){if(u.key==="Enter"){if(a||u.nativeEvent.isComposing||u.shiftKey)return;u.preventDefault();let{form:d}=u.currentTarget;if(d?.querySelector('button[type="submit"]')?.disabled)return;d?.requestSubmit()}if(u.key==="Backspace"&&u.currentTarget.value===""&&s.files.length>0){u.preventDefault();let d=s.files.at(-1);d&&s.remove(d.id)}}},[t,a,s]),p=q(u=>{let d=u.clipboardData?.items;if(!d)return;let C=[];for(let v of d)if(v.kind==="file"){let E=v.getAsFile();E&&C.push(E)}C.length>0&&(u.preventDefault(),s.add(C))},[s]);return O("textarea",{className:i("field-sizing-content max-h-48 min-h-16 w-full resize-none border-0 bg-transparent px-3 py-3 text-sm outline-none placeholder:text-muted-foreground",o),name:"message",onCompositionEnd:()=>l(!1),onCompositionStart:()=>l(!0),onKeyDown:f,onPaste:p,placeholder:r,onChange:e,...n})},le=({className:e,status:t,onStop:o,onClick:r,children:n,...s})=>{let a=t==="submitted"||t==="streaming",l=O(yt,{className:"size-4"});t==="submitted"?l=O(Ct,{className:"size-4 animate-spin"}):t==="streaming"&&(l=O(Tt,{className:"size-4"}));let f=q(p=>{if(a&&o){p.preventDefault(),o();return}r?.(p)},[a,o,r]);return O(J,{"aria-label":a?"Stop":"Submit",className:i("bg-foreground text-background hover:bg-foreground",e),onClick:f,size:"icon-sm",type:a&&o?"button":"submit",variant:"ghost",...s,children:n??l})},ue=({className:e,children:t,...o})=>{let r=ze();return r.files.length>0?_e(J,{className:i("group relative",e),onClick:()=>r.clear(),size:"icon-sm",type:"button",variant:"ghost","aria-label":"Remove all attachments",...o,children:[O("span",{className:"flex size-5 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground transition-opacity group-hover:opacity-0",children:r.files.length}),O(wt,{className:"absolute size-4 opacity-0 transition-opacity group-hover:opacity-100"})]}):O(J,{className:i(e),onClick:()=>r.openFileDialog(),size:"icon-sm",type:"button",variant:"ghost",...o,children:t??O(vt,{className:"size-4"})})};import{FileIcon as It}from"lucide-react";import{jsx as Y,jsxs as Nt}from"react/jsx-runtime";var We=({files:e,className:t,...o})=>e.length===0?null:Y("div",{className:i("flex flex-wrap gap-1.5",t),...o,children:e.map((r,n)=>Y(Rt,{file:r},n))});function Rt({file:e}){return e.mediaType?.startsWith("image/")&&e.url?Y("img",{src:e.url,alt:e.filename??"attachment",className:"h-16 max-w-32 rounded object-cover"}):Nt("span",{className:"inline-flex items-center gap-1.5 rounded bg-background/20 px-2 py-1 text-xs",children:[Y(It,{className:"size-3 shrink-0"}),Y("span",{className:"max-w-24 truncate",children:e.filename??"file"})]})}import{jsx as $e}from"react/jsx-runtime";var ke=({className:e,size:t=5,...o})=>$e("div",{className:i("flex items-center gap-1",e),...o,children:[0,1,2].map(r=>$e("div",{className:"rounded-full bg-muted-foreground/60",style:{width:t,height:t,animation:"ww-pulse 1.4s ease-in-out infinite",animationDelay:`${r*.2}s`}},r))});import{cjk as Lt}from"@streamdown/cjk";import{code as At}from"@streamdown/code";import{memo as Ht}from"react";import{Streamdown as Bt}from"streamdown";import{jsx as Se}from"react/jsx-runtime";var ce=({className:e,from:t,...o})=>Se("div",{className:i("group flex w-full max-w-[95%] flex-col gap-2",t==="user"?"is-user ml-auto justify-end":"is-assistant",e),...o}),pe=({children:e,className:t,...o})=>Se("div",{className:i("flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-base","group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-user-bubble group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-primary-foreground","group-[.is-assistant]:text-foreground",t),...o,children:e}),Dt={cjk:Lt,code:At},de=Ht(({className:e,...t})=>Se(Bt,{className:i("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",e),plugins:Dt,...t}),(e,t)=>e.children===t.children);de.displayName="MessageResponse";import{jsx as Ft}from"react/jsx-runtime";function je({className:e,text:t,...o}){return t?Ft("pre",{className:i("mb-2 overflow-x-auto whitespace-pre-wrap break-words text-xs font-mono text-muted-foreground",e),...o,children:t}):null}import{BracesIcon as Ut,CheckIcon as Ot,ChevronDownIcon as zt,ChevronRightIcon as _t,ClipboardCopyIcon as Wt,ServerIcon as xr}from"lucide-react";import{createContext as $t,useCallback as jt,useContext as Ve,useEffect as qt,useMemo as Vt,useRef as Jt,useState as Ee}from"react";import{Fragment as qe,jsx as w,jsxs as K}from"react/jsx-runtime";function Kt(e,t=80){if(e==null)return String(e);if(typeof e!="object")return String(e).slice(0,t);if(Array.isArray(e))return`Array(${e.length})`;let o=JSON.stringify(e);if(o.length<=t)return o;let r=Object.entries(e),n=[],s=t-2;for(let[a,l]of r){if(s<=8)break;let f=a.length>4?`${a.slice(0,4)}\u2026`:a,p;typeof l=="string"?p=l.length>2?`'${l.slice(0,1)}\u2026`:`'${l}'`:Array.isArray(l)?p=`Array(${l.length})`:typeof l=="object"&&l!==null?p="{\u2026}":p=String(l);let u=`${f}\u2009${p}`;n.push(u),s-=u.length+3}return`{${n.join(", ")}}`}function Gt({text:e,className:t}){let[o,r]=Ee(!1),n=Jt(null);qt(()=>()=>{n.current&&clearTimeout(n.current)},[]);let s=jt(async a=>{a.stopPropagation();try{await navigator.clipboard.writeText(e),r(!0),n.current&&clearTimeout(n.current),n.current=setTimeout(()=>r(!1),2e3)}catch{}},[e]);return w(J,{variant:"ghost",size:"sm",onClick:s,className:i("h-auto gap-1 px-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground",t),children:o?K(qe,{children:[w(Ot,{className:"size-3.5"}),w("span",{children:"Copied"})]}):K(qe,{children:[w(Wt,{className:"size-3.5"}),w("span",{children:"Copy"})]})})}function Je({data:e,label:t,className:o,...r}){let[n,s]=Ee(!1),a=Vt(()=>JSON.stringify(e,null,2),[e]),l=Kt(e);return K("div",{className:i("rounded-lg bg-tool-card",o),...r,children:[K("div",{className:"flex items-center justify-between px-3 pt-2.5 pb-1.5",children:[w("span",{className:"text-xs font-medium text-muted-foreground",children:t}),w(Gt,{text:a})]}),K("button",{type:"button",onClick:()=>s(f=>!f),className:"flex w-full items-start gap-2 px-3 pb-3 text-left",children:[w(_t,{className:i("mt-0.5 size-3.5 shrink-0 text-muted-foreground transition-transform duration-150",n&&"rotate-90")}),n?w("pre",{className:"overflow-x-auto text-xs font-mono text-foreground whitespace-pre-wrap break-all",children:w("code",{children:a})}):w("span",{className:"truncate text-xs font-mono text-foreground/80",children:l})]})]})}var Ie=$t({open:!1,toggle:()=>{}});function Ke({className:e,defaultOpen:t=!1,children:o,...r}){let[n,s]=Ee(t);return w(Ie.Provider,{value:{open:n,toggle:()=>s(a=>!a)},children:w("div",{className:i("mb-4 w-full",e),"data-state":n?"open":"closed",...r,children:o})})}function Ge({className:e,title:t,state:o,...r}){let{open:n,toggle:s}=Ve(Ie),a=o==="input-available"||o==="input-streaming";return K("button",{type:"button",onClick:s,className:i("flex w-full items-center justify-between gap-3 py-1.5",e),"aria-expanded":n,...r,children:[K("div",{className:"flex min-w-0 items-center gap-2",children:[w(Ut,{className:"size-4 shrink-0 text-muted-foreground"}),w("span",{className:"truncate text-sm font-medium",children:t}),a&&w("span",{className:"size-2 shrink-0 rounded-full bg-primary animate-pulse"})]}),w(zt,{className:i("size-4 shrink-0 text-muted-foreground transition-transform duration-200",n&&"rotate-180")})]})}function Xe({className:e,children:t,...o}){let{open:r}=Ve(Ie);return w("div",{className:i("grid transition-[grid-template-rows,opacity] duration-200 ease-out",r?"grid-rows-[1fr] opacity-100":"grid-rows-[0fr] opacity-0"),children:w("div",{className:"min-h-0 overflow-hidden",children:w("div",{className:i("mt-2 space-y-3 rounded-lg border border-border bg-background p-3",e),...o,children:t})})})}function Ye({className:e,input:t,...o}){return w(Je,{data:t,label:"Request",className:e,...o})}function Ze(e){if(typeof e!="object"||e===null)return;let t=e._meta;if(typeof t!="object"||t===null)return;let o=t.ui;if(!(typeof o!="object"||o===null))return o}function Qe(e){let t=Ze(e)?.resourceUri;return typeof t=="string"?t:void 0}function et(e){return Ze(e)?.autoHeight===!0}function tt({className:e,output:t,errorText:o,...r}){return t||o?o?K("div",{className:i("space-y-2",e),...r,children:[w("h4",{className:"text-xs font-medium uppercase tracking-wide text-muted-foreground",children:"Error"}),w("div",{className:"rounded-lg bg-destructive/10 p-3 text-xs text-destructive",children:o})]}):w(Je,{data:t,label:"Response",className:e,...r}):null}import{useCallback as Xt,useEffect as ot,useMemo as Yt,useRef as W,useState as rt}from"react";import{jsx as no}from"react/jsx-runtime";var Zt="/api/mcp/resource",Qt=500,eo=0,to="2026-01-26",oo=300,ro=3e3,Re=3;function Ne({resourceUri:e,toolInput:t,toolResult:o,resourceEndpoint:r=Zt,isDark:n=!1,className:s,autoHeight:a=!0,onOpenLink:l,onFollowUp:f}){let p=W(null),u=W(t),d=W(o),C=W({width:0,height:0}),v=W(null),E=W(!1),P=W(0),[g,c]=rt(eo),[m,y]=rt(void 0),D=W(l),x=W(f);u.current=t,d.current=o,D.current=l,x.current=f;let T=Xt(h=>a?Math.max(h,0):Math.min(Math.max(h,50),Qt),[a]),M=Yt(()=>`${r}?uri=${encodeURIComponent(e)}`,[r,e]),N=W(n);return N.current=n,ot(()=>{if(!E.current)return;let h=p.current;h?.contentWindow&&h.contentWindow.postMessage({jsonrpc:"2.0",method:"ui/notifications/host-context-changed",params:{theme:n?"dark":"light"}},"*")},[n]),ot(()=>{let h=p.current;if(!h)return;let I=!1,R=!1,k=(...S)=>console.debug("[McpAppFrame]",...S);k("effect mounted, waiting for handshake");let L=setTimeout(()=>{if(I||R)return;if(P.current>=Re){k("handshake failed after",Re,"retries, giving up");return}P.current+=1,k("handshake timeout, reloading iframe (retry",P.current,"of",Re,")");let S=new URL(h.src);S.searchParams.set("_retry",String(P.current)),h.src=S.toString()},ro),b=S=>{k("\u2192 send",S.method??`response:${S.id}`,S),h.contentWindow?.postMessage(S,"*")},A=S=>{if(I||S.source!==h.contentWindow)return;let B=S.data;if(!B||typeof B!="object"||B.jsonrpc!=="2.0")return;let j=B.method,F=B.id;if(k("\u2190 recv",j??`response:${F}`,B),j==="ui/initialize"&&F!=null){R=!0,clearTimeout(L),k("handshake started"),b({jsonrpc:"2.0",id:F,result:{protocolVersion:B.params?.protocolVersion??to,hostInfo:{name:"WaniWani Chat",version:"1.0.0"},hostCapabilities:{openLinks:{},message:{}},hostContext:{theme:N.current?"dark":"light",displayMode:"inline"}}});return}if(j==="ui/notifications/initialized"){k("handshake complete, sending tool data"),E.current=!0;let z=u.current,_=d.current;b({jsonrpc:"2.0",method:"ui/notifications/tool-input",params:{arguments:z}});let V=_.content??[{type:"text",text:JSON.stringify(_)}];b({jsonrpc:"2.0",method:"ui/notifications/tool-result",params:{content:V,structuredContent:_.structuredContent}});return}if(j==="ui/notifications/size-changed"){let z=B.params,_=typeof z?.height=="number"?z.height:void 0,V=typeof z?.width=="number"?z.width:void 0,G=C.current,ve=_!==void 0&&_!==G.height,Te=V!==void 0&&V!==G.width;if(k("size-changed",{newHeight:_,newWidth:V,lastHeight:G.height,lastWidth:G.width,heightChanged:ve,widthChanged:Te}),!ve&&!Te)return;if(ve&&_!==void 0){G.height=_;let we=T(_),De=h.getBoundingClientRect().height;if(v.current&&(v.current.cancel(),v.current=null),c(we),h.animate&&Math.abs(De-we)>2){let te=h.animate([{height:`${De}px`},{height:`${we}px`}],{duration:oo,easing:"ease-out",fill:"forwards"});v.current=te,te.onfinish=()=>{v.current===te&&(te.cancel(),v.current=null)}}}Te&&a&&V!==void 0&&(G.width=V,y(V));return}if(j==="ui/open-link"&&F!=null){let z=B.params?.url;typeof z=="string"&&(D.current?D.current(z):window.open(z,"_blank","noopener,noreferrer")),b({jsonrpc:"2.0",id:F,result:{}});return}if(j==="ui/message"&&F!=null){x.current&&B.params&&x.current(B.params),b({jsonrpc:"2.0",id:F,result:{}});return}if(j==="ui/request-display-mode"&&F!=null){b({jsonrpc:"2.0",id:F,result:{}});return}if(j==="ui/resource-teardown"&&F!=null){b({jsonrpc:"2.0",id:F,result:{}});return}j==="ping"&&F!=null&&b({jsonrpc:"2.0",id:F,result:{}})};return window.addEventListener("message",A),()=>{k("effect cleanup (disposed)"),I=!0,clearTimeout(L),window.removeEventListener("message",A)}},[a,T]),no("iframe",{ref:p,src:M,sandbox:"allow-scripts allow-forms allow-same-origin",className:i("rounded-md border border-border",s),style:{height:g,minWidth:m?`min(${m}px, 100%)`:void 0,width:"100%",border:"none",colorScheme:"auto"},title:"MCP App"})}import{Component as so}from"react";import{jsx as nt,jsxs as ao}from"react/jsx-runtime";var me=class extends so{state={hasError:!1};static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(t){console.warn("[WaniWani] Widget failed to render:",t.message)}render(){return this.state.hasError?ao("div",{className:"flex items-center justify-between rounded-md border border-border bg-muted/50 px-4 py-3 text-sm text-muted-foreground",children:[nt("span",{children:"Widget failed to load"}),nt("button",{type:"button",onClick:()=>this.setState({hasError:!1}),className:"text-xs font-medium text-primary hover:underline",children:"Retry"})]}):this.props.children}};import{Fragment as lo,jsx as H,jsxs as X}from"react/jsx-runtime";function io(e){return e.replace(/[-_]/g," ").replace(/^\w/,t=>t.toUpperCase())}function fe({messages:e,status:t,welcomeMessage:o,resourceEndpoint:r,isDark:n,onFollowUp:s}){let a=t==="submitted"||t==="streaming",l=e[e.length-1],f=e.length>0,p=a&&(!f||l.role==="user");return X(lo,{children:[o&&H(ce,{from:"assistant",children:H(pe,{children:H(de,{children:o})})}),e.map(u=>{let d=u.parts.filter(c=>c.type==="text"),C=u.parts.filter(c=>c.type==="reasoning"),v=u.parts.filter(c=>c.type==="file"),E=u.parts.filter(c=>"toolCallId"in c),P=u===l&&u.role==="assistant",g=d.length>0;return X(ce,{from:u.role,children:[C.map((c,m)=>H(je,{text:c.text},`reasoning-${u.id}-${m}`)),E.map(c=>{let m="output"in c?c.output:void 0,y=m!==void 0?Qe(m):void 0,D=m!==void 0?et(m):!1;return X("div",{children:[X(Ke,{defaultOpen:c.state==="output-available",children:[H(Ge,{title:c.title??io(c.toolName),state:c.state}),X(Xe,{children:[H(Ye,{input:c.input}),m!==void 0&&H(tt,{output:m,errorText:"errorText"in c?c.errorText:void 0})]})]}),y&&m!==void 0&&H(me,{children:H(Ne,{resourceUri:y,toolInput:c.input??{},toolResult:{content:m.content,structuredContent:m.structuredContent},resourceEndpoint:r,isDark:n,autoHeight:D,onFollowUp:s})})]},c.toolCallId)}),X(pe,{children:[v.length>0&&H(We,{files:v}),g?d.map((c,m)=>H(de,{children:c.type==="text"?c.text:""},`${u.id}-${m}`)):P&&a&&H(ke,{})]})]},u.id)}),p&&H(ce,{from:"assistant",children:H(pe,{children:H(ke,{})})})]})}import{jsx as Le}from"react/jsx-runtime";function ge({suggestions:e,isLoading:t,onSelect:o,className:r,...n}){return e.length===0&&!t?null:Le("div",{className:i("flex flex-wrap gap-2 px-3 py-2",r),...n,children:t?[0,1,2].map(s=>Le("div",{className:"h-7 rounded-full bg-accent animate-pulse",style:{width:`${60+s*20}px`}},s)):e.map((s,a)=>Le("button",{type:"button",onClick:()=>o(s),className:i("rounded-full border border-border bg-background px-3 py-1 text-xs","text-foreground hover:bg-accent hover:border-primary/30","transition-all duration-200 ease-out cursor-pointer","animate-[ww-fade-in_0.2s_ease-out_both]"),style:{animationDelay:`${a*50}ms`},children:s},s))})}import{useChat as uo}from"@ai-sdk/react";import{DefaultChatTransport as co}from"ai";import{useCallback as st,useRef as po,useState as mo}from"react";function he(e){let{api:t="https://app.waniwani.ai/api/chat",headers:o,body:r,onMessageSent:n,onResponseReceived:s}=e,a=po(new co({api:t,headers:{...o},body:r})),{messages:l,sendMessage:f,status:p}=uo({transport:a.current,onFinish(){s?.()},onError(m){console.warn("[WaniWani] Chat error:",m.message)}}),[u,d]=mo(""),C=st(m=>{let y=!!m.text?.trim(),D=!!m.files?.length;(y||D)&&(f({text:m.text||"",files:m.files}),n?.(m.text||""),d(""))},[f,n]),v=st(m=>{d(m.target.value)},[]),E=p==="submitted"||p==="streaming",P=l[l.length-1],g=l.length>0,c=E&&(!g||P.role==="user");return{messages:l,status:p,text:u,setText:d,handleSubmit:C,handleTextChange:v,isLoading:E,showLoaderBubble:c,lastMessage:P,hasMessages:g,sendMessage:f}}import{useCallback as fo,useEffect as at,useRef as go,useState as ho}from"react";function bo(e){for(let t of e.parts){let o=t;if(o.type==="data"||o.type==="data-suggestions"){let r=o.data;if(r&&Array.isArray(r.suggestions))return r.suggestions}}return null}function xo(e){return typeof e=="object"&&e!==null&&"initial"in e}function be(e){let{messages:t,status:o,config:r}=e,[n,s]=ho((xo(r)&&r.initial?r.initial:[])??[]),a=go(o),l=!!r,f=fo(()=>{s([])},[]),p=t[t.length-1];return at(()=>{p?.role==="user"&&f()},[p,f]),at(()=>{let u=a.current;if(a.current=o,u==="streaming"&&o==="ready"&&l){let d=[...t].reverse().find(v=>v.role==="assistant");if(!d)return;console.log("[WaniWani] Assistant parts:",d.parts);let C=bo(d);console.log("[WaniWani] Extracted suggestions:",C),C&&s(C)}},[o,l,t]),{suggestions:n,isLoading:!1,clear:f}}import{useEffect as yo,useRef as Co,useState as vo}from"react";var To=50,wo=30,Po=2e3,it=500;function xe(e,t=!0){let[o,r]=vo(""),n=Co(void 0);return yo(()=>{if(!t){r("");return}let s=0,a=!1,l=!1,f=()=>{l||(a?(s--,r(e.slice(0,s)),s<=0?(a=!1,n.current=setTimeout(f,it)):n.current=setTimeout(f,wo)):(s++,r(e.slice(0,s)),s>=e.length?(a=!0,n.current=setTimeout(f,Po)):n.current=setTimeout(f,To)))};return n.current=setTimeout(f,it),()=>{l=!0,clearTimeout(n.current)}},[e,t]),o}var lt={primaryColor:"#6366f1",primaryForeground:"#1f2937",backgroundColor:"#ffffff",textColor:"#1f2937",mutedColor:"#6b7280",borderColor:"#e5e7eb",assistantBubbleColor:"#f3f4f6",userBubbleColor:"#f4f4f4",inputBackgroundColor:"#f9fafb",borderRadius:16,messageBorderRadius:12,fontFamily:"system-ui, -apple-system, 'Segoe UI', sans-serif",headerBackgroundColor:"#ffffff",headerTextColor:"#1f2937",statusColor:"#22c55e",toolCardColor:"#f4f4f5"},Mo={backgroundColor:"#212121",headerBackgroundColor:"#1e1e1e",headerTextColor:"#ececec",textColor:"#ececec",primaryForeground:"#ffffff",mutedColor:"#8e8ea0",borderColor:"#303030",assistantBubbleColor:"#2f2f2f",userBubbleColor:"#303030",inputBackgroundColor:"#2f2f2f",primaryColor:"#6366f1",statusColor:"#22c55e",toolCardColor:"#262626"},ko={primaryColor:["--ww-primary","--color-primary"],primaryForeground:["--ww-primary-fg","--color-primary-foreground"],backgroundColor:["--ww-bg","--color-background"],textColor:["--ww-text","--color-foreground","--color-accent-foreground"],mutedColor:["--ww-muted","--color-muted-foreground"],borderColor:["--ww-border","--color-border"],assistantBubbleColor:["--ww-assistant-bubble","--color-accent"],userBubbleColor:["--ww-user-bubble"],inputBackgroundColor:["--ww-input-bg","--color-input"],borderRadius:["--ww-radius","--radius"],messageBorderRadius:["--ww-msg-radius"],fontFamily:["--ww-font"],headerBackgroundColor:["--ww-header-bg"],headerTextColor:["--ww-header-text"],statusColor:["--ww-status"],toolCardColor:["--ww-tool-card","--color-tool-card"]};function Z(e){return{...lt,...e}}function ye(e){let t=e.backgroundColor.replace("#",""),o=parseInt(t.substring(0,2),16),r=parseInt(t.substring(2,4),16),n=parseInt(t.substring(4,6),16);return(o*299+r*587+n*114)/1e3<128}function Q(e){let t={};for(let[o,r]of Object.entries(ko)){let n=e[o],s=typeof n=="number"?`${n}px`:String(n);for(let a of r)t[a]=s}return t}import{jsx as $,jsxs as Ae}from"react/jsx-runtime";var He=So(function(t,o){let{theme:r,width:n=600,expandedHeight:s=400,allowAttachments:a=!1,welcomeMessage:l,placeholder:f="Ask me anything...",triggerEvent:p="triggerDemoRequest",resourceEndpoint:u,api:d}=t,C=u??(d?`${d}/resource`:void 0),v=Z(r),E=Q(v),P=ye(v),g=he(t),c=be({messages:g.messages,status:g.status,config:t.suggestions}),m=Ce(b=>{let A=b.content.map(S=>S.text??"").join("").trim();A&&g.handleSubmit({text:A,files:[]})},[g.handleSubmit]),y=Ce(b=>{c.clear(),g.handleSubmit({text:b,files:[]})},[c.clear,g.handleSubmit]),D=xe(f,!g.text),[x,T]=pt(!1),[M,N]=pt(!1),h=ct(null),I=ct(void 0),R=Ce(()=>{let b=h.current;if(!b)return;b.scrollIntoView({behavior:"smooth",block:"center"});let A=b.querySelector("textarea");A&&setTimeout(()=>A.focus(),300),T(!0),N(!0),clearTimeout(I.current),I.current=setTimeout(()=>N(!1),2e3)},[]);Eo(o,()=>({sendMessage:b=>{g.handleSubmit({text:b,files:[]}),R()},focus:R}),[g.handleSubmit,R]),ut(()=>{if(!p)return;let b=A=>{let S=A.detail,B=typeof S?.message=="string"?S.message:void 0;B&&g.handleSubmit({text:B,files:[]}),R()};return window.addEventListener(p,b),()=>window.removeEventListener(p,b)},[p,g.handleSubmit,R]);let k=x;ut(()=>{if(!x)return;let b=A=>{h.current&&!h.current.contains(A.target)&&T(!1)};return document.addEventListener("mousedown",b),()=>document.removeEventListener("mousedown",b)},[x]);let L=Ce(()=>{T(!0)},[]);return Ae("div",{ref:h,style:{...E,width:n},"data-waniwani-chat":"","data-waniwani-layout":"bar",...P?{"data-waniwani-dark":""}:{},className:"flex flex-col font-[family-name:var(--ww-font)] text-foreground",children:[$("div",{className:i("overflow-hidden bg-background/80 backdrop-blur-xl transition-all duration-300 ease-out",k?"opacity-100 translate-y-0":"opacity-0 translate-y-2 pointer-events-none max-h-0"),style:{...k?{maxHeight:s}:void 0,maskImage:"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",maskComposite:"intersect",WebkitMaskImage:"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",WebkitMaskComposite:"source-in"},children:Ae(re,{className:"flex-1",style:{height:s},children:[$(ne,{children:$(fe,{messages:g.messages,status:g.status,welcomeMessage:l,resourceEndpoint:C,isDark:P,onFollowUp:m})}),$(se,{})]})}),$(ge,{suggestions:c.suggestions,isLoading:c.isLoading,onSelect:y}),$("div",{className:"shrink-0",children:$(ae,{onSubmit:g.handleSubmit,globalDrop:a,multiple:a,className:i("rounded-[var(--ww-radius)] shadow-sm transition-all duration-300 ease-out",M&&"ring-2 ring-blue-400/70 ring-offset-2 ring-offset-background"),children:Ae("div",{className:"flex items-center gap-1 px-3 py-2",children:[a&&$(ue,{}),$(ie,{onChange:g.handleTextChange,value:g.text,placeholder:D,onFocus:L,className:"min-h-0 py-1.5 px-2"}),$(le,{status:g.status})]})})})]})});import{forwardRef as Io,useCallback as Be,useEffect as Ro,useImperativeHandle as No,useRef as dt,useState as Lo}from"react";import{jsx as U,jsxs as ee}from"react/jsx-runtime";var Ao=Io(function(t,o){let{theme:r,title:n="Assistant",subtitle:s,showStatus:a=!0,width:l=500,height:f=600,allowAttachments:p=!1,welcomeMessage:u,placeholder:d="Ask me anything...",triggerEvent:C="triggerDemoRequest",resourceEndpoint:v,api:E}=t,P=v??(E?`${E}/resource`:void 0),g=Z(r),c=Q(g),m=ye(g),y=he(t),D=xe(d,!y.text),[x,T]=Lo(!1),M=dt(null),N=dt(void 0),h=Be(()=>{let L=M.current;if(!L)return;L.scrollIntoView({behavior:"smooth",block:"center"});let b=L.querySelector("textarea");b&&setTimeout(()=>b.focus(),300),T(!0),clearTimeout(N.current),N.current=setTimeout(()=>T(!1),2e3)},[]),I=be({messages:y.messages,status:y.status,config:t.suggestions}),R=Be(L=>{let b=L.content.map(A=>A.text??"").join("").trim();b&&y.handleSubmit({text:b,files:[]})},[y.handleSubmit]),k=Be(L=>{I.clear(),y.handleSubmit({text:L,files:[]})},[I.clear,y.handleSubmit]);return No(o,()=>({sendMessage:L=>{y.handleSubmit({text:L,files:[]}),h()},focus:h}),[y.handleSubmit,h]),Ro(()=>{if(!C)return;let L=b=>{let A=b.detail,S=typeof A?.message=="string"?A.message:void 0;S&&y.handleSubmit({text:S,files:[]}),h()};return window.addEventListener(C,L),()=>window.removeEventListener(C,L)},[C,y.handleSubmit,h]),ee("div",{ref:M,style:{...c,width:l,height:f},"data-waniwani-chat":"","data-waniwani-layout":"card",...m?{"data-waniwani-dark":""}:{},className:i("flex flex-col font-[family-name:var(--ww-font)] text-foreground bg-background rounded-[var(--ww-radius)] border border-border shadow-md overflow-hidden transition-shadow duration-300",x&&"ring-2 ring-blue-400/70 ring-offset-2 ring-offset-background"),children:[ee("div",{className:"shrink-0 flex items-center gap-3 px-4 py-2 border-b border-border",style:{backgroundColor:g.headerBackgroundColor,color:g.headerTextColor},children:[a&&U("span",{className:"size-2.5 rounded-full bg-status"}),ee("div",{className:"flex-1 min-w-0",children:[U("div",{className:"text-xs font-semibold truncate",children:n}),s&&U("div",{className:"text-[11px] text-muted-foreground truncate",children:s})]})]}),ee(re,{className:"flex-1 min-h-0 bg-background",children:[U(ne,{children:U(fe,{messages:y.messages,status:y.status,welcomeMessage:u,resourceEndpoint:P,isDark:m,onFollowUp:R})}),U(se,{})]}),U(ge,{suggestions:I.suggestions,isLoading:I.isLoading,onSelect:k,className:"border-t border-border"}),U("div",{className:"shrink-0 border-t border-border bg-background",children:U(ae,{onSubmit:y.handleSubmit,globalDrop:p,multiple:p,className:i("rounded-none border-0"),children:ee("div",{className:"flex items-center gap-1 px-3 py-2",children:[p&&U(ue,{}),U(ie,{onChange:y.handleTextChange,value:y.text,placeholder:D,className:"min-h-0 py-1.5 px-2"}),U(le,{status:y.status})]})})})]})});export{He as ChatBar,Ao as ChatCard,He as ChatWidget,Mo as DARK_THEME,lt as DEFAULT_THEME,Ne as McpAppFrame,Z as mergeTheme,Q as themeToCSSProperties};
2
+ import{forwardRef as Eo,useCallback as ye,useEffect as lt,useImperativeHandle as Io,useRef as ut,useState as ct}from"react";import{ArrowDownIcon as ht}from"lucide-react";import{useCallback as bt}from"react";import{StickToBottom as Fe,useStickToBottomContext as xt}from"use-stick-to-bottom";import{clsx as dt}from"clsx";import{extendTailwindMerge as mt}from"tailwind-merge";var ft=mt({prefix:"ww"});function i(...e){return ft(dt(e))}import{jsx as gt}from"react/jsx-runtime";var J=({className:e,variant:t="default",size:o="default",type:r="button",...n})=>gt("button",{type:r,className:i("ww:inline-flex ww:cursor-pointer ww:items-center ww:justify-center ww:rounded-md ww:font-medium ww:transition-colors ww:disabled:pointer-events-none ww:disabled:opacity-50",t==="default"&&"ww:bg-primary ww:text-primary-foreground ww:hover:bg-primary/90",t==="outline"&&"ww:border ww:border-border ww:bg-background ww:hover:bg-accent ww:hover:text-accent-foreground",t==="ghost"&&"ww:hover:bg-accent ww:hover:text-accent-foreground",o==="default"&&"ww:h-9 ww:px-4 ww:py-2 ww:text-sm",o==="sm"&&"ww:h-8 ww:px-3 ww:text-xs",o==="icon"&&"ww:size-9",o==="icon-sm"&&"ww:size-7",e),...n});import{jsx as oe}from"react/jsx-runtime";var re=({className:e,...t})=>oe(Fe,{className:i("ww:relative ww:flex-1 ww:overflow-y-hidden",e),initial:"smooth",resize:"smooth",role:"log",...t}),ne=({className:e,...t})=>oe(Fe.Content,{className:i("ww:flex ww:flex-col ww:gap-8 ww:p-4",e),...t}),se=({className:e,...t})=>{let{isAtBottom:o,scrollToBottom:r}=xt(),n=bt(()=>{r()},[r]);return!o&&oe(J,{className:i("ww:absolute ww:bottom-4 ww:left-[50%] ww:translate-x-[-50%] ww:rounded-full",e),onClick:n,size:"icon",variant:"outline",...t,children:oe(ht,{className:"ww:size-4"})})};import{ArrowUpIcon as yt,LoaderIcon as Ct,PaperclipIcon as vt,SquareIcon as Tt,XIcon as Pt}from"lucide-react";import{nanoid as Mt}from"nanoid";import{createContext as kt,useCallback as q,useContext as St,useEffect as Pe,useMemo as Et,useRef as Me,useState as Ue}from"react";import{jsx as O,jsxs as _e}from"react/jsx-runtime";var It=async e=>{try{let o=await(await fetch(e)).blob();return new Promise(r=>{let n=new FileReader;n.onloadend=()=>r(n.result),n.onerror=()=>r(null),n.readAsDataURL(o)})}catch{return null}},Oe=kt(null),ze=()=>{let e=St(Oe);if(!e)throw new Error("usePromptInputAttachments must be used within a PromptInput");return e},ae=({className:e,accept:t,multiple:o,globalDrop:r,maxFiles:n,maxFileSize:s,onSubmit:a,children:w,...m})=>{let c=Me(null),l=Me(null),[p,y]=Ue([]),C=Me(p);Pe(()=>{C.current=p},[p]);let E=q(()=>{c.current?.click()},[]),P=q(b=>{let v=[...b];if(v.length===0)return;let M=g=>s?g.size<=s:!0,N=v.filter(M);y(g=>{let I=typeof n=="number"?Math.max(0,n-g.length):void 0,R=typeof I=="number"?N.slice(0,I):N;return[...g,...R.map(k=>({filename:k.name,id:Mt(),mediaType:k.type,type:"file",url:URL.createObjectURL(k)}))]})},[n,s]),f=q(b=>{y(v=>{let M=v.find(N=>N.id===b);return M?.url&&URL.revokeObjectURL(M.url),v.filter(N=>N.id!==b)})},[]),u=q(()=>{y(b=>{for(let v of b)v.url&&URL.revokeObjectURL(v.url);return[]})},[]);Pe(()=>()=>{for(let b of C.current)b.url&&URL.revokeObjectURL(b.url)},[]);let d=q(b=>{b.currentTarget.files&&P(b.currentTarget.files),b.currentTarget.value=""},[P]);Pe(()=>{if(!r)return;let b=M=>{M.dataTransfer?.types?.includes("Files")&&M.preventDefault()},v=M=>{M.dataTransfer?.types?.includes("Files")&&M.preventDefault(),M.dataTransfer?.files&&M.dataTransfer.files.length>0&&P(M.dataTransfer.files)};return document.addEventListener("dragover",b),document.addEventListener("drop",v),()=>{document.removeEventListener("dragover",b),document.removeEventListener("drop",v)}},[P,r]);let x=q(async b=>{b.preventDefault();let v=b.currentTarget,N=new FormData(v).get("message")||"";v.reset();let g=await Promise.all(p.map(async({id:I,...R})=>{if(R.url?.startsWith("blob:")){let k=await It(R.url);return{...R,url:k??R.url}}return R}));try{let I=a({files:g,text:N},b);I instanceof Promise&&await I,u()}catch{}},[p,a,u]),D=Et(()=>({add:P,clear:u,files:p,openFileDialog:E,remove:f}),[p,P,f,u,E]);return _e(Oe.Provider,{value:D,children:[O("input",{accept:t,"aria-label":"Upload files",className:"ww:hidden",multiple:o,onChange:d,ref:c,title:"Upload files",type:"file"}),O("form",{className:i("ww:flex ww:w-full ww:flex-col ww:rounded-lg ww:border ww:border-border ww:bg-background",e),onSubmit:x,ref:l,...m,children:w})]})};var ie=({onChange:e,onKeyDown:t,className:o,placeholder:r="What would you like to know?",...n})=>{let s=ze(),[a,w]=Ue(!1),m=q(l=>{if(t?.(l),!l.defaultPrevented){if(l.key==="Enter"){if(a||l.nativeEvent.isComposing||l.shiftKey)return;l.preventDefault();let{form:p}=l.currentTarget;if(p?.querySelector('button[type="submit"]')?.disabled)return;p?.requestSubmit()}if(l.key==="Backspace"&&l.currentTarget.value===""&&s.files.length>0){l.preventDefault();let p=s.files.at(-1);p&&s.remove(p.id)}}},[t,a,s]),c=q(l=>{let p=l.clipboardData?.items;if(!p)return;let y=[];for(let C of p)if(C.kind==="file"){let E=C.getAsFile();E&&y.push(E)}y.length>0&&(l.preventDefault(),s.add(y))},[s]);return O("textarea",{className:i("ww:field-sizing-content ww:max-h-48 ww:min-h-16 ww:w-full ww:resize-none ww:border-0 ww:bg-transparent ww:px-3 ww:py-3 ww:text-sm ww:outline-none ww:placeholder:text-muted-foreground",o),name:"message",onCompositionEnd:()=>w(!1),onCompositionStart:()=>w(!0),onKeyDown:m,onPaste:c,placeholder:r,onChange:e,...n})},we=({className:e,status:t,onStop:o,onClick:r,children:n,...s})=>{let a=t==="submitted"||t==="streaming",w=O(yt,{className:"ww:size-4"});t==="submitted"?w=O(Ct,{className:"ww:size-4 ww:animate-spin"}):t==="streaming"&&(w=O(Tt,{className:"ww:size-4"}));let m=q(c=>{if(a&&o){c.preventDefault(),o();return}r?.(c)},[a,o,r]);return O(J,{"aria-label":a?"Stop":"Submit",className:i("ww:bg-foreground ww:text-background ww:hover:bg-foreground",e),onClick:m,size:"icon-sm",type:a&&o?"button":"submit",variant:"ghost",...s,children:n??w})},le=({className:e,children:t,...o})=>{let r=ze();return r.files.length>0?_e(J,{className:i("ww:group ww:relative",e),onClick:()=>r.clear(),size:"icon-sm",type:"button",variant:"ghost","aria-label":"Remove all attachments",...o,children:[O("span",{className:"ww:flex ww:size-5 ww:items-center ww:justify-center ww:rounded-full ww:bg-primary ww:text-[10px] ww:font-medium ww:text-primary-foreground ww:transition-opacity ww:group-hover:opacity-0",children:r.files.length}),O(Pt,{className:"ww:absolute ww:size-4 ww:opacity-0 ww:transition-opacity ww:group-hover:opacity-100"})]}):O(J,{className:i(e),onClick:()=>r.openFileDialog(),size:"icon-sm",type:"button",variant:"ghost",...o,children:t??O(vt,{className:"ww:size-4"})})};import{FileIcon as Rt}from"lucide-react";import{jsx as Y,jsxs as Lt}from"react/jsx-runtime";var We=({files:e,className:t,...o})=>e.length===0?null:Y("div",{className:i("ww:flex ww:flex-wrap ww:gap-1.5",t),...o,children:e.map((r,n)=>Y(Nt,{file:r},n))});function Nt({file:e}){return e.mediaType?.startsWith("image/")&&e.url?Y("img",{src:e.url,alt:e.filename??"attachment",className:"ww:h-16 ww:max-w-32 ww:rounded ww:object-cover"}):Lt("span",{className:"ww:inline-flex ww:items-center ww:gap-1.5 ww:rounded ww:bg-background/20 ww:px-2 ww:py-1 ww:text-xs",children:[Y(Rt,{className:"ww:size-3 ww:shrink-0"}),Y("span",{className:"ww:max-w-24 ww:truncate",children:e.filename??"file"})]})}import{jsx as $e}from"react/jsx-runtime";var ke=({className:e,size:t=5,...o})=>$e("div",{className:i("ww:flex ww:items-center ww:gap-1",e),...o,children:[0,1,2].map(r=>$e("div",{className:"ww:rounded-full ww:bg-muted-foreground/60",style:{width:t,height:t,animation:"ww-pulse 1.4s ease-in-out infinite",animationDelay:`${r*.2}s`}},r))});import{cjk as At}from"@streamdown/cjk";import{code as Ht}from"@streamdown/code";import{memo as Bt}from"react";import{Streamdown as Dt}from"streamdown";import{jsx as Se}from"react/jsx-runtime";var ue=({className:e,from:t,...o})=>Se("div",{className:i("ww:group ww:flex ww:w-full ww:max-w-[95%] ww:flex-col ww:gap-2",t==="user"?"is-user ww:ml-auto ww:justify-end":"is-assistant",e),...o}),ce=({children:e,className:t,...o})=>Se("div",{className:i("ww:flex ww:w-fit ww:min-w-0 ww:max-w-full ww:flex-col ww:gap-2 ww:overflow-hidden ww:text-base","ww:group-[.is-user]:ml-auto ww:group-[.is-user]:rounded-lg ww:group-[.is-user]:bg-user-bubble ww:group-[.is-user]:px-4 ww:group-[.is-user]:py-3 ww:group-[.is-user]:text-primary-foreground","ww:group-[.is-assistant]:text-foreground",t),...o,children:e}),Ft={cjk:At,code:Ht},pe=Bt(({className:e,...t})=>Se(Dt,{className:i("ww:size-full ww:[&>*:first-child]:mt-0 ww:[&>*:last-child]:mb-0",e),plugins:Ft,...t}),(e,t)=>e.children===t.children);pe.displayName="MessageResponse";import{jsx as Ut}from"react/jsx-runtime";function je({className:e,text:t,...o}){return t?Ut("pre",{className:i("ww:mb-2 ww:overflow-x-auto ww:whitespace-pre-wrap ww:break-words ww:text-xs ww:font-mono ww:text-muted-foreground",e),...o,children:t}):null}import{BracesIcon as Ot,CheckIcon as zt,ChevronDownIcon as _t,ChevronRightIcon as Wt,ClipboardCopyIcon as $t,ServerIcon as xr}from"lucide-react";import{createContext as jt,useCallback as qt,useContext as Ve,useEffect as Vt,useMemo as Jt,useRef as Kt,useState as Ee}from"react";import{Fragment as qe,jsx as T,jsxs as K}from"react/jsx-runtime";function Gt(e,t=80){if(e==null)return String(e);if(typeof e!="object")return String(e).slice(0,t);if(Array.isArray(e))return`Array(${e.length})`;let o=JSON.stringify(e);if(o.length<=t)return o;let r=Object.entries(e),n=[],s=t-2;for(let[a,w]of r){if(s<=8)break;let m=a.length>4?`${a.slice(0,4)}\u2026`:a,c;typeof w=="string"?c=w.length>2?`'${w.slice(0,1)}\u2026`:`'${w}'`:Array.isArray(w)?c=`Array(${w.length})`:typeof w=="object"&&w!==null?c="{\u2026}":c=String(w);let l=`${m}\u2009${c}`;n.push(l),s-=l.length+3}return`{${n.join(", ")}}`}function Xt({text:e,className:t}){let[o,r]=Ee(!1),n=Kt(null);Vt(()=>()=>{n.current&&clearTimeout(n.current)},[]);let s=qt(async a=>{a.stopPropagation();try{await navigator.clipboard.writeText(e),r(!0),n.current&&clearTimeout(n.current),n.current=setTimeout(()=>r(!1),2e3)}catch{}},[e]);return T(J,{variant:"ghost",size:"sm",onClick:s,className:i("ww:h-auto ww:gap-1 ww:px-1.5 ww:py-0.5 ww:text-xs ww:text-muted-foreground ww:hover:text-foreground",t),children:o?K(qe,{children:[T(zt,{className:"ww:size-3.5"}),T("span",{children:"Copied"})]}):K(qe,{children:[T($t,{className:"ww:size-3.5"}),T("span",{children:"Copy"})]})})}function Je({data:e,label:t,className:o,...r}){let[n,s]=Ee(!1),a=Jt(()=>JSON.stringify(e,null,2),[e]),w=Gt(e);return K("div",{className:i("ww:rounded-lg ww:bg-tool-card",o),...r,children:[K("div",{className:"ww:flex ww:items-center ww:justify-between ww:px-3 ww:pt-2.5 ww:pb-1.5",children:[T("span",{className:"ww:text-xs ww:font-medium ww:text-muted-foreground",children:t}),T(Xt,{text:a})]}),K("button",{type:"button",onClick:()=>s(m=>!m),className:"ww:flex ww:w-full ww:items-start ww:gap-2 ww:px-3 ww:pb-3 ww:text-left",children:[T(Wt,{className:i("ww:mt-0.5 ww:size-3.5 ww:shrink-0 ww:text-muted-foreground ww:transition-transform ww:duration-150",n&&"ww:rotate-90")}),n?T("pre",{className:"ww:overflow-x-auto ww:text-xs ww:font-mono ww:text-foreground ww:whitespace-pre-wrap ww:break-all",children:T("code",{children:a})}):T("span",{className:"ww:truncate ww:text-xs ww:font-mono ww:text-foreground/80",children:w})]})]})}var Ie=jt({open:!1,toggle:()=>{}});function Ke({className:e,defaultOpen:t=!1,children:o,...r}){let[n,s]=Ee(t);return T(Ie.Provider,{value:{open:n,toggle:()=>s(a=>!a)},children:T("div",{className:i("ww:mb-4 ww:w-full",e),"data-state":n?"open":"closed",...r,children:o})})}function Ge({className:e,title:t,state:o,...r}){let{open:n,toggle:s}=Ve(Ie),a=o==="input-available"||o==="input-streaming";return K("button",{type:"button",onClick:s,className:i("ww:flex ww:w-full ww:items-center ww:justify-between ww:gap-3 ww:py-1.5",e),"aria-expanded":n,...r,children:[K("div",{className:"ww:flex ww:min-w-0 ww:items-center ww:gap-2",children:[T(Ot,{className:"ww:size-4 ww:shrink-0 ww:text-muted-foreground"}),T("span",{className:"ww:truncate ww:text-sm ww:font-medium",children:t}),a&&T("span",{className:"ww:size-2 ww:shrink-0 ww:rounded-full ww:bg-primary ww:animate-pulse"})]}),T(_t,{className:i("ww:size-4 ww:shrink-0 ww:text-muted-foreground ww:transition-transform ww:duration-200",n&&"ww:rotate-180")})]})}function Xe({className:e,children:t,...o}){let{open:r}=Ve(Ie);return T("div",{className:i("ww:grid ww:transition-[grid-template-rows,opacity] ww:duration-200 ww:ease-out",r?"ww:grid-rows-[1fr] ww:opacity-100":"ww:grid-rows-[0fr] ww:opacity-0"),children:T("div",{className:"ww:min-h-0 ww:overflow-hidden",children:T("div",{className:i("ww:mt-2 ww:space-y-3 ww:rounded-lg ww:border ww:border-border ww:bg-background ww:p-3",e),...o,children:t})})})}function Ye({className:e,input:t,...o}){return T(Je,{data:t,label:"Request",className:e,...o})}function Ze(e){if(typeof e!="object"||e===null)return;let t=e._meta;if(typeof t!="object"||t===null)return;let o=t.ui;if(!(typeof o!="object"||o===null))return o}function Qe(e){let t=Ze(e)?.resourceUri;return typeof t=="string"?t:void 0}function et(e){return Ze(e)?.autoHeight===!0}function tt({className:e,output:t,errorText:o,...r}){return t||o?o?K("div",{className:i("ww:space-y-2",e),...r,children:[T("h4",{className:"ww:text-xs ww:font-medium ww:uppercase ww:tracking-wide ww:text-muted-foreground",children:"Error"}),T("div",{className:"ww:rounded-lg ww:bg-destructive/10 ww:p-3 ww:text-xs ww:text-destructive",children:o})]}):T(Je,{data:t,label:"Response",className:e,...r}):null}import{useCallback as Yt,useEffect as ot,useMemo as Zt,useRef as W,useState as rt}from"react";import{jsx as so}from"react/jsx-runtime";var Qt="/api/mcp/resource",eo=500,to=0,oo="2026-01-26",ro=300,no=3e3,Re=3;function Ne({resourceUri:e,toolInput:t,toolResult:o,resourceEndpoint:r=Qt,isDark:n=!1,className:s,autoHeight:a=!0,onOpenLink:w,onFollowUp:m}){let c=W(null),l=W(t),p=W(o),y=W({width:0,height:0}),C=W(null),E=W(!1),P=W(0),[f,u]=rt(to),[d,x]=rt(void 0),D=W(w),b=W(m);l.current=t,p.current=o,D.current=w,b.current=m;let v=Yt(g=>a?Math.max(g,0):Math.min(Math.max(g,50),eo),[a]),M=Zt(()=>`${r}?uri=${encodeURIComponent(e)}`,[r,e]),N=W(n);return N.current=n,ot(()=>{if(!E.current)return;let g=c.current;g?.contentWindow&&g.contentWindow.postMessage({jsonrpc:"2.0",method:"ui/notifications/host-context-changed",params:{theme:n?"dark":"light"}},"*")},[n]),ot(()=>{let g=c.current;if(!g)return;let I=!1,R=!1,k=(...S)=>console.debug("[McpAppFrame]",...S);k("effect mounted, waiting for handshake");let L=setTimeout(()=>{if(I||R)return;if(P.current>=Re){k("handshake failed after",Re,"retries, giving up");return}P.current+=1,k("handshake timeout, reloading iframe (retry",P.current,"of",Re,")");let S=new URL(g.src);S.searchParams.set("_retry",String(P.current)),g.src=S.toString()},no),h=S=>{k("\u2192 send",S.method??`response:${S.id}`,S),g.contentWindow?.postMessage(S,"*")},A=S=>{if(I||S.source!==g.contentWindow)return;let B=S.data;if(!B||typeof B!="object"||B.jsonrpc!=="2.0")return;let j=B.method,F=B.id;if(k("\u2190 recv",j??`response:${F}`,B),j==="ui/initialize"&&F!=null){R=!0,clearTimeout(L),k("handshake started"),h({jsonrpc:"2.0",id:F,result:{protocolVersion:B.params?.protocolVersion??oo,hostInfo:{name:"WaniWani Chat",version:"1.0.0"},hostCapabilities:{openLinks:{},message:{}},hostContext:{theme:N.current?"dark":"light",displayMode:"inline"}}});return}if(j==="ui/notifications/initialized"){k("handshake complete, sending tool data"),E.current=!0;let z=l.current,_=p.current;h({jsonrpc:"2.0",method:"ui/notifications/tool-input",params:{arguments:z}});let V=_.content??[{type:"text",text:JSON.stringify(_)}];h({jsonrpc:"2.0",method:"ui/notifications/tool-result",params:{content:V,structuredContent:_.structuredContent}});return}if(j==="ui/notifications/size-changed"){let z=B.params,_=typeof z?.height=="number"?z.height:void 0,V=typeof z?.width=="number"?z.width:void 0,G=y.current,Ce=_!==void 0&&_!==G.height,ve=V!==void 0&&V!==G.width;if(k("size-changed",{newHeight:_,newWidth:V,lastHeight:G.height,lastWidth:G.width,heightChanged:Ce,widthChanged:ve}),!Ce&&!ve)return;if(Ce&&_!==void 0){G.height=_;let Te=v(_),De=g.getBoundingClientRect().height;if(C.current&&(C.current.cancel(),C.current=null),u(Te),g.animate&&Math.abs(De-Te)>2){let te=g.animate([{height:`${De}px`},{height:`${Te}px`}],{duration:ro,easing:"ease-out",fill:"forwards"});C.current=te,te.onfinish=()=>{C.current===te&&(te.cancel(),C.current=null)}}}ve&&a&&V!==void 0&&(G.width=V,x(V));return}if(j==="ui/open-link"&&F!=null){let z=B.params?.url;typeof z=="string"&&(D.current?D.current(z):window.open(z,"_blank","noopener,noreferrer")),h({jsonrpc:"2.0",id:F,result:{}});return}if(j==="ui/message"&&F!=null){b.current&&B.params&&b.current(B.params),h({jsonrpc:"2.0",id:F,result:{}});return}if(j==="ui/request-display-mode"&&F!=null){h({jsonrpc:"2.0",id:F,result:{}});return}if(j==="ui/resource-teardown"&&F!=null){h({jsonrpc:"2.0",id:F,result:{}});return}j==="ping"&&F!=null&&h({jsonrpc:"2.0",id:F,result:{}})};return window.addEventListener("message",A),()=>{k("effect cleanup (disposed)"),I=!0,clearTimeout(L),window.removeEventListener("message",A)}},[a,v]),so("iframe",{ref:c,src:M,sandbox:"allow-scripts allow-forms allow-same-origin",className:i("ww:rounded-md ww:border ww:border-border",s),style:{height:f,minWidth:d?`min(${d}px, 100%)`:void 0,width:"100%",border:"none",colorScheme:"auto"},title:"MCP App"})}import{Component as ao}from"react";import{jsx as nt,jsxs as io}from"react/jsx-runtime";var de=class extends ao{state={hasError:!1};static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(t){console.warn("[WaniWani] Widget failed to render:",t.message)}render(){return this.state.hasError?io("div",{className:"ww:flex ww:items-center ww:justify-between ww:rounded-md ww:border ww:border-border ww:bg-muted/50 ww:px-4 ww:py-3 ww:text-sm ww:text-muted-foreground",children:[nt("span",{children:"Widget failed to load"}),nt("button",{type:"button",onClick:()=>this.setState({hasError:!1}),className:"ww:text-xs ww:font-medium ww:text-primary ww:hover:underline",children:"Retry"})]}):this.props.children}};import{Fragment as lo,jsx as H,jsxs as X}from"react/jsx-runtime";function wo(e){return e.replace(/[-_]/g," ").replace(/^\w/,t=>t.toUpperCase())}function me({messages:e,status:t,welcomeMessage:o,resourceEndpoint:r,isDark:n,onFollowUp:s}){let a=t==="submitted"||t==="streaming",w=e[e.length-1],m=e.length>0,c=a&&(!m||w.role==="user");return X(lo,{children:[o&&H(ue,{from:"assistant",children:H(ce,{children:H(pe,{children:o})})}),e.map(l=>{let p=l.parts.filter(u=>u.type==="text"),y=l.parts.filter(u=>u.type==="reasoning"),C=l.parts.filter(u=>u.type==="file"),E=l.parts.filter(u=>"toolCallId"in u),P=l===w&&l.role==="assistant",f=p.length>0;return X(ue,{from:l.role,children:[y.map((u,d)=>H(je,{text:u.text},`reasoning-${l.id}-${d}`)),E.map(u=>{let d="output"in u?u.output:void 0,x=d!==void 0?Qe(d):void 0,D=d!==void 0?et(d):!1;return X("div",{children:[X(Ke,{defaultOpen:u.state==="output-available",children:[H(Ge,{title:u.title??wo(u.toolName),state:u.state}),X(Xe,{children:[H(Ye,{input:u.input}),d!==void 0&&H(tt,{output:d,errorText:"errorText"in u?u.errorText:void 0})]})]}),x&&d!==void 0&&H(de,{children:H(Ne,{resourceUri:x,toolInput:u.input??{},toolResult:{content:d.content,structuredContent:d.structuredContent},resourceEndpoint:r,isDark:n,autoHeight:D,onFollowUp:s})})]},u.toolCallId)}),X(ce,{children:[C.length>0&&H(We,{files:C}),f?p.map((u,d)=>H(pe,{children:u.type==="text"?u.text:""},`${l.id}-${d}`)):P&&a&&H(ke,{})]})]},l.id)}),c&&H(ue,{from:"assistant",children:H(ce,{children:H(ke,{})})})]})}import{jsx as Le}from"react/jsx-runtime";function fe({suggestions:e,isLoading:t,onSelect:o,className:r,...n}){return e.length===0&&!t?null:Le("div",{className:i("ww:flex ww:flex-wrap ww:gap-2 ww:px-3 ww:py-2",r),...n,children:t?[0,1,2].map(s=>Le("div",{className:"ww:h-7 ww:rounded-full ww:bg-accent ww:animate-pulse",style:{width:`${60+s*20}px`}},s)):e.map((s,a)=>Le("button",{type:"button",onClick:()=>o(s),className:i("ww:rounded-full ww:border ww:border-border ww:bg-background ww:px-3 ww:py-1 ww:text-xs","ww:text-foreground ww:hover:bg-accent ww:hover:border-primary/30","ww:transition-all ww:duration-200 ww:ease-out ww:cursor-pointer","ww:animate-[ww-fade-in_0.2s_ease-out_both]"),style:{animationDelay:`${a*50}ms`},children:s},s))})}import{useChat as uo}from"@ai-sdk/react";import{DefaultChatTransport as co}from"ai";import{useCallback as st,useRef as po,useState as mo}from"react";function ge(e){let{api:t="https://app.waniwani.ai/api/chat",headers:o,body:r,onMessageSent:n,onResponseReceived:s}=e,a=po(new co({api:t,headers:{...o},body:r})),{messages:w,sendMessage:m,status:c}=uo({transport:a.current,onFinish(){s?.()},onError(d){console.warn("[WaniWani] Chat error:",d.message)}}),[l,p]=mo(""),y=st(d=>{let x=!!d.text?.trim(),D=!!d.files?.length;(x||D)&&(m({text:d.text||"",files:d.files}),n?.(d.text||""),p(""))},[m,n]),C=st(d=>{p(d.target.value)},[]),E=c==="submitted"||c==="streaming",P=w[w.length-1],f=w.length>0,u=E&&(!f||P.role==="user");return{messages:w,status:c,text:l,setText:p,handleSubmit:y,handleTextChange:C,isLoading:E,showLoaderBubble:u,lastMessage:P,hasMessages:f,sendMessage:m}}import{useCallback as fo,useEffect as at,useRef as go,useState as ho}from"react";function bo(e){for(let t of e.parts){let o=t;if(o.type==="data"||o.type==="data-suggestions"){let r=o.data;if(r&&Array.isArray(r.suggestions))return r.suggestions}}return null}function xo(e){return typeof e=="object"&&e!==null&&"initial"in e}function he(e){let{messages:t,status:o,config:r}=e,[n,s]=ho((xo(r)&&r.initial?r.initial:[])??[]),a=go(o),w=!!r,m=fo(()=>{s([])},[]),c=t[t.length-1];return at(()=>{c?.role==="user"&&m()},[c,m]),at(()=>{let l=a.current;if(a.current=o,l==="streaming"&&o==="ready"&&w){let p=[...t].reverse().find(C=>C.role==="assistant");if(!p)return;console.log("[WaniWani] Assistant parts:",p.parts);let y=bo(p);console.log("[WaniWani] Extracted suggestions:",y),y&&s(y)}},[o,w,t]),{suggestions:n,isLoading:!1,clear:m}}import{useEffect as yo,useRef as Co,useState as vo}from"react";var To=50,Po=30,Mo=2e3,it=500;function be(e,t=!0){let[o,r]=vo(""),n=Co(void 0);return yo(()=>{if(!t){r("");return}let s=0,a=!1,w=!1,m=()=>{w||(a?(s--,r(e.slice(0,s)),s<=0?(a=!1,n.current=setTimeout(m,it)):n.current=setTimeout(m,Po)):(s++,r(e.slice(0,s)),s>=e.length?(a=!0,n.current=setTimeout(m,Mo)):n.current=setTimeout(m,To)))};return n.current=setTimeout(m,it),()=>{w=!0,clearTimeout(n.current)}},[e,t]),o}var wt={primaryColor:"#6366f1",primaryForeground:"#1f2937",backgroundColor:"#ffffff",textColor:"#1f2937",mutedColor:"#6b7280",borderColor:"#e5e7eb",assistantBubbleColor:"#f3f4f6",userBubbleColor:"#f4f4f4",inputBackgroundColor:"#f9fafb",borderRadius:16,messageBorderRadius:12,fontFamily:"system-ui, -apple-system, 'Segoe UI', sans-serif",headerBackgroundColor:"#ffffff",headerTextColor:"#1f2937",statusColor:"#22c55e",toolCardColor:"#f4f4f5"},ko={backgroundColor:"#212121",headerBackgroundColor:"#1e1e1e",headerTextColor:"#ececec",textColor:"#ececec",primaryForeground:"#ffffff",mutedColor:"#8e8ea0",borderColor:"#303030",assistantBubbleColor:"#2f2f2f",userBubbleColor:"#303030",inputBackgroundColor:"#2f2f2f",primaryColor:"#6366f1",statusColor:"#22c55e",toolCardColor:"#262626"},So={primaryColor:["--ww-primary","--ww-color-primary"],primaryForeground:["--ww-primary-fg","--ww-color-primary-foreground"],backgroundColor:["--ww-bg","--ww-color-background"],textColor:["--ww-text","--ww-color-foreground","--ww-color-accent-foreground"],mutedColor:["--ww-muted","--ww-color-muted-foreground"],borderColor:["--ww-border","--ww-color-border"],assistantBubbleColor:["--ww-assistant-bubble","--ww-color-accent"],userBubbleColor:["--ww-user-bubble"],inputBackgroundColor:["--ww-input-bg","--ww-color-input"],borderRadius:["--ww-radius"],messageBorderRadius:["--ww-msg-radius"],fontFamily:["--ww-font"],headerBackgroundColor:["--ww-header-bg"],headerTextColor:["--ww-header-text"],statusColor:["--ww-status"],toolCardColor:["--ww-tool-card","--ww-color-tool-card"]};function Z(e){return{...wt,...e}}function xe(e){let t=e.backgroundColor.replace("#",""),o=parseInt(t.substring(0,2),16),r=parseInt(t.substring(2,4),16),n=parseInt(t.substring(4,6),16);return(o*299+r*587+n*114)/1e3<128}function Q(e){let t={};for(let[o,r]of Object.entries(So)){let n=e[o],s=typeof n=="number"?`${n}px`:String(n);for(let a of r)t[a]=s}return t}import{jsx as $,jsxs as Ae}from"react/jsx-runtime";var He=Eo(function(t,o){let{theme:r,width:n=600,expandedHeight:s=400,allowAttachments:a=!1,welcomeMessage:w,placeholder:m="Ask me anything...",triggerEvent:c="triggerDemoRequest",resourceEndpoint:l,api:p}=t,y=l??(p?`${p}/resource`:void 0),C=Z(r),E=Q(C),P=xe(C),f=ge(t),u=he({messages:f.messages,status:f.status,config:t.suggestions}),d=ye(h=>{let A=h.content.map(S=>S.text??"").join("").trim();A&&f.handleSubmit({text:A,files:[]})},[f.handleSubmit]),x=ye(h=>{u.clear(),f.handleSubmit({text:h,files:[]})},[u.clear,f.handleSubmit]),D=be(m,!f.text),[b,v]=ct(!1),[M,N]=ct(!1),g=ut(null),I=ut(void 0),R=ye(()=>{let h=g.current;if(!h)return;h.scrollIntoView({behavior:"smooth",block:"center"});let A=h.querySelector("textarea");A&&setTimeout(()=>A.focus(),300),v(!0),N(!0),clearTimeout(I.current),I.current=setTimeout(()=>N(!1),2e3)},[]);Io(o,()=>({sendMessage:h=>{f.handleSubmit({text:h,files:[]}),R()},focus:R}),[f.handleSubmit,R]),lt(()=>{if(!c)return;let h=A=>{let S=A.detail,B=typeof S?.message=="string"?S.message:void 0;B&&f.handleSubmit({text:B,files:[]}),R()};return window.addEventListener(c,h),()=>window.removeEventListener(c,h)},[c,f.handleSubmit,R]);let k=b;lt(()=>{if(!b)return;let h=A=>{g.current&&!g.current.contains(A.target)&&v(!1)};return document.addEventListener("mousedown",h),()=>document.removeEventListener("mousedown",h)},[b]);let L=ye(()=>{v(!0)},[]);return Ae("div",{ref:g,style:{...E,width:n},"data-waniwani-chat":"","data-waniwani-layout":"bar",...P?{"data-waniwani-dark":""}:{},className:"ww:flex ww:flex-col ww:font-[family-name:var(--ww-font)] ww:text-foreground",children:[$("div",{className:i("ww:overflow-hidden ww:bg-background/80 ww:backdrop-blur-xl ww:transition-all ww:duration-300 ww:ease-out",k?"ww:opacity-100 ww:translate-y-0":"ww:opacity-0 ww:translate-y-2 ww:pointer-events-none ww:max-h-0"),style:{...k?{maxHeight:s}:void 0,maskImage:"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",maskComposite:"intersect",WebkitMaskImage:"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",WebkitMaskComposite:"source-in"},children:Ae(re,{className:"ww:flex-1",style:{height:s},children:[$(ne,{children:$(me,{messages:f.messages,status:f.status,welcomeMessage:w,resourceEndpoint:y,isDark:P,onFollowUp:d})}),$(se,{})]})}),$(fe,{suggestions:u.suggestions,isLoading:u.isLoading,onSelect:x}),$("div",{className:"ww:shrink-0",children:$(ae,{onSubmit:f.handleSubmit,globalDrop:a,multiple:a,className:i("ww:rounded-[var(--ww-radius)] ww:shadow-sm ww:transition-all ww:duration-300 ww:ease-out",M&&"ww:ring-2 ww:ring-blue-400/70 ww:ring-offset-2 ww:ring-offset-background"),children:Ae("div",{className:"ww:flex ww:items-center ww:gap-1 ww:px-3 ww:py-2",children:[a&&$(le,{}),$(ie,{onChange:f.handleTextChange,value:f.text,placeholder:D,onFocus:L,className:"ww:min-h-0 ww:py-1.5 ww:px-2"}),$(we,{status:f.status})]})})})]})});import{forwardRef as Ro,useCallback as Be,useEffect as No,useImperativeHandle as Lo,useRef as pt,useState as Ao}from"react";import{jsx as U,jsxs as ee}from"react/jsx-runtime";var Ho=Ro(function(t,o){let{theme:r,title:n="Assistant",subtitle:s,showStatus:a=!0,width:w=500,height:m=600,allowAttachments:c=!1,welcomeMessage:l,placeholder:p="Ask me anything...",triggerEvent:y="triggerDemoRequest",resourceEndpoint:C,api:E}=t,P=C??(E?`${E}/resource`:void 0),f=Z(r),u=Q(f),d=xe(f),x=ge(t),D=be(p,!x.text),[b,v]=Ao(!1),M=pt(null),N=pt(void 0),g=Be(()=>{let L=M.current;if(!L)return;L.scrollIntoView({behavior:"smooth",block:"center"});let h=L.querySelector("textarea");h&&setTimeout(()=>h.focus(),300),v(!0),clearTimeout(N.current),N.current=setTimeout(()=>v(!1),2e3)},[]),I=he({messages:x.messages,status:x.status,config:t.suggestions}),R=Be(L=>{let h=L.content.map(A=>A.text??"").join("").trim();h&&x.handleSubmit({text:h,files:[]})},[x.handleSubmit]),k=Be(L=>{I.clear(),x.handleSubmit({text:L,files:[]})},[I.clear,x.handleSubmit]);return Lo(o,()=>({sendMessage:L=>{x.handleSubmit({text:L,files:[]}),g()},focus:g}),[x.handleSubmit,g]),No(()=>{if(!y)return;let L=h=>{let A=h.detail,S=typeof A?.message=="string"?A.message:void 0;S&&x.handleSubmit({text:S,files:[]}),g()};return window.addEventListener(y,L),()=>window.removeEventListener(y,L)},[y,x.handleSubmit,g]),ee("div",{ref:M,style:{...u,width:w,height:m},"data-waniwani-chat":"","data-waniwani-layout":"card",...d?{"data-waniwani-dark":""}:{},className:i("ww:flex ww:flex-col ww:font-[family-name:var(--ww-font)] ww:text-foreground ww:bg-background ww:rounded-[var(--ww-radius)] ww:border ww:border-border ww:shadow-md ww:overflow-hidden ww:transition-shadow ww:duration-300",b&&"ww:ring-2 ww:ring-blue-400/70 ww:ring-offset-2 ww:ring-offset-background"),children:[ee("div",{className:"ww:shrink-0 ww:flex ww:items-center ww:gap-3 ww:px-4 ww:py-2 ww:border-b ww:border-border",style:{backgroundColor:f.headerBackgroundColor,color:f.headerTextColor},children:[a&&U("span",{className:"ww:size-2.5 ww:rounded-full ww:bg-status"}),ee("div",{className:"ww:flex-1 ww:min-w-0",children:[U("div",{className:"ww:text-xs ww:font-semibold ww:truncate",children:n}),s&&U("div",{className:"ww:text-[11px] ww:text-muted-foreground ww:truncate",children:s})]})]}),ee(re,{className:"ww:flex-1 ww:min-h-0 ww:bg-background",children:[U(ne,{children:U(me,{messages:x.messages,status:x.status,welcomeMessage:l,resourceEndpoint:P,isDark:d,onFollowUp:R})}),U(se,{})]}),U(fe,{suggestions:I.suggestions,isLoading:I.isLoading,onSelect:k,className:"ww:border-t ww:border-border"}),U("div",{className:"ww:shrink-0 ww:border-t ww:border-border ww:bg-background",children:U(ae,{onSubmit:x.handleSubmit,globalDrop:c,multiple:c,className:i("ww:rounded-none ww:border-0"),children:ee("div",{className:"ww:flex ww:items-center ww:gap-1 ww:px-3 ww:py-2",children:[c&&U(le,{}),U(ie,{onChange:x.handleTextChange,value:x.text,placeholder:D,className:"ww:min-h-0 ww:py-1.5 ww:px-2"}),U(we,{status:x.status})]})})})]})});export{He as ChatBar,Ho as ChatCard,He as ChatWidget,ko as DARK_THEME,wt as DEFAULT_THEME,Ne as McpAppFrame,Z as mergeTheme,Q as themeToCSSProperties};
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/chat/web/layouts/chat-bar.tsx","../../src/chat/web/ai-elements/conversation.tsx","../../src/chat/web/lib/utils.ts","../../src/chat/web/ui/button.tsx","../../src/chat/web/ai-elements/prompt-input.tsx","../../src/chat/web/ai-elements/attachments.tsx","../../src/chat/web/ai-elements/loader.tsx","../../src/chat/web/ai-elements/message.tsx","../../src/chat/web/ai-elements/reasoning.tsx","../../src/chat/web/ai-elements/tool.tsx","../../src/chat/web/components/mcp-app-frame.tsx","../../src/chat/web/components/widget-error-boundary.tsx","../../src/chat/web/components/message-list.tsx","../../src/chat/web/components/suggestions.tsx","../../src/chat/web/hooks/use-chat-engine.ts","../../src/chat/web/hooks/use-suggestions.ts","../../src/chat/web/hooks/use-typing-placeholder.ts","../../src/chat/web/theme.ts","../../src/chat/web/layouts/chat-card.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n\tforwardRef,\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport type { ChatBarProps, ChatHandle } from \"../@types\";\nimport {\n\tConversation,\n\tConversationContent,\n\tConversationScrollButton,\n} from \"../ai-elements/conversation\";\nimport {\n\tPromptInput,\n\tPromptInputAddAttachments,\n\tPromptInputSubmit,\n\tPromptInputTextarea,\n} from \"../ai-elements/prompt-input\";\nimport { MessageList } from \"../components/message-list\";\nimport { Suggestions } from \"../components/suggestions\";\nimport { useChatEngine } from \"../hooks/use-chat-engine\";\nimport { useSuggestions } from \"../hooks/use-suggestions\";\nimport { useTypingPlaceholder } from \"../hooks/use-typing-placeholder\";\nimport { cn } from \"../lib/utils\";\nimport { isDarkTheme, mergeTheme, themeToCSSProperties } from \"../theme\";\n\nexport const ChatBar = forwardRef<ChatHandle, ChatBarProps>(\n\tfunction ChatBar(props, ref) {\n\t\tconst {\n\t\t\ttheme: userTheme,\n\t\t\twidth = 600,\n\t\t\texpandedHeight = 400,\n\t\t\tallowAttachments = false,\n\t\t\twelcomeMessage,\n\t\t\tplaceholder = \"Ask me anything...\",\n\t\t\ttriggerEvent = \"triggerDemoRequest\",\n\t\t\tresourceEndpoint,\n\t\t\tapi,\n\t\t} = props;\n\n\t\tconst effectiveResourceEndpoint =\n\t\t\tresourceEndpoint ?? (api ? `${api}/resource` : undefined);\n\n\t\tconst resolvedTheme = mergeTheme(userTheme);\n\t\tconst cssVars = themeToCSSProperties(resolvedTheme);\n\t\tconst isDark = isDarkTheme(resolvedTheme);\n\n\t\tconst engine = useChatEngine(props);\n\n\t\tconst suggestionsState = useSuggestions({\n\t\t\tmessages: engine.messages,\n\t\t\tstatus: engine.status,\n\t\t\tconfig: props.suggestions,\n\t\t});\n\n\t\tconst handleWidgetMessage = useCallback(\n\t\t\t(message: {\n\t\t\t\trole: string;\n\t\t\t\tcontent: Array<{ type: string; text?: string }>;\n\t\t\t}) => {\n\t\t\t\tconst text = message.content\n\t\t\t\t\t.map((c) => c.text ?? \"\")\n\t\t\t\t\t.join(\"\")\n\t\t\t\t\t.trim();\n\t\t\t\tif (text) engine.handleSubmit({ text, files: [] });\n\t\t\t},\n\t\t\t[engine.handleSubmit],\n\t\t);\n\n\t\tconst handleSuggestionSelect = useCallback(\n\t\t\t(suggestion: string) => {\n\t\t\t\tsuggestionsState.clear();\n\t\t\t\tengine.handleSubmit({ text: suggestion, files: [] });\n\t\t\t},\n\t\t\t[suggestionsState.clear, engine.handleSubmit],\n\t\t);\n\n\t\tconst animatedPlaceholder = useTypingPlaceholder(placeholder, !engine.text);\n\n\t\tconst [isFocused, setIsFocused] = useState(false);\n\t\tconst [isHighlighted, setIsHighlighted] = useState(false);\n\t\tconst containerRef = useRef<HTMLDivElement>(null);\n\t\tconst highlightTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\t\tconst focusInput = useCallback(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tif (!container) return;\n\t\t\tcontainer.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\t\tconst textarea = container.querySelector(\"textarea\");\n\t\t\tif (textarea) {\n\t\t\t\tsetTimeout(() => textarea.focus(), 300);\n\t\t\t}\n\t\t\tsetIsFocused(true);\n\t\t\tsetIsHighlighted(true);\n\t\t\tclearTimeout(highlightTimerRef.current);\n\t\t\thighlightTimerRef.current = setTimeout(\n\t\t\t\t() => setIsHighlighted(false),\n\t\t\t\t2000,\n\t\t\t);\n\t\t}, []);\n\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tsendMessage: (text: string) => {\n\t\t\t\t\tengine.handleSubmit({ text, files: [] });\n\t\t\t\t\tfocusInput();\n\t\t\t\t},\n\t\t\t\tfocus: focusInput,\n\t\t\t}),\n\t\t\t[engine.handleSubmit, focusInput],\n\t\t);\n\n\t\t// Listen for custom trigger event (e.g. \"triggerDemoRequest\")\n\t\tuseEffect(() => {\n\t\t\tif (!triggerEvent) return;\n\t\t\tconst handler = (e: Event) => {\n\t\t\t\tconst detail = (e as CustomEvent).detail;\n\t\t\t\tconst message =\n\t\t\t\t\ttypeof detail?.message === \"string\" ? detail.message : undefined;\n\t\t\t\tif (message) {\n\t\t\t\t\tengine.handleSubmit({ text: message, files: [] });\n\t\t\t\t}\n\t\t\t\tfocusInput();\n\t\t\t};\n\t\t\twindow.addEventListener(triggerEvent, handler);\n\t\t\treturn () => window.removeEventListener(triggerEvent, handler);\n\t\t}, [triggerEvent, engine.handleSubmit, focusInput]);\n\t\tconst isExpanded = isFocused;\n\n\t\t// Close on outside click\n\t\tuseEffect(() => {\n\t\t\tif (!isFocused) return;\n\t\t\tconst handleClickOutside = (e: MouseEvent) => {\n\t\t\t\tif (\n\t\t\t\t\tcontainerRef.current &&\n\t\t\t\t\t!containerRef.current.contains(e.target as Node)\n\t\t\t\t) {\n\t\t\t\t\tsetIsFocused(false);\n\t\t\t\t}\n\t\t\t};\n\t\t\tdocument.addEventListener(\"mousedown\", handleClickOutside);\n\t\t\treturn () =>\n\t\t\t\tdocument.removeEventListener(\"mousedown\", handleClickOutside);\n\t\t}, [isFocused]);\n\n\t\tconst handleFocus = useCallback(() => {\n\t\t\tsetIsFocused(true);\n\t\t}, []);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tstyle={{ ...cssVars, width }}\n\t\t\t\tdata-waniwani-chat=\"\"\n\t\t\t\tdata-waniwani-layout=\"bar\"\n\t\t\t\t{...(isDark ? { \"data-waniwani-dark\": \"\" } : {})}\n\t\t\t\tclassName=\"flex flex-col font-[family-name:var(--ww-font)] text-foreground\"\n\t\t\t>\n\t\t\t\t{/* Messages panel — fades up on expand */}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"overflow-hidden bg-background/80 backdrop-blur-xl transition-all duration-300 ease-out\",\n\t\t\t\t\t\tisExpanded\n\t\t\t\t\t\t\t? \"opacity-100 translate-y-0\"\n\t\t\t\t\t\t\t: \"opacity-0 translate-y-2 pointer-events-none max-h-0\",\n\t\t\t\t\t)}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\t...(isExpanded ? { maxHeight: expandedHeight } : undefined),\n\t\t\t\t\t\tmaskImage:\n\t\t\t\t\t\t\t\"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)\",\n\t\t\t\t\t\tmaskComposite: \"intersect\",\n\t\t\t\t\t\tWebkitMaskImage:\n\t\t\t\t\t\t\t\"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)\",\n\t\t\t\t\t\tWebkitMaskComposite: \"source-in\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Conversation className=\"flex-1\" style={{ height: expandedHeight }}>\n\t\t\t\t\t\t<ConversationContent>\n\t\t\t\t\t\t\t<MessageList\n\t\t\t\t\t\t\t\tmessages={engine.messages}\n\t\t\t\t\t\t\t\tstatus={engine.status}\n\t\t\t\t\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\t\t\t\t\tresourceEndpoint={effectiveResourceEndpoint}\n\t\t\t\t\t\t\t\tisDark={isDark}\n\t\t\t\t\t\t\t\tonFollowUp={handleWidgetMessage}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</ConversationContent>\n\t\t\t\t\t\t<ConversationScrollButton />\n\t\t\t\t\t</Conversation>\n\t\t\t\t</div>\n\n\t\t\t\t{/* Suggestions */}\n\t\t\t\t<Suggestions\n\t\t\t\t\tsuggestions={suggestionsState.suggestions}\n\t\t\t\t\tisLoading={suggestionsState.isLoading}\n\t\t\t\t\tonSelect={handleSuggestionSelect}\n\t\t\t\t/>\n\n\t\t\t\t{/* Input bar — always visible */}\n\t\t\t\t<div className=\"shrink-0\">\n\t\t\t\t\t<PromptInput\n\t\t\t\t\t\tonSubmit={engine.handleSubmit}\n\t\t\t\t\t\tglobalDrop={allowAttachments}\n\t\t\t\t\t\tmultiple={allowAttachments}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"rounded-[var(--ww-radius)] shadow-sm transition-all duration-300 ease-out\",\n\t\t\t\t\t\t\tisHighlighted &&\n\t\t\t\t\t\t\t\t\"ring-2 ring-blue-400/70 ring-offset-2 ring-offset-background\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"flex items-center gap-1 px-3 py-2\">\n\t\t\t\t\t\t\t{allowAttachments && <PromptInputAddAttachments />}\n\t\t\t\t\t\t\t<PromptInputTextarea\n\t\t\t\t\t\t\t\tonChange={engine.handleTextChange}\n\t\t\t\t\t\t\t\tvalue={engine.text}\n\t\t\t\t\t\t\t\tplaceholder={animatedPlaceholder}\n\t\t\t\t\t\t\t\tonFocus={handleFocus}\n\t\t\t\t\t\t\t\tclassName=\"min-h-0 py-1.5 px-2\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<PromptInputSubmit status={engine.status} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</PromptInput>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t},\n);\n","\"use client\";\n\nimport { ArrowDownIcon } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { useCallback } from \"react\";\nimport { StickToBottom, useStickToBottomContext } from \"use-stick-to-bottom\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\n\nexport type ConversationProps = ComponentProps<typeof StickToBottom>;\n\nexport const Conversation = ({ className, ...props }: ConversationProps) => (\n\t<StickToBottom\n\t\tclassName={cn(\"relative flex-1 overflow-y-hidden\", className)}\n\t\tinitial=\"smooth\"\n\t\tresize=\"smooth\"\n\t\trole=\"log\"\n\t\t{...props}\n\t/>\n);\n\nexport type ConversationContentProps = ComponentProps<\n\ttypeof StickToBottom.Content\n>;\n\nexport const ConversationContent = ({\n\tclassName,\n\t...props\n}: ConversationContentProps) => (\n\t<StickToBottom.Content\n\t\tclassName={cn(\"flex flex-col gap-8 p-4\", className)}\n\t\t{...props}\n\t/>\n);\n\nexport type ConversationScrollButtonProps = ComponentProps<typeof Button>;\n\nexport const ConversationScrollButton = ({\n\tclassName,\n\t...props\n}: ConversationScrollButtonProps) => {\n\tconst { isAtBottom, scrollToBottom } = useStickToBottomContext();\n\n\tconst handleScrollToBottom = useCallback(() => {\n\t\tscrollToBottom();\n\t}, [scrollToBottom]);\n\n\treturn (\n\t\t!isAtBottom && (\n\t\t\t<Button\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonClick={handleScrollToBottom}\n\t\t\t\tsize=\"icon\"\n\t\t\t\tvariant=\"outline\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<ArrowDownIcon className=\"size-4\" />\n\t\t\t</Button>\n\t\t)\n\t);\n};\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type ButtonProps = ComponentProps<\"button\"> & {\n\tvariant?: \"default\" | \"outline\" | \"ghost\";\n\tsize?: \"default\" | \"sm\" | \"icon\" | \"icon-sm\";\n};\n\nexport const Button = ({\n\tclassName,\n\tvariant = \"default\",\n\tsize = \"default\",\n\ttype = \"button\",\n\t...props\n}: ButtonProps) => (\n\t<button\n\t\ttype={type}\n\t\tclassName={cn(\n\t\t\t\"inline-flex cursor-pointer items-center justify-center rounded-md font-medium transition-colors disabled:pointer-events-none disabled:opacity-50\",\n\t\t\tvariant === \"default\" &&\n\t\t\t\t\"bg-primary text-primary-foreground hover:bg-primary/90\",\n\t\t\tvariant === \"outline\" &&\n\t\t\t\t\"border border-border bg-background hover:bg-accent hover:text-accent-foreground\",\n\t\t\tvariant === \"ghost\" && \"hover:bg-accent hover:text-accent-foreground\",\n\t\t\tsize === \"default\" && \"h-9 px-4 py-2 text-sm\",\n\t\t\tsize === \"sm\" && \"h-8 px-3 text-xs\",\n\t\t\tsize === \"icon\" && \"size-9\",\n\t\t\tsize === \"icon-sm\" && \"size-7\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n","\"use client\";\n\nimport type { ChatStatus, FileUIPart } from \"ai\";\nimport {\n\tArrowUpIcon,\n\tLoaderIcon,\n\tPaperclipIcon,\n\tSquareIcon,\n\tXIcon,\n} from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport type {\n\tChangeEvent,\n\tClipboardEventHandler,\n\tComponentProps,\n\tFormEvent,\n\tFormEventHandler,\n\tHTMLAttributes,\n\tKeyboardEventHandler,\n} from \"react\";\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nconst convertBlobUrlToDataUrl = async (url: string): Promise<string | null> => {\n\ttry {\n\t\tconst response = await fetch(url);\n\t\tconst blob = await response.blob();\n\t\treturn new Promise((resolve) => {\n\t\t\tconst reader = new FileReader();\n\t\t\treader.onloadend = () => resolve(reader.result as string);\n\t\t\treader.onerror = () => resolve(null);\n\t\t\treader.readAsDataURL(blob);\n\t\t});\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n// ============================================================================\n// Attachments Context\n// ============================================================================\n\nexport interface AttachmentsContext {\n\tfiles: (FileUIPart & { id: string })[];\n\tadd: (files: File[] | FileList) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\topenFileDialog: () => void;\n}\n\nconst LocalAttachmentsContext = createContext<AttachmentsContext | null>(null);\n\nexport const usePromptInputAttachments = () => {\n\tconst context = useContext(LocalAttachmentsContext);\n\tif (!context) {\n\t\tthrow new Error(\n\t\t\t\"usePromptInputAttachments must be used within a PromptInput\",\n\t\t);\n\t}\n\treturn context;\n};\n\n// ============================================================================\n// PromptInput Message Type\n// ============================================================================\n\nexport interface PromptInputMessage {\n\ttext: string;\n\tfiles: FileUIPart[];\n}\n\n// ============================================================================\n// PromptInput\n// ============================================================================\n\nexport type PromptInputProps = Omit<\n\tHTMLAttributes<HTMLFormElement>,\n\t\"onSubmit\"\n> & {\n\taccept?: string;\n\tmultiple?: boolean;\n\tglobalDrop?: boolean;\n\tmaxFiles?: number;\n\tmaxFileSize?: number;\n\tonSubmit: (\n\t\tmessage: PromptInputMessage,\n\t\tevent: FormEvent<HTMLFormElement>,\n\t) => void | Promise<void>;\n};\n\nexport const PromptInput = ({\n\tclassName,\n\taccept,\n\tmultiple,\n\tglobalDrop,\n\tmaxFiles,\n\tmaxFileSize,\n\tonSubmit,\n\tchildren,\n\t...props\n}: PromptInputProps) => {\n\tconst inputRef = useRef<HTMLInputElement | null>(null);\n\tconst formRef = useRef<HTMLFormElement | null>(null);\n\tconst [items, setItems] = useState<(FileUIPart & { id: string })[]>([]);\n\tconst filesRef = useRef(items);\n\n\tuseEffect(() => {\n\t\tfilesRef.current = items;\n\t}, [items]);\n\n\tconst openFileDialog = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\tconst add = useCallback(\n\t\t(fileList: File[] | FileList) => {\n\t\t\tconst incoming = [...fileList];\n\t\t\tif (incoming.length === 0) return;\n\n\t\t\tconst withinSize = (f: File) =>\n\t\t\t\tmaxFileSize ? f.size <= maxFileSize : true;\n\t\t\tconst valid = incoming.filter(withinSize);\n\n\t\t\tsetItems((prev) => {\n\t\t\t\tconst capacity =\n\t\t\t\t\ttypeof maxFiles === \"number\"\n\t\t\t\t\t\t? Math.max(0, maxFiles - prev.length)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst capped =\n\t\t\t\t\ttypeof capacity === \"number\" ? valid.slice(0, capacity) : valid;\n\t\t\t\treturn [\n\t\t\t\t\t...prev,\n\t\t\t\t\t...capped.map((file) => ({\n\t\t\t\t\t\tfilename: file.name,\n\t\t\t\t\t\tid: nanoid(),\n\t\t\t\t\t\tmediaType: file.type,\n\t\t\t\t\t\ttype: \"file\" as const,\n\t\t\t\t\t\turl: URL.createObjectURL(file),\n\t\t\t\t\t})),\n\t\t\t\t];\n\t\t\t});\n\t\t},\n\t\t[maxFiles, maxFileSize],\n\t);\n\n\tconst remove = useCallback((id: string) => {\n\t\tsetItems((prev) => {\n\t\t\tconst found = prev.find((f) => f.id === id);\n\t\t\tif (found?.url) URL.revokeObjectURL(found.url);\n\t\t\treturn prev.filter((f) => f.id !== id);\n\t\t});\n\t}, []);\n\n\tconst clear = useCallback(() => {\n\t\tsetItems((prev) => {\n\t\t\tfor (const f of prev) {\n\t\t\t\tif (f.url) URL.revokeObjectURL(f.url);\n\t\t\t}\n\t\t\treturn [];\n\t\t});\n\t}, []);\n\n\t// Cleanup blob URLs on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tfor (const f of filesRef.current) {\n\t\t\t\tif (f.url) URL.revokeObjectURL(f.url);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst handleChange = useCallback(\n\t\t(event: ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (event.currentTarget.files) {\n\t\t\t\tadd(event.currentTarget.files);\n\t\t\t}\n\t\t\tevent.currentTarget.value = \"\";\n\t\t},\n\t\t[add],\n\t);\n\n\t// Global drop support\n\tuseEffect(() => {\n\t\tif (!globalDrop) return;\n\t\tconst onDragOver = (e: DragEvent) => {\n\t\t\tif (e.dataTransfer?.types?.includes(\"Files\")) e.preventDefault();\n\t\t};\n\t\tconst onDrop = (e: DragEvent) => {\n\t\t\tif (e.dataTransfer?.types?.includes(\"Files\")) e.preventDefault();\n\t\t\tif (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n\t\t\t\tadd(e.dataTransfer.files);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener(\"dragover\", onDragOver);\n\t\tdocument.addEventListener(\"drop\", onDrop);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"dragover\", onDragOver);\n\t\t\tdocument.removeEventListener(\"drop\", onDrop);\n\t\t};\n\t}, [add, globalDrop]);\n\n\tconst handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(\n\t\tasync (event) => {\n\t\t\tevent.preventDefault();\n\t\t\tconst form = event.currentTarget;\n\t\t\tconst formData = new FormData(form);\n\t\t\tconst text = (formData.get(\"message\") as string) || \"\";\n\n\t\t\tform.reset();\n\n\t\t\tconst convertedFiles: FileUIPart[] = await Promise.all(\n\t\t\t\titems.map(async ({ id: _id, ...item }) => {\n\t\t\t\t\tif (item.url?.startsWith(\"blob:\")) {\n\t\t\t\t\t\tconst dataUrl = await convertBlobUrlToDataUrl(item.url);\n\t\t\t\t\t\treturn { ...item, url: dataUrl ?? item.url };\n\t\t\t\t\t}\n\t\t\t\t\treturn item;\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\ttry {\n\t\t\t\tconst result = onSubmit({ files: convertedFiles, text }, event);\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\tawait result;\n\t\t\t\t}\n\t\t\t\tclear();\n\t\t\t} catch {\n\t\t\t\t// Don't clear on error\n\t\t\t}\n\t\t},\n\t\t[items, onSubmit, clear],\n\t);\n\n\tconst attachmentsCtx = useMemo<AttachmentsContext>(\n\t\t() => ({\n\t\t\tadd,\n\t\t\tclear,\n\t\t\tfiles: items,\n\t\t\topenFileDialog,\n\t\t\tremove,\n\t\t}),\n\t\t[items, add, remove, clear, openFileDialog],\n\t);\n\n\treturn (\n\t\t<LocalAttachmentsContext.Provider value={attachmentsCtx}>\n\t\t\t<input\n\t\t\t\taccept={accept}\n\t\t\t\taria-label=\"Upload files\"\n\t\t\t\tclassName=\"hidden\"\n\t\t\t\tmultiple={multiple}\n\t\t\t\tonChange={handleChange}\n\t\t\t\tref={inputRef}\n\t\t\t\ttitle=\"Upload files\"\n\t\t\t\ttype=\"file\"\n\t\t\t/>\n\t\t\t<form\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex w-full flex-col rounded-lg border border-border bg-background\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\tref={formRef}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</form>\n\t\t</LocalAttachmentsContext.Provider>\n\t);\n};\n\n// ============================================================================\n// Layout Components\n// ============================================================================\n\nexport type PromptInputHeaderProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputHeader = ({\n\tclassName,\n\t...props\n}: PromptInputHeaderProps) => (\n\t<div className={cn(\"flex flex-wrap gap-1 px-3 pt-3\", className)} {...props} />\n);\n\nexport type PromptInputBodyProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputBody = ({\n\tclassName,\n\t...props\n}: PromptInputBodyProps) => (\n\t<div className={cn(\"contents\", className)} {...props} />\n);\n\nexport type PromptInputFooterProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputFooter = ({\n\tclassName,\n\t...props\n}: PromptInputFooterProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"flex items-center justify-between gap-1 px-3 pb-3\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n\nexport type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTools = ({\n\tclassName,\n\t...props\n}: PromptInputToolsProps) => (\n\t<div\n\t\tclassName={cn(\"flex min-w-0 items-center gap-1\", className)}\n\t\t{...props}\n\t/>\n);\n\n// ============================================================================\n// Textarea\n// ============================================================================\n\nexport type PromptInputTextareaProps = ComponentProps<\"textarea\">;\n\nexport const PromptInputTextarea = ({\n\tonChange,\n\tonKeyDown,\n\tclassName,\n\tplaceholder = \"What would you like to know?\",\n\t...props\n}: PromptInputTextareaProps) => {\n\tconst attachments = usePromptInputAttachments();\n\tconst [isComposing, setIsComposing] = useState(false);\n\n\tconst handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useCallback(\n\t\t(e) => {\n\t\t\tonKeyDown?.(e);\n\t\t\tif (e.defaultPrevented) return;\n\n\t\t\tif (e.key === \"Enter\") {\n\t\t\t\tif (isComposing || e.nativeEvent.isComposing) return;\n\t\t\t\tif (e.shiftKey) return;\n\t\t\t\te.preventDefault();\n\n\t\t\t\tconst { form } = e.currentTarget;\n\t\t\t\tconst submitButton = form?.querySelector(\n\t\t\t\t\t'button[type=\"submit\"]',\n\t\t\t\t) as HTMLButtonElement | null;\n\t\t\t\tif (submitButton?.disabled) return;\n\t\t\t\tform?.requestSubmit();\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\te.key === \"Backspace\" &&\n\t\t\t\te.currentTarget.value === \"\" &&\n\t\t\t\tattachments.files.length > 0\n\t\t\t) {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst lastAttachment = attachments.files.at(-1);\n\t\t\t\tif (lastAttachment) attachments.remove(lastAttachment.id);\n\t\t\t}\n\t\t},\n\t\t[onKeyDown, isComposing, attachments],\n\t);\n\n\tconst handlePaste: ClipboardEventHandler<HTMLTextAreaElement> = useCallback(\n\t\t(event) => {\n\t\t\tconst items = event.clipboardData?.items;\n\t\t\tif (!items) return;\n\n\t\t\tconst files: File[] = [];\n\t\t\tfor (const item of items) {\n\t\t\t\tif (item.kind === \"file\") {\n\t\t\t\t\tconst file = item.getAsFile();\n\t\t\t\t\tif (file) files.push(file);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (files.length > 0) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tattachments.add(files);\n\t\t\t}\n\t\t},\n\t\t[attachments],\n\t);\n\n\treturn (\n\t\t<textarea\n\t\t\tclassName={cn(\n\t\t\t\t\"field-sizing-content max-h-48 min-h-16 w-full resize-none border-0 bg-transparent px-3 py-3 text-sm outline-none placeholder:text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tname=\"message\"\n\t\t\tonCompositionEnd={() => setIsComposing(false)}\n\t\t\tonCompositionStart={() => setIsComposing(true)}\n\t\t\tonKeyDown={handleKeyDown}\n\t\t\tonPaste={handlePaste}\n\t\t\tplaceholder={placeholder}\n\t\t\tonChange={onChange}\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n\n// ============================================================================\n// Submit Button\n// ============================================================================\n\nexport type PromptInputSubmitProps = ComponentProps<typeof Button> & {\n\tstatus?: ChatStatus;\n\tonStop?: () => void;\n};\n\nexport const PromptInputSubmit = ({\n\tclassName,\n\tstatus,\n\tonStop,\n\tonClick,\n\tchildren,\n\t...props\n}: PromptInputSubmitProps) => {\n\tconst isGenerating = status === \"submitted\" || status === \"streaming\";\n\n\tlet Icon = <ArrowUpIcon className=\"size-4\" />;\n\tif (status === \"submitted\") {\n\t\tIcon = <LoaderIcon className=\"size-4 animate-spin\" />;\n\t} else if (status === \"streaming\") {\n\t\tIcon = <SquareIcon className=\"size-4\" />;\n\t}\n\n\tconst handleClick = useCallback(\n\t\t(e: React.MouseEvent<HTMLButtonElement>) => {\n\t\t\tif (isGenerating && onStop) {\n\t\t\t\te.preventDefault();\n\t\t\t\tonStop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tonClick?.(e);\n\t\t},\n\t\t[isGenerating, onStop, onClick],\n\t);\n\n\treturn (\n\t\t<Button\n\t\t\taria-label={isGenerating ? \"Stop\" : \"Submit\"}\n\t\t\tclassName={cn(\n\t\t\t\t\"bg-foreground text-background hover:bg-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonClick={handleClick}\n\t\t\tsize=\"icon-sm\"\n\t\t\ttype={isGenerating && onStop ? \"button\" : \"submit\"}\n\t\t\tvariant=\"ghost\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children ?? Icon}\n\t\t</Button>\n\t);\n};\n\n// ============================================================================\n// Attachment Add Button (simple file picker, no Radix dropdown)\n// ============================================================================\n\nexport type PromptInputAddAttachmentsProps = ComponentProps<typeof Button>;\n\nexport const PromptInputAddAttachments = ({\n\tclassName,\n\tchildren,\n\t...props\n}: PromptInputAddAttachmentsProps) => {\n\tconst attachments = usePromptInputAttachments();\n\tconst hasFiles = attachments.files.length > 0;\n\n\tif (hasFiles) {\n\t\treturn (\n\t\t\t<Button\n\t\t\t\tclassName={cn(\"group relative\", className)}\n\t\t\t\tonClick={() => attachments.clear()}\n\t\t\t\tsize=\"icon-sm\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tvariant=\"ghost\"\n\t\t\t\taria-label=\"Remove all attachments\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<span className=\"flex size-5 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground transition-opacity group-hover:opacity-0\">\n\t\t\t\t\t{attachments.files.length}\n\t\t\t\t</span>\n\t\t\t\t<XIcon className=\"absolute size-4 opacity-0 transition-opacity group-hover:opacity-100\" />\n\t\t\t</Button>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Button\n\t\t\tclassName={cn(className)}\n\t\t\tonClick={() => attachments.openFileDialog()}\n\t\t\tsize=\"icon-sm\"\n\t\t\ttype=\"button\"\n\t\t\tvariant=\"ghost\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children ?? <PaperclipIcon className=\"size-4\" />}\n\t\t</Button>\n\t);\n};\n","\"use client\";\n\nimport type { FileUIPart } from \"ai\";\nimport { FileIcon } from \"lucide-react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\n// ============================================================================\n// Attachments (inline list for chat bubbles)\n// ============================================================================\n\nexport type AttachmentsProps = HTMLAttributes<HTMLDivElement> & {\n\tfiles: FileUIPart[];\n};\n\nexport const Attachments = ({\n\tfiles,\n\tclassName,\n\t...props\n}: AttachmentsProps) => {\n\tif (files.length === 0) return null;\n\n\treturn (\n\t\t<div className={cn(\"flex flex-wrap gap-1.5\", className)} {...props}>\n\t\t\t{files.map((file, i) => (\n\t\t\t\t<AttachmentItem key={i} file={file} />\n\t\t\t))}\n\t\t</div>\n\t);\n};\n\n// ============================================================================\n// AttachmentItem\n// ============================================================================\n\nfunction AttachmentItem({ file }: { file: FileUIPart }) {\n\tconst isImage = file.mediaType?.startsWith(\"image/\");\n\n\tif (isImage && file.url) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={file.url}\n\t\t\t\talt={file.filename ?? \"attachment\"}\n\t\t\t\tclassName=\"h-16 max-w-32 rounded object-cover\"\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<span className=\"inline-flex items-center gap-1.5 rounded bg-background/20 px-2 py-1 text-xs\">\n\t\t\t<FileIcon className=\"size-3 shrink-0\" />\n\t\t\t<span className=\"max-w-24 truncate\">{file.filename ?? \"file\"}</span>\n\t\t</span>\n\t);\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type LoaderProps = HTMLAttributes<HTMLDivElement> & {\n\tsize?: number;\n};\n\nexport const Loader = ({ className, size = 5, ...props }: LoaderProps) => (\n\t<div className={cn(\"flex items-center gap-1\", className)} {...props}>\n\t\t{[0, 1, 2].map((i) => (\n\t\t\t<div\n\t\t\t\tkey={i}\n\t\t\t\tclassName=\"rounded-full bg-muted-foreground/60\"\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: size,\n\t\t\t\t\theight: size,\n\t\t\t\t\tanimation: \"ww-pulse 1.4s ease-in-out infinite\",\n\t\t\t\t\tanimationDelay: `${i * 0.2}s`,\n\t\t\t\t}}\n\t\t\t/>\n\t\t))}\n\t</div>\n);\n","\"use client\";\n\nimport { cjk } from \"@streamdown/cjk\";\nimport { code } from \"@streamdown/code\";\nimport type { UIMessage } from \"ai\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport { memo } from \"react\";\nimport { Streamdown } from \"streamdown\";\nimport { cn } from \"../lib/utils\";\n\nexport type MessageProps = HTMLAttributes<HTMLDivElement> & {\n\tfrom: UIMessage[\"role\"];\n};\n\nexport const Message = ({ className, from, ...props }: MessageProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"group flex w-full max-w-[95%] flex-col gap-2\",\n\t\t\tfrom === \"user\" ? \"is-user ml-auto justify-end\" : \"is-assistant\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n\nexport type MessageContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const MessageContent = ({\n\tchildren,\n\tclassName,\n\t...props\n}: MessageContentProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-base\",\n\t\t\t\"group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-user-bubble group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-primary-foreground\",\n\t\t\t\"group-[.is-assistant]:text-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t{children}\n\t</div>\n);\n\nexport type MessageResponseProps = ComponentProps<typeof Streamdown>;\n\nconst streamdownPlugins = { cjk, code };\n\nexport const MessageResponse = memo(\n\t({ className, ...props }: MessageResponseProps) => (\n\t\t<Streamdown\n\t\t\tclassName={cn(\n\t\t\t\t\"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tplugins={streamdownPlugins}\n\t\t\t{...props}\n\t\t/>\n\t),\n\t(prevProps, nextProps) => prevProps.children === nextProps.children,\n);\n\nMessageResponse.displayName = \"MessageResponse\";\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type ReasoningProps = HTMLAttributes<HTMLPreElement> & {\n\ttext: string;\n};\n\n/** Displays reasoning text inline with muted styling. */\nexport function Reasoning({ className, text, ...props }: ReasoningProps) {\n\tif (!text) return null;\n\n\treturn (\n\t\t<pre\n\t\t\tclassName={cn(\n\t\t\t\t\"mb-2 overflow-x-auto whitespace-pre-wrap break-words text-xs font-mono text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{text}\n\t\t</pre>\n\t);\n}\n","\"use client\";\n\nimport type { ToolUIPart } from \"ai\";\nimport {\n\tBracesIcon,\n\tCheckIcon,\n\tChevronDownIcon,\n\tChevronRightIcon,\n\tClipboardCopyIcon,\n\tServerIcon,\n} from \"lucide-react\";\nimport type { HTMLAttributes } from \"react\";\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\n\n/**\n * Produces an abbreviated single-line JSON preview for collapsed display.\n * Objects show truncated keys/values: `{ci… 'M…, pos… '2…, squa… 80}`\n * Arrays show their length: `Array(13)`\n */\nfunction truncateJSON(data: unknown, maxLength = 80): string {\n\tif (data === null || data === undefined) return String(data);\n\tif (typeof data !== \"object\") return String(data).slice(0, maxLength);\n\n\tif (Array.isArray(data)) {\n\t\treturn `Array(${data.length})`;\n\t}\n\n\tconst stringified = JSON.stringify(data);\n\tif (stringified.length <= maxLength) return stringified;\n\n\tconst entries = Object.entries(data as Record<string, unknown>);\n\tconst parts: string[] = [];\n\tlet remaining = maxLength - 2;\n\n\tfor (const [key, value] of entries) {\n\t\tif (remaining <= 8) break;\n\t\tconst keyAbbrev = key.length > 4 ? `${key.slice(0, 4)}\\u2026` : key;\n\t\tlet valStr: string;\n\t\tif (typeof value === \"string\") {\n\t\t\tvalStr = value.length > 2 ? `'${value.slice(0, 1)}\\u2026` : `'${value}'`;\n\t\t} else if (Array.isArray(value)) {\n\t\t\tvalStr = `Array(${value.length})`;\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\tvalStr = `{\\u2026}`;\n\t\t} else {\n\t\t\tvalStr = String(value);\n\t\t}\n\t\tconst part = `${keyAbbrev}\\u2009${valStr}`;\n\t\tparts.push(part);\n\t\tremaining -= part.length + 3;\n\t}\n\n\treturn `{${parts.join(\", \")}}`;\n}\n\ninterface CopyButtonProps {\n\ttext: string;\n\tclassName?: string;\n}\n\n/** Ghost button that copies `text` to clipboard, showing \"Copied\" for 2s. */\nfunction CopyButton({ text, className }: CopyButtonProps) {\n\tconst [copied, setCopied] = useState(false);\n\tconst timeoutRef = useRef<ReturnType<typeof setTimeout>>(null);\n\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tif (timeoutRef.current) {\n\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t}\n\t\t};\n\t}, []);\n\n\tconst handleCopy = useCallback(\n\t\tasync (e: React.MouseEvent) => {\n\t\t\te.stopPropagation();\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(text);\n\t\t\t\tsetCopied(true);\n\t\t\t\tif (timeoutRef.current) {\n\t\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t\t}\n\t\t\t\ttimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n\t\t\t} catch {\n\t\t\t\t// Clipboard API not available\n\t\t\t}\n\t\t},\n\t\t[text],\n\t);\n\n\treturn (\n\t\t<Button\n\t\t\tvariant=\"ghost\"\n\t\t\tsize=\"sm\"\n\t\t\tonClick={handleCopy}\n\t\t\tclassName={cn(\n\t\t\t\t\"h-auto gap-1 px-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{copied ? (\n\t\t\t\t<>\n\t\t\t\t\t<CheckIcon className=\"size-3.5\" />\n\t\t\t\t\t<span>Copied</span>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<ClipboardCopyIcon className=\"size-3.5\" />\n\t\t\t\t\t<span>Copy</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</Button>\n\t);\n}\n\ninterface CollapsibleJSONProps extends HTMLAttributes<HTMLDivElement> {\n\tdata: unknown;\n\tlabel: string;\n}\n\n/**\n * Labeled JSON section with a Copy button and a collapsible preview.\n * Collapsed: shows a truncated single-line abbreviation with a `>` chevron.\n * Expanded: rotates the chevron and shows full pretty-printed JSON.\n */\nfunction CollapsibleJSON({\n\tdata,\n\tlabel,\n\tclassName,\n\t...props\n}: CollapsibleJSONProps) {\n\tconst [expanded, setExpanded] = useState(false);\n\tconst fullJSON = useMemo(() => JSON.stringify(data, null, 2), [data]);\n\tconst preview = truncateJSON(data);\n\n\treturn (\n\t\t<div className={cn(\"rounded-lg bg-tool-card\", className)} {...props}>\n\t\t\t<div className=\"flex items-center justify-between px-3 pt-2.5 pb-1.5\">\n\t\t\t\t<span className=\"text-xs font-medium text-muted-foreground\">\n\t\t\t\t\t{label}\n\t\t\t\t</span>\n\t\t\t\t<CopyButton text={fullJSON} />\n\t\t\t</div>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tonClick={() => setExpanded((v) => !v)}\n\t\t\t\tclassName=\"flex w-full items-start gap-2 px-3 pb-3 text-left\"\n\t\t\t>\n\t\t\t\t<ChevronRightIcon\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"mt-0.5 size-3.5 shrink-0 text-muted-foreground transition-transform duration-150\",\n\t\t\t\t\t\texpanded && \"rotate-90\",\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t{expanded ? (\n\t\t\t\t\t<pre className=\"overflow-x-auto text-xs font-mono text-foreground whitespace-pre-wrap break-all\">\n\t\t\t\t\t\t<code>{fullJSON}</code>\n\t\t\t\t\t</pre>\n\t\t\t\t) : (\n\t\t\t\t\t<span className=\"truncate text-xs font-mono text-foreground/80\">\n\t\t\t\t\t\t{preview}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n\nconst ToolOpenContext = createContext<{\n\topen: boolean;\n\ttoggle: () => void;\n}>({ open: false, toggle: () => {} });\n\nexport type ToolProps = HTMLAttributes<HTMLDivElement> & {\n\tdefaultOpen?: boolean;\n};\n\n/**\n * Compound component root for a tool call display.\n * Provides open/closed state via context to ToolHeader and ToolContent.\n *\n * ```tsx\n * <Tool defaultOpen>\n * <ToolHeader title=\"Price estimate ready\" state=\"output-available\" />\n * <ToolContent>\n * <ToolServerInfo toolName=\"get_price_estimate\" serverName=\"Tuio v2\" />\n * <ToolInput input={args} />\n * <ToolOutput output={result} errorText={undefined} />\n * </ToolContent>\n * </Tool>\n * ```\n */\nexport function Tool({\n\tclassName,\n\tdefaultOpen = false,\n\tchildren,\n\t...props\n}: ToolProps) {\n\tconst [open, setOpen] = useState(defaultOpen);\n\treturn (\n\t\t<ToolOpenContext.Provider\n\t\t\tvalue={{ open, toggle: () => setOpen((o) => !o) }}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={cn(\"mb-4 w-full\", className)}\n\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ToolOpenContext.Provider>\n\t);\n}\n\nexport type ToolHeaderProps = HTMLAttributes<HTMLButtonElement> & {\n\ttitle?: string;\n\tstate: ToolUIPart[\"state\"];\n};\n\n/** Clickable header that toggles the tool accordion. Shows a `{≡}` icon, title, and chevron. */\nexport function ToolHeader({\n\tclassName,\n\ttitle,\n\tstate,\n\t...props\n}: ToolHeaderProps) {\n\tconst { open, toggle } = useContext(ToolOpenContext);\n\tconst isRunning = state === \"input-available\" || state === \"input-streaming\";\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tonClick={toggle}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex w-full items-center justify-between gap-3 py-1.5\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\taria-expanded={open}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"flex min-w-0 items-center gap-2\">\n\t\t\t\t<BracesIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n\t\t\t\t<span className=\"truncate text-sm font-medium\">{title}</span>\n\t\t\t\t{isRunning && (\n\t\t\t\t\t<span className=\"size-2 shrink-0 rounded-full bg-primary animate-pulse\" />\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<ChevronDownIcon\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"size-4 shrink-0 text-muted-foreground transition-transform duration-200\",\n\t\t\t\t\topen && \"rotate-180\",\n\t\t\t\t)}\n\t\t\t/>\n\t\t</button>\n\t);\n}\n\nexport type ToolServerInfoProps = HTMLAttributes<HTMLDivElement> & {\n\tserverName?: string;\n\tserverIcon?: string;\n\ttoolName: string;\n};\n\n/** Optional MCP server identity card. Shows server icon + name and the tool function name. Renders nothing if no props need display. */\nexport function ToolServerInfo({\n\tclassName,\n\tserverName,\n\tserverIcon,\n\ttoolName,\n\t...props\n}: ToolServerInfoProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex items-center gap-3 rounded-lg border border-border px-3 py-2.5\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{serverIcon ? (\n\t\t\t\t<img\n\t\t\t\t\tsrc={serverIcon}\n\t\t\t\t\talt={serverName ?? \"\"}\n\t\t\t\t\tclassName=\"size-8 shrink-0 rounded-full object-cover\"\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex size-8 shrink-0 items-center justify-center rounded-full border border-border bg-muted\">\n\t\t\t\t\t<ServerIcon className=\"size-4 text-muted-foreground\" />\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"flex min-w-0 flex-col\">\n\t\t\t\t{serverName && (\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">{serverName}</span>\n\t\t\t\t)}\n\t\t\t\t<span className=\"truncate text-sm font-semibold\">{toolName}</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport type ToolContentProps = HTMLAttributes<HTMLDivElement>;\n\n/** Collapsible body that animates open/closed. Content below smoothly pushes up/down via a grid-row height transition. */\nexport function ToolContent({\n\tclassName,\n\tchildren,\n\t...props\n}: ToolContentProps) {\n\tconst { open } = useContext(ToolOpenContext);\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"grid transition-[grid-template-rows,opacity] duration-200 ease-out\",\n\t\t\t\topen ? \"grid-rows-[1fr] opacity-100\" : \"grid-rows-[0fr] opacity-0\",\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"min-h-0 overflow-hidden\">\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"mt-2 space-y-3 rounded-lg border border-border bg-background p-3\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport type ToolInputProps = HTMLAttributes<HTMLDivElement> & {\n\tinput: ToolUIPart[\"input\"];\n};\n\n/** Displays the tool call request parameters as a collapsible JSON section labeled \"Request\". */\nexport function ToolInput({ className, input, ...props }: ToolInputProps) {\n\treturn (\n\t\t<CollapsibleJSON\n\t\t\tdata={input}\n\t\t\tlabel=\"Request\"\n\t\t\tclassName={className}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport type ToolOutputProps = HTMLAttributes<HTMLDivElement> & {\n\toutput: ToolUIPart[\"output\"];\n\terrorText: ToolUIPart[\"errorText\"];\n};\n\nfunction getUiMeta(output: unknown): Record<string, unknown> | undefined {\n\tif (typeof output !== \"object\" || output === null) return undefined;\n\tconst meta = (output as Record<string, unknown>)._meta;\n\tif (typeof meta !== \"object\" || meta === null) return undefined;\n\tconst ui = (meta as Record<string, unknown>).ui;\n\tif (typeof ui !== \"object\" || ui === null) return undefined;\n\treturn ui as Record<string, unknown>;\n}\n\n/** Extract the MCP app resource URI from `output._meta.ui.resourceUri`, if present. */\nexport function getResourceUri(output: unknown): string | undefined {\n\tconst uri = getUiMeta(output)?.resourceUri;\n\treturn typeof uri === \"string\" ? uri : undefined;\n}\n\n/** Extract the auto-height flag from `output._meta.ui.autoHeight`, if present. */\nexport function getAutoHeight(output: unknown): boolean {\n\treturn getUiMeta(output)?.autoHeight === true;\n}\n\n/** Displays the tool call result as a collapsible JSON section labeled \"Response\", or an error block if `errorText` is set. */\nexport function ToolOutput({\n\tclassName,\n\toutput,\n\terrorText,\n\t...props\n}: ToolOutputProps) {\n\tif (!(output || errorText)) return null;\n\n\tif (errorText) {\n\t\treturn (\n\t\t\t<div className={cn(\"space-y-2\", className)} {...props}>\n\t\t\t\t<h4 className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n\t\t\t\t\tError\n\t\t\t\t</h4>\n\t\t\t\t<div className=\"rounded-lg bg-destructive/10 p-3 text-xs text-destructive\">\n\t\t\t\t\t{errorText}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<CollapsibleJSON\n\t\t\tdata={output}\n\t\t\tlabel=\"Response\"\n\t\t\tclassName={className}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nconst DEFAULT_RESOURCE_ENDPOINT = \"/api/mcp/resource\";\nconst MAX_HEIGHT = 500;\nconst DEFAULT_HEIGHT = 0;\nconst PROTOCOL_VERSION = \"2026-01-26\";\nconst RESIZE_ANIMATION_MS = 300;\nconst HANDSHAKE_TIMEOUT_MS = 3000;\nconst MAX_RETRIES = 3;\n\nexport interface McpAppFrameProps {\n\tresourceUri: string;\n\ttoolInput: Record<string, unknown>;\n\ttoolResult: {\n\t\tcontent?: Array<{ type: string; text?: string }>;\n\t\tstructuredContent?: Record<string, unknown>;\n\t};\n\tresourceEndpoint?: string;\n\tisDark?: boolean;\n\tclassName?: string;\n\t/** When true, the iframe height auto-adapts to its content. Set via `_meta.ui.autoHeight` in the tool result. */\n\tautoHeight?: boolean;\n\t/** Called when the view requests to open a URL */\n\tonOpenLink?: (url: string) => void;\n\t/** Called when a widget sends a follow-up message via `ui/message` */\n\tonFollowUp?: (message: {\n\t\trole: string;\n\t\tcontent: Array<{ type: string; text?: string }>;\n\t}) => void;\n}\n\nexport function McpAppFrame({\n\tresourceUri,\n\ttoolInput,\n\ttoolResult,\n\tresourceEndpoint = DEFAULT_RESOURCE_ENDPOINT,\n\tisDark = false,\n\tclassName,\n\t// TODO: REMOVE — defaulting to true for playground testing\n\tautoHeight = true,\n\tonOpenLink,\n\tonFollowUp,\n}: McpAppFrameProps) {\n\tconst iframeRef = useRef<HTMLIFrameElement>(null);\n\tconst toolInputRef = useRef(toolInput);\n\tconst toolResultRef = useRef(toolResult);\n\tconst lastSizeRef = useRef({ width: 0, height: 0 });\n\tconst animationRef = useRef<Animation | null>(null);\n\tconst initializedRef = useRef(false);\n\tconst retryCountRef = useRef(0);\n\tconst [height, setHeight] = useState(DEFAULT_HEIGHT);\n\tconst [width, setWidth] = useState<number | undefined>(undefined);\n\tconst onOpenLinkRef = useRef(onOpenLink);\n\tconst onFollowUpRef = useRef(onFollowUp);\n\n\ttoolInputRef.current = toolInput;\n\ttoolResultRef.current = toolResult;\n\tonOpenLinkRef.current = onOpenLink;\n\tonFollowUpRef.current = onFollowUp;\n\n\tconst clampHeight = useCallback(\n\t\t(h: number) => {\n\t\t\tif (autoHeight) return Math.max(h, 0);\n\t\t\treturn Math.min(Math.max(h, 50), MAX_HEIGHT);\n\t\t},\n\t\t[autoHeight],\n\t);\n\n\t// Build the iframe src URL directly — avoids null-origin issues with srcdoc\n\tconst iframeSrc = useMemo(\n\t\t() => `${resourceEndpoint}?uri=${encodeURIComponent(resourceUri)}`,\n\t\t[resourceEndpoint, resourceUri],\n\t);\n\n\tconst isDarkRef = useRef(isDark);\n\tisDarkRef.current = isDark;\n\n\t// Send theme changes to the iframe (only after handshake is complete)\n\tuseEffect(() => {\n\t\tif (!initializedRef.current) return;\n\t\tconst iframe = iframeRef.current;\n\t\tif (!iframe?.contentWindow) return;\n\n\t\tiframe.contentWindow.postMessage(\n\t\t\t{\n\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\tmethod: \"ui/notifications/host-context-changed\",\n\t\t\t\tparams: {\n\t\t\t\t\ttheme: isDark ? \"dark\" : \"light\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"*\",\n\t\t);\n\t}, [isDark]);\n\n\t// Synchronous postMessage protocol handler — no async imports, no timing issues.\n\t// Handles the MCP UI protocol (ui/initialize, notifications, etc.) directly.\n\tuseEffect(() => {\n\t\tconst iframe = iframeRef.current;\n\t\tif (!iframe) return;\n\n\t\tlet disposed = false;\n\t\tlet handshakeReceived = false;\n\t\tconst debug = (...args: unknown[]) =>\n\t\t\tconsole.debug(\"[McpAppFrame]\", ...args);\n\n\t\tdebug(\"effect mounted, waiting for handshake\");\n\n\t\t// Retry: reload iframe if handshake doesn't arrive in time\n\t\tconst handshakeTimer = setTimeout(() => {\n\t\t\tif (disposed || handshakeReceived) return;\n\t\t\tif (retryCountRef.current >= MAX_RETRIES) {\n\t\t\t\tdebug(\"handshake failed after\", MAX_RETRIES, \"retries, giving up\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tretryCountRef.current += 1;\n\t\t\tdebug(\n\t\t\t\t\"handshake timeout, reloading iframe (retry\",\n\t\t\t\tretryCountRef.current,\n\t\t\t\t\"of\",\n\t\t\t\tMAX_RETRIES,\n\t\t\t\t\")\",\n\t\t\t);\n\t\t\t// Force reload with a cache-busting param\n\t\t\tconst url = new URL(iframe.src);\n\t\t\turl.searchParams.set(\"_retry\", String(retryCountRef.current));\n\t\t\tiframe.src = url.toString();\n\t\t}, HANDSHAKE_TIMEOUT_MS);\n\n\t\tconst postToIframe = (msg: Record<string, unknown>) => {\n\t\t\tdebug(\"→ send\", msg.method ?? `response:${msg.id}`, msg);\n\t\t\tiframe.contentWindow?.postMessage(msg, \"*\");\n\t\t};\n\n\t\tconst handleMessage = (event: MessageEvent) => {\n\t\t\tif (disposed) return;\n\t\t\tif (event.source !== iframe.contentWindow) return;\n\n\t\t\tconst data = event.data;\n\t\t\tif (!data || typeof data !== \"object\" || data.jsonrpc !== \"2.0\") return;\n\n\t\t\tconst method: string | undefined = data.method;\n\t\t\tconst id: number | string | undefined = data.id;\n\n\t\t\tdebug(\"← recv\", method ?? `response:${id}`, data);\n\n\t\t\t// ui/initialize — widget requests handshake\n\t\t\tif (method === \"ui/initialize\" && id != null) {\n\t\t\t\thandshakeReceived = true;\n\t\t\t\tclearTimeout(handshakeTimer);\n\t\t\t\tdebug(\"handshake started\");\n\t\t\t\tpostToIframe({\n\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\tid,\n\t\t\t\t\tresult: {\n\t\t\t\t\t\tprotocolVersion: data.params?.protocolVersion ?? PROTOCOL_VERSION,\n\t\t\t\t\t\thostInfo: { name: \"WaniWani Chat\", version: \"1.0.0\" },\n\t\t\t\t\t\thostCapabilities: {\n\t\t\t\t\t\t\topenLinks: {},\n\t\t\t\t\t\t\tmessage: {},\n\t\t\t\t\t\t},\n\t\t\t\t\t\thostContext: {\n\t\t\t\t\t\t\ttheme: isDarkRef.current ? \"dark\" : \"light\",\n\t\t\t\t\t\t\tdisplayMode: \"inline\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/notifications/initialized — widget confirms init, we send tool data\n\t\t\tif (method === \"ui/notifications/initialized\") {\n\t\t\t\tdebug(\"handshake complete, sending tool data\");\n\t\t\t\tinitializedRef.current = true;\n\t\t\t\tconst input = toolInputRef.current;\n\t\t\t\tconst result = toolResultRef.current;\n\n\t\t\t\tpostToIframe({\n\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\tmethod: \"ui/notifications/tool-input\",\n\t\t\t\t\tparams: { arguments: input },\n\t\t\t\t});\n\n\t\t\t\tconst content = result.content ?? [\n\t\t\t\t\t{ type: \"text\", text: JSON.stringify(result) },\n\t\t\t\t];\n\t\t\t\tpostToIframe({\n\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\tmethod: \"ui/notifications/tool-result\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\tstructuredContent: result.structuredContent,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/notifications/size-changed — widget reports content size\n\t\t\tif (method === \"ui/notifications/size-changed\") {\n\t\t\t\tconst params = data.params;\n\t\t\t\tconst newHeight =\n\t\t\t\t\ttypeof params?.height === \"number\" ? params.height : undefined;\n\t\t\t\tconst newWidth =\n\t\t\t\t\ttypeof params?.width === \"number\" ? params.width : undefined;\n\n\t\t\t\t// Deduplicate — only update if values actually changed (prevents feedback loops)\n\t\t\t\tconst last = lastSizeRef.current;\n\t\t\t\tconst heightChanged =\n\t\t\t\t\tnewHeight !== undefined && newHeight !== last.height;\n\t\t\t\tconst widthChanged = newWidth !== undefined && newWidth !== last.width;\n\n\t\t\t\tdebug(\"size-changed\", {\n\t\t\t\t\tnewHeight,\n\t\t\t\t\tnewWidth,\n\t\t\t\t\tlastHeight: last.height,\n\t\t\t\t\tlastWidth: last.width,\n\t\t\t\t\theightChanged,\n\t\t\t\t\twidthChanged,\n\t\t\t\t});\n\n\t\t\t\tif (!heightChanged && !widthChanged) return;\n\n\t\t\t\tif (heightChanged && newHeight !== undefined) {\n\t\t\t\t\tlast.height = newHeight;\n\t\t\t\t\tconst clamped = clampHeight(newHeight);\n\n\t\t\t\t\t// Get current visual height before canceling the old animation\n\t\t\t\t\tconst from = iframe.getBoundingClientRect().height;\n\n\t\t\t\t\t// Cancel previous animation so its fill: \"forwards\" stops overriding inline style\n\t\t\t\t\tif (animationRef.current) {\n\t\t\t\t\t\tanimationRef.current.cancel();\n\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the target height in React state (takes effect once no animation overrides it)\n\t\t\t\t\tsetHeight(clamped);\n\n\t\t\t\t\t// Animate the height transition\n\t\t\t\t\tif (iframe.animate && Math.abs(from - clamped) > 2) {\n\t\t\t\t\t\tconst anim = iframe.animate(\n\t\t\t\t\t\t\t[{ height: `${from}px` }, { height: `${clamped}px` }],\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tduration: RESIZE_ANIMATION_MS,\n\t\t\t\t\t\t\t\teasing: \"ease-out\",\n\t\t\t\t\t\t\t\tfill: \"forwards\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tanimationRef.current = anim;\n\t\t\t\t\t\t// Once done, remove the animation so the inline style is the source of truth\n\t\t\t\t\t\tanim.onfinish = () => {\n\t\t\t\t\t\t\tif (animationRef.current === anim) {\n\t\t\t\t\t\t\t\tanim.cancel();\n\t\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (widthChanged && autoHeight && newWidth !== undefined) {\n\t\t\t\t\tlast.width = newWidth;\n\t\t\t\t\tsetWidth(newWidth);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/open-link — widget requests to open a URL\n\t\t\tif (method === \"ui/open-link\" && id != null) {\n\t\t\t\tconst url = data.params?.url;\n\t\t\t\tif (typeof url === \"string\") {\n\t\t\t\t\tif (onOpenLinkRef.current) {\n\t\t\t\t\t\tonOpenLinkRef.current(url);\n\t\t\t\t\t} else {\n\t\t\t\t\t\twindow.open(url, \"_blank\", \"noopener,noreferrer\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/message — widget sends a chat message\n\t\t\tif (method === \"ui/message\" && id != null) {\n\t\t\t\tif (onFollowUpRef.current && data.params) {\n\t\t\t\t\tonFollowUpRef.current(data.params);\n\t\t\t\t}\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/request-display-mode — widget requests fullscreen/inline/pip\n\t\t\tif (method === \"ui/request-display-mode\" && id != null) {\n\t\t\t\t// Acknowledge but stay inline for now\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/resource-teardown — graceful shutdown\n\t\t\tif (method === \"ui/resource-teardown\" && id != null) {\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ping — keep-alive\n\t\t\tif (method === \"ping\" && id != null) {\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t}\n\t\t};\n\n\t\twindow.addEventListener(\"message\", handleMessage);\n\n\t\treturn () => {\n\t\t\tdebug(\"effect cleanup (disposed)\");\n\t\t\tdisposed = true;\n\t\t\tclearTimeout(handshakeTimer);\n\t\t\twindow.removeEventListener(\"message\", handleMessage);\n\t\t};\n\t}, [autoHeight, clampHeight]);\n\n\treturn (\n\t\t<iframe\n\t\t\tref={iframeRef}\n\t\t\tsrc={iframeSrc}\n\t\t\tsandbox=\"allow-scripts allow-forms allow-same-origin\"\n\t\t\tclassName={cn(\"rounded-md border border-border\", className)}\n\t\t\tstyle={{\n\t\t\t\theight,\n\t\t\t\tminWidth: width ? `min(${width}px, 100%)` : undefined,\n\t\t\t\twidth: \"100%\",\n\t\t\t\tborder: \"none\",\n\t\t\t\tcolorScheme: \"auto\",\n\t\t\t}}\n\t\t\ttitle=\"MCP App\"\n\t\t/>\n\t);\n}\n","\"use client\";\n\nimport { Component, type ReactNode } from \"react\";\n\ninterface Props {\n\tchildren: ReactNode;\n}\n\ninterface State {\n\thasError: boolean;\n}\n\nexport class WidgetErrorBoundary extends Component<Props, State> {\n\tstate: State = { hasError: false };\n\n\tstatic getDerivedStateFromError(): State {\n\t\treturn { hasError: true };\n\t}\n\n\tcomponentDidCatch(error: Error) {\n\t\tconsole.warn(\"[WaniWani] Widget failed to render:\", error.message);\n\t}\n\n\trender() {\n\t\tif (this.state.hasError) {\n\t\t\treturn (\n\t\t\t\t<div className=\"flex items-center justify-between rounded-md border border-border bg-muted/50 px-4 py-3 text-sm text-muted-foreground\">\n\t\t\t\t\t<span>Widget failed to load</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tonClick={() => this.setState({ hasError: false })}\n\t\t\t\t\t\tclassName=\"text-xs font-medium text-primary hover:underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tRetry\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n","\"use client\";\n\nimport type { ChatStatus, ReasoningUIPart, ToolUIPart, UIMessage } from \"ai\";\n\nimport { Attachments } from \"../ai-elements/attachments\";\nimport { Loader } from \"../ai-elements/loader\";\nimport {\n\tMessage,\n\tMessageContent,\n\tMessageResponse,\n} from \"../ai-elements/message\";\nimport { Reasoning } from \"../ai-elements/reasoning\";\nimport {\n\tgetAutoHeight,\n\tgetResourceUri,\n\tTool,\n\tToolContent,\n\tToolHeader,\n\tToolInput,\n\tToolOutput,\n} from \"../ai-elements/tool\";\nimport { McpAppFrame } from \"./mcp-app-frame\";\nimport { WidgetErrorBoundary } from \"./widget-error-boundary\";\n\n/** Converts `get_price_estimate` or `compare-prices` → `Get price estimate` / `Compare prices` */\nfunction formatToolName(name: string): string {\n\treturn name.replace(/[-_]/g, \" \").replace(/^\\w/, (c) => c.toUpperCase());\n}\n\ninterface MessageListProps {\n\tmessages: UIMessage[];\n\tstatus: ChatStatus;\n\twelcomeMessage?: string;\n\tresourceEndpoint?: string;\n\tisDark?: boolean;\n\tonFollowUp?: (message: {\n\t\trole: string;\n\t\tcontent: Array<{ type: string; text?: string }>;\n\t}) => void;\n}\n\nexport function MessageList({\n\tmessages,\n\tstatus,\n\twelcomeMessage,\n\tresourceEndpoint,\n\tisDark,\n\tonFollowUp,\n}: MessageListProps) {\n\tconst isLoading = status === \"submitted\" || status === \"streaming\";\n\tconst lastMessage = messages[messages.length - 1];\n\tconst hasMessages = messages.length > 0;\n\tconst showLoaderBubble =\n\t\tisLoading && (!hasMessages || lastMessage.role === \"user\");\n\n\treturn (\n\t\t<>\n\t\t\t{welcomeMessage && (\n\t\t\t\t<Message from=\"assistant\">\n\t\t\t\t\t<MessageContent>\n\t\t\t\t\t\t<MessageResponse>{welcomeMessage}</MessageResponse>\n\t\t\t\t\t</MessageContent>\n\t\t\t\t</Message>\n\t\t\t)}\n\t\t\t{messages.map((message) => {\n\t\t\t\tconst textParts = message.parts.filter((p) => p.type === \"text\");\n\t\t\t\tconst reasoningParts = message.parts.filter(\n\t\t\t\t\t(p): p is ReasoningUIPart => p.type === \"reasoning\",\n\t\t\t\t);\n\t\t\t\tconst fileParts = message.parts.filter((p) => p.type === \"file\");\n\t\t\t\tconst toolParts = message.parts.filter(\n\t\t\t\t\t(\n\t\t\t\t\t\tp,\n\t\t\t\t\t): p is typeof p & {\n\t\t\t\t\t\ttoolCallId: string;\n\t\t\t\t\t\ttoolName: string;\n\t\t\t\t\t\tstate: ToolUIPart[\"state\"];\n\t\t\t\t\t\tinput: unknown;\n\t\t\t\t\t\ttitle?: string;\n\t\t\t\t\t} => \"toolCallId\" in p,\n\t\t\t\t);\n\t\t\t\tconst isLastAssistant =\n\t\t\t\t\tmessage === lastMessage && message.role === \"assistant\";\n\t\t\t\tconst hasTextContent = textParts.length > 0;\n\n\t\t\t\treturn (\n\t\t\t\t\t<Message from={message.role} key={message.id}>\n\t\t\t\t\t\t{reasoningParts.map((part, i) => (\n\t\t\t\t\t\t\t<Reasoning\n\t\t\t\t\t\t\t\tkey={`reasoning-${message.id}-${i}`}\n\t\t\t\t\t\t\t\ttext={part.text}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{toolParts.map((part) => {\n\t\t\t\t\t\t\tconst output = \"output\" in part ? part.output : undefined;\n\t\t\t\t\t\t\tconst resourceUri =\n\t\t\t\t\t\t\t\toutput !== undefined ? getResourceUri(output) : undefined;\n\t\t\t\t\t\t\tconst autoHeight =\n\t\t\t\t\t\t\t\toutput !== undefined ? getAutoHeight(output) : false;\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={part.toolCallId}>\n\t\t\t\t\t\t\t\t\t<Tool defaultOpen={part.state === \"output-available\"}>\n\t\t\t\t\t\t\t\t\t\t<ToolHeader\n\t\t\t\t\t\t\t\t\t\t\ttitle={part.title ?? formatToolName(part.toolName)}\n\t\t\t\t\t\t\t\t\t\t\tstate={part.state}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<ToolContent>\n\t\t\t\t\t\t\t\t\t\t\t<ToolInput input={part.input} />\n\t\t\t\t\t\t\t\t\t\t\t{output !== undefined && (\n\t\t\t\t\t\t\t\t\t\t\t\t<ToolOutput\n\t\t\t\t\t\t\t\t\t\t\t\t\toutput={output}\n\t\t\t\t\t\t\t\t\t\t\t\t\terrorText={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"errorText\" in part ? part.errorText : undefined\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ToolContent>\n\t\t\t\t\t\t\t\t\t</Tool>\n\t\t\t\t\t\t\t\t\t{resourceUri && output !== undefined && (\n\t\t\t\t\t\t\t\t\t\t<WidgetErrorBoundary>\n\t\t\t\t\t\t\t\t\t\t\t<McpAppFrame\n\t\t\t\t\t\t\t\t\t\t\t\tresourceUri={resourceUri}\n\t\t\t\t\t\t\t\t\t\t\t\ttoolInput={\n\t\t\t\t\t\t\t\t\t\t\t\t\t(part.input as Record<string, unknown>) ?? {}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\ttoolResult={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tcontent: (output as Record<string, unknown>)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.content as\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| Array<{ type: string; text?: string }>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\t\t\t\t\t\t\tstructuredContent: (output as Record<string, unknown>)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.structuredContent as\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| Record<string, unknown>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\tresourceEndpoint={resourceEndpoint}\n\t\t\t\t\t\t\t\t\t\t\t\tisDark={isDark}\n\t\t\t\t\t\t\t\t\t\t\t\tautoHeight={autoHeight}\n\t\t\t\t\t\t\t\t\t\t\t\tonFollowUp={onFollowUp}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t</WidgetErrorBoundary>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t\t<MessageContent>\n\t\t\t\t\t\t\t{fileParts.length > 0 && <Attachments files={fileParts} />}\n\t\t\t\t\t\t\t{hasTextContent\n\t\t\t\t\t\t\t\t? textParts.map((part, i) => (\n\t\t\t\t\t\t\t\t\t\t<MessageResponse key={`${message.id}-${i}`}>\n\t\t\t\t\t\t\t\t\t\t\t{part.type === \"text\" ? part.text : \"\"}\n\t\t\t\t\t\t\t\t\t\t</MessageResponse>\n\t\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t\t: isLastAssistant && isLoading && <Loader />}\n\t\t\t\t\t\t</MessageContent>\n\t\t\t\t\t</Message>\n\t\t\t\t);\n\t\t\t})}\n\t\t\t{showLoaderBubble && (\n\t\t\t\t<Message from=\"assistant\">\n\t\t\t\t\t<MessageContent>\n\t\t\t\t\t\t<Loader />\n\t\t\t\t\t</MessageContent>\n\t\t\t\t</Message>\n\t\t\t)}\n\t\t</>\n\t);\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface SuggestionsProps\n\textends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n\tsuggestions: string[];\n\tisLoading?: boolean;\n\tonSelect: (suggestion: string) => void;\n}\n\nexport function Suggestions({\n\tsuggestions,\n\tisLoading,\n\tonSelect,\n\tclassName,\n\t...props\n}: SuggestionsProps) {\n\tif (suggestions.length === 0 && !isLoading) return null;\n\n\treturn (\n\t\t<div className={cn(\"flex flex-wrap gap-2 px-3 py-2\", className)} {...props}>\n\t\t\t{isLoading\n\t\t\t\t? [0, 1, 2].map((i) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\tclassName=\"h-7 rounded-full bg-accent animate-pulse\"\n\t\t\t\t\t\t\tstyle={{ width: `${60 + i * 20}px` }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))\n\t\t\t\t: suggestions.map((suggestion, index) => (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tkey={suggestion}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={() => onSelect(suggestion)}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"rounded-full border border-border bg-background px-3 py-1 text-xs\",\n\t\t\t\t\t\t\t\t\"text-foreground hover:bg-accent hover:border-primary/30\",\n\t\t\t\t\t\t\t\t\"transition-all duration-200 ease-out cursor-pointer\",\n\t\t\t\t\t\t\t\t\"animate-[ww-fade-in_0.2s_ease-out_both]\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tstyle={{ animationDelay: `${index * 50}ms` }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{suggestion}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t))}\n\t\t</div>\n\t);\n}\n","\"use client\";\n\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { ChatBaseProps } from \"../@types\";\nimport type { PromptInputMessage } from \"../ai-elements/prompt-input\";\n\nexport function useChatEngine(props: ChatBaseProps) {\n\tconst {\n\t\tapi = \"https://app.waniwani.ai/api/chat\",\n\t\theaders: userHeaders,\n\t\tbody,\n\t\tonMessageSent,\n\t\tonResponseReceived,\n\t} = props;\n\n\tconst transportRef = useRef(\n\t\tnew DefaultChatTransport({\n\t\t\tapi,\n\t\t\theaders: {\n\t\t\t\t...userHeaders,\n\t\t\t},\n\t\t\tbody,\n\t\t}),\n\t);\n\n\tconst { messages, sendMessage, status } = useChat({\n\t\ttransport: transportRef.current,\n\t\tonFinish() {\n\t\t\tonResponseReceived?.();\n\t\t},\n\t\tonError(error) {\n\t\t\tconsole.warn(\"[WaniWani] Chat error:\", error.message);\n\t\t},\n\t});\n\n\tconst [text, setText] = useState(\"\");\n\n\tconst handleSubmit = useCallback(\n\t\t(message: PromptInputMessage) => {\n\t\t\tconst hasText = Boolean(message.text?.trim());\n\t\t\tconst hasFiles = Boolean(message.files?.length);\n\t\t\tif (!(hasText || hasFiles)) return;\n\n\t\t\tsendMessage({\n\t\t\t\ttext: message.text || \"\",\n\t\t\t\tfiles: message.files,\n\t\t\t});\n\n\t\t\tonMessageSent?.(message.text || \"\");\n\t\t\tsetText(\"\");\n\t\t},\n\t\t[sendMessage, onMessageSent],\n\t);\n\n\tconst handleTextChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\t\tsetText(e.target.value);\n\t\t},\n\t\t[],\n\t);\n\n\tconst isLoading = status === \"submitted\" || status === \"streaming\";\n\tconst lastMessage = messages[messages.length - 1];\n\tconst hasMessages = messages.length > 0;\n\tconst showLoaderBubble =\n\t\tisLoading && (!hasMessages || lastMessage.role === \"user\");\n\n\treturn {\n\t\tmessages,\n\t\tstatus,\n\t\ttext,\n\t\tsetText,\n\t\thandleSubmit,\n\t\thandleTextChange,\n\t\tisLoading,\n\t\tshowLoaderBubble,\n\t\tlastMessage,\n\t\thasMessages,\n\t\tsendMessage,\n\t};\n}\n","\"use client\";\n\nimport type { ChatStatus, UIMessage } from \"ai\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { SuggestionsConfig } from \"../@types\";\n\nexport interface UseSuggestionsOptions {\n\tmessages: UIMessage[];\n\tstatus: ChatStatus;\n\tconfig?: boolean | SuggestionsConfig;\n}\n\n/**\n * Extract suggestions from the last assistant message's data part.\n * The API streams a `data-suggestions` part at the end of the response:\n * `{ type: \"data-suggestions\", data: { suggestions: string[] } }`\n */\nfunction extractSuggestions(message: UIMessage): string[] | null {\n\tfor (const part of message.parts) {\n\t\tconst p = part as Record<string, unknown>;\n\t\t// Handle both \"data-suggestions\" and generic \"data\" part types\n\t\tif (p.type === \"data\" || p.type === \"data-suggestions\") {\n\t\t\tconst data = p.data as Record<string, unknown> | undefined;\n\t\t\tif (data && Array.isArray(data.suggestions)) {\n\t\t\t\treturn data.suggestions as string[];\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction isConfigObject(\n\tconfig: boolean | SuggestionsConfig | undefined,\n): config is SuggestionsConfig {\n\treturn typeof config === \"object\" && config !== null && \"initial\" in config;\n}\n\nexport function useSuggestions(options: UseSuggestionsOptions) {\n\tconst { messages, status, config } = options;\n\n\tconst [suggestions, setSuggestions] = useState<string[]>(\n\t\t(isConfigObject(config) && config.initial ? config.initial : []) ?? [],\n\t);\n\tconst prevStatusRef = useRef<ChatStatus>(status);\n\n\tconst isEnabled = Boolean(config);\n\n\tconst clear = useCallback(() => {\n\t\tsetSuggestions([]);\n\t}, []);\n\n\t// Clear when a new user message arrives\n\tconst lastMessage = messages[messages.length - 1];\n\tuseEffect(() => {\n\t\tif (lastMessage?.role === \"user\") {\n\t\t\tclear();\n\t\t}\n\t}, [lastMessage, clear]);\n\n\t// Extract suggestions from message parts on streaming → ready transition\n\tuseEffect(() => {\n\t\tconst prevStatus = prevStatusRef.current;\n\t\tprevStatusRef.current = status;\n\n\t\tif (prevStatus === \"streaming\" && status === \"ready\" && isEnabled) {\n\t\t\tconst lastAssistant = [...messages]\n\t\t\t\t.reverse()\n\t\t\t\t.find((m) => m.role === \"assistant\");\n\t\t\tif (!lastAssistant) return;\n\n\t\t\tconsole.log(\"[WaniWani] Assistant parts:\", lastAssistant.parts);\n\n\t\t\tconst extracted = extractSuggestions(lastAssistant);\n\t\t\tconsole.log(\"[WaniWani] Extracted suggestions:\", extracted);\n\t\t\tif (extracted) {\n\t\t\t\tsetSuggestions(extracted);\n\t\t\t}\n\t\t}\n\t}, [status, isEnabled, messages]);\n\n\treturn { suggestions, isLoading: false, clear };\n}\n","import { useEffect, useRef, useState } from \"react\";\n\nconst TYPE_SPEED_MS = 50;\nconst DELETE_SPEED_MS = 30;\nconst PAUSE_AFTER_TYPE_MS = 2000;\nconst PAUSE_AFTER_DELETE_MS = 500;\n\n/**\n * Returns a string that animates like someone typing and deleting the placeholder text.\n * Only animates when `active` is true (i.e. the input is empty).\n */\nexport function useTypingPlaceholder(text: string, active = true): string {\n\tconst [displayed, setDisplayed] = useState(\"\");\n\tconst timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\tuseEffect(() => {\n\t\tif (!active) {\n\t\t\t// Reset so the animation restarts fresh when re-activated\n\t\t\tsetDisplayed(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\tlet i = 0;\n\t\tlet deleting = false;\n\t\tlet disposed = false;\n\n\t\tconst tick = () => {\n\t\t\tif (disposed) return;\n\n\t\t\tif (!deleting) {\n\t\t\t\t// Typing forward\n\t\t\t\ti++;\n\t\t\t\tsetDisplayed(text.slice(0, i));\n\n\t\t\t\tif (i >= text.length) {\n\t\t\t\t\t// Finished typing — pause then start deleting\n\t\t\t\t\tdeleting = true;\n\t\t\t\t\ttimerRef.current = setTimeout(tick, PAUSE_AFTER_TYPE_MS);\n\t\t\t\t} else {\n\t\t\t\t\ttimerRef.current = setTimeout(tick, TYPE_SPEED_MS);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Deleting\n\t\t\t\ti--;\n\t\t\t\tsetDisplayed(text.slice(0, i));\n\n\t\t\t\tif (i <= 0) {\n\t\t\t\t\t// Finished deleting — pause then start typing again\n\t\t\t\t\tdeleting = false;\n\t\t\t\t\ttimerRef.current = setTimeout(tick, PAUSE_AFTER_DELETE_MS);\n\t\t\t\t} else {\n\t\t\t\t\ttimerRef.current = setTimeout(tick, DELETE_SPEED_MS);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Start after a small delay\n\t\ttimerRef.current = setTimeout(tick, PAUSE_AFTER_DELETE_MS);\n\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tclearTimeout(timerRef.current);\n\t\t};\n\t}, [text, active]);\n\n\treturn displayed;\n}\n","import type { ChatTheme } from \"./@types\";\n\nexport const DEFAULT_THEME: Required<ChatTheme> = {\n\tprimaryColor: \"#6366f1\",\n\tprimaryForeground: \"#1f2937\",\n\tbackgroundColor: \"#ffffff\",\n\ttextColor: \"#1f2937\",\n\tmutedColor: \"#6b7280\",\n\tborderColor: \"#e5e7eb\",\n\tassistantBubbleColor: \"#f3f4f6\",\n\tuserBubbleColor: \"#f4f4f4\",\n\tinputBackgroundColor: \"#f9fafb\",\n\tborderRadius: 16,\n\tmessageBorderRadius: 12,\n\tfontFamily: \"system-ui, -apple-system, 'Segoe UI', sans-serif\",\n\theaderBackgroundColor: \"#ffffff\",\n\theaderTextColor: \"#1f2937\",\n\tstatusColor: \"#22c55e\",\n\ttoolCardColor: \"#f4f4f5\",\n};\n\nexport const DARK_THEME: ChatTheme = {\n\tbackgroundColor: \"#212121\",\n\theaderBackgroundColor: \"#1e1e1e\",\n\theaderTextColor: \"#ececec\",\n\ttextColor: \"#ececec\",\n\tprimaryForeground: \"#ffffff\",\n\tmutedColor: \"#8e8ea0\",\n\tborderColor: \"#303030\",\n\tassistantBubbleColor: \"#2f2f2f\",\n\tuserBubbleColor: \"#303030\",\n\tinputBackgroundColor: \"#2f2f2f\",\n\tprimaryColor: \"#6366f1\",\n\tstatusColor: \"#22c55e\",\n\ttoolCardColor: \"#262626\",\n};\n\nconst CSS_VAR_MAP: Record<keyof ChatTheme, string[]> = {\n\tprimaryColor: [\"--ww-primary\", \"--color-primary\"],\n\tprimaryForeground: [\"--ww-primary-fg\", \"--color-primary-foreground\"],\n\tbackgroundColor: [\"--ww-bg\", \"--color-background\"],\n\ttextColor: [\"--ww-text\", \"--color-foreground\", \"--color-accent-foreground\"],\n\tmutedColor: [\"--ww-muted\", \"--color-muted-foreground\"],\n\tborderColor: [\"--ww-border\", \"--color-border\"],\n\tassistantBubbleColor: [\"--ww-assistant-bubble\", \"--color-accent\"],\n\tuserBubbleColor: [\"--ww-user-bubble\"],\n\tinputBackgroundColor: [\"--ww-input-bg\", \"--color-input\"],\n\tborderRadius: [\"--ww-radius\", \"--radius\"],\n\tmessageBorderRadius: [\"--ww-msg-radius\"],\n\tfontFamily: [\"--ww-font\"],\n\theaderBackgroundColor: [\"--ww-header-bg\"],\n\theaderTextColor: [\"--ww-header-text\"],\n\tstatusColor: [\"--ww-status\"],\n\ttoolCardColor: [\"--ww-tool-card\", \"--color-tool-card\"],\n};\n\nexport function mergeTheme(userTheme?: ChatTheme): Required<ChatTheme> {\n\treturn { ...DEFAULT_THEME, ...userTheme };\n}\n\nexport function isDarkTheme(theme: Required<ChatTheme>): boolean {\n\tconst hex = theme.backgroundColor.replace(\"#\", \"\");\n\tconst r = parseInt(hex.substring(0, 2), 16);\n\tconst g = parseInt(hex.substring(2, 4), 16);\n\tconst b = parseInt(hex.substring(4, 6), 16);\n\treturn (r * 299 + g * 587 + b * 114) / 1000 < 128;\n}\n\nexport function themeToCSSProperties(\n\ttheme: Required<ChatTheme>,\n): Record<string, string> {\n\tconst vars: Record<string, string> = {};\n\tfor (const [key, cssVars] of Object.entries(CSS_VAR_MAP)) {\n\t\tconst value = theme[key as keyof ChatTheme];\n\t\tconst resolved = typeof value === \"number\" ? `${value}px` : String(value);\n\t\tfor (const cssVar of cssVars) {\n\t\t\tvars[cssVar] = resolved;\n\t\t}\n\t}\n\treturn vars;\n}\n","\"use client\";\n\nimport {\n\tforwardRef,\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport type { ChatCardProps, ChatHandle } from \"../@types\";\nimport {\n\tConversation,\n\tConversationContent,\n\tConversationScrollButton,\n} from \"../ai-elements/conversation\";\nimport {\n\tPromptInput,\n\tPromptInputAddAttachments,\n\tPromptInputSubmit,\n\tPromptInputTextarea,\n} from \"../ai-elements/prompt-input\";\nimport { MessageList } from \"../components/message-list\";\nimport { Suggestions } from \"../components/suggestions\";\nimport { useChatEngine } from \"../hooks/use-chat-engine\";\nimport { useSuggestions } from \"../hooks/use-suggestions\";\nimport { useTypingPlaceholder } from \"../hooks/use-typing-placeholder\";\nimport { cn } from \"../lib/utils\";\nimport { isDarkTheme, mergeTheme, themeToCSSProperties } from \"../theme\";\n\nexport const ChatCard = forwardRef<ChatHandle, ChatCardProps>(\n\tfunction ChatCard(props, ref) {\n\t\tconst {\n\t\t\ttheme: userTheme,\n\t\t\ttitle = \"Assistant\",\n\t\t\tsubtitle,\n\t\t\tshowStatus = true,\n\t\t\twidth = 500,\n\t\t\theight = 600,\n\t\t\tallowAttachments = false,\n\t\t\twelcomeMessage,\n\t\t\tplaceholder = \"Ask me anything...\",\n\t\t\ttriggerEvent = \"triggerDemoRequest\",\n\t\t\tresourceEndpoint,\n\t\t\tapi,\n\t\t} = props;\n\n\t\tconst effectiveResourceEndpoint =\n\t\t\tresourceEndpoint ?? (api ? `${api}/resource` : undefined);\n\n\t\tconst resolvedTheme = mergeTheme(userTheme);\n\t\tconst cssVars = themeToCSSProperties(resolvedTheme);\n\t\tconst isDark = isDarkTheme(resolvedTheme);\n\n\t\tconst engine = useChatEngine(props);\n\n\t\tconst animatedPlaceholder = useTypingPlaceholder(placeholder, !engine.text);\n\n\t\tconst [isHighlighted, setIsHighlighted] = useState(false);\n\t\tconst cardRef = useRef<HTMLDivElement>(null);\n\t\tconst highlightTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\t\tconst focusInput = useCallback(() => {\n\t\t\tconst container = cardRef.current;\n\t\t\tif (!container) return;\n\t\t\tcontainer.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\t\tconst textarea = container.querySelector(\"textarea\");\n\t\t\tif (textarea) {\n\t\t\t\tsetTimeout(() => textarea.focus(), 300);\n\t\t\t}\n\t\t\tsetIsHighlighted(true);\n\t\t\tclearTimeout(highlightTimerRef.current);\n\t\t\thighlightTimerRef.current = setTimeout(\n\t\t\t\t() => setIsHighlighted(false),\n\t\t\t\t2000,\n\t\t\t);\n\t\t}, []);\n\n\t\tconst suggestionsState = useSuggestions({\n\t\t\tmessages: engine.messages,\n\t\t\tstatus: engine.status,\n\t\t\tconfig: props.suggestions,\n\t\t});\n\n\t\tconst handleWidgetMessage = useCallback(\n\t\t\t(message: {\n\t\t\t\trole: string;\n\t\t\t\tcontent: Array<{ type: string; text?: string }>;\n\t\t\t}) => {\n\t\t\t\tconst text = message.content\n\t\t\t\t\t.map((c) => c.text ?? \"\")\n\t\t\t\t\t.join(\"\")\n\t\t\t\t\t.trim();\n\t\t\t\tif (text) engine.handleSubmit({ text, files: [] });\n\t\t\t},\n\t\t\t[engine.handleSubmit],\n\t\t);\n\n\t\tconst handleSuggestionSelect = useCallback(\n\t\t\t(suggestion: string) => {\n\t\t\t\tsuggestionsState.clear();\n\t\t\t\tengine.handleSubmit({ text: suggestion, files: [] });\n\t\t\t},\n\t\t\t[suggestionsState.clear, engine.handleSubmit],\n\t\t);\n\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tsendMessage: (text: string) => {\n\t\t\t\t\tengine.handleSubmit({ text, files: [] });\n\t\t\t\t\tfocusInput();\n\t\t\t\t},\n\t\t\t\tfocus: focusInput,\n\t\t\t}),\n\t\t\t[engine.handleSubmit, focusInput],\n\t\t);\n\n\t\t// Listen for custom trigger event (e.g. \"triggerDemoRequest\")\n\t\tuseEffect(() => {\n\t\t\tif (!triggerEvent) return;\n\t\t\tconst handler = (e: Event) => {\n\t\t\t\tconst detail = (e as CustomEvent).detail;\n\t\t\t\tconst message =\n\t\t\t\t\ttypeof detail?.message === \"string\" ? detail.message : undefined;\n\t\t\t\tif (message) {\n\t\t\t\t\tengine.handleSubmit({ text: message, files: [] });\n\t\t\t\t}\n\t\t\t\tfocusInput();\n\t\t\t};\n\t\t\twindow.addEventListener(triggerEvent, handler);\n\t\t\treturn () => window.removeEventListener(triggerEvent, handler);\n\t\t}, [triggerEvent, engine.handleSubmit, focusInput]);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={cardRef}\n\t\t\t\tstyle={{ ...cssVars, width, height }}\n\t\t\t\tdata-waniwani-chat=\"\"\n\t\t\t\tdata-waniwani-layout=\"card\"\n\t\t\t\t{...(isDark ? { \"data-waniwani-dark\": \"\" } : {})}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex flex-col font-[family-name:var(--ww-font)] text-foreground bg-background rounded-[var(--ww-radius)] border border-border shadow-md overflow-hidden transition-shadow duration-300\",\n\t\t\t\t\tisHighlighted &&\n\t\t\t\t\t\t\"ring-2 ring-blue-400/70 ring-offset-2 ring-offset-background\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{/* Header */}\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"shrink-0 flex items-center gap-3 px-4 py-2 border-b border-border\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackgroundColor: resolvedTheme.headerBackgroundColor,\n\t\t\t\t\t\tcolor: resolvedTheme.headerTextColor,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{showStatus && <span className=\"size-2.5 rounded-full bg-status\" />}\n\t\t\t\t\t<div className=\"flex-1 min-w-0\">\n\t\t\t\t\t\t<div className=\"text-xs font-semibold truncate\">{title}</div>\n\t\t\t\t\t\t{subtitle && (\n\t\t\t\t\t\t\t<div className=\"text-[11px] text-muted-foreground truncate\">\n\t\t\t\t\t\t\t\t{subtitle}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t{/* Messages */}\n\t\t\t\t<Conversation className=\"flex-1 min-h-0 bg-background\">\n\t\t\t\t\t<ConversationContent>\n\t\t\t\t\t\t<MessageList\n\t\t\t\t\t\t\tmessages={engine.messages}\n\t\t\t\t\t\t\tstatus={engine.status}\n\t\t\t\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\t\t\t\tresourceEndpoint={effectiveResourceEndpoint}\n\t\t\t\t\t\t\tisDark={isDark}\n\t\t\t\t\t\t\tonFollowUp={handleWidgetMessage}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</ConversationContent>\n\t\t\t\t\t<ConversationScrollButton />\n\t\t\t\t</Conversation>\n\n\t\t\t\t{/* Suggestions */}\n\t\t\t\t<Suggestions\n\t\t\t\t\tsuggestions={suggestionsState.suggestions}\n\t\t\t\t\tisLoading={suggestionsState.isLoading}\n\t\t\t\t\tonSelect={handleSuggestionSelect}\n\t\t\t\t\tclassName=\"border-t border-border\"\n\t\t\t\t/>\n\n\t\t\t\t{/* Input */}\n\t\t\t\t<div className=\"shrink-0 border-t border-border bg-background\">\n\t\t\t\t\t<PromptInput\n\t\t\t\t\t\tonSubmit={engine.handleSubmit}\n\t\t\t\t\t\tglobalDrop={allowAttachments}\n\t\t\t\t\t\tmultiple={allowAttachments}\n\t\t\t\t\t\tclassName={cn(\"rounded-none border-0\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"flex items-center gap-1 px-3 py-2\">\n\t\t\t\t\t\t\t{allowAttachments && <PromptInputAddAttachments />}\n\t\t\t\t\t\t\t<PromptInputTextarea\n\t\t\t\t\t\t\t\tonChange={engine.handleTextChange}\n\t\t\t\t\t\t\t\tvalue={engine.text}\n\t\t\t\t\t\t\t\tplaceholder={animatedPlaceholder}\n\t\t\t\t\t\t\t\tclassName=\"min-h-0 py-1.5 px-2\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<PromptInputSubmit status={engine.status} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</PromptInput>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t},\n);\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useRef","useState","ArrowDownIcon","useCallback","StickToBottom","useStickToBottomContext","clsx","twMerge","cn","inputs","jsx","Button","className","variant","size","type","props","cn","jsx","Conversation","className","props","StickToBottom","cn","ConversationContent","ConversationScrollButton","isAtBottom","scrollToBottom","useStickToBottomContext","handleScrollToBottom","useCallback","Button","ArrowDownIcon","ArrowUpIcon","LoaderIcon","PaperclipIcon","SquareIcon","XIcon","nanoid","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","jsx","jsxs","convertBlobUrlToDataUrl","url","blob","resolve","reader","LocalAttachmentsContext","createContext","usePromptInputAttachments","context","useContext","PromptInput","className","accept","multiple","globalDrop","maxFiles","maxFileSize","onSubmit","children","props","inputRef","useRef","formRef","items","setItems","useState","filesRef","useEffect","openFileDialog","useCallback","add","fileList","incoming","withinSize","f","valid","prev","capacity","capped","file","nanoid","remove","id","found","clear","handleChange","event","onDragOver","e","onDrop","handleSubmit","form","text","convertedFiles","_id","item","dataUrl","result","attachmentsCtx","useMemo","cn","PromptInputTextarea","onChange","onKeyDown","className","placeholder","props","attachments","usePromptInputAttachments","isComposing","setIsComposing","useState","handleKeyDown","useCallback","e","form","lastAttachment","handlePaste","event","items","files","item","file","jsx","cn","PromptInputSubmit","status","onStop","onClick","children","isGenerating","Icon","ArrowUpIcon","LoaderIcon","SquareIcon","handleClick","Button","PromptInputAddAttachments","jsxs","XIcon","PaperclipIcon","FileIcon","jsx","jsxs","Attachments","files","className","props","cn","file","i","AttachmentItem","FileIcon","jsx","Loader","className","size","props","cn","i","cjk","code","memo","Streamdown","jsx","Message","className","from","props","cn","MessageContent","children","streamdownPlugins","cjk","code","MessageResponse","memo","Streamdown","prevProps","nextProps","jsx","Reasoning","className","text","props","cn","BracesIcon","CheckIcon","ChevronDownIcon","ChevronRightIcon","ClipboardCopyIcon","ServerIcon","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","truncateJSON","data","maxLength","stringified","entries","parts","remaining","key","value","keyAbbrev","valStr","part","CopyButton","text","className","copied","setCopied","useState","timeoutRef","useRef","useEffect","handleCopy","useCallback","e","Button","cn","CheckIcon","ClipboardCopyIcon","CollapsibleJSON","label","props","expanded","setExpanded","fullJSON","useMemo","preview","v","ChevronRightIcon","ToolOpenContext","createContext","Tool","defaultOpen","children","open","setOpen","o","ToolHeader","title","state","toggle","useContext","isRunning","BracesIcon","ChevronDownIcon","ToolContent","className","children","props","open","useContext","ToolOpenContext","jsx","cn","ToolInput","input","CollapsibleJSON","getUiMeta","output","meta","ui","getResourceUri","uri","getAutoHeight","ToolOutput","errorText","jsxs","useCallback","useEffect","useMemo","useRef","useState","jsx","DEFAULT_RESOURCE_ENDPOINT","MAX_HEIGHT","DEFAULT_HEIGHT","PROTOCOL_VERSION","RESIZE_ANIMATION_MS","HANDSHAKE_TIMEOUT_MS","MAX_RETRIES","McpAppFrame","resourceUri","toolInput","toolResult","resourceEndpoint","isDark","className","autoHeight","onOpenLink","onFollowUp","iframeRef","useRef","toolInputRef","toolResultRef","lastSizeRef","animationRef","initializedRef","retryCountRef","height","setHeight","useState","width","setWidth","onOpenLinkRef","onFollowUpRef","clampHeight","useCallback","iframeSrc","useMemo","isDarkRef","useEffect","iframe","disposed","handshakeReceived","debug","args","handshakeTimer","url","postToIframe","msg","handleMessage","event","data","method","id","input","result","content","params","newHeight","newWidth","last","heightChanged","widthChanged","clamped","from","anim","cn","Component","jsx","jsxs","WidgetErrorBoundary","error","Fragment","jsx","jsxs","formatToolName","name","c","MessageList","messages","status","welcomeMessage","resourceEndpoint","isDark","onFollowUp","isLoading","lastMessage","hasMessages","showLoaderBubble","Message","MessageContent","MessageResponse","message","textParts","p","reasoningParts","fileParts","toolParts","isLastAssistant","hasTextContent","part","i","Reasoning","output","resourceUri","getResourceUri","autoHeight","getAutoHeight","Tool","ToolHeader","ToolContent","ToolInput","ToolOutput","WidgetErrorBoundary","McpAppFrame","Attachments","Loader","jsx","Suggestions","suggestions","isLoading","onSelect","className","props","cn","i","suggestion","index","useChat","DefaultChatTransport","useCallback","useRef","useState","useChatEngine","props","api","userHeaders","body","onMessageSent","onResponseReceived","transportRef","messages","sendMessage","status","error","text","setText","handleSubmit","message","hasText","hasFiles","handleTextChange","e","isLoading","lastMessage","hasMessages","showLoaderBubble","useCallback","useEffect","useRef","useState","extractSuggestions","message","part","p","data","isConfigObject","config","useSuggestions","options","messages","status","suggestions","setSuggestions","prevStatusRef","isEnabled","clear","lastMessage","prevStatus","lastAssistant","m","extracted","useEffect","useRef","useState","TYPE_SPEED_MS","DELETE_SPEED_MS","PAUSE_AFTER_TYPE_MS","PAUSE_AFTER_DELETE_MS","useTypingPlaceholder","text","active","displayed","setDisplayed","timerRef","i","deleting","disposed","tick","DEFAULT_THEME","DARK_THEME","CSS_VAR_MAP","mergeTheme","userTheme","isDarkTheme","theme","hex","r","g","b","themeToCSSProperties","vars","key","cssVars","value","resolved","cssVar","jsx","jsxs","ChatBar","forwardRef","props","ref","userTheme","width","expandedHeight","allowAttachments","welcomeMessage","placeholder","triggerEvent","resourceEndpoint","api","effectiveResourceEndpoint","resolvedTheme","mergeTheme","cssVars","themeToCSSProperties","isDark","isDarkTheme","engine","useChatEngine","suggestionsState","useSuggestions","handleWidgetMessage","useCallback","message","text","c","handleSuggestionSelect","suggestion","animatedPlaceholder","useTypingPlaceholder","isFocused","setIsFocused","useState","isHighlighted","setIsHighlighted","containerRef","useRef","highlightTimerRef","focusInput","container","textarea","useImperativeHandle","useEffect","handler","e","detail","isExpanded","handleClickOutside","handleFocus","cn","Conversation","ConversationContent","MessageList","ConversationScrollButton","Suggestions","PromptInput","PromptInputAddAttachments","PromptInputTextarea","PromptInputSubmit","forwardRef","useCallback","useEffect","useImperativeHandle","useRef","useState","jsx","jsxs","ChatCard","forwardRef","props","ref","userTheme","title","subtitle","showStatus","width","height","allowAttachments","welcomeMessage","placeholder","triggerEvent","resourceEndpoint","api","effectiveResourceEndpoint","resolvedTheme","mergeTheme","cssVars","themeToCSSProperties","isDark","isDarkTheme","engine","useChatEngine","animatedPlaceholder","useTypingPlaceholder","isHighlighted","setIsHighlighted","useState","cardRef","useRef","highlightTimerRef","focusInput","useCallback","container","textarea","suggestionsState","useSuggestions","handleWidgetMessage","message","text","c","handleSuggestionSelect","suggestion","useImperativeHandle","useEffect","handler","e","detail","cn","Conversation","ConversationContent","MessageList","ConversationScrollButton","Suggestions","PromptInput","PromptInputAddAttachments","PromptInputTextarea","PromptInputSubmit"]}
1
+ {"version":3,"sources":["../../src/chat/web/layouts/chat-bar.tsx","../../src/chat/web/ai-elements/conversation.tsx","../../src/chat/web/lib/utils.ts","../../src/chat/web/ui/button.tsx","../../src/chat/web/ai-elements/prompt-input.tsx","../../src/chat/web/ai-elements/attachments.tsx","../../src/chat/web/ai-elements/loader.tsx","../../src/chat/web/ai-elements/message.tsx","../../src/chat/web/ai-elements/reasoning.tsx","../../src/chat/web/ai-elements/tool.tsx","../../src/chat/web/components/mcp-app-frame.tsx","../../src/chat/web/components/widget-error-boundary.tsx","../../src/chat/web/components/message-list.tsx","../../src/chat/web/components/suggestions.tsx","../../src/chat/web/hooks/use-chat-engine.ts","../../src/chat/web/hooks/use-suggestions.ts","../../src/chat/web/hooks/use-typing-placeholder.ts","../../src/chat/web/theme.ts","../../src/chat/web/layouts/chat-card.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n\tforwardRef,\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport type { ChatBarProps, ChatHandle } from \"../@types\";\nimport {\n\tConversation,\n\tConversationContent,\n\tConversationScrollButton,\n} from \"../ai-elements/conversation\";\nimport {\n\tPromptInput,\n\tPromptInputAddAttachments,\n\tPromptInputSubmit,\n\tPromptInputTextarea,\n} from \"../ai-elements/prompt-input\";\nimport { MessageList } from \"../components/message-list\";\nimport { Suggestions } from \"../components/suggestions\";\nimport { useChatEngine } from \"../hooks/use-chat-engine\";\nimport { useSuggestions } from \"../hooks/use-suggestions\";\nimport { useTypingPlaceholder } from \"../hooks/use-typing-placeholder\";\nimport { cn } from \"../lib/utils\";\nimport { isDarkTheme, mergeTheme, themeToCSSProperties } from \"../theme\";\n\nexport const ChatBar = forwardRef<ChatHandle, ChatBarProps>(\n\tfunction ChatBar(props, ref) {\n\t\tconst {\n\t\t\ttheme: userTheme,\n\t\t\twidth = 600,\n\t\t\texpandedHeight = 400,\n\t\t\tallowAttachments = false,\n\t\t\twelcomeMessage,\n\t\t\tplaceholder = \"Ask me anything...\",\n\t\t\ttriggerEvent = \"triggerDemoRequest\",\n\t\t\tresourceEndpoint,\n\t\t\tapi,\n\t\t} = props;\n\n\t\tconst effectiveResourceEndpoint =\n\t\t\tresourceEndpoint ?? (api ? `${api}/resource` : undefined);\n\n\t\tconst resolvedTheme = mergeTheme(userTheme);\n\t\tconst cssVars = themeToCSSProperties(resolvedTheme);\n\t\tconst isDark = isDarkTheme(resolvedTheme);\n\n\t\tconst engine = useChatEngine(props);\n\n\t\tconst suggestionsState = useSuggestions({\n\t\t\tmessages: engine.messages,\n\t\t\tstatus: engine.status,\n\t\t\tconfig: props.suggestions,\n\t\t});\n\n\t\tconst handleWidgetMessage = useCallback(\n\t\t\t(message: {\n\t\t\t\trole: string;\n\t\t\t\tcontent: Array<{ type: string; text?: string }>;\n\t\t\t}) => {\n\t\t\t\tconst text = message.content\n\t\t\t\t\t.map((c) => c.text ?? \"\")\n\t\t\t\t\t.join(\"\")\n\t\t\t\t\t.trim();\n\t\t\t\tif (text) engine.handleSubmit({ text, files: [] });\n\t\t\t},\n\t\t\t[engine.handleSubmit],\n\t\t);\n\n\t\tconst handleSuggestionSelect = useCallback(\n\t\t\t(suggestion: string) => {\n\t\t\t\tsuggestionsState.clear();\n\t\t\t\tengine.handleSubmit({ text: suggestion, files: [] });\n\t\t\t},\n\t\t\t[suggestionsState.clear, engine.handleSubmit],\n\t\t);\n\n\t\tconst animatedPlaceholder = useTypingPlaceholder(placeholder, !engine.text);\n\n\t\tconst [isFocused, setIsFocused] = useState(false);\n\t\tconst [isHighlighted, setIsHighlighted] = useState(false);\n\t\tconst containerRef = useRef<HTMLDivElement>(null);\n\t\tconst highlightTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\t\tconst focusInput = useCallback(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tif (!container) return;\n\t\t\tcontainer.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\t\tconst textarea = container.querySelector(\"textarea\");\n\t\t\tif (textarea) {\n\t\t\t\tsetTimeout(() => textarea.focus(), 300);\n\t\t\t}\n\t\t\tsetIsFocused(true);\n\t\t\tsetIsHighlighted(true);\n\t\t\tclearTimeout(highlightTimerRef.current);\n\t\t\thighlightTimerRef.current = setTimeout(\n\t\t\t\t() => setIsHighlighted(false),\n\t\t\t\t2000,\n\t\t\t);\n\t\t}, []);\n\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tsendMessage: (text: string) => {\n\t\t\t\t\tengine.handleSubmit({ text, files: [] });\n\t\t\t\t\tfocusInput();\n\t\t\t\t},\n\t\t\t\tfocus: focusInput,\n\t\t\t}),\n\t\t\t[engine.handleSubmit, focusInput],\n\t\t);\n\n\t\t// Listen for custom trigger event (e.g. \"triggerDemoRequest\")\n\t\tuseEffect(() => {\n\t\t\tif (!triggerEvent) return;\n\t\t\tconst handler = (e: Event) => {\n\t\t\t\tconst detail = (e as CustomEvent).detail;\n\t\t\t\tconst message =\n\t\t\t\t\ttypeof detail?.message === \"string\" ? detail.message : undefined;\n\t\t\t\tif (message) {\n\t\t\t\t\tengine.handleSubmit({ text: message, files: [] });\n\t\t\t\t}\n\t\t\t\tfocusInput();\n\t\t\t};\n\t\t\twindow.addEventListener(triggerEvent, handler);\n\t\t\treturn () => window.removeEventListener(triggerEvent, handler);\n\t\t}, [triggerEvent, engine.handleSubmit, focusInput]);\n\t\tconst isExpanded = isFocused;\n\n\t\t// Close on outside click\n\t\tuseEffect(() => {\n\t\t\tif (!isFocused) return;\n\t\t\tconst handleClickOutside = (e: MouseEvent) => {\n\t\t\t\tif (\n\t\t\t\t\tcontainerRef.current &&\n\t\t\t\t\t!containerRef.current.contains(e.target as Node)\n\t\t\t\t) {\n\t\t\t\t\tsetIsFocused(false);\n\t\t\t\t}\n\t\t\t};\n\t\t\tdocument.addEventListener(\"mousedown\", handleClickOutside);\n\t\t\treturn () =>\n\t\t\t\tdocument.removeEventListener(\"mousedown\", handleClickOutside);\n\t\t}, [isFocused]);\n\n\t\tconst handleFocus = useCallback(() => {\n\t\t\tsetIsFocused(true);\n\t\t}, []);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tstyle={{ ...cssVars, width }}\n\t\t\t\tdata-waniwani-chat=\"\"\n\t\t\t\tdata-waniwani-layout=\"bar\"\n\t\t\t\t{...(isDark ? { \"data-waniwani-dark\": \"\" } : {})}\n\t\t\t\tclassName=\"ww:flex ww:flex-col ww:font-[family-name:var(--ww-font)] ww:text-foreground\"\n\t\t\t>\n\t\t\t\t{/* Messages panel — fades up on expand */}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"ww:overflow-hidden ww:bg-background/80 ww:backdrop-blur-xl ww:transition-all ww:duration-300 ww:ease-out\",\n\t\t\t\t\t\tisExpanded\n\t\t\t\t\t\t\t? \"ww:opacity-100 ww:translate-y-0\"\n\t\t\t\t\t\t\t: \"ww:opacity-0 ww:translate-y-2 ww:pointer-events-none ww:max-h-0\",\n\t\t\t\t\t)}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\t...(isExpanded ? { maxHeight: expandedHeight } : undefined),\n\t\t\t\t\t\tmaskImage:\n\t\t\t\t\t\t\t\"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)\",\n\t\t\t\t\t\tmaskComposite: \"intersect\",\n\t\t\t\t\t\tWebkitMaskImage:\n\t\t\t\t\t\t\t\"linear-gradient(to bottom, transparent, black 24px, black calc(100% - 16px), transparent), linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)\",\n\t\t\t\t\t\tWebkitMaskComposite: \"source-in\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Conversation\n\t\t\t\t\t\tclassName=\"ww:flex-1\"\n\t\t\t\t\t\tstyle={{ height: expandedHeight }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ConversationContent>\n\t\t\t\t\t\t\t<MessageList\n\t\t\t\t\t\t\t\tmessages={engine.messages}\n\t\t\t\t\t\t\t\tstatus={engine.status}\n\t\t\t\t\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\t\t\t\t\tresourceEndpoint={effectiveResourceEndpoint}\n\t\t\t\t\t\t\t\tisDark={isDark}\n\t\t\t\t\t\t\t\tonFollowUp={handleWidgetMessage}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</ConversationContent>\n\t\t\t\t\t\t<ConversationScrollButton />\n\t\t\t\t\t</Conversation>\n\t\t\t\t</div>\n\n\t\t\t\t{/* Suggestions */}\n\t\t\t\t<Suggestions\n\t\t\t\t\tsuggestions={suggestionsState.suggestions}\n\t\t\t\t\tisLoading={suggestionsState.isLoading}\n\t\t\t\t\tonSelect={handleSuggestionSelect}\n\t\t\t\t/>\n\n\t\t\t\t{/* Input bar — always visible */}\n\t\t\t\t<div className=\"ww:shrink-0\">\n\t\t\t\t\t<PromptInput\n\t\t\t\t\t\tonSubmit={engine.handleSubmit}\n\t\t\t\t\t\tglobalDrop={allowAttachments}\n\t\t\t\t\t\tmultiple={allowAttachments}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"ww:rounded-[var(--ww-radius)] ww:shadow-sm ww:transition-all ww:duration-300 ww:ease-out\",\n\t\t\t\t\t\t\tisHighlighted &&\n\t\t\t\t\t\t\t\t\"ww:ring-2 ww:ring-blue-400/70 ww:ring-offset-2 ww:ring-offset-background\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"ww:flex ww:items-center ww:gap-1 ww:px-3 ww:py-2\">\n\t\t\t\t\t\t\t{allowAttachments && <PromptInputAddAttachments />}\n\t\t\t\t\t\t\t<PromptInputTextarea\n\t\t\t\t\t\t\t\tonChange={engine.handleTextChange}\n\t\t\t\t\t\t\t\tvalue={engine.text}\n\t\t\t\t\t\t\t\tplaceholder={animatedPlaceholder}\n\t\t\t\t\t\t\t\tonFocus={handleFocus}\n\t\t\t\t\t\t\t\tclassName=\"ww:min-h-0 ww:py-1.5 ww:px-2\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<PromptInputSubmit status={engine.status} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</PromptInput>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t},\n);\n","\"use client\";\n\nimport { ArrowDownIcon } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { useCallback } from \"react\";\nimport { StickToBottom, useStickToBottomContext } from \"use-stick-to-bottom\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\n\nexport type ConversationProps = ComponentProps<typeof StickToBottom>;\n\nexport const Conversation = ({ className, ...props }: ConversationProps) => (\n\t<StickToBottom\n\t\tclassName={cn(\"ww:relative ww:flex-1 ww:overflow-y-hidden\", className)}\n\t\tinitial=\"smooth\"\n\t\tresize=\"smooth\"\n\t\trole=\"log\"\n\t\t{...props}\n\t/>\n);\n\nexport type ConversationContentProps = ComponentProps<\n\ttypeof StickToBottom.Content\n>;\n\nexport const ConversationContent = ({\n\tclassName,\n\t...props\n}: ConversationContentProps) => (\n\t<StickToBottom.Content\n\t\tclassName={cn(\"ww:flex ww:flex-col ww:gap-8 ww:p-4\", className)}\n\t\t{...props}\n\t/>\n);\n\nexport type ConversationScrollButtonProps = ComponentProps<typeof Button>;\n\nexport const ConversationScrollButton = ({\n\tclassName,\n\t...props\n}: ConversationScrollButtonProps) => {\n\tconst { isAtBottom, scrollToBottom } = useStickToBottomContext();\n\n\tconst handleScrollToBottom = useCallback(() => {\n\t\tscrollToBottom();\n\t}, [scrollToBottom]);\n\n\treturn (\n\t\t!isAtBottom && (\n\t\t\t<Button\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"ww:absolute ww:bottom-4 ww:left-[50%] ww:translate-x-[-50%] ww:rounded-full\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonClick={handleScrollToBottom}\n\t\t\t\tsize=\"icon\"\n\t\t\t\tvariant=\"outline\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<ArrowDownIcon className=\"ww:size-4\" />\n\t\t\t</Button>\n\t\t)\n\t);\n};\n","import { type ClassValue, clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({ prefix: \"ww\" });\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type ButtonProps = ComponentProps<\"button\"> & {\n\tvariant?: \"default\" | \"outline\" | \"ghost\";\n\tsize?: \"default\" | \"sm\" | \"icon\" | \"icon-sm\";\n};\n\nexport const Button = ({\n\tclassName,\n\tvariant = \"default\",\n\tsize = \"default\",\n\ttype = \"button\",\n\t...props\n}: ButtonProps) => (\n\t<button\n\t\ttype={type}\n\t\tclassName={cn(\n\t\t\t\"ww:inline-flex ww:cursor-pointer ww:items-center ww:justify-center ww:rounded-md ww:font-medium ww:transition-colors ww:disabled:pointer-events-none ww:disabled:opacity-50\",\n\t\t\tvariant === \"default\" &&\n\t\t\t\t\"ww:bg-primary ww:text-primary-foreground ww:hover:bg-primary/90\",\n\t\t\tvariant === \"outline\" &&\n\t\t\t\t\"ww:border ww:border-border ww:bg-background ww:hover:bg-accent ww:hover:text-accent-foreground\",\n\t\t\tvariant === \"ghost\" &&\n\t\t\t\t\"ww:hover:bg-accent ww:hover:text-accent-foreground\",\n\t\t\tsize === \"default\" && \"ww:h-9 ww:px-4 ww:py-2 ww:text-sm\",\n\t\t\tsize === \"sm\" && \"ww:h-8 ww:px-3 ww:text-xs\",\n\t\t\tsize === \"icon\" && \"ww:size-9\",\n\t\t\tsize === \"icon-sm\" && \"ww:size-7\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n","\"use client\";\n\nimport type { ChatStatus, FileUIPart } from \"ai\";\nimport {\n\tArrowUpIcon,\n\tLoaderIcon,\n\tPaperclipIcon,\n\tSquareIcon,\n\tXIcon,\n} from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport type {\n\tChangeEvent,\n\tClipboardEventHandler,\n\tComponentProps,\n\tFormEvent,\n\tFormEventHandler,\n\tHTMLAttributes,\n\tKeyboardEventHandler,\n} from \"react\";\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nconst convertBlobUrlToDataUrl = async (url: string): Promise<string | null> => {\n\ttry {\n\t\tconst response = await fetch(url);\n\t\tconst blob = await response.blob();\n\t\treturn new Promise((resolve) => {\n\t\t\tconst reader = new FileReader();\n\t\t\treader.onloadend = () => resolve(reader.result as string);\n\t\t\treader.onerror = () => resolve(null);\n\t\t\treader.readAsDataURL(blob);\n\t\t});\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n// ============================================================================\n// Attachments Context\n// ============================================================================\n\nexport interface AttachmentsContext {\n\tfiles: (FileUIPart & { id: string })[];\n\tadd: (files: File[] | FileList) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\topenFileDialog: () => void;\n}\n\nconst LocalAttachmentsContext = createContext<AttachmentsContext | null>(null);\n\nexport const usePromptInputAttachments = () => {\n\tconst context = useContext(LocalAttachmentsContext);\n\tif (!context) {\n\t\tthrow new Error(\n\t\t\t\"usePromptInputAttachments must be used within a PromptInput\",\n\t\t);\n\t}\n\treturn context;\n};\n\n// ============================================================================\n// PromptInput Message Type\n// ============================================================================\n\nexport interface PromptInputMessage {\n\ttext: string;\n\tfiles: FileUIPart[];\n}\n\n// ============================================================================\n// PromptInput\n// ============================================================================\n\nexport type PromptInputProps = Omit<\n\tHTMLAttributes<HTMLFormElement>,\n\t\"onSubmit\"\n> & {\n\taccept?: string;\n\tmultiple?: boolean;\n\tglobalDrop?: boolean;\n\tmaxFiles?: number;\n\tmaxFileSize?: number;\n\tonSubmit: (\n\t\tmessage: PromptInputMessage,\n\t\tevent: FormEvent<HTMLFormElement>,\n\t) => void | Promise<void>;\n};\n\nexport const PromptInput = ({\n\tclassName,\n\taccept,\n\tmultiple,\n\tglobalDrop,\n\tmaxFiles,\n\tmaxFileSize,\n\tonSubmit,\n\tchildren,\n\t...props\n}: PromptInputProps) => {\n\tconst inputRef = useRef<HTMLInputElement | null>(null);\n\tconst formRef = useRef<HTMLFormElement | null>(null);\n\tconst [items, setItems] = useState<(FileUIPart & { id: string })[]>([]);\n\tconst filesRef = useRef(items);\n\n\tuseEffect(() => {\n\t\tfilesRef.current = items;\n\t}, [items]);\n\n\tconst openFileDialog = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\tconst add = useCallback(\n\t\t(fileList: File[] | FileList) => {\n\t\t\tconst incoming = [...fileList];\n\t\t\tif (incoming.length === 0) return;\n\n\t\t\tconst withinSize = (f: File) =>\n\t\t\t\tmaxFileSize ? f.size <= maxFileSize : true;\n\t\t\tconst valid = incoming.filter(withinSize);\n\n\t\t\tsetItems((prev) => {\n\t\t\t\tconst capacity =\n\t\t\t\t\ttypeof maxFiles === \"number\"\n\t\t\t\t\t\t? Math.max(0, maxFiles - prev.length)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst capped =\n\t\t\t\t\ttypeof capacity === \"number\" ? valid.slice(0, capacity) : valid;\n\t\t\t\treturn [\n\t\t\t\t\t...prev,\n\t\t\t\t\t...capped.map((file) => ({\n\t\t\t\t\t\tfilename: file.name,\n\t\t\t\t\t\tid: nanoid(),\n\t\t\t\t\t\tmediaType: file.type,\n\t\t\t\t\t\ttype: \"file\" as const,\n\t\t\t\t\t\turl: URL.createObjectURL(file),\n\t\t\t\t\t})),\n\t\t\t\t];\n\t\t\t});\n\t\t},\n\t\t[maxFiles, maxFileSize],\n\t);\n\n\tconst remove = useCallback((id: string) => {\n\t\tsetItems((prev) => {\n\t\t\tconst found = prev.find((f) => f.id === id);\n\t\t\tif (found?.url) URL.revokeObjectURL(found.url);\n\t\t\treturn prev.filter((f) => f.id !== id);\n\t\t});\n\t}, []);\n\n\tconst clear = useCallback(() => {\n\t\tsetItems((prev) => {\n\t\t\tfor (const f of prev) {\n\t\t\t\tif (f.url) URL.revokeObjectURL(f.url);\n\t\t\t}\n\t\t\treturn [];\n\t\t});\n\t}, []);\n\n\t// Cleanup blob URLs on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tfor (const f of filesRef.current) {\n\t\t\t\tif (f.url) URL.revokeObjectURL(f.url);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst handleChange = useCallback(\n\t\t(event: ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (event.currentTarget.files) {\n\t\t\t\tadd(event.currentTarget.files);\n\t\t\t}\n\t\t\tevent.currentTarget.value = \"\";\n\t\t},\n\t\t[add],\n\t);\n\n\t// Global drop support\n\tuseEffect(() => {\n\t\tif (!globalDrop) return;\n\t\tconst onDragOver = (e: DragEvent) => {\n\t\t\tif (e.dataTransfer?.types?.includes(\"Files\")) e.preventDefault();\n\t\t};\n\t\tconst onDrop = (e: DragEvent) => {\n\t\t\tif (e.dataTransfer?.types?.includes(\"Files\")) e.preventDefault();\n\t\t\tif (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n\t\t\t\tadd(e.dataTransfer.files);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener(\"dragover\", onDragOver);\n\t\tdocument.addEventListener(\"drop\", onDrop);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"dragover\", onDragOver);\n\t\t\tdocument.removeEventListener(\"drop\", onDrop);\n\t\t};\n\t}, [add, globalDrop]);\n\n\tconst handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(\n\t\tasync (event) => {\n\t\t\tevent.preventDefault();\n\t\t\tconst form = event.currentTarget;\n\t\t\tconst formData = new FormData(form);\n\t\t\tconst text = (formData.get(\"message\") as string) || \"\";\n\n\t\t\tform.reset();\n\n\t\t\tconst convertedFiles: FileUIPart[] = await Promise.all(\n\t\t\t\titems.map(async ({ id: _id, ...item }) => {\n\t\t\t\t\tif (item.url?.startsWith(\"blob:\")) {\n\t\t\t\t\t\tconst dataUrl = await convertBlobUrlToDataUrl(item.url);\n\t\t\t\t\t\treturn { ...item, url: dataUrl ?? item.url };\n\t\t\t\t\t}\n\t\t\t\t\treturn item;\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\ttry {\n\t\t\t\tconst result = onSubmit({ files: convertedFiles, text }, event);\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\tawait result;\n\t\t\t\t}\n\t\t\t\tclear();\n\t\t\t} catch {\n\t\t\t\t// Don't clear on error\n\t\t\t}\n\t\t},\n\t\t[items, onSubmit, clear],\n\t);\n\n\tconst attachmentsCtx = useMemo<AttachmentsContext>(\n\t\t() => ({\n\t\t\tadd,\n\t\t\tclear,\n\t\t\tfiles: items,\n\t\t\topenFileDialog,\n\t\t\tremove,\n\t\t}),\n\t\t[items, add, remove, clear, openFileDialog],\n\t);\n\n\treturn (\n\t\t<LocalAttachmentsContext.Provider value={attachmentsCtx}>\n\t\t\t<input\n\t\t\t\taccept={accept}\n\t\t\t\taria-label=\"Upload files\"\n\t\t\t\tclassName=\"ww:hidden\"\n\t\t\t\tmultiple={multiple}\n\t\t\t\tonChange={handleChange}\n\t\t\t\tref={inputRef}\n\t\t\t\ttitle=\"Upload files\"\n\t\t\t\ttype=\"file\"\n\t\t\t/>\n\t\t\t<form\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"ww:flex ww:w-full ww:flex-col ww:rounded-lg ww:border ww:border-border ww:bg-background\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\tref={formRef}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</form>\n\t\t</LocalAttachmentsContext.Provider>\n\t);\n};\n\n// ============================================================================\n// Layout Components\n// ============================================================================\n\nexport type PromptInputHeaderProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputHeader = ({\n\tclassName,\n\t...props\n}: PromptInputHeaderProps) => (\n\t<div\n\t\tclassName={cn(\"ww:flex ww:flex-wrap ww:gap-1 ww:px-3 ww:pt-3\", className)}\n\t\t{...props}\n\t/>\n);\n\nexport type PromptInputBodyProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputBody = ({\n\tclassName,\n\t...props\n}: PromptInputBodyProps) => (\n\t<div className={cn(\"ww:contents\", className)} {...props} />\n);\n\nexport type PromptInputFooterProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputFooter = ({\n\tclassName,\n\t...props\n}: PromptInputFooterProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"ww:flex ww:items-center ww:justify-between ww:gap-1 ww:px-3 ww:pb-3\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n\nexport type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const PromptInputTools = ({\n\tclassName,\n\t...props\n}: PromptInputToolsProps) => (\n\t<div\n\t\tclassName={cn(\"ww:flex ww:min-w-0 ww:items-center ww:gap-1\", className)}\n\t\t{...props}\n\t/>\n);\n\n// ============================================================================\n// Textarea\n// ============================================================================\n\nexport type PromptInputTextareaProps = ComponentProps<\"textarea\">;\n\nexport const PromptInputTextarea = ({\n\tonChange,\n\tonKeyDown,\n\tclassName,\n\tplaceholder = \"What would you like to know?\",\n\t...props\n}: PromptInputTextareaProps) => {\n\tconst attachments = usePromptInputAttachments();\n\tconst [isComposing, setIsComposing] = useState(false);\n\n\tconst handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useCallback(\n\t\t(e) => {\n\t\t\tonKeyDown?.(e);\n\t\t\tif (e.defaultPrevented) return;\n\n\t\t\tif (e.key === \"Enter\") {\n\t\t\t\tif (isComposing || e.nativeEvent.isComposing) return;\n\t\t\t\tif (e.shiftKey) return;\n\t\t\t\te.preventDefault();\n\n\t\t\t\tconst { form } = e.currentTarget;\n\t\t\t\tconst submitButton = form?.querySelector(\n\t\t\t\t\t'button[type=\"submit\"]',\n\t\t\t\t) as HTMLButtonElement | null;\n\t\t\t\tif (submitButton?.disabled) return;\n\t\t\t\tform?.requestSubmit();\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\te.key === \"Backspace\" &&\n\t\t\t\te.currentTarget.value === \"\" &&\n\t\t\t\tattachments.files.length > 0\n\t\t\t) {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst lastAttachment = attachments.files.at(-1);\n\t\t\t\tif (lastAttachment) attachments.remove(lastAttachment.id);\n\t\t\t}\n\t\t},\n\t\t[onKeyDown, isComposing, attachments],\n\t);\n\n\tconst handlePaste: ClipboardEventHandler<HTMLTextAreaElement> = useCallback(\n\t\t(event) => {\n\t\t\tconst items = event.clipboardData?.items;\n\t\t\tif (!items) return;\n\n\t\t\tconst files: File[] = [];\n\t\t\tfor (const item of items) {\n\t\t\t\tif (item.kind === \"file\") {\n\t\t\t\t\tconst file = item.getAsFile();\n\t\t\t\t\tif (file) files.push(file);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (files.length > 0) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tattachments.add(files);\n\t\t\t}\n\t\t},\n\t\t[attachments],\n\t);\n\n\treturn (\n\t\t<textarea\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:field-sizing-content ww:max-h-48 ww:min-h-16 ww:w-full ww:resize-none ww:border-0 ww:bg-transparent ww:px-3 ww:py-3 ww:text-sm ww:outline-none ww:placeholder:text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tname=\"message\"\n\t\t\tonCompositionEnd={() => setIsComposing(false)}\n\t\t\tonCompositionStart={() => setIsComposing(true)}\n\t\t\tonKeyDown={handleKeyDown}\n\t\t\tonPaste={handlePaste}\n\t\t\tplaceholder={placeholder}\n\t\t\tonChange={onChange}\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n\n// ============================================================================\n// Submit Button\n// ============================================================================\n\nexport type PromptInputSubmitProps = ComponentProps<typeof Button> & {\n\tstatus?: ChatStatus;\n\tonStop?: () => void;\n};\n\nexport const PromptInputSubmit = ({\n\tclassName,\n\tstatus,\n\tonStop,\n\tonClick,\n\tchildren,\n\t...props\n}: PromptInputSubmitProps) => {\n\tconst isGenerating = status === \"submitted\" || status === \"streaming\";\n\n\tlet Icon = <ArrowUpIcon className=\"ww:size-4\" />;\n\tif (status === \"submitted\") {\n\t\tIcon = <LoaderIcon className=\"ww:size-4 ww:animate-spin\" />;\n\t} else if (status === \"streaming\") {\n\t\tIcon = <SquareIcon className=\"ww:size-4\" />;\n\t}\n\n\tconst handleClick = useCallback(\n\t\t(e: React.MouseEvent<HTMLButtonElement>) => {\n\t\t\tif (isGenerating && onStop) {\n\t\t\t\te.preventDefault();\n\t\t\t\tonStop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tonClick?.(e);\n\t\t},\n\t\t[isGenerating, onStop, onClick],\n\t);\n\n\treturn (\n\t\t<Button\n\t\t\taria-label={isGenerating ? \"Stop\" : \"Submit\"}\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:bg-foreground ww:text-background ww:hover:bg-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonClick={handleClick}\n\t\t\tsize=\"icon-sm\"\n\t\t\ttype={isGenerating && onStop ? \"button\" : \"submit\"}\n\t\t\tvariant=\"ghost\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children ?? Icon}\n\t\t</Button>\n\t);\n};\n\n// ============================================================================\n// Attachment Add Button (simple file picker, no Radix dropdown)\n// ============================================================================\n\nexport type PromptInputAddAttachmentsProps = ComponentProps<typeof Button>;\n\nexport const PromptInputAddAttachments = ({\n\tclassName,\n\tchildren,\n\t...props\n}: PromptInputAddAttachmentsProps) => {\n\tconst attachments = usePromptInputAttachments();\n\tconst hasFiles = attachments.files.length > 0;\n\n\tif (hasFiles) {\n\t\treturn (\n\t\t\t<Button\n\t\t\t\tclassName={cn(\"ww:group ww:relative\", className)}\n\t\t\t\tonClick={() => attachments.clear()}\n\t\t\t\tsize=\"icon-sm\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tvariant=\"ghost\"\n\t\t\t\taria-label=\"Remove all attachments\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<span className=\"ww:flex ww:size-5 ww:items-center ww:justify-center ww:rounded-full ww:bg-primary ww:text-[10px] ww:font-medium ww:text-primary-foreground ww:transition-opacity ww:group-hover:opacity-0\">\n\t\t\t\t\t{attachments.files.length}\n\t\t\t\t</span>\n\t\t\t\t<XIcon className=\"ww:absolute ww:size-4 ww:opacity-0 ww:transition-opacity ww:group-hover:opacity-100\" />\n\t\t\t</Button>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Button\n\t\t\tclassName={cn(className)}\n\t\t\tonClick={() => attachments.openFileDialog()}\n\t\t\tsize=\"icon-sm\"\n\t\t\ttype=\"button\"\n\t\t\tvariant=\"ghost\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children ?? <PaperclipIcon className=\"ww:size-4\" />}\n\t\t</Button>\n\t);\n};\n","\"use client\";\n\nimport type { FileUIPart } from \"ai\";\nimport { FileIcon } from \"lucide-react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\n// ============================================================================\n// Attachments (inline list for chat bubbles)\n// ============================================================================\n\nexport type AttachmentsProps = HTMLAttributes<HTMLDivElement> & {\n\tfiles: FileUIPart[];\n};\n\nexport const Attachments = ({\n\tfiles,\n\tclassName,\n\t...props\n}: AttachmentsProps) => {\n\tif (files.length === 0) return null;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"ww:flex ww:flex-wrap ww:gap-1.5\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{files.map((file, i) => (\n\t\t\t\t<AttachmentItem key={i} file={file} />\n\t\t\t))}\n\t\t</div>\n\t);\n};\n\n// ============================================================================\n// AttachmentItem\n// ============================================================================\n\nfunction AttachmentItem({ file }: { file: FileUIPart }) {\n\tconst isImage = file.mediaType?.startsWith(\"image/\");\n\n\tif (isImage && file.url) {\n\t\treturn (\n\t\t\t<img\n\t\t\t\tsrc={file.url}\n\t\t\t\talt={file.filename ?? \"attachment\"}\n\t\t\t\tclassName=\"ww:h-16 ww:max-w-32 ww:rounded ww:object-cover\"\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<span className=\"ww:inline-flex ww:items-center ww:gap-1.5 ww:rounded ww:bg-background/20 ww:px-2 ww:py-1 ww:text-xs\">\n\t\t\t<FileIcon className=\"ww:size-3 ww:shrink-0\" />\n\t\t\t<span className=\"ww:max-w-24 ww:truncate\">{file.filename ?? \"file\"}</span>\n\t\t</span>\n\t);\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type LoaderProps = HTMLAttributes<HTMLDivElement> & {\n\tsize?: number;\n};\n\nexport const Loader = ({ className, size = 5, ...props }: LoaderProps) => (\n\t<div className={cn(\"ww:flex ww:items-center ww:gap-1\", className)} {...props}>\n\t\t{[0, 1, 2].map((i) => (\n\t\t\t<div\n\t\t\t\tkey={i}\n\t\t\t\tclassName=\"ww:rounded-full ww:bg-muted-foreground/60\"\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: size,\n\t\t\t\t\theight: size,\n\t\t\t\t\tanimation: \"ww-pulse 1.4s ease-in-out infinite\",\n\t\t\t\t\tanimationDelay: `${i * 0.2}s`,\n\t\t\t\t}}\n\t\t\t/>\n\t\t))}\n\t</div>\n);\n","\"use client\";\n\nimport { cjk } from \"@streamdown/cjk\";\nimport { code } from \"@streamdown/code\";\nimport type { UIMessage } from \"ai\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport { memo } from \"react\";\nimport { Streamdown } from \"streamdown\";\nimport { cn } from \"../lib/utils\";\n\nexport type MessageProps = HTMLAttributes<HTMLDivElement> & {\n\tfrom: UIMessage[\"role\"];\n};\n\nexport const Message = ({ className, from, ...props }: MessageProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"ww:group ww:flex ww:w-full ww:max-w-[95%] ww:flex-col ww:gap-2\",\n\t\t\tfrom === \"user\" ? \"is-user ww:ml-auto ww:justify-end\" : \"is-assistant\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\n\nexport type MessageContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const MessageContent = ({\n\tchildren,\n\tclassName,\n\t...props\n}: MessageContentProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"ww:flex ww:w-fit ww:min-w-0 ww:max-w-full ww:flex-col ww:gap-2 ww:overflow-hidden ww:text-base\",\n\t\t\t\"ww:group-[.is-user]:ml-auto ww:group-[.is-user]:rounded-lg ww:group-[.is-user]:bg-user-bubble ww:group-[.is-user]:px-4 ww:group-[.is-user]:py-3 ww:group-[.is-user]:text-primary-foreground\",\n\t\t\t\"ww:group-[.is-assistant]:text-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t{children}\n\t</div>\n);\n\nexport type MessageResponseProps = ComponentProps<typeof Streamdown>;\n\nconst streamdownPlugins = { cjk, code };\n\nexport const MessageResponse = memo(\n\t({ className, ...props }: MessageResponseProps) => (\n\t\t<Streamdown\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:size-full ww:[&>*:first-child]:mt-0 ww:[&>*:last-child]:mb-0\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tplugins={streamdownPlugins}\n\t\t\t{...props}\n\t\t/>\n\t),\n\t(prevProps, nextProps) => prevProps.children === nextProps.children,\n);\n\nMessageResponse.displayName = \"MessageResponse\";\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type ReasoningProps = HTMLAttributes<HTMLPreElement> & {\n\ttext: string;\n};\n\n/** Displays reasoning text inline with muted styling. */\nexport function Reasoning({ className, text, ...props }: ReasoningProps) {\n\tif (!text) return null;\n\n\treturn (\n\t\t<pre\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:mb-2 ww:overflow-x-auto ww:whitespace-pre-wrap ww:break-words ww:text-xs ww:font-mono ww:text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{text}\n\t\t</pre>\n\t);\n}\n","\"use client\";\n\nimport type { ToolUIPart } from \"ai\";\nimport {\n\tBracesIcon,\n\tCheckIcon,\n\tChevronDownIcon,\n\tChevronRightIcon,\n\tClipboardCopyIcon,\n\tServerIcon,\n} from \"lucide-react\";\nimport type { HTMLAttributes } from \"react\";\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\n\n/**\n * Produces an abbreviated single-line JSON preview for collapsed display.\n * Objects show truncated keys/values: `{ci… 'M…, pos… '2…, squa… 80}`\n * Arrays show their length: `Array(13)`\n */\nfunction truncateJSON(data: unknown, maxLength = 80): string {\n\tif (data === null || data === undefined) return String(data);\n\tif (typeof data !== \"object\") return String(data).slice(0, maxLength);\n\n\tif (Array.isArray(data)) {\n\t\treturn `Array(${data.length})`;\n\t}\n\n\tconst stringified = JSON.stringify(data);\n\tif (stringified.length <= maxLength) return stringified;\n\n\tconst entries = Object.entries(data as Record<string, unknown>);\n\tconst parts: string[] = [];\n\tlet remaining = maxLength - 2;\n\n\tfor (const [key, value] of entries) {\n\t\tif (remaining <= 8) break;\n\t\tconst keyAbbrev = key.length > 4 ? `${key.slice(0, 4)}\\u2026` : key;\n\t\tlet valStr: string;\n\t\tif (typeof value === \"string\") {\n\t\t\tvalStr = value.length > 2 ? `'${value.slice(0, 1)}\\u2026` : `'${value}'`;\n\t\t} else if (Array.isArray(value)) {\n\t\t\tvalStr = `Array(${value.length})`;\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\tvalStr = `{\\u2026}`;\n\t\t} else {\n\t\t\tvalStr = String(value);\n\t\t}\n\t\tconst part = `${keyAbbrev}\\u2009${valStr}`;\n\t\tparts.push(part);\n\t\tremaining -= part.length + 3;\n\t}\n\n\treturn `{${parts.join(\", \")}}`;\n}\n\ninterface CopyButtonProps {\n\ttext: string;\n\tclassName?: string;\n}\n\n/** Ghost button that copies `text` to clipboard, showing \"Copied\" for 2s. */\nfunction CopyButton({ text, className }: CopyButtonProps) {\n\tconst [copied, setCopied] = useState(false);\n\tconst timeoutRef = useRef<ReturnType<typeof setTimeout>>(null);\n\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tif (timeoutRef.current) {\n\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t}\n\t\t};\n\t}, []);\n\n\tconst handleCopy = useCallback(\n\t\tasync (e: React.MouseEvent) => {\n\t\t\te.stopPropagation();\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(text);\n\t\t\t\tsetCopied(true);\n\t\t\t\tif (timeoutRef.current) {\n\t\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t\t}\n\t\t\t\ttimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n\t\t\t} catch {\n\t\t\t\t// Clipboard API not available\n\t\t\t}\n\t\t},\n\t\t[text],\n\t);\n\n\treturn (\n\t\t<Button\n\t\t\tvariant=\"ghost\"\n\t\t\tsize=\"sm\"\n\t\t\tonClick={handleCopy}\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:h-auto ww:gap-1 ww:px-1.5 ww:py-0.5 ww:text-xs ww:text-muted-foreground ww:hover:text-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{copied ? (\n\t\t\t\t<>\n\t\t\t\t\t<CheckIcon className=\"ww:size-3.5\" />\n\t\t\t\t\t<span>Copied</span>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<ClipboardCopyIcon className=\"ww:size-3.5\" />\n\t\t\t\t\t<span>Copy</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</Button>\n\t);\n}\n\ninterface CollapsibleJSONProps extends HTMLAttributes<HTMLDivElement> {\n\tdata: unknown;\n\tlabel: string;\n}\n\n/**\n * Labeled JSON section with a Copy button and a collapsible preview.\n * Collapsed: shows a truncated single-line abbreviation with a `>` chevron.\n * Expanded: rotates the chevron and shows full pretty-printed JSON.\n */\nfunction CollapsibleJSON({\n\tdata,\n\tlabel,\n\tclassName,\n\t...props\n}: CollapsibleJSONProps) {\n\tconst [expanded, setExpanded] = useState(false);\n\tconst fullJSON = useMemo(() => JSON.stringify(data, null, 2), [data]);\n\tconst preview = truncateJSON(data);\n\n\treturn (\n\t\t<div className={cn(\"ww:rounded-lg ww:bg-tool-card\", className)} {...props}>\n\t\t\t<div className=\"ww:flex ww:items-center ww:justify-between ww:px-3 ww:pt-2.5 ww:pb-1.5\">\n\t\t\t\t<span className=\"ww:text-xs ww:font-medium ww:text-muted-foreground\">\n\t\t\t\t\t{label}\n\t\t\t\t</span>\n\t\t\t\t<CopyButton text={fullJSON} />\n\t\t\t</div>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tonClick={() => setExpanded((v) => !v)}\n\t\t\t\tclassName=\"ww:flex ww:w-full ww:items-start ww:gap-2 ww:px-3 ww:pb-3 ww:text-left\"\n\t\t\t>\n\t\t\t\t<ChevronRightIcon\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"ww:mt-0.5 ww:size-3.5 ww:shrink-0 ww:text-muted-foreground ww:transition-transform ww:duration-150\",\n\t\t\t\t\t\texpanded && \"ww:rotate-90\",\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t{expanded ? (\n\t\t\t\t\t<pre className=\"ww:overflow-x-auto ww:text-xs ww:font-mono ww:text-foreground ww:whitespace-pre-wrap ww:break-all\">\n\t\t\t\t\t\t<code>{fullJSON}</code>\n\t\t\t\t\t</pre>\n\t\t\t\t) : (\n\t\t\t\t\t<span className=\"ww:truncate ww:text-xs ww:font-mono ww:text-foreground/80\">\n\t\t\t\t\t\t{preview}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n\nconst ToolOpenContext = createContext<{\n\topen: boolean;\n\ttoggle: () => void;\n}>({ open: false, toggle: () => {} });\n\nexport type ToolProps = HTMLAttributes<HTMLDivElement> & {\n\tdefaultOpen?: boolean;\n};\n\n/**\n * Compound component root for a tool call display.\n * Provides open/closed state via context to ToolHeader and ToolContent.\n *\n * ```tsx\n * <Tool defaultOpen>\n * <ToolHeader title=\"Price estimate ready\" state=\"output-available\" />\n * <ToolContent>\n * <ToolServerInfo toolName=\"get_price_estimate\" serverName=\"Tuio v2\" />\n * <ToolInput input={args} />\n * <ToolOutput output={result} errorText={undefined} />\n * </ToolContent>\n * </Tool>\n * ```\n */\nexport function Tool({\n\tclassName,\n\tdefaultOpen = false,\n\tchildren,\n\t...props\n}: ToolProps) {\n\tconst [open, setOpen] = useState(defaultOpen);\n\treturn (\n\t\t<ToolOpenContext.Provider\n\t\t\tvalue={{ open, toggle: () => setOpen((o) => !o) }}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={cn(\"ww:mb-4 ww:w-full\", className)}\n\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ToolOpenContext.Provider>\n\t);\n}\n\nexport type ToolHeaderProps = HTMLAttributes<HTMLButtonElement> & {\n\ttitle?: string;\n\tstate: ToolUIPart[\"state\"];\n};\n\n/** Clickable header that toggles the tool accordion. Shows a `{≡}` icon, title, and chevron. */\nexport function ToolHeader({\n\tclassName,\n\ttitle,\n\tstate,\n\t...props\n}: ToolHeaderProps) {\n\tconst { open, toggle } = useContext(ToolOpenContext);\n\tconst isRunning = state === \"input-available\" || state === \"input-streaming\";\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tonClick={toggle}\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:flex ww:w-full ww:items-center ww:justify-between ww:gap-3 ww:py-1.5\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\taria-expanded={open}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"ww:flex ww:min-w-0 ww:items-center ww:gap-2\">\n\t\t\t\t<BracesIcon className=\"ww:size-4 ww:shrink-0 ww:text-muted-foreground\" />\n\t\t\t\t<span className=\"ww:truncate ww:text-sm ww:font-medium\">{title}</span>\n\t\t\t\t{isRunning && (\n\t\t\t\t\t<span className=\"ww:size-2 ww:shrink-0 ww:rounded-full ww:bg-primary ww:animate-pulse\" />\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<ChevronDownIcon\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"ww:size-4 ww:shrink-0 ww:text-muted-foreground ww:transition-transform ww:duration-200\",\n\t\t\t\t\topen && \"ww:rotate-180\",\n\t\t\t\t)}\n\t\t\t/>\n\t\t</button>\n\t);\n}\n\nexport type ToolServerInfoProps = HTMLAttributes<HTMLDivElement> & {\n\tserverName?: string;\n\tserverIcon?: string;\n\ttoolName: string;\n};\n\n/** Optional MCP server identity card. Shows server icon + name and the tool function name. Renders nothing if no props need display. */\nexport function ToolServerInfo({\n\tclassName,\n\tserverName,\n\tserverIcon,\n\ttoolName,\n\t...props\n}: ToolServerInfoProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:flex ww:items-center ww:gap-3 ww:rounded-lg ww:border ww:border-border ww:px-3 ww:py-2.5\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{serverIcon ? (\n\t\t\t\t<img\n\t\t\t\t\tsrc={serverIcon}\n\t\t\t\t\talt={serverName ?? \"\"}\n\t\t\t\t\tclassName=\"ww:size-8 ww:shrink-0 ww:rounded-full ww:object-cover\"\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"ww:flex ww:size-8 ww:shrink-0 ww:items-center ww:justify-center ww:rounded-full ww:border ww:border-border ww:bg-muted\">\n\t\t\t\t\t<ServerIcon className=\"ww:size-4 ww:text-muted-foreground\" />\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"ww:flex ww:min-w-0 ww:flex-col\">\n\t\t\t\t{serverName && (\n\t\t\t\t\t<span className=\"ww:text-xs ww:text-muted-foreground\">\n\t\t\t\t\t\t{serverName}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t\t<span className=\"ww:truncate ww:text-sm ww:font-semibold\">\n\t\t\t\t\t{toolName}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport type ToolContentProps = HTMLAttributes<HTMLDivElement>;\n\n/** Collapsible body that animates open/closed. Content below smoothly pushes up/down via a grid-row height transition. */\nexport function ToolContent({\n\tclassName,\n\tchildren,\n\t...props\n}: ToolContentProps) {\n\tconst { open } = useContext(ToolOpenContext);\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"ww:grid ww:transition-[grid-template-rows,opacity] ww:duration-200 ww:ease-out\",\n\t\t\t\topen\n\t\t\t\t\t? \"ww:grid-rows-[1fr] ww:opacity-100\"\n\t\t\t\t\t: \"ww:grid-rows-[0fr] ww:opacity-0\",\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"ww:min-h-0 ww:overflow-hidden\">\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"ww:mt-2 ww:space-y-3 ww:rounded-lg ww:border ww:border-border ww:bg-background ww:p-3\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport type ToolInputProps = HTMLAttributes<HTMLDivElement> & {\n\tinput: ToolUIPart[\"input\"];\n};\n\n/** Displays the tool call request parameters as a collapsible JSON section labeled \"Request\". */\nexport function ToolInput({ className, input, ...props }: ToolInputProps) {\n\treturn (\n\t\t<CollapsibleJSON\n\t\t\tdata={input}\n\t\t\tlabel=\"Request\"\n\t\t\tclassName={className}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport type ToolOutputProps = HTMLAttributes<HTMLDivElement> & {\n\toutput: ToolUIPart[\"output\"];\n\terrorText: ToolUIPart[\"errorText\"];\n};\n\nfunction getUiMeta(output: unknown): Record<string, unknown> | undefined {\n\tif (typeof output !== \"object\" || output === null) return undefined;\n\tconst meta = (output as Record<string, unknown>)._meta;\n\tif (typeof meta !== \"object\" || meta === null) return undefined;\n\tconst ui = (meta as Record<string, unknown>).ui;\n\tif (typeof ui !== \"object\" || ui === null) return undefined;\n\treturn ui as Record<string, unknown>;\n}\n\n/** Extract the MCP app resource URI from `output._meta.ui.resourceUri`, if present. */\nexport function getResourceUri(output: unknown): string | undefined {\n\tconst uri = getUiMeta(output)?.resourceUri;\n\treturn typeof uri === \"string\" ? uri : undefined;\n}\n\n/** Extract the auto-height flag from `output._meta.ui.autoHeight`, if present. */\nexport function getAutoHeight(output: unknown): boolean {\n\treturn getUiMeta(output)?.autoHeight === true;\n}\n\n/** Displays the tool call result as a collapsible JSON section labeled \"Response\", or an error block if `errorText` is set. */\nexport function ToolOutput({\n\tclassName,\n\toutput,\n\terrorText,\n\t...props\n}: ToolOutputProps) {\n\tif (!(output || errorText)) return null;\n\n\tif (errorText) {\n\t\treturn (\n\t\t\t<div className={cn(\"ww:space-y-2\", className)} {...props}>\n\t\t\t\t<h4 className=\"ww:text-xs ww:font-medium ww:uppercase ww:tracking-wide ww:text-muted-foreground\">\n\t\t\t\t\tError\n\t\t\t\t</h4>\n\t\t\t\t<div className=\"ww:rounded-lg ww:bg-destructive/10 ww:p-3 ww:text-xs ww:text-destructive\">\n\t\t\t\t\t{errorText}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<CollapsibleJSON\n\t\t\tdata={output}\n\t\t\tlabel=\"Response\"\n\t\t\tclassName={className}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nconst DEFAULT_RESOURCE_ENDPOINT = \"/api/mcp/resource\";\nconst MAX_HEIGHT = 500;\nconst DEFAULT_HEIGHT = 0;\nconst PROTOCOL_VERSION = \"2026-01-26\";\nconst RESIZE_ANIMATION_MS = 300;\nconst HANDSHAKE_TIMEOUT_MS = 3000;\nconst MAX_RETRIES = 3;\n\nexport interface McpAppFrameProps {\n\tresourceUri: string;\n\ttoolInput: Record<string, unknown>;\n\ttoolResult: {\n\t\tcontent?: Array<{ type: string; text?: string }>;\n\t\tstructuredContent?: Record<string, unknown>;\n\t};\n\tresourceEndpoint?: string;\n\tisDark?: boolean;\n\tclassName?: string;\n\t/** When true, the iframe height auto-adapts to its content. Set via `_meta.ui.autoHeight` in the tool result. */\n\tautoHeight?: boolean;\n\t/** Called when the view requests to open a URL */\n\tonOpenLink?: (url: string) => void;\n\t/** Called when a widget sends a follow-up message via `ui/message` */\n\tonFollowUp?: (message: {\n\t\trole: string;\n\t\tcontent: Array<{ type: string; text?: string }>;\n\t}) => void;\n}\n\nexport function McpAppFrame({\n\tresourceUri,\n\ttoolInput,\n\ttoolResult,\n\tresourceEndpoint = DEFAULT_RESOURCE_ENDPOINT,\n\tisDark = false,\n\tclassName,\n\t// TODO: REMOVE — defaulting to true for playground testing\n\tautoHeight = true,\n\tonOpenLink,\n\tonFollowUp,\n}: McpAppFrameProps) {\n\tconst iframeRef = useRef<HTMLIFrameElement>(null);\n\tconst toolInputRef = useRef(toolInput);\n\tconst toolResultRef = useRef(toolResult);\n\tconst lastSizeRef = useRef({ width: 0, height: 0 });\n\tconst animationRef = useRef<Animation | null>(null);\n\tconst initializedRef = useRef(false);\n\tconst retryCountRef = useRef(0);\n\tconst [height, setHeight] = useState(DEFAULT_HEIGHT);\n\tconst [width, setWidth] = useState<number | undefined>(undefined);\n\tconst onOpenLinkRef = useRef(onOpenLink);\n\tconst onFollowUpRef = useRef(onFollowUp);\n\n\ttoolInputRef.current = toolInput;\n\ttoolResultRef.current = toolResult;\n\tonOpenLinkRef.current = onOpenLink;\n\tonFollowUpRef.current = onFollowUp;\n\n\tconst clampHeight = useCallback(\n\t\t(h: number) => {\n\t\t\tif (autoHeight) return Math.max(h, 0);\n\t\t\treturn Math.min(Math.max(h, 50), MAX_HEIGHT);\n\t\t},\n\t\t[autoHeight],\n\t);\n\n\t// Build the iframe src URL directly — avoids null-origin issues with srcdoc\n\tconst iframeSrc = useMemo(\n\t\t() => `${resourceEndpoint}?uri=${encodeURIComponent(resourceUri)}`,\n\t\t[resourceEndpoint, resourceUri],\n\t);\n\n\tconst isDarkRef = useRef(isDark);\n\tisDarkRef.current = isDark;\n\n\t// Send theme changes to the iframe (only after handshake is complete)\n\tuseEffect(() => {\n\t\tif (!initializedRef.current) return;\n\t\tconst iframe = iframeRef.current;\n\t\tif (!iframe?.contentWindow) return;\n\n\t\tiframe.contentWindow.postMessage(\n\t\t\t{\n\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\tmethod: \"ui/notifications/host-context-changed\",\n\t\t\t\tparams: {\n\t\t\t\t\ttheme: isDark ? \"dark\" : \"light\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"*\",\n\t\t);\n\t}, [isDark]);\n\n\t// Synchronous postMessage protocol handler — no async imports, no timing issues.\n\t// Handles the MCP UI protocol (ui/initialize, notifications, etc.) directly.\n\tuseEffect(() => {\n\t\tconst iframe = iframeRef.current;\n\t\tif (!iframe) return;\n\n\t\tlet disposed = false;\n\t\tlet handshakeReceived = false;\n\t\tconst debug = (...args: unknown[]) =>\n\t\t\tconsole.debug(\"[McpAppFrame]\", ...args);\n\n\t\tdebug(\"effect mounted, waiting for handshake\");\n\n\t\t// Retry: reload iframe if handshake doesn't arrive in time\n\t\tconst handshakeTimer = setTimeout(() => {\n\t\t\tif (disposed || handshakeReceived) return;\n\t\t\tif (retryCountRef.current >= MAX_RETRIES) {\n\t\t\t\tdebug(\"handshake failed after\", MAX_RETRIES, \"retries, giving up\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tretryCountRef.current += 1;\n\t\t\tdebug(\n\t\t\t\t\"handshake timeout, reloading iframe (retry\",\n\t\t\t\tretryCountRef.current,\n\t\t\t\t\"of\",\n\t\t\t\tMAX_RETRIES,\n\t\t\t\t\")\",\n\t\t\t);\n\t\t\t// Force reload with a cache-busting param\n\t\t\tconst url = new URL(iframe.src);\n\t\t\turl.searchParams.set(\"_retry\", String(retryCountRef.current));\n\t\t\tiframe.src = url.toString();\n\t\t}, HANDSHAKE_TIMEOUT_MS);\n\n\t\tconst postToIframe = (msg: Record<string, unknown>) => {\n\t\t\tdebug(\"→ send\", msg.method ?? `response:${msg.id}`, msg);\n\t\t\tiframe.contentWindow?.postMessage(msg, \"*\");\n\t\t};\n\n\t\tconst handleMessage = (event: MessageEvent) => {\n\t\t\tif (disposed) return;\n\t\t\tif (event.source !== iframe.contentWindow) return;\n\n\t\t\tconst data = event.data;\n\t\t\tif (!data || typeof data !== \"object\" || data.jsonrpc !== \"2.0\") return;\n\n\t\t\tconst method: string | undefined = data.method;\n\t\t\tconst id: number | string | undefined = data.id;\n\n\t\t\tdebug(\"← recv\", method ?? `response:${id}`, data);\n\n\t\t\t// ui/initialize — widget requests handshake\n\t\t\tif (method === \"ui/initialize\" && id != null) {\n\t\t\t\thandshakeReceived = true;\n\t\t\t\tclearTimeout(handshakeTimer);\n\t\t\t\tdebug(\"handshake started\");\n\t\t\t\tpostToIframe({\n\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\tid,\n\t\t\t\t\tresult: {\n\t\t\t\t\t\tprotocolVersion: data.params?.protocolVersion ?? PROTOCOL_VERSION,\n\t\t\t\t\t\thostInfo: { name: \"WaniWani Chat\", version: \"1.0.0\" },\n\t\t\t\t\t\thostCapabilities: {\n\t\t\t\t\t\t\topenLinks: {},\n\t\t\t\t\t\t\tmessage: {},\n\t\t\t\t\t\t},\n\t\t\t\t\t\thostContext: {\n\t\t\t\t\t\t\ttheme: isDarkRef.current ? \"dark\" : \"light\",\n\t\t\t\t\t\t\tdisplayMode: \"inline\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/notifications/initialized — widget confirms init, we send tool data\n\t\t\tif (method === \"ui/notifications/initialized\") {\n\t\t\t\tdebug(\"handshake complete, sending tool data\");\n\t\t\t\tinitializedRef.current = true;\n\t\t\t\tconst input = toolInputRef.current;\n\t\t\t\tconst result = toolResultRef.current;\n\n\t\t\t\tpostToIframe({\n\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\tmethod: \"ui/notifications/tool-input\",\n\t\t\t\t\tparams: { arguments: input },\n\t\t\t\t});\n\n\t\t\t\tconst content = result.content ?? [\n\t\t\t\t\t{ type: \"text\", text: JSON.stringify(result) },\n\t\t\t\t];\n\t\t\t\tpostToIframe({\n\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\tmethod: \"ui/notifications/tool-result\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\tstructuredContent: result.structuredContent,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/notifications/size-changed — widget reports content size\n\t\t\tif (method === \"ui/notifications/size-changed\") {\n\t\t\t\tconst params = data.params;\n\t\t\t\tconst newHeight =\n\t\t\t\t\ttypeof params?.height === \"number\" ? params.height : undefined;\n\t\t\t\tconst newWidth =\n\t\t\t\t\ttypeof params?.width === \"number\" ? params.width : undefined;\n\n\t\t\t\t// Deduplicate — only update if values actually changed (prevents feedback loops)\n\t\t\t\tconst last = lastSizeRef.current;\n\t\t\t\tconst heightChanged =\n\t\t\t\t\tnewHeight !== undefined && newHeight !== last.height;\n\t\t\t\tconst widthChanged = newWidth !== undefined && newWidth !== last.width;\n\n\t\t\t\tdebug(\"size-changed\", {\n\t\t\t\t\tnewHeight,\n\t\t\t\t\tnewWidth,\n\t\t\t\t\tlastHeight: last.height,\n\t\t\t\t\tlastWidth: last.width,\n\t\t\t\t\theightChanged,\n\t\t\t\t\twidthChanged,\n\t\t\t\t});\n\n\t\t\t\tif (!heightChanged && !widthChanged) return;\n\n\t\t\t\tif (heightChanged && newHeight !== undefined) {\n\t\t\t\t\tlast.height = newHeight;\n\t\t\t\t\tconst clamped = clampHeight(newHeight);\n\n\t\t\t\t\t// Get current visual height before canceling the old animation\n\t\t\t\t\tconst from = iframe.getBoundingClientRect().height;\n\n\t\t\t\t\t// Cancel previous animation so its fill: \"forwards\" stops overriding inline style\n\t\t\t\t\tif (animationRef.current) {\n\t\t\t\t\t\tanimationRef.current.cancel();\n\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the target height in React state (takes effect once no animation overrides it)\n\t\t\t\t\tsetHeight(clamped);\n\n\t\t\t\t\t// Animate the height transition\n\t\t\t\t\tif (iframe.animate && Math.abs(from - clamped) > 2) {\n\t\t\t\t\t\tconst anim = iframe.animate(\n\t\t\t\t\t\t\t[{ height: `${from}px` }, { height: `${clamped}px` }],\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tduration: RESIZE_ANIMATION_MS,\n\t\t\t\t\t\t\t\teasing: \"ease-out\",\n\t\t\t\t\t\t\t\tfill: \"forwards\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tanimationRef.current = anim;\n\t\t\t\t\t\t// Once done, remove the animation so the inline style is the source of truth\n\t\t\t\t\t\tanim.onfinish = () => {\n\t\t\t\t\t\t\tif (animationRef.current === anim) {\n\t\t\t\t\t\t\t\tanim.cancel();\n\t\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (widthChanged && autoHeight && newWidth !== undefined) {\n\t\t\t\t\tlast.width = newWidth;\n\t\t\t\t\tsetWidth(newWidth);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/open-link — widget requests to open a URL\n\t\t\tif (method === \"ui/open-link\" && id != null) {\n\t\t\t\tconst url = data.params?.url;\n\t\t\t\tif (typeof url === \"string\") {\n\t\t\t\t\tif (onOpenLinkRef.current) {\n\t\t\t\t\t\tonOpenLinkRef.current(url);\n\t\t\t\t\t} else {\n\t\t\t\t\t\twindow.open(url, \"_blank\", \"noopener,noreferrer\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/message — widget sends a chat message\n\t\t\tif (method === \"ui/message\" && id != null) {\n\t\t\t\tif (onFollowUpRef.current && data.params) {\n\t\t\t\t\tonFollowUpRef.current(data.params);\n\t\t\t\t}\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/request-display-mode — widget requests fullscreen/inline/pip\n\t\t\tif (method === \"ui/request-display-mode\" && id != null) {\n\t\t\t\t// Acknowledge but stay inline for now\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ui/resource-teardown — graceful shutdown\n\t\t\tif (method === \"ui/resource-teardown\" && id != null) {\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ping — keep-alive\n\t\t\tif (method === \"ping\" && id != null) {\n\t\t\t\tpostToIframe({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t}\n\t\t};\n\n\t\twindow.addEventListener(\"message\", handleMessage);\n\n\t\treturn () => {\n\t\t\tdebug(\"effect cleanup (disposed)\");\n\t\t\tdisposed = true;\n\t\t\tclearTimeout(handshakeTimer);\n\t\t\twindow.removeEventListener(\"message\", handleMessage);\n\t\t};\n\t}, [autoHeight, clampHeight]);\n\n\treturn (\n\t\t<iframe\n\t\t\tref={iframeRef}\n\t\t\tsrc={iframeSrc}\n\t\t\tsandbox=\"allow-scripts allow-forms allow-same-origin\"\n\t\t\tclassName={cn(\"ww:rounded-md ww:border ww:border-border\", className)}\n\t\t\tstyle={{\n\t\t\t\theight,\n\t\t\t\tminWidth: width ? `min(${width}px, 100%)` : undefined,\n\t\t\t\twidth: \"100%\",\n\t\t\t\tborder: \"none\",\n\t\t\t\tcolorScheme: \"auto\",\n\t\t\t}}\n\t\t\ttitle=\"MCP App\"\n\t\t/>\n\t);\n}\n","\"use client\";\n\nimport { Component, type ReactNode } from \"react\";\n\ninterface Props {\n\tchildren: ReactNode;\n}\n\ninterface State {\n\thasError: boolean;\n}\n\nexport class WidgetErrorBoundary extends Component<Props, State> {\n\tstate: State = { hasError: false };\n\n\tstatic getDerivedStateFromError(): State {\n\t\treturn { hasError: true };\n\t}\n\n\tcomponentDidCatch(error: Error) {\n\t\tconsole.warn(\"[WaniWani] Widget failed to render:\", error.message);\n\t}\n\n\trender() {\n\t\tif (this.state.hasError) {\n\t\t\treturn (\n\t\t\t\t<div className=\"ww:flex ww:items-center ww:justify-between ww:rounded-md ww:border ww:border-border ww:bg-muted/50 ww:px-4 ww:py-3 ww:text-sm ww:text-muted-foreground\">\n\t\t\t\t\t<span>Widget failed to load</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tonClick={() => this.setState({ hasError: false })}\n\t\t\t\t\t\tclassName=\"ww:text-xs ww:font-medium ww:text-primary ww:hover:underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tRetry\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n","\"use client\";\n\nimport type { ChatStatus, ReasoningUIPart, ToolUIPart, UIMessage } from \"ai\";\n\nimport { Attachments } from \"../ai-elements/attachments\";\nimport { Loader } from \"../ai-elements/loader\";\nimport {\n\tMessage,\n\tMessageContent,\n\tMessageResponse,\n} from \"../ai-elements/message\";\nimport { Reasoning } from \"../ai-elements/reasoning\";\nimport {\n\tgetAutoHeight,\n\tgetResourceUri,\n\tTool,\n\tToolContent,\n\tToolHeader,\n\tToolInput,\n\tToolOutput,\n} from \"../ai-elements/tool\";\nimport { McpAppFrame } from \"./mcp-app-frame\";\nimport { WidgetErrorBoundary } from \"./widget-error-boundary\";\n\n/** Converts `get_price_estimate` or `compare-prices` → `Get price estimate` / `Compare prices` */\nfunction formatToolName(name: string): string {\n\treturn name.replace(/[-_]/g, \" \").replace(/^\\w/, (c) => c.toUpperCase());\n}\n\ninterface MessageListProps {\n\tmessages: UIMessage[];\n\tstatus: ChatStatus;\n\twelcomeMessage?: string;\n\tresourceEndpoint?: string;\n\tisDark?: boolean;\n\tonFollowUp?: (message: {\n\t\trole: string;\n\t\tcontent: Array<{ type: string; text?: string }>;\n\t}) => void;\n}\n\nexport function MessageList({\n\tmessages,\n\tstatus,\n\twelcomeMessage,\n\tresourceEndpoint,\n\tisDark,\n\tonFollowUp,\n}: MessageListProps) {\n\tconst isLoading = status === \"submitted\" || status === \"streaming\";\n\tconst lastMessage = messages[messages.length - 1];\n\tconst hasMessages = messages.length > 0;\n\tconst showLoaderBubble =\n\t\tisLoading && (!hasMessages || lastMessage.role === \"user\");\n\n\treturn (\n\t\t<>\n\t\t\t{welcomeMessage && (\n\t\t\t\t<Message from=\"assistant\">\n\t\t\t\t\t<MessageContent>\n\t\t\t\t\t\t<MessageResponse>{welcomeMessage}</MessageResponse>\n\t\t\t\t\t</MessageContent>\n\t\t\t\t</Message>\n\t\t\t)}\n\t\t\t{messages.map((message) => {\n\t\t\t\tconst textParts = message.parts.filter((p) => p.type === \"text\");\n\t\t\t\tconst reasoningParts = message.parts.filter(\n\t\t\t\t\t(p): p is ReasoningUIPart => p.type === \"reasoning\",\n\t\t\t\t);\n\t\t\t\tconst fileParts = message.parts.filter((p) => p.type === \"file\");\n\t\t\t\tconst toolParts = message.parts.filter(\n\t\t\t\t\t(\n\t\t\t\t\t\tp,\n\t\t\t\t\t): p is typeof p & {\n\t\t\t\t\t\ttoolCallId: string;\n\t\t\t\t\t\ttoolName: string;\n\t\t\t\t\t\tstate: ToolUIPart[\"state\"];\n\t\t\t\t\t\tinput: unknown;\n\t\t\t\t\t\ttitle?: string;\n\t\t\t\t\t} => \"toolCallId\" in p,\n\t\t\t\t);\n\t\t\t\tconst isLastAssistant =\n\t\t\t\t\tmessage === lastMessage && message.role === \"assistant\";\n\t\t\t\tconst hasTextContent = textParts.length > 0;\n\n\t\t\t\treturn (\n\t\t\t\t\t<Message from={message.role} key={message.id}>\n\t\t\t\t\t\t{reasoningParts.map((part, i) => (\n\t\t\t\t\t\t\t<Reasoning\n\t\t\t\t\t\t\t\tkey={`reasoning-${message.id}-${i}`}\n\t\t\t\t\t\t\t\ttext={part.text}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{toolParts.map((part) => {\n\t\t\t\t\t\t\tconst output = \"output\" in part ? part.output : undefined;\n\t\t\t\t\t\t\tconst resourceUri =\n\t\t\t\t\t\t\t\toutput !== undefined ? getResourceUri(output) : undefined;\n\t\t\t\t\t\t\tconst autoHeight =\n\t\t\t\t\t\t\t\toutput !== undefined ? getAutoHeight(output) : false;\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={part.toolCallId}>\n\t\t\t\t\t\t\t\t\t<Tool defaultOpen={part.state === \"output-available\"}>\n\t\t\t\t\t\t\t\t\t\t<ToolHeader\n\t\t\t\t\t\t\t\t\t\t\ttitle={part.title ?? formatToolName(part.toolName)}\n\t\t\t\t\t\t\t\t\t\t\tstate={part.state}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<ToolContent>\n\t\t\t\t\t\t\t\t\t\t\t<ToolInput input={part.input} />\n\t\t\t\t\t\t\t\t\t\t\t{output !== undefined && (\n\t\t\t\t\t\t\t\t\t\t\t\t<ToolOutput\n\t\t\t\t\t\t\t\t\t\t\t\t\toutput={output}\n\t\t\t\t\t\t\t\t\t\t\t\t\terrorText={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"errorText\" in part ? part.errorText : undefined\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ToolContent>\n\t\t\t\t\t\t\t\t\t</Tool>\n\t\t\t\t\t\t\t\t\t{resourceUri && output !== undefined && (\n\t\t\t\t\t\t\t\t\t\t<WidgetErrorBoundary>\n\t\t\t\t\t\t\t\t\t\t\t<McpAppFrame\n\t\t\t\t\t\t\t\t\t\t\t\tresourceUri={resourceUri}\n\t\t\t\t\t\t\t\t\t\t\t\ttoolInput={\n\t\t\t\t\t\t\t\t\t\t\t\t\t(part.input as Record<string, unknown>) ?? {}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\ttoolResult={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tcontent: (output as Record<string, unknown>)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.content as\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| Array<{ type: string; text?: string }>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\t\t\t\t\t\t\tstructuredContent: (output as Record<string, unknown>)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.structuredContent as\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| Record<string, unknown>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\tresourceEndpoint={resourceEndpoint}\n\t\t\t\t\t\t\t\t\t\t\t\tisDark={isDark}\n\t\t\t\t\t\t\t\t\t\t\t\tautoHeight={autoHeight}\n\t\t\t\t\t\t\t\t\t\t\t\tonFollowUp={onFollowUp}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t</WidgetErrorBoundary>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t\t<MessageContent>\n\t\t\t\t\t\t\t{fileParts.length > 0 && <Attachments files={fileParts} />}\n\t\t\t\t\t\t\t{hasTextContent\n\t\t\t\t\t\t\t\t? textParts.map((part, i) => (\n\t\t\t\t\t\t\t\t\t\t<MessageResponse key={`${message.id}-${i}`}>\n\t\t\t\t\t\t\t\t\t\t\t{part.type === \"text\" ? part.text : \"\"}\n\t\t\t\t\t\t\t\t\t\t</MessageResponse>\n\t\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t\t: isLastAssistant && isLoading && <Loader />}\n\t\t\t\t\t\t</MessageContent>\n\t\t\t\t\t</Message>\n\t\t\t\t);\n\t\t\t})}\n\t\t\t{showLoaderBubble && (\n\t\t\t\t<Message from=\"assistant\">\n\t\t\t\t\t<MessageContent>\n\t\t\t\t\t\t<Loader />\n\t\t\t\t\t</MessageContent>\n\t\t\t\t</Message>\n\t\t\t)}\n\t\t</>\n\t);\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface SuggestionsProps\n\textends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n\tsuggestions: string[];\n\tisLoading?: boolean;\n\tonSelect: (suggestion: string) => void;\n}\n\nexport function Suggestions({\n\tsuggestions,\n\tisLoading,\n\tonSelect,\n\tclassName,\n\t...props\n}: SuggestionsProps) {\n\tif (suggestions.length === 0 && !isLoading) return null;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"ww:flex ww:flex-wrap ww:gap-2 ww:px-3 ww:py-2\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{isLoading\n\t\t\t\t? [0, 1, 2].map((i) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\tclassName=\"ww:h-7 ww:rounded-full ww:bg-accent ww:animate-pulse\"\n\t\t\t\t\t\t\tstyle={{ width: `${60 + i * 20}px` }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))\n\t\t\t\t: suggestions.map((suggestion, index) => (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tkey={suggestion}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={() => onSelect(suggestion)}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"ww:rounded-full ww:border ww:border-border ww:bg-background ww:px-3 ww:py-1 ww:text-xs\",\n\t\t\t\t\t\t\t\t\"ww:text-foreground ww:hover:bg-accent ww:hover:border-primary/30\",\n\t\t\t\t\t\t\t\t\"ww:transition-all ww:duration-200 ww:ease-out ww:cursor-pointer\",\n\t\t\t\t\t\t\t\t\"ww:animate-[ww-fade-in_0.2s_ease-out_both]\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tstyle={{ animationDelay: `${index * 50}ms` }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{suggestion}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t))}\n\t\t</div>\n\t);\n}\n","\"use client\";\n\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { ChatBaseProps } from \"../@types\";\nimport type { PromptInputMessage } from \"../ai-elements/prompt-input\";\n\nexport function useChatEngine(props: ChatBaseProps) {\n\tconst {\n\t\tapi = \"https://app.waniwani.ai/api/chat\",\n\t\theaders: userHeaders,\n\t\tbody,\n\t\tonMessageSent,\n\t\tonResponseReceived,\n\t} = props;\n\n\tconst transportRef = useRef(\n\t\tnew DefaultChatTransport({\n\t\t\tapi,\n\t\t\theaders: {\n\t\t\t\t...userHeaders,\n\t\t\t},\n\t\t\tbody,\n\t\t}),\n\t);\n\n\tconst { messages, sendMessage, status } = useChat({\n\t\ttransport: transportRef.current,\n\t\tonFinish() {\n\t\t\tonResponseReceived?.();\n\t\t},\n\t\tonError(error) {\n\t\t\tconsole.warn(\"[WaniWani] Chat error:\", error.message);\n\t\t},\n\t});\n\n\tconst [text, setText] = useState(\"\");\n\n\tconst handleSubmit = useCallback(\n\t\t(message: PromptInputMessage) => {\n\t\t\tconst hasText = Boolean(message.text?.trim());\n\t\t\tconst hasFiles = Boolean(message.files?.length);\n\t\t\tif (!(hasText || hasFiles)) return;\n\n\t\t\tsendMessage({\n\t\t\t\ttext: message.text || \"\",\n\t\t\t\tfiles: message.files,\n\t\t\t});\n\n\t\t\tonMessageSent?.(message.text || \"\");\n\t\t\tsetText(\"\");\n\t\t},\n\t\t[sendMessage, onMessageSent],\n\t);\n\n\tconst handleTextChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\t\tsetText(e.target.value);\n\t\t},\n\t\t[],\n\t);\n\n\tconst isLoading = status === \"submitted\" || status === \"streaming\";\n\tconst lastMessage = messages[messages.length - 1];\n\tconst hasMessages = messages.length > 0;\n\tconst showLoaderBubble =\n\t\tisLoading && (!hasMessages || lastMessage.role === \"user\");\n\n\treturn {\n\t\tmessages,\n\t\tstatus,\n\t\ttext,\n\t\tsetText,\n\t\thandleSubmit,\n\t\thandleTextChange,\n\t\tisLoading,\n\t\tshowLoaderBubble,\n\t\tlastMessage,\n\t\thasMessages,\n\t\tsendMessage,\n\t};\n}\n","\"use client\";\n\nimport type { ChatStatus, UIMessage } from \"ai\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { SuggestionsConfig } from \"../@types\";\n\nexport interface UseSuggestionsOptions {\n\tmessages: UIMessage[];\n\tstatus: ChatStatus;\n\tconfig?: boolean | SuggestionsConfig;\n}\n\n/**\n * Extract suggestions from the last assistant message's data part.\n * The API streams a `data-suggestions` part at the end of the response:\n * `{ type: \"data-suggestions\", data: { suggestions: string[] } }`\n */\nfunction extractSuggestions(message: UIMessage): string[] | null {\n\tfor (const part of message.parts) {\n\t\tconst p = part as Record<string, unknown>;\n\t\t// Handle both \"data-suggestions\" and generic \"data\" part types\n\t\tif (p.type === \"data\" || p.type === \"data-suggestions\") {\n\t\t\tconst data = p.data as Record<string, unknown> | undefined;\n\t\t\tif (data && Array.isArray(data.suggestions)) {\n\t\t\t\treturn data.suggestions as string[];\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction isConfigObject(\n\tconfig: boolean | SuggestionsConfig | undefined,\n): config is SuggestionsConfig {\n\treturn typeof config === \"object\" && config !== null && \"initial\" in config;\n}\n\nexport function useSuggestions(options: UseSuggestionsOptions) {\n\tconst { messages, status, config } = options;\n\n\tconst [suggestions, setSuggestions] = useState<string[]>(\n\t\t(isConfigObject(config) && config.initial ? config.initial : []) ?? [],\n\t);\n\tconst prevStatusRef = useRef<ChatStatus>(status);\n\n\tconst isEnabled = Boolean(config);\n\n\tconst clear = useCallback(() => {\n\t\tsetSuggestions([]);\n\t}, []);\n\n\t// Clear when a new user message arrives\n\tconst lastMessage = messages[messages.length - 1];\n\tuseEffect(() => {\n\t\tif (lastMessage?.role === \"user\") {\n\t\t\tclear();\n\t\t}\n\t}, [lastMessage, clear]);\n\n\t// Extract suggestions from message parts on streaming → ready transition\n\tuseEffect(() => {\n\t\tconst prevStatus = prevStatusRef.current;\n\t\tprevStatusRef.current = status;\n\n\t\tif (prevStatus === \"streaming\" && status === \"ready\" && isEnabled) {\n\t\t\tconst lastAssistant = [...messages]\n\t\t\t\t.reverse()\n\t\t\t\t.find((m) => m.role === \"assistant\");\n\t\t\tif (!lastAssistant) return;\n\n\t\t\tconsole.log(\"[WaniWani] Assistant parts:\", lastAssistant.parts);\n\n\t\t\tconst extracted = extractSuggestions(lastAssistant);\n\t\t\tconsole.log(\"[WaniWani] Extracted suggestions:\", extracted);\n\t\t\tif (extracted) {\n\t\t\t\tsetSuggestions(extracted);\n\t\t\t}\n\t\t}\n\t}, [status, isEnabled, messages]);\n\n\treturn { suggestions, isLoading: false, clear };\n}\n","import { useEffect, useRef, useState } from \"react\";\n\nconst TYPE_SPEED_MS = 50;\nconst DELETE_SPEED_MS = 30;\nconst PAUSE_AFTER_TYPE_MS = 2000;\nconst PAUSE_AFTER_DELETE_MS = 500;\n\n/**\n * Returns a string that animates like someone typing and deleting the placeholder text.\n * Only animates when `active` is true (i.e. the input is empty).\n */\nexport function useTypingPlaceholder(text: string, active = true): string {\n\tconst [displayed, setDisplayed] = useState(\"\");\n\tconst timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\tuseEffect(() => {\n\t\tif (!active) {\n\t\t\t// Reset so the animation restarts fresh when re-activated\n\t\t\tsetDisplayed(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\tlet i = 0;\n\t\tlet deleting = false;\n\t\tlet disposed = false;\n\n\t\tconst tick = () => {\n\t\t\tif (disposed) return;\n\n\t\t\tif (!deleting) {\n\t\t\t\t// Typing forward\n\t\t\t\ti++;\n\t\t\t\tsetDisplayed(text.slice(0, i));\n\n\t\t\t\tif (i >= text.length) {\n\t\t\t\t\t// Finished typing — pause then start deleting\n\t\t\t\t\tdeleting = true;\n\t\t\t\t\ttimerRef.current = setTimeout(tick, PAUSE_AFTER_TYPE_MS);\n\t\t\t\t} else {\n\t\t\t\t\ttimerRef.current = setTimeout(tick, TYPE_SPEED_MS);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Deleting\n\t\t\t\ti--;\n\t\t\t\tsetDisplayed(text.slice(0, i));\n\n\t\t\t\tif (i <= 0) {\n\t\t\t\t\t// Finished deleting — pause then start typing again\n\t\t\t\t\tdeleting = false;\n\t\t\t\t\ttimerRef.current = setTimeout(tick, PAUSE_AFTER_DELETE_MS);\n\t\t\t\t} else {\n\t\t\t\t\ttimerRef.current = setTimeout(tick, DELETE_SPEED_MS);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Start after a small delay\n\t\ttimerRef.current = setTimeout(tick, PAUSE_AFTER_DELETE_MS);\n\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tclearTimeout(timerRef.current);\n\t\t};\n\t}, [text, active]);\n\n\treturn displayed;\n}\n","import type { ChatTheme } from \"./@types\";\n\nexport const DEFAULT_THEME: Required<ChatTheme> = {\n\tprimaryColor: \"#6366f1\",\n\tprimaryForeground: \"#1f2937\",\n\tbackgroundColor: \"#ffffff\",\n\ttextColor: \"#1f2937\",\n\tmutedColor: \"#6b7280\",\n\tborderColor: \"#e5e7eb\",\n\tassistantBubbleColor: \"#f3f4f6\",\n\tuserBubbleColor: \"#f4f4f4\",\n\tinputBackgroundColor: \"#f9fafb\",\n\tborderRadius: 16,\n\tmessageBorderRadius: 12,\n\tfontFamily: \"system-ui, -apple-system, 'Segoe UI', sans-serif\",\n\theaderBackgroundColor: \"#ffffff\",\n\theaderTextColor: \"#1f2937\",\n\tstatusColor: \"#22c55e\",\n\ttoolCardColor: \"#f4f4f5\",\n};\n\nexport const DARK_THEME: ChatTheme = {\n\tbackgroundColor: \"#212121\",\n\theaderBackgroundColor: \"#1e1e1e\",\n\theaderTextColor: \"#ececec\",\n\ttextColor: \"#ececec\",\n\tprimaryForeground: \"#ffffff\",\n\tmutedColor: \"#8e8ea0\",\n\tborderColor: \"#303030\",\n\tassistantBubbleColor: \"#2f2f2f\",\n\tuserBubbleColor: \"#303030\",\n\tinputBackgroundColor: \"#2f2f2f\",\n\tprimaryColor: \"#6366f1\",\n\tstatusColor: \"#22c55e\",\n\ttoolCardColor: \"#262626\",\n};\n\nconst CSS_VAR_MAP: Record<keyof ChatTheme, string[]> = {\n\tprimaryColor: [\"--ww-primary\", \"--ww-color-primary\"],\n\tprimaryForeground: [\"--ww-primary-fg\", \"--ww-color-primary-foreground\"],\n\tbackgroundColor: [\"--ww-bg\", \"--ww-color-background\"],\n\ttextColor: [\n\t\t\"--ww-text\",\n\t\t\"--ww-color-foreground\",\n\t\t\"--ww-color-accent-foreground\",\n\t],\n\tmutedColor: [\"--ww-muted\", \"--ww-color-muted-foreground\"],\n\tborderColor: [\"--ww-border\", \"--ww-color-border\"],\n\tassistantBubbleColor: [\"--ww-assistant-bubble\", \"--ww-color-accent\"],\n\tuserBubbleColor: [\"--ww-user-bubble\"],\n\tinputBackgroundColor: [\"--ww-input-bg\", \"--ww-color-input\"],\n\tborderRadius: [\"--ww-radius\"],\n\tmessageBorderRadius: [\"--ww-msg-radius\"],\n\tfontFamily: [\"--ww-font\"],\n\theaderBackgroundColor: [\"--ww-header-bg\"],\n\theaderTextColor: [\"--ww-header-text\"],\n\tstatusColor: [\"--ww-status\"],\n\ttoolCardColor: [\"--ww-tool-card\", \"--ww-color-tool-card\"],\n};\n\nexport function mergeTheme(userTheme?: ChatTheme): Required<ChatTheme> {\n\treturn { ...DEFAULT_THEME, ...userTheme };\n}\n\nexport function isDarkTheme(theme: Required<ChatTheme>): boolean {\n\tconst hex = theme.backgroundColor.replace(\"#\", \"\");\n\tconst r = parseInt(hex.substring(0, 2), 16);\n\tconst g = parseInt(hex.substring(2, 4), 16);\n\tconst b = parseInt(hex.substring(4, 6), 16);\n\treturn (r * 299 + g * 587 + b * 114) / 1000 < 128;\n}\n\nexport function themeToCSSProperties(\n\ttheme: Required<ChatTheme>,\n): Record<string, string> {\n\tconst vars: Record<string, string> = {};\n\tfor (const [key, cssVars] of Object.entries(CSS_VAR_MAP)) {\n\t\tconst value = theme[key as keyof ChatTheme];\n\t\tconst resolved = typeof value === \"number\" ? `${value}px` : String(value);\n\t\tfor (const cssVar of cssVars) {\n\t\t\tvars[cssVar] = resolved;\n\t\t}\n\t}\n\treturn vars;\n}\n","\"use client\";\n\nimport {\n\tforwardRef,\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport type { ChatCardProps, ChatHandle } from \"../@types\";\nimport {\n\tConversation,\n\tConversationContent,\n\tConversationScrollButton,\n} from \"../ai-elements/conversation\";\nimport {\n\tPromptInput,\n\tPromptInputAddAttachments,\n\tPromptInputSubmit,\n\tPromptInputTextarea,\n} from \"../ai-elements/prompt-input\";\nimport { MessageList } from \"../components/message-list\";\nimport { Suggestions } from \"../components/suggestions\";\nimport { useChatEngine } from \"../hooks/use-chat-engine\";\nimport { useSuggestions } from \"../hooks/use-suggestions\";\nimport { useTypingPlaceholder } from \"../hooks/use-typing-placeholder\";\nimport { cn } from \"../lib/utils\";\nimport { isDarkTheme, mergeTheme, themeToCSSProperties } from \"../theme\";\n\nexport const ChatCard = forwardRef<ChatHandle, ChatCardProps>(\n\tfunction ChatCard(props, ref) {\n\t\tconst {\n\t\t\ttheme: userTheme,\n\t\t\ttitle = \"Assistant\",\n\t\t\tsubtitle,\n\t\t\tshowStatus = true,\n\t\t\twidth = 500,\n\t\t\theight = 600,\n\t\t\tallowAttachments = false,\n\t\t\twelcomeMessage,\n\t\t\tplaceholder = \"Ask me anything...\",\n\t\t\ttriggerEvent = \"triggerDemoRequest\",\n\t\t\tresourceEndpoint,\n\t\t\tapi,\n\t\t} = props;\n\n\t\tconst effectiveResourceEndpoint =\n\t\t\tresourceEndpoint ?? (api ? `${api}/resource` : undefined);\n\n\t\tconst resolvedTheme = mergeTheme(userTheme);\n\t\tconst cssVars = themeToCSSProperties(resolvedTheme);\n\t\tconst isDark = isDarkTheme(resolvedTheme);\n\n\t\tconst engine = useChatEngine(props);\n\n\t\tconst animatedPlaceholder = useTypingPlaceholder(placeholder, !engine.text);\n\n\t\tconst [isHighlighted, setIsHighlighted] = useState(false);\n\t\tconst cardRef = useRef<HTMLDivElement>(null);\n\t\tconst highlightTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n\t\tconst focusInput = useCallback(() => {\n\t\t\tconst container = cardRef.current;\n\t\t\tif (!container) return;\n\t\t\tcontainer.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\t\tconst textarea = container.querySelector(\"textarea\");\n\t\t\tif (textarea) {\n\t\t\t\tsetTimeout(() => textarea.focus(), 300);\n\t\t\t}\n\t\t\tsetIsHighlighted(true);\n\t\t\tclearTimeout(highlightTimerRef.current);\n\t\t\thighlightTimerRef.current = setTimeout(\n\t\t\t\t() => setIsHighlighted(false),\n\t\t\t\t2000,\n\t\t\t);\n\t\t}, []);\n\n\t\tconst suggestionsState = useSuggestions({\n\t\t\tmessages: engine.messages,\n\t\t\tstatus: engine.status,\n\t\t\tconfig: props.suggestions,\n\t\t});\n\n\t\tconst handleWidgetMessage = useCallback(\n\t\t\t(message: {\n\t\t\t\trole: string;\n\t\t\t\tcontent: Array<{ type: string; text?: string }>;\n\t\t\t}) => {\n\t\t\t\tconst text = message.content\n\t\t\t\t\t.map((c) => c.text ?? \"\")\n\t\t\t\t\t.join(\"\")\n\t\t\t\t\t.trim();\n\t\t\t\tif (text) engine.handleSubmit({ text, files: [] });\n\t\t\t},\n\t\t\t[engine.handleSubmit],\n\t\t);\n\n\t\tconst handleSuggestionSelect = useCallback(\n\t\t\t(suggestion: string) => {\n\t\t\t\tsuggestionsState.clear();\n\t\t\t\tengine.handleSubmit({ text: suggestion, files: [] });\n\t\t\t},\n\t\t\t[suggestionsState.clear, engine.handleSubmit],\n\t\t);\n\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tsendMessage: (text: string) => {\n\t\t\t\t\tengine.handleSubmit({ text, files: [] });\n\t\t\t\t\tfocusInput();\n\t\t\t\t},\n\t\t\t\tfocus: focusInput,\n\t\t\t}),\n\t\t\t[engine.handleSubmit, focusInput],\n\t\t);\n\n\t\t// Listen for custom trigger event (e.g. \"triggerDemoRequest\")\n\t\tuseEffect(() => {\n\t\t\tif (!triggerEvent) return;\n\t\t\tconst handler = (e: Event) => {\n\t\t\t\tconst detail = (e as CustomEvent).detail;\n\t\t\t\tconst message =\n\t\t\t\t\ttypeof detail?.message === \"string\" ? detail.message : undefined;\n\t\t\t\tif (message) {\n\t\t\t\t\tengine.handleSubmit({ text: message, files: [] });\n\t\t\t\t}\n\t\t\t\tfocusInput();\n\t\t\t};\n\t\t\twindow.addEventListener(triggerEvent, handler);\n\t\t\treturn () => window.removeEventListener(triggerEvent, handler);\n\t\t}, [triggerEvent, engine.handleSubmit, focusInput]);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={cardRef}\n\t\t\t\tstyle={{ ...cssVars, width, height }}\n\t\t\t\tdata-waniwani-chat=\"\"\n\t\t\t\tdata-waniwani-layout=\"card\"\n\t\t\t\t{...(isDark ? { \"data-waniwani-dark\": \"\" } : {})}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"ww:flex ww:flex-col ww:font-[family-name:var(--ww-font)] ww:text-foreground ww:bg-background ww:rounded-[var(--ww-radius)] ww:border ww:border-border ww:shadow-md ww:overflow-hidden ww:transition-shadow ww:duration-300\",\n\t\t\t\t\tisHighlighted &&\n\t\t\t\t\t\t\"ww:ring-2 ww:ring-blue-400/70 ww:ring-offset-2 ww:ring-offset-background\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{/* Header */}\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"ww:shrink-0 ww:flex ww:items-center ww:gap-3 ww:px-4 ww:py-2 ww:border-b ww:border-border\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackgroundColor: resolvedTheme.headerBackgroundColor,\n\t\t\t\t\t\tcolor: resolvedTheme.headerTextColor,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{showStatus && (\n\t\t\t\t\t\t<span className=\"ww:size-2.5 ww:rounded-full ww:bg-status\" />\n\t\t\t\t\t)}\n\t\t\t\t\t<div className=\"ww:flex-1 ww:min-w-0\">\n\t\t\t\t\t\t<div className=\"ww:text-xs ww:font-semibold ww:truncate\">\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{subtitle && (\n\t\t\t\t\t\t\t<div className=\"ww:text-[11px] ww:text-muted-foreground ww:truncate\">\n\t\t\t\t\t\t\t\t{subtitle}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t{/* Messages */}\n\t\t\t\t<Conversation className=\"ww:flex-1 ww:min-h-0 ww:bg-background\">\n\t\t\t\t\t<ConversationContent>\n\t\t\t\t\t\t<MessageList\n\t\t\t\t\t\t\tmessages={engine.messages}\n\t\t\t\t\t\t\tstatus={engine.status}\n\t\t\t\t\t\t\twelcomeMessage={welcomeMessage}\n\t\t\t\t\t\t\tresourceEndpoint={effectiveResourceEndpoint}\n\t\t\t\t\t\t\tisDark={isDark}\n\t\t\t\t\t\t\tonFollowUp={handleWidgetMessage}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</ConversationContent>\n\t\t\t\t\t<ConversationScrollButton />\n\t\t\t\t</Conversation>\n\n\t\t\t\t{/* Suggestions */}\n\t\t\t\t<Suggestions\n\t\t\t\t\tsuggestions={suggestionsState.suggestions}\n\t\t\t\t\tisLoading={suggestionsState.isLoading}\n\t\t\t\t\tonSelect={handleSuggestionSelect}\n\t\t\t\t\tclassName=\"ww:border-t ww:border-border\"\n\t\t\t\t/>\n\n\t\t\t\t{/* Input */}\n\t\t\t\t<div className=\"ww:shrink-0 ww:border-t ww:border-border ww:bg-background\">\n\t\t\t\t\t<PromptInput\n\t\t\t\t\t\tonSubmit={engine.handleSubmit}\n\t\t\t\t\t\tglobalDrop={allowAttachments}\n\t\t\t\t\t\tmultiple={allowAttachments}\n\t\t\t\t\t\tclassName={cn(\"ww:rounded-none ww:border-0\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"ww:flex ww:items-center ww:gap-1 ww:px-3 ww:py-2\">\n\t\t\t\t\t\t\t{allowAttachments && <PromptInputAddAttachments />}\n\t\t\t\t\t\t\t<PromptInputTextarea\n\t\t\t\t\t\t\t\tonChange={engine.handleTextChange}\n\t\t\t\t\t\t\t\tvalue={engine.text}\n\t\t\t\t\t\t\t\tplaceholder={animatedPlaceholder}\n\t\t\t\t\t\t\t\tclassName=\"ww:min-h-0 ww:py-1.5 ww:px-2\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<PromptInputSubmit status={engine.status} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</PromptInput>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t},\n);\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useRef","useState","ArrowDownIcon","useCallback","StickToBottom","useStickToBottomContext","clsx","extendTailwindMerge","twMerge","cn","inputs","jsx","Button","className","variant","size","type","props","cn","jsx","Conversation","className","props","StickToBottom","cn","ConversationContent","ConversationScrollButton","isAtBottom","scrollToBottom","useStickToBottomContext","handleScrollToBottom","useCallback","Button","ArrowDownIcon","ArrowUpIcon","LoaderIcon","PaperclipIcon","SquareIcon","XIcon","nanoid","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","jsx","jsxs","convertBlobUrlToDataUrl","url","blob","resolve","reader","LocalAttachmentsContext","createContext","usePromptInputAttachments","context","useContext","PromptInput","className","accept","multiple","globalDrop","maxFiles","maxFileSize","onSubmit","children","props","inputRef","useRef","formRef","items","setItems","useState","filesRef","useEffect","openFileDialog","useCallback","add","fileList","incoming","withinSize","f","valid","prev","capacity","capped","file","nanoid","remove","id","found","clear","handleChange","event","onDragOver","e","onDrop","handleSubmit","form","text","convertedFiles","_id","item","dataUrl","result","attachmentsCtx","useMemo","cn","PromptInputTextarea","onChange","onKeyDown","className","placeholder","props","attachments","usePromptInputAttachments","isComposing","setIsComposing","useState","handleKeyDown","useCallback","e","form","lastAttachment","handlePaste","event","items","files","item","file","jsx","cn","PromptInputSubmit","status","onStop","onClick","children","isGenerating","Icon","ArrowUpIcon","LoaderIcon","SquareIcon","handleClick","Button","PromptInputAddAttachments","jsxs","XIcon","PaperclipIcon","FileIcon","jsx","jsxs","Attachments","files","className","props","cn","file","i","AttachmentItem","FileIcon","jsx","Loader","className","size","props","cn","i","cjk","code","memo","Streamdown","jsx","Message","className","from","props","cn","MessageContent","children","streamdownPlugins","cjk","code","MessageResponse","memo","Streamdown","prevProps","nextProps","jsx","Reasoning","className","text","props","cn","BracesIcon","CheckIcon","ChevronDownIcon","ChevronRightIcon","ClipboardCopyIcon","ServerIcon","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","truncateJSON","data","maxLength","stringified","entries","parts","remaining","key","value","keyAbbrev","valStr","part","CopyButton","text","className","copied","setCopied","useState","timeoutRef","useRef","useEffect","handleCopy","useCallback","e","Button","cn","CheckIcon","ClipboardCopyIcon","CollapsibleJSON","label","props","expanded","setExpanded","fullJSON","useMemo","preview","v","ChevronRightIcon","ToolOpenContext","createContext","Tool","defaultOpen","children","open","setOpen","o","ToolHeader","title","state","toggle","useContext","isRunning","BracesIcon","ChevronDownIcon","ToolContent","className","children","props","open","useContext","ToolOpenContext","jsx","cn","ToolInput","input","CollapsibleJSON","getUiMeta","output","meta","ui","getResourceUri","uri","getAutoHeight","ToolOutput","errorText","jsxs","useCallback","useEffect","useMemo","useRef","useState","jsx","DEFAULT_RESOURCE_ENDPOINT","MAX_HEIGHT","DEFAULT_HEIGHT","PROTOCOL_VERSION","RESIZE_ANIMATION_MS","HANDSHAKE_TIMEOUT_MS","MAX_RETRIES","McpAppFrame","resourceUri","toolInput","toolResult","resourceEndpoint","isDark","className","autoHeight","onOpenLink","onFollowUp","iframeRef","useRef","toolInputRef","toolResultRef","lastSizeRef","animationRef","initializedRef","retryCountRef","height","setHeight","useState","width","setWidth","onOpenLinkRef","onFollowUpRef","clampHeight","useCallback","h","iframeSrc","useMemo","isDarkRef","useEffect","iframe","disposed","handshakeReceived","debug","args","handshakeTimer","url","postToIframe","msg","handleMessage","event","data","method","id","input","result","content","params","newHeight","newWidth","last","heightChanged","widthChanged","clamped","from","anim","cn","Component","jsx","jsxs","WidgetErrorBoundary","error","Fragment","jsx","jsxs","formatToolName","name","c","MessageList","messages","status","welcomeMessage","resourceEndpoint","isDark","onFollowUp","isLoading","lastMessage","hasMessages","showLoaderBubble","Message","MessageContent","MessageResponse","message","textParts","p","reasoningParts","fileParts","toolParts","isLastAssistant","hasTextContent","part","i","Reasoning","output","resourceUri","getResourceUri","autoHeight","getAutoHeight","Tool","ToolHeader","ToolContent","ToolInput","ToolOutput","WidgetErrorBoundary","McpAppFrame","Attachments","Loader","jsx","Suggestions","suggestions","isLoading","onSelect","className","props","cn","i","suggestion","index","useChat","DefaultChatTransport","useCallback","useRef","useState","useChatEngine","props","api","userHeaders","body","onMessageSent","onResponseReceived","transportRef","messages","sendMessage","status","error","text","setText","handleSubmit","message","hasText","hasFiles","handleTextChange","e","isLoading","lastMessage","hasMessages","showLoaderBubble","useCallback","useEffect","useRef","useState","extractSuggestions","message","part","p","data","isConfigObject","config","useSuggestions","options","messages","status","suggestions","setSuggestions","prevStatusRef","isEnabled","clear","lastMessage","prevStatus","lastAssistant","m","extracted","useEffect","useRef","useState","TYPE_SPEED_MS","DELETE_SPEED_MS","PAUSE_AFTER_TYPE_MS","PAUSE_AFTER_DELETE_MS","useTypingPlaceholder","text","active","displayed","setDisplayed","timerRef","i","deleting","disposed","tick","DEFAULT_THEME","DARK_THEME","CSS_VAR_MAP","mergeTheme","userTheme","isDarkTheme","theme","hex","r","g","b","themeToCSSProperties","vars","key","cssVars","value","resolved","cssVar","jsx","jsxs","ChatBar","forwardRef","props","ref","userTheme","width","expandedHeight","allowAttachments","welcomeMessage","placeholder","triggerEvent","resourceEndpoint","api","effectiveResourceEndpoint","resolvedTheme","mergeTheme","cssVars","themeToCSSProperties","isDark","isDarkTheme","engine","useChatEngine","suggestionsState","useSuggestions","handleWidgetMessage","useCallback","message","text","c","handleSuggestionSelect","suggestion","animatedPlaceholder","useTypingPlaceholder","isFocused","setIsFocused","useState","isHighlighted","setIsHighlighted","containerRef","useRef","highlightTimerRef","focusInput","container","textarea","useImperativeHandle","useEffect","handler","e","detail","isExpanded","handleClickOutside","handleFocus","cn","Conversation","ConversationContent","MessageList","ConversationScrollButton","Suggestions","PromptInput","PromptInputAddAttachments","PromptInputTextarea","PromptInputSubmit","forwardRef","useCallback","useEffect","useImperativeHandle","useRef","useState","jsx","jsxs","ChatCard","forwardRef","props","ref","userTheme","title","subtitle","showStatus","width","height","allowAttachments","welcomeMessage","placeholder","triggerEvent","resourceEndpoint","api","effectiveResourceEndpoint","resolvedTheme","mergeTheme","cssVars","themeToCSSProperties","isDark","isDarkTheme","engine","useChatEngine","animatedPlaceholder","useTypingPlaceholder","isHighlighted","setIsHighlighted","useState","cardRef","useRef","highlightTimerRef","focusInput","useCallback","container","textarea","suggestionsState","useSuggestions","handleWidgetMessage","message","text","c","handleSuggestionSelect","suggestion","useImperativeHandle","useEffect","handler","e","detail","cn","Conversation","ConversationContent","MessageList","ConversationScrollButton","Suggestions","PromptInput","PromptInputAddAttachments","PromptInputTextarea","PromptInputSubmit"]}
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:system-ui,-apple-system,"Segoe UI",sans-serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-400:oklch(70.4% .191 22.216);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-teal-400:oklch(77.7% .152 181.912);--color-cyan-400:oklch(78.9% .154 211.53);--color-blue-400:oklch(70.7% .165 254.624);--color-indigo-400:oklch(67.3% .182 276.935);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0,0,.2,1)infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--animate-bounce:bounce 1s infinite;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:16px;--color-background:#fff;--color-foreground:#1f2937;--color-primary:#6366f1;--color-primary-foreground:#1f2937;--color-muted:#f1f5f9;--color-muted-foreground:#6b7280;--color-border:#e5e7eb;--color-input:#f9fafb;--color-accent:#f3f4f6;--color-accent-foreground:#1f2937;--color-user-bubble:#f4f4f4;--color-status:#22c55e;--color-tool-card:#f4f4f5}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing)*0)}.top-0\.5{top:calc(var(--spacing)*.5)}.right-0{right:calc(var(--spacing)*0)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.bottom-0\.5{bottom:calc(var(--spacing)*.5)}.bottom-1{bottom:calc(var(--spacing)*1)}.bottom-4{bottom:calc(var(--spacing)*4)}.bottom-14{bottom:calc(var(--spacing)*14)}.left-0{left:calc(var(--spacing)*0)}.left-\[50\%\]{left:50%}.z-10{z-index:10}.z-\[9998\]{z-index:9998}.z-\[9999\]{z-index:9999}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing)*4)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.field-sizing-content{field-sizing:content}.size-2{width:calc(var(--spacing)*2);height:calc(var(--spacing)*2)}.size-2\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-7{width:calc(var(--spacing)*7);height:calc(var(--spacing)*7)}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-full{width:100%;height:100%}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-11{height:calc(var(--spacing)*11)}.h-16{height:calc(var(--spacing)*16)}.h-auto{height:auto}.h-full{height:100%}.max-h-0{max-height:calc(var(--spacing)*0)}.max-h-48{max-height:calc(var(--spacing)*48)}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-16{min-height:calc(var(--spacing)*16)}.min-h-\[120px\]{min-height:120px}.min-h-\[160px\]{min-height:160px}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-8{width:calc(var(--spacing)*8)}.w-11{width:calc(var(--spacing)*11)}.w-16{width:calc(var(--spacing)*16)}.w-80{width:calc(var(--spacing)*80)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-24{max-width:calc(var(--spacing)*24)}.max-w-32{max-width:calc(var(--spacing)*32)}.max-w-\[95\%\]{max-width:95%}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-0{--tw-translate-y:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-2{--tw-translate-y:calc(var(--spacing)*2);translate:var(--tw-translate-x)var(--tw-translate-y)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x)var(--tw-scale-y)}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-\[shimmer_1\.5s_ease-in-out_infinite\]{animation:1.5s ease-in-out infinite shimmer}.animate-\[ww-fade-in_0\.2s_ease-out_both\]{animation:.2s ease-out both ww-fade-in}.animate-bounce{animation:var(--animate-bounce)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*5)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.rounded{border-radius:var(--radius)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[var\(--ww-radius\)\]{border-radius:var(--ww-radius)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-\[\#414141\]{border-color:#414141}.border-\[\#424242\]{border-color:#424242}.border-blue-400\/20{border-color:#54a2ff33}@supports (color:color-mix(in lab, red, red)){.border-blue-400\/20{border-color:color-mix(in oklab,var(--color-blue-400)20%,transparent)}}.border-border{border-color:var(--color-border)}.bg-\[\#2f2f2f\]{background-color:#2f2f2f}.bg-\[\#212121\]{background-color:#212121}.bg-\[\#424242\]{background-color:#424242}.bg-accent{background-color:var(--color-accent)}.bg-background{background-color:var(--color-background)}.bg-background\/20{background-color:#fff3}@supports (color:color-mix(in lab, red, red)){.bg-background\/20{background-color:color-mix(in oklab,var(--color-background)20%,transparent)}}.bg-background\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-background\/80{background-color:color-mix(in oklab,var(--color-background)80%,transparent)}}.bg-emerald-500\/20{background-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/20{background-color:color-mix(in oklab,var(--color-emerald-500)20%,transparent)}}.bg-foreground{background-color:var(--color-foreground)}.bg-gray-500\/20{background-color:#6a728233}@supports (color:color-mix(in lab, red, red)){.bg-gray-500\/20{background-color:color-mix(in oklab,var(--color-gray-500)20%,transparent)}}.bg-muted{background-color:var(--color-muted)}.bg-muted-foreground\/60{background-color:#6b728099}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/60{background-color:color-mix(in oklab,var(--color-muted-foreground)60%,transparent)}}.bg-muted\/50{background-color:#f1f5f980}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab,var(--color-muted)50%,transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-status{background-color:var(--color-status)}.bg-tool-card{background-color:var(--color-tool-card)}.bg-transparent{background-color:#0000}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-400{--tw-gradient-from:var(--color-blue-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-cyan-400{--tw-gradient-from:var(--color-cyan-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-teal-400{--tw-gradient-from:var(--color-teal-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.via-slate-200{--tw-gradient-via:var(--color-slate-200);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-cyan-400{--tw-gradient-to:var(--color-cyan-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-emerald-400{--tw-gradient-to:var(--color-emerald-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-slate-400{--tw-gradient-to:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-teal-400{--tw-gradient-to:var(--color-teal-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.bg-\[length\:200\%_100\%\]{background-size:200% 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.object-cover{object-fit:cover}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-8{padding:calc(var(--spacing)*8)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-12{padding-block:calc(var(--spacing)*12)}.pt-2\.5{padding-top:calc(var(--spacing)*2.5)}.pt-3{padding-top:calc(var(--spacing)*3)}.pb-1\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.text-center{text-align:center}.text-left{text-align:left}.font-\[\'Inter\'\,_system-ui\,_sans-serif\]{font-family:Inter,system-ui,sans-serif}.font-\[family-name\:var\(--ww-font\)\]{font-family:var(--ww-font)}.font-mono{font-family:var(--font-mono)}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-background{color:var(--color-background)}.text-emerald-400{color:var(--color-emerald-400)}.text-foreground{color:var(--color-foreground)}.text-foreground\/80{color:#1f2937cc}@supports (color:color-mix(in lab, red, red)){.text-foreground\/80{color:color-mix(in oklab,var(--color-foreground)80%,transparent)}}.text-gray-200{color:var(--color-gray-200)}.text-gray-300{color:var(--color-gray-300)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-indigo-400{color:var(--color-indigo-400)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-red-400{color:var(--color-red-400)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-blue-400\/70{--tw-ring-color:#54a2ffb3}@supports (color:color-mix(in lab, red, red)){.ring-blue-400\/70{--tw-ring-color:color-mix(in oklab,var(--color-blue-400)70%,transparent)}}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.ring-offset-background{--tw-ring-offset-color:var(--color-background)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-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,);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,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[grid-template-rows\,opacity\]{transition-property:grid-template-rows,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.\[animation-delay\:-0\.3s\]{animation-delay:-.3s}.\[animation-delay\:-0\.15s\]{animation-delay:-.15s}@media (hover:hover){.group-hover\:text-white:is(:where(.group):hover *){color:var(--color-white)}.group-hover\:opacity-0:is(:where(.group):hover *){opacity:0}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.group-\[\.is-assistant\]\:text-foreground:is(:where(.group).is-assistant *){color:var(--color-foreground)}.group-\[\.is-user\]\:ml-auto:is(:where(.group).is-user *){margin-left:auto}.group-\[\.is-user\]\:rounded-lg:is(:where(.group).is-user *){border-radius:var(--radius-lg)}.group-\[\.is-user\]\:bg-user-bubble:is(:where(.group).is-user *){background-color:var(--color-user-bubble)}.group-\[\.is-user\]\:px-4:is(:where(.group).is-user *){padding-inline:calc(var(--spacing)*4)}.group-\[\.is-user\]\:py-3:is(:where(.group).is-user *){padding-block:calc(var(--spacing)*3)}.group-\[\.is-user\]\:text-primary-foreground:is(:where(.group).is-user *){color:var(--color-primary-foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--color-muted-foreground)}@media (hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:border-primary\/30:hover{border-color:#6366f14d}@supports (color:color-mix(in lab, red, red)){.hover\:border-primary\/30:hover{border-color:color-mix(in oklab,var(--color-primary)30%,transparent)}}.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-foreground:hover{background-color:var(--color-foreground)}.hover\:bg-primary\/90:hover{background-color:#6366f1e6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary)90%,transparent)}}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white)5%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}.hover\:text-foreground:hover{color:var(--color-foreground)}.hover\:text-gray-200:hover{color:var(--color-gray-200)}.hover\:text-gray-300:hover{color:var(--color-gray-300)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:rounded-3xl{border-radius:var(--radius-3xl)}}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:calc(var(--spacing)*0)}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:calc(var(--spacing)*0)}}@keyframes ww-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes ww-fade-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}@keyframes ww-pulse{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}[data-waniwani-chat]{--color-background:var(--ww-bg);--color-foreground:var(--ww-text);--color-primary:var(--ww-primary);--color-primary-foreground:var(--ww-primary-fg);--color-muted-foreground:var(--ww-muted);--color-border:var(--ww-border);--color-input:var(--ww-input-bg);--color-accent:var(--ww-assistant-bubble);--color-accent-foreground:var(--ww-text);--color-user-bubble:var(--ww-user-bubble);--color-card:var(--ww-bg);--color-card-foreground:var(--ww-text);--color-card-header:var(--ww-header-bg);--color-card-header-foreground:var(--ww-header-text);--color-status:var(--ww-status);--color-tool-card:var(--ww-tool-card);--radius:var(--ww-radius);--font-sans:var(--ww-font)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--ww-font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ww-color-blue-400:oklch(70.7% .165 254.624);--ww-spacing:.25rem;--ww-text-xs:.75rem;--ww-text-xs--line-height:calc(1/.75);--ww-text-sm:.875rem;--ww-text-sm--line-height:calc(1.25/.875);--ww-text-base:1rem;--ww-text-base--line-height:calc(1.5/1);--ww-font-weight-medium:500;--ww-font-weight-semibold:600;--ww-tracking-wide:.025em;--ww-radius-md:.375rem;--ww-radius-lg:.5rem;--ww-ease-out:cubic-bezier(0,0,.2,1);--ww-animate-spin:spin 1s linear infinite;--ww-animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--ww-blur-xl:24px;--ww-default-transition-duration:.15s;--ww-default-transition-timing-function:cubic-bezier(.4,0,.2,1);--ww-default-font-family:var(--ww-font-sans,system-ui,-apple-system,"Segoe UI",sans-serif);--ww-default-mono-font-family:var(--ww-font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--ww-default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--ww-default-font-feature-settings,normal);font-variation-settings:var(--ww-default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--ww-default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--ww-default-mono-font-feature-settings,normal);font-variation-settings:var(--ww-default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.ww\:pointer-events-none{pointer-events:none}.ww\:absolute{position:absolute}.ww\:relative{position:relative}.ww\:bottom-4{bottom:calc(var(--ww-spacing)*4)}.ww\:left-\[50\%\]{left:50%}.ww\:mt-0\.5{margin-top:calc(var(--ww-spacing)*.5)}.ww\:mt-2{margin-top:calc(var(--ww-spacing)*2)}.ww\:mb-2{margin-bottom:calc(var(--ww-spacing)*2)}.ww\:mb-4{margin-bottom:calc(var(--ww-spacing)*4)}.ww\:ml-auto{margin-left:auto}.ww\:contents{display:contents}.ww\:flex{display:flex}.ww\:grid{display:grid}.ww\:hidden{display:none}.ww\:inline-flex{display:inline-flex}.ww\:field-sizing-content{field-sizing:content}.ww\:size-2{width:calc(var(--ww-spacing)*2);height:calc(var(--ww-spacing)*2)}.ww\:size-2\.5{width:calc(var(--ww-spacing)*2.5);height:calc(var(--ww-spacing)*2.5)}.ww\:size-3{width:calc(var(--ww-spacing)*3);height:calc(var(--ww-spacing)*3)}.ww\:size-3\.5{width:calc(var(--ww-spacing)*3.5);height:calc(var(--ww-spacing)*3.5)}.ww\:size-4{width:calc(var(--ww-spacing)*4);height:calc(var(--ww-spacing)*4)}.ww\:size-5{width:calc(var(--ww-spacing)*5);height:calc(var(--ww-spacing)*5)}.ww\:size-7{width:calc(var(--ww-spacing)*7);height:calc(var(--ww-spacing)*7)}.ww\:size-8{width:calc(var(--ww-spacing)*8);height:calc(var(--ww-spacing)*8)}.ww\:size-9{width:calc(var(--ww-spacing)*9);height:calc(var(--ww-spacing)*9)}.ww\:size-full{width:100%;height:100%}.ww\:h-7{height:calc(var(--ww-spacing)*7)}.ww\:h-8{height:calc(var(--ww-spacing)*8)}.ww\:h-9{height:calc(var(--ww-spacing)*9)}.ww\:h-16{height:calc(var(--ww-spacing)*16)}.ww\:h-auto{height:auto}.ww\:max-h-0{max-height:calc(var(--ww-spacing)*0)}.ww\:max-h-48{max-height:calc(var(--ww-spacing)*48)}.ww\:min-h-0{min-height:calc(var(--ww-spacing)*0)}.ww\:min-h-16{min-height:calc(var(--ww-spacing)*16)}.ww\:w-fit{width:fit-content}.ww\:w-full{width:100%}.ww\:max-w-24{max-width:calc(var(--ww-spacing)*24)}.ww\:max-w-32{max-width:calc(var(--ww-spacing)*32)}.ww\:max-w-\[95\%\]{max-width:95%}.ww\:max-w-full{max-width:100%}.ww\:min-w-0{min-width:calc(var(--ww-spacing)*0)}.ww\:flex-1{flex:1}.ww\:shrink-0{flex-shrink:0}.ww\:translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.ww\:translate-y-0{--tw-translate-y:calc(var(--ww-spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.ww\:translate-y-2{--tw-translate-y:calc(var(--ww-spacing)*2);translate:var(--tw-translate-x)var(--tw-translate-y)}.ww\:rotate-90{rotate:90deg}.ww\:rotate-180{rotate:180deg}.ww\:animate-\[ww-fade-in_0\.2s_ease-out_both\]{animation:.2s ease-out both ww-fade-in}.ww\:animate-pulse{animation:var(--ww-animate-pulse)}.ww\:animate-spin{animation:var(--ww-animate-spin)}.ww\:cursor-pointer{cursor:pointer}.ww\:resize-none{resize:none}.ww\:grid-rows-\[0fr\]{grid-template-rows:0fr}.ww\:grid-rows-\[1fr\]{grid-template-rows:1fr}.ww\:flex-col{flex-direction:column}.ww\:flex-wrap{flex-wrap:wrap}.ww\:items-center{align-items:center}.ww\:items-start{align-items:flex-start}.ww\:justify-between{justify-content:space-between}.ww\:justify-center{justify-content:center}.ww\:justify-end{justify-content:flex-end}.ww\:gap-1{gap:calc(var(--ww-spacing)*1)}.ww\:gap-1\.5{gap:calc(var(--ww-spacing)*1.5)}.ww\:gap-2{gap:calc(var(--ww-spacing)*2)}.ww\:gap-3{gap:calc(var(--ww-spacing)*3)}.ww\:gap-8{gap:calc(var(--ww-spacing)*8)}:where(.ww\:space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ww-spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ww-spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.ww\:space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ww-spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ww-spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}.ww\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ww\:overflow-hidden{overflow:hidden}.ww\:overflow-x-auto{overflow-x:auto}.ww\:overflow-y-hidden{overflow-y:hidden}.ww\:rounded{border-radius:var(--ww-radius,16px)}.ww\:rounded-\[var\(--ww-radius\)\]{border-radius:var(--ww-radius)}.ww\:rounded-full{border-radius:3.40282e38px}.ww\:rounded-lg{border-radius:var(--ww-radius-lg)}.ww\:rounded-md{border-radius:var(--ww-radius-md)}.ww\:rounded-none{border-radius:0}.ww\:border{border-style:var(--tw-border-style);border-width:1px}.ww\:border-0{border-style:var(--tw-border-style);border-width:0}.ww\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.ww\:border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ww\:border-border{border-color:var(--ww-color-border,#e5e7eb)}.ww\:bg-accent{background-color:var(--ww-color-accent,#f3f4f6)}.ww\:bg-background,.ww\:bg-background\/20{background-color:var(--ww-color-background,#fff)}@supports (color:color-mix(in lab, red, red)){.ww\:bg-background\/20{background-color:color-mix(in oklab,var(--ww-color-background,#fff)20%,transparent)}}.ww\:bg-background\/80{background-color:var(--ww-color-background,#fff)}@supports (color:color-mix(in lab, red, red)){.ww\:bg-background\/80{background-color:color-mix(in oklab,var(--ww-color-background,#fff)80%,transparent)}}.ww\:bg-foreground{background-color:var(--ww-color-foreground,#1f2937)}.ww\:bg-muted{background-color:var(--ww-color-muted,#f1f5f9)}.ww\:bg-muted-foreground\/60{background-color:var(--ww-color-muted-foreground,#6b7280)}@supports (color:color-mix(in lab, red, red)){.ww\:bg-muted-foreground\/60{background-color:color-mix(in oklab,var(--ww-color-muted-foreground,#6b7280)60%,transparent)}}.ww\:bg-muted\/50{background-color:var(--ww-color-muted,#f1f5f9)}@supports (color:color-mix(in lab, red, red)){.ww\:bg-muted\/50{background-color:color-mix(in oklab,var(--ww-color-muted,#f1f5f9)50%,transparent)}}.ww\:bg-primary{background-color:var(--ww-color-primary,#6366f1)}.ww\:bg-status{background-color:var(--ww-color-status,#22c55e)}.ww\:bg-tool-card{background-color:var(--ww-color-tool-card,#f4f4f5)}.ww\:bg-transparent{background-color:#0000}.ww\:object-cover{object-fit:cover}.ww\:p-3{padding:calc(var(--ww-spacing)*3)}.ww\:p-4{padding:calc(var(--ww-spacing)*4)}.ww\:px-1\.5{padding-inline:calc(var(--ww-spacing)*1.5)}.ww\:px-2{padding-inline:calc(var(--ww-spacing)*2)}.ww\:px-3{padding-inline:calc(var(--ww-spacing)*3)}.ww\:px-4{padding-inline:calc(var(--ww-spacing)*4)}.ww\:py-0\.5{padding-block:calc(var(--ww-spacing)*.5)}.ww\:py-1{padding-block:calc(var(--ww-spacing)*1)}.ww\:py-1\.5{padding-block:calc(var(--ww-spacing)*1.5)}.ww\:py-2{padding-block:calc(var(--ww-spacing)*2)}.ww\:py-2\.5{padding-block:calc(var(--ww-spacing)*2.5)}.ww\:py-3{padding-block:calc(var(--ww-spacing)*3)}.ww\:pt-2\.5{padding-top:calc(var(--ww-spacing)*2.5)}.ww\:pt-3{padding-top:calc(var(--ww-spacing)*3)}.ww\:pb-1\.5{padding-bottom:calc(var(--ww-spacing)*1.5)}.ww\:pb-3{padding-bottom:calc(var(--ww-spacing)*3)}.ww\:text-left{text-align:left}.ww\:font-\[family-name\:var\(--ww-font\)\]{font-family:var(--ww-font)}.ww\:font-mono{font-family:var(--ww-font-mono)}.ww\:text-base{font-size:var(--ww-text-base);line-height:var(--tw-leading,var(--ww-text-base--line-height))}.ww\:text-sm{font-size:var(--ww-text-sm);line-height:var(--tw-leading,var(--ww-text-sm--line-height))}.ww\:text-xs{font-size:var(--ww-text-xs);line-height:var(--tw-leading,var(--ww-text-xs--line-height))}.ww\:text-\[10px\]{font-size:10px}.ww\:text-\[11px\]{font-size:11px}.ww\:font-medium{--tw-font-weight:var(--ww-font-weight-medium);font-weight:var(--ww-font-weight-medium)}.ww\:font-semibold{--tw-font-weight:var(--ww-font-weight-semibold);font-weight:var(--ww-font-weight-semibold)}.ww\:tracking-wide{--tw-tracking:var(--ww-tracking-wide);letter-spacing:var(--ww-tracking-wide)}.ww\:break-words{overflow-wrap:break-word}.ww\:break-all{word-break:break-all}.ww\:whitespace-pre-wrap{white-space:pre-wrap}.ww\:text-background{color:var(--ww-color-background,#fff)}.ww\:text-foreground,.ww\:text-foreground\/80{color:var(--ww-color-foreground,#1f2937)}@supports (color:color-mix(in lab, red, red)){.ww\:text-foreground\/80{color:color-mix(in oklab,var(--ww-color-foreground,#1f2937)80%,transparent)}}.ww\:text-muted-foreground{color:var(--ww-color-muted-foreground,#6b7280)}.ww\:text-primary{color:var(--ww-color-primary,#6366f1)}.ww\:text-primary-foreground{color:var(--ww-color-primary-foreground,#1f2937)}.ww\:uppercase{text-transform:uppercase}.ww\:opacity-0{opacity:0}.ww\:opacity-100{opacity:1}.ww\:shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ww\:shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ww\:ring-2{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ww\:ring-blue-400\/70{--tw-ring-color:var(--ww-color-blue-400)}@supports (color:color-mix(in lab, red, red)){.ww\:ring-blue-400\/70{--tw-ring-color:color-mix(in oklab,var(--ww-color-blue-400)70%,transparent)}}.ww\:ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.ww\:ring-offset-background{--tw-ring-offset-color:var(--ww-color-background,#fff)}.ww\:backdrop-blur-xl{--tw-backdrop-blur:blur(var(--ww-blur-xl));-webkit-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,);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,)}.ww\:transition-\[grid-template-rows\,opacity\]{transition-property:grid-template-rows,opacity;transition-timing-function:var(--tw-ease,var(--ww-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ww-default-transition-duration))}.ww\:transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--ww-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ww-default-transition-duration))}.ww\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--ww-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ww-default-transition-duration))}.ww\:transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--ww-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ww-default-transition-duration))}.ww\:transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--ww-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ww-default-transition-duration))}.ww\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--ww-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ww-default-transition-duration))}.ww\:duration-150{--tw-duration:.15s;transition-duration:.15s}.ww\:duration-200{--tw-duration:.2s;transition-duration:.2s}.ww\:duration-300{--tw-duration:.3s;transition-duration:.3s}.ww\:ease-out{--tw-ease:var(--ww-ease-out);transition-timing-function:var(--ww-ease-out)}.ww\:outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.ww\:group-hover\:opacity-0:is(:where(.ww\:group):hover *){opacity:0}.ww\:group-hover\:opacity-100:is(:where(.ww\:group):hover *){opacity:1}}.ww\:group-\[\.is-assistant\]\:text-foreground:is(:where(.ww\:group).is-assistant *){color:var(--ww-color-foreground,#1f2937)}.ww\:group-\[\.is-user\]\:ml-auto:is(:where(.ww\:group).is-user *){margin-left:auto}.ww\:group-\[\.is-user\]\:rounded-lg:is(:where(.ww\:group).is-user *){border-radius:var(--ww-radius-lg)}.ww\:group-\[\.is-user\]\:bg-user-bubble:is(:where(.ww\:group).is-user *){background-color:var(--ww-color-user-bubble,#f4f4f4)}.ww\:group-\[\.is-user\]\:px-4:is(:where(.ww\:group).is-user *){padding-inline:calc(var(--ww-spacing)*4)}.ww\:group-\[\.is-user\]\:py-3:is(:where(.ww\:group).is-user *){padding-block:calc(var(--ww-spacing)*3)}.ww\:group-\[\.is-user\]\:text-primary-foreground:is(:where(.ww\:group).is-user *){color:var(--ww-color-primary-foreground,#1f2937)}.ww\:placeholder\:text-muted-foreground::placeholder{color:var(--ww-color-muted-foreground,#6b7280)}@media (hover:hover){.ww\:hover\:border-primary\/30:hover{border-color:var(--ww-color-primary,#6366f1)}@supports (color:color-mix(in lab, red, red)){.ww\:hover\:border-primary\/30:hover{border-color:color-mix(in oklab,var(--ww-color-primary,#6366f1)30%,transparent)}}.ww\:hover\:bg-accent:hover{background-color:var(--ww-color-accent,#f3f4f6)}.ww\:hover\:bg-foreground:hover{background-color:var(--ww-color-foreground,#1f2937)}.ww\:hover\:bg-primary\/90:hover{background-color:var(--ww-color-primary,#6366f1)}@supports (color:color-mix(in lab, red, red)){.ww\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--ww-color-primary,#6366f1)90%,transparent)}}.ww\:hover\:text-accent-foreground:hover{color:var(--ww-color-accent-foreground,#1f2937)}.ww\:hover\:text-foreground:hover{color:var(--ww-color-foreground,#1f2937)}.ww\:hover\:underline:hover{text-decoration-line:underline}}.ww\:disabled\:pointer-events-none:disabled{pointer-events:none}.ww\:disabled\:opacity-50:disabled{opacity:.5}.ww\:\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:calc(var(--ww-spacing)*0)}.ww\:\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:calc(var(--ww-spacing)*0)}}@keyframes ww-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes ww-fade-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}@keyframes ww-pulse{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}[data-waniwani-chat]{--ww-color-background:var(--ww-bg,#fff);--ww-color-foreground:var(--ww-text,#1f2937);--ww-color-primary:var(--ww-primary,#6366f1);--ww-color-primary-foreground:var(--ww-primary-fg,#1f2937);--ww-color-muted-foreground:var(--ww-muted,#6b7280);--ww-color-border:var(--ww-border,#e5e7eb);--ww-color-input:var(--ww-input-bg,#f9fafb);--ww-color-accent:var(--ww-assistant-bubble,#f3f4f6);--ww-color-accent-foreground:var(--ww-text,#1f2937);--ww-color-user-bubble:var(--ww-user-bubble,#f4f4f4);--ww-color-card:var(--ww-bg,#fff);--ww-color-card-foreground:var(--ww-text,#1f2937);--ww-color-card-header:var(--ww-header-bg,#fff);--ww-color-card-header-foreground:var(--ww-header-text,#1f2937);--ww-color-status:var(--ww-status,#22c55e);--ww-color-tool-card:var(--ww-tool-card,#f4f4f5);--ww-radius:var(--ww-radius,16px);--ww-font-sans:var(--ww-font,system-ui,-apple-system,"Segoe UI",sans-serif)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waniwani/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "WaniWani SDK - MCP event tracking, widget framework, and tools",
5
5
  "type": "module",
6
6
  "exports": {