@nextclaw/ui 0.11.7 → 0.11.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/assets/{ChannelsList-B5qf0xhV.js → ChannelsList-XGMfinnc.js} +1 -1
- package/dist/assets/ChatPage-DYTcCRPp.js +37 -0
- package/dist/assets/{DocBrowser-DVf0dNDK.js → DocBrowser-DTRCNsSM.js} +1 -1
- package/dist/assets/{LogoBadge-CjflvkiJ.js → LogoBadge-CPMOwWdA.js} +1 -1
- package/dist/assets/{MarketplacePage-BuaJoa1g.js → MarketplacePage-De2qZ9C0.js} +1 -1
- package/dist/assets/{McpMarketplacePage-B_CgbggZ.js → McpMarketplacePage-cjVKSQ2f.js} +1 -1
- package/dist/assets/{ModelConfig-DBd5AZd4.js → ModelConfig-CMn3-VZk.js} +1 -1
- package/dist/assets/{ProvidersList-DRny22PF.js → ProvidersList-CArDOswN.js} +1 -1
- package/dist/assets/{RemoteAccessPage-D8w9gegZ.js → RemoteAccessPage-C0I4tHey.js} +1 -1
- package/dist/assets/{RuntimeConfig-B7YGx-tX.js → RuntimeConfig-B4o6uJq9.js} +1 -1
- package/dist/assets/{SearchConfig-CYfBuDKk.js → SearchConfig-a38m8Ynx.js} +1 -1
- package/dist/assets/{SecretsConfig-x2wjudLu.js → SecretsConfig-B6mf4JY9.js} +1 -1
- package/dist/assets/{SessionsConfig-D38IEjwE.js → SessionsConfig-B_WQ1lVd.js} +1 -1
- package/dist/assets/index-Bro-iRcb.css +1 -0
- package/dist/assets/{index-CmUXqYBT.js → index-D-wEIgPn.js} +2 -2
- package/dist/assets/{label-DUP7zBqn.js → label-usOOP7mv.js} +1 -1
- package/dist/assets/{ncp-session-adapter-BO_kDsJR.js → ncp-session-adapter-DSacECph.js} +1 -1
- package/dist/assets/{page-layout-YfOVwslF.js → page-layout-CuIf20mx.js} +1 -1
- package/dist/assets/{popover-D3DIXnQO.js → popover-CTtTCP5d.js} +1 -1
- package/dist/assets/{security-config-BpDorUQD.js → security-config-Bxrrv8Ac.js} +1 -1
- package/dist/assets/{skeleton-ATAzNDF-.js → skeleton-BNUaFYE7.js} +1 -1
- package/dist/assets/{status-dot-IK6hDwPV.js → status-dot-BeHTBy9k.js} +1 -1
- package/dist/assets/{switch-HPdfKWmj.js → switch-CtNnWZpa.js} +1 -1
- package/dist/assets/{tabs-custom-nkje9L_8.js → tabs-custom-Dz_4tV62.js} +1 -1
- package/dist/assets/{useConfirmDialog-Cvinc6iP.js → useConfirmDialog-C_n_JIEq.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/src/components/chat/ChatConversationPanel.tsx +59 -29
- package/src/components/chat/adapters/chat-message.adapter.ts +17 -5
- package/src/components/chat/containers/chat-message-list.container.test.tsx +56 -0
- package/src/components/chat/containers/chat-message-list.container.tsx +85 -47
- package/dist/assets/ChatPage-CSKgAkAj.js +0 -37
- package/dist/assets/index-DbiQF_x_.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as s,j as o}from"./vendor-BEQcLDx6.js";import{c as t}from"./index-
|
|
1
|
+
import{r as s,j as o}from"./vendor-BEQcLDx6.js";import{c as t}from"./index-D-wEIgPn.js";const l=s.forwardRef(({className:e,...a},r)=>o.jsx("label",{ref:r,className:t("text-sm font-medium leading-none text-gray-700 peer-disabled:cursor-not-allowed peer-disabled:opacity-70",e),...a}));l.displayName="Label";export{l as L};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as o,ae as l}from"./vendor-BEQcLDx6.js";import{t as u,c}from"./index-
|
|
1
|
+
import{j as o,ae as l}from"./vendor-BEQcLDx6.js";import{t as u,c}from"./index-D-wEIgPn.js";function R({status:e,className:n}){const t=e==="running"?u("sessionsRunStatusRunning"):u("sessionsRunStatusQueued");return o.jsxs("span",{className:c("inline-flex h-3.5 w-3.5 items-center justify-center text-gray-400",n),title:t,"aria-label":t,children:[o.jsx(l,{className:"h-3 w-3 animate-spin"}),o.jsx("span",{className:"sr-only",children:t})]})}var s=(e=>(e.CALL="call",e.RESULT="result",e.PARTIAL_CALL="partial-call",e.ERROR="error",e.CANCELLED="cancelled",e))(s||{});function b(e){if(e.label&&e.label.trim())return e.label.trim();const n=e.key.split(":");return n[n.length-1]||e.key}const p=new Set(["off","minimal","low","medium","high","adaptive","xhigh"]);function f(e){if(typeof e=="string")return e;try{return JSON.stringify(e??{})}catch{return String(e??"")}}function r(e){if(typeof e!="string")return null;const n=e.trim();return n.length>0?n:null}function a(e){const{metadata:n}=e;return!n||typeof n!="object"||Array.isArray(n)?null:n}function d(e){const n=a(e);return n?r(n.preferred_model)??r(n.preferredModel)??r(n.model):null}function m(e){const n=a(e);if(!n)return null;const t=r(n.preferred_thinking)??r(n.thinking)??r(n.thinking_level)??r(n.thinkingLevel);if(!t)return null;const i=t.toLowerCase();return p.has(i)?i:null}function y(e){const n=a(e);return n?r(n.label):null}function g(e){const n=a(e);return n?r(n.session_type)??r(n.sessionType)??"native":"native"}function h(e){return e.state==="result"?s.RESULT:e.state==="partial-call"?s.PARTIAL_CALL:s.CALL}function S(e){const n=[];for(const t of e){if(t.type==="text"){n.push({type:"text",text:t.text});continue}if(t.type==="rich-text"){n.push({type:"text",text:t.text});continue}if(t.type==="reasoning"){n.push({type:"reasoning",reasoning:t.text,details:[]});continue}if(t.type==="source"){n.push({type:"source",source:{sourceType:"url",id:t.url??t.title??Math.random().toString(36).slice(2,8),url:t.url??"",...t.title?{title:t.title}:{}}});continue}if(t.type==="file"&&t.contentBase64){n.push({type:"file",...t.name?{name:t.name}:{},mimeType:t.mimeType??"application/octet-stream",data:t.contentBase64,...t.url?{url:t.url}:{},...typeof t.sizeBytes=="number"?{sizeBytes:t.sizeBytes}:{}});continue}if(t.type==="file"&&t.url){n.push({type:"file",...t.name?{name:t.name}:{},mimeType:t.mimeType??"application/octet-stream",data:"",url:t.url,...typeof t.sizeBytes=="number"?{sizeBytes:t.sizeBytes}:{}});continue}if(t.type==="step-start"){n.push({type:"step-start"});continue}t.type==="tool-invocation"&&n.push({type:"tool-invocation",toolInvocation:{status:h(t),toolCallId:t.toolCallId??`${t.toolName}-${Math.random().toString(36).slice(2,8)}`,toolName:t.toolName,args:f(t.args),result:t.result}})}return n}function L(e){return e==="service"?"system":e==="tool"?"assistant":e}function N(e){return{id:e.id,role:L(e.role),parts:S(e.parts),meta:{source:"stream",status:e.status,sessionKey:e.sessionId,timestamp:e.timestamp}}}function M(e){return e.map(N)}function x(e){const n=y(e),t=d(e),i=m(e);return{key:e.sessionId,createdAt:e.updatedAt,updatedAt:e.updatedAt,...n?{label:n}:{},...t?{preferredModel:t}:{},...i?{preferredThinking:i}:{},sessionType:g(e),sessionTypeMutable:!1,messageCount:e.messageCount}}function C(e){return e.map(x)}function k(e){const n=new Map;for(const i of e.summaries)i.status==="running"&&n.set(i.sessionId,"running");const t=r(e.activeSessionId);return e.isLocallyRunning&&t&&n.set(t,"running"),n}function B(){return`ncp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}export{R as S,C as a,M as b,B as c,k as d,b as s};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./vendor-BEQcLDx6.js";import{c as l}from"./index-
|
|
1
|
+
import{j as e}from"./vendor-BEQcLDx6.js";import{c as l}from"./index-D-wEIgPn.js";function x({children:t,fullHeight:s=!1,className:a}){return e.jsx("div",{className:l("animate-fade-in",s?"h-[calc(100vh-80px)] w-full flex flex-col":"pb-16",a),children:t})}function c({title:t,description:s,actions:a,className:r}){return e.jsxs("div",{className:l("flex items-center justify-between mb-6 shrink-0",r),children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-900",children:t}),s&&e.jsx("p",{className:"text-sm text-gray-500 mt-1",children:s})]}),a&&e.jsx("div",{className:"flex items-center gap-2 shrink-0",children:a})]})}export{x as P,c as a};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as l,aI as $,j as c,aJ as z,aK as G,aL as A,aM as O,aN as P,aO as _,aP as w,aQ as b,aR as H,aS as K,aT as U,aU as V,aV as W,aW as Z,aX as J,aY as Q,aZ as X,a_ as Y}from"./vendor-BEQcLDx6.js";import{c as q}from"./index-
|
|
1
|
+
import{r as l,aI as $,j as c,aJ as z,aK as G,aL as A,aM as O,aN as P,aO as _,aP as w,aQ as b,aR as H,aS as K,aT as U,aU as V,aV as W,aW as Z,aX as J,aY as Q,aZ as X,a_ as Y}from"./vendor-BEQcLDx6.js";import{c as q}from"./index-D-wEIgPn.js";var m="Popover",[E]=K(m,[w]),g=w(),[B,d]=E(m),j=e=>{const{__scopePopover:a,children:t,open:n,defaultOpen:o,onOpenChange:r,modal:s=!1}=e,i=g(a),p=l.useRef(null),[u,h]=l.useState(!1),[C,f]=$({prop:n,defaultProp:o??!1,onChange:r,caller:m});return c.jsx(z,{...i,children:c.jsx(B,{scope:a,contentId:G(),triggerRef:p,open:C,onOpenChange:f,onOpenToggle:l.useCallback(()=>f(x=>!x),[f]),hasCustomAnchor:u,onCustomAnchorAdd:l.useCallback(()=>h(!0),[]),onCustomAnchorRemove:l.useCallback(()=>h(!1),[]),modal:s,children:t})})};j.displayName=m;var N="PopoverAnchor",y=l.forwardRef((e,a)=>{const{__scopePopover:t,...n}=e,o=d(N,t),r=g(t),{onCustomAnchorAdd:s,onCustomAnchorRemove:i}=o;return l.useEffect(()=>(s(),()=>i()),[s,i]),c.jsx(_,{...r,...n,ref:a})});y.displayName=N;var F="PopoverTrigger",S=l.forwardRef((e,a)=>{const{__scopePopover:t,...n}=e,o=d(F,t),r=g(t),s=A(a,o.triggerRef),i=c.jsx(O.button,{type:"button","aria-haspopup":"dialog","aria-expanded":o.open,"aria-controls":o.contentId,"data-state":k(o.open),...n,ref:s,onClick:P(e.onClick,o.onOpenToggle)});return o.hasCustomAnchor?i:c.jsx(_,{asChild:!0,...r,children:i})});S.displayName=F;var R="PopoverPortal",[ee,oe]=E(R,{forceMount:void 0}),M=e=>{const{__scopePopover:a,forceMount:t,children:n,container:o}=e,r=d(R,a);return c.jsx(ee,{scope:a,forceMount:t,children:c.jsx(b,{present:t||r.open,children:c.jsx(H,{asChild:!0,container:o,children:n})})})};M.displayName=R;var v="PopoverContent",T=l.forwardRef((e,a)=>{const t=oe(v,e.__scopePopover),{forceMount:n=t.forceMount,...o}=e,r=d(v,e.__scopePopover);return c.jsx(b,{present:n||r.open,children:r.modal?c.jsx(re,{...o,ref:a}):c.jsx(ae,{...o,ref:a})})});T.displayName=v;var te=W("PopoverContent.RemoveScroll"),re=l.forwardRef((e,a)=>{const t=d(v,e.__scopePopover),n=l.useRef(null),o=A(a,n),r=l.useRef(!1);return l.useEffect(()=>{const s=n.current;if(s)return U(s)},[]),c.jsx(V,{as:te,allowPinchZoom:!0,children:c.jsx(D,{...e,ref:o,trapFocus:t.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:P(e.onCloseAutoFocus,s=>{var i;s.preventDefault(),r.current||(i=t.triggerRef.current)==null||i.focus()}),onPointerDownOutside:P(e.onPointerDownOutside,s=>{const i=s.detail.originalEvent,p=i.button===0&&i.ctrlKey===!0,u=i.button===2||p;r.current=u},{checkForDefaultPrevented:!1}),onFocusOutside:P(e.onFocusOutside,s=>s.preventDefault(),{checkForDefaultPrevented:!1})})})}),ae=l.forwardRef((e,a)=>{const t=d(v,e.__scopePopover),n=l.useRef(!1),o=l.useRef(!1);return c.jsx(D,{...e,ref:a,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:r=>{var s,i;(s=e.onCloseAutoFocus)==null||s.call(e,r),r.defaultPrevented||(n.current||(i=t.triggerRef.current)==null||i.focus(),r.preventDefault()),n.current=!1,o.current=!1},onInteractOutside:r=>{var p,u;(p=e.onInteractOutside)==null||p.call(e,r),r.defaultPrevented||(n.current=!0,r.detail.originalEvent.type==="pointerdown"&&(o.current=!0));const s=r.target;((u=t.triggerRef.current)==null?void 0:u.contains(s))&&r.preventDefault(),r.detail.originalEvent.type==="focusin"&&o.current&&r.preventDefault()}})}),D=l.forwardRef((e,a)=>{const{__scopePopover:t,trapFocus:n,onOpenAutoFocus:o,onCloseAutoFocus:r,disableOutsidePointerEvents:s,onEscapeKeyDown:i,onPointerDownOutside:p,onFocusOutside:u,onInteractOutside:h,...C}=e,f=d(v,t),x=g(t);return Z(),c.jsx(J,{asChild:!0,loop:!0,trapped:n,onMountAutoFocus:o,onUnmountAutoFocus:r,children:c.jsx(Q,{asChild:!0,disableOutsidePointerEvents:s,onInteractOutside:h,onEscapeKeyDown:i,onPointerDownOutside:p,onFocusOutside:u,onDismiss:()=>f.onOpenChange(!1),children:c.jsx(X,{"data-state":k(f.open),role:"dialog",id:f.contentId,...x,...C,ref:a,style:{...C.style,"--radix-popover-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-popover-content-available-width":"var(--radix-popper-available-width)","--radix-popover-content-available-height":"var(--radix-popper-available-height)","--radix-popover-trigger-width":"var(--radix-popper-anchor-width)","--radix-popover-trigger-height":"var(--radix-popper-anchor-height)"}})})})}),I="PopoverClose",ne=l.forwardRef((e,a)=>{const{__scopePopover:t,...n}=e,o=d(I,t);return c.jsx(O.button,{type:"button",...n,ref:a,onClick:P(e.onClick,()=>o.onOpenChange(!1))})});ne.displayName=I;var se="PopoverArrow",ce=l.forwardRef((e,a)=>{const{__scopePopover:t,...n}=e,o=g(t);return c.jsx(Y,{...o,...n,ref:a})});ce.displayName=se;function k(e){return e?"open":"closed"}var ie=j,ve=y,le=S,pe=M,L=T;const Pe=ie,ge=le,ue=l.forwardRef(({className:e,sideOffset:a=8,align:t="start",...n},o)=>c.jsx(pe,{children:c.jsx(L,{ref:o,sideOffset:a,align:t,className:q("z-[var(--z-popover,50)] w-72 overflow-hidden rounded-2xl border border-gray-200/50 bg-white p-4 shadow-lg animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",e),...n})}));ue.displayName=L.displayName;export{ve as A,L as C,pe as P,ie as R,le as T,Pe as a,ge as b,ue as c};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as c,j as e,e as M}from"./vendor-BEQcLDx6.js";import{$ as O,a0 as R,a1 as I,a2 as _,a3 as B,C as u,Y as h,Z as x,t as s,_ as m,y as p,B as j,I as l}from"./index-
|
|
1
|
+
import{r as c,j as e,e as M}from"./vendor-BEQcLDx6.js";import{$ as O,a0 as R,a1 as I,a2 as _,a3 as B,C as u,Y as h,Z as x,t as s,_ as m,y as p,B as j,I as l}from"./index-D-wEIgPn.js";import{L as o}from"./label-usOOP7mv.js";import{S as G}from"./switch-CtNnWZpa.js";import{P as V,a as W}from"./page-layout-CuIf20mx.js";const Y=8;function A(r){return r.trim().length>=Y}function L(r,n){return r!==n?(M.error(s("authPasswordMismatch")),!1):!0}function Z(){const r=O(),n=R(),S=I(),y=_(),g=B(),[f,U]=c.useState(""),[i,N]=c.useState(""),[w,b]=c.useState(""),[d,v]=c.useState(""),[P,C]=c.useState(""),a=r.data,E=f.trim().length>0&&A(i)&&i===w&&!n.isPending,D=A(d)&&d===P&&!y.isPending,T=async()=>{if(L(i,w))try{await n.mutateAsync({username:f.trim(),password:i}),N(""),b("")}catch{}},F=async()=>{if(L(d,P))try{await y.mutateAsync({password:d}),v(""),C("")}catch{}},H=async t=>{try{await S.mutateAsync({enabled:t})}catch{}},k=async()=>{try{await g.mutateAsync()}catch{}};return r.isLoading&&!a?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsx(p,{className:"text-sm text-gray-500",children:s("loading")})]}):r.isError||!a?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-gray-500",children:s("authStatusLoadFailed")}),e.jsx(j,{variant:"outline",onClick:()=>{r.refetch()},children:s("authRetryStatus")})]})]}):a.configured?e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-xl border border-gray-200 p-4",children:[e.jsxs("div",{className:"flex flex-col gap-4 md:flex-row md:items-start md:justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authStatusLabel")}),e.jsx("p",{className:"text-sm text-gray-600",children:s("authStatusConfiguredUser").replace("{username}",a.username??"")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authUsernameFixedHelp")})]}),e.jsx("span",{className:"inline-flex items-center rounded-full bg-gray-100 px-3 py-1 text-xs font-medium text-gray-700",children:a.enabled?s("enabled"):s("disabled")})]}),e.jsxs("div",{className:"mt-4 flex flex-col gap-4 border-t border-gray-200 pt-4 md:flex-row md:items-center md:justify-between",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authEnableLabel")}),e.jsx("p",{className:"text-xs text-gray-500",children:a.enabled?s("authEnableOnHelp"):s("authEnableOffHelp")})]}),e.jsx(G,{checked:a.enabled,disabled:S.isPending,onCheckedChange:t=>{H(t)}})]})]}),e.jsxs("div",{className:"rounded-xl border border-gray-200 p-4 space-y-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authPasswordSectionTitle")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authPasswordSectionDescription")})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-password-next",children:s("authPassword")}),e.jsx(l,{id:"auth-password-next",type:"password",value:d,onChange:t=>v(t.target.value),placeholder:s("authPasswordPlaceholder")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-password-confirm",children:s("authConfirmPassword")}),e.jsx(l,{id:"auth-password-confirm",type:"password",value:P,onChange:t=>C(t.target.value),placeholder:s("authConfirmPasswordPlaceholder")})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx(j,{type:"button",disabled:!D,onClick:()=>void F(),children:y.isPending?s("authPasswordUpdating"):s("authPasswordAction")}),a.enabled&&a.authenticated?e.jsx(j,{type:"button",variant:"outline",disabled:g.isPending,onClick:()=>void k(),children:g.isPending?s("authLoggingOut"):s("authLogoutAction")}):null]}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authSessionMemoryNotice")})]})]})]}):e.jsxs(u,{children:[e.jsxs(h,{children:[e.jsx(x,{children:s("authSecurityTitle")}),e.jsx(m,{children:s("authSecurityDescription")})]}),e.jsxs(p,{className:"space-y-5",children:[e.jsxs("div",{className:"rounded-xl border border-dashed border-gray-200 bg-gray-50/70 p-4",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900",children:s("authSetupTitle")}),e.jsx("p",{className:"mt-1 text-sm text-gray-500",children:s("authSetupDescription")})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-username",children:s("authUsername")}),e.jsx(l,{id:"auth-setup-username",value:f,onChange:t=>U(t.target.value),placeholder:s("authUsernamePlaceholder")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-password",children:s("authPassword")}),e.jsx(l,{id:"auth-setup-password",type:"password",value:i,onChange:t=>N(t.target.value),placeholder:s("authPasswordPlaceholder")})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(o,{htmlFor:"auth-setup-confirm",children:s("authConfirmPassword")}),e.jsx(l,{id:"auth-setup-confirm",type:"password",value:w,onChange:t=>b(t.target.value),placeholder:s("authConfirmPasswordPlaceholder")}),e.jsx("p",{className:"text-xs text-gray-500",children:s("authPasswordMinLengthHint")})]}),e.jsx(j,{type:"button",disabled:!E,onClick:()=>void T(),children:n.isPending?s("authSettingUp"):s("authSetupAction")})]})]})}function Q(){return e.jsxs(V,{className:"space-y-6",children:[e.jsx(W,{title:s("authSecurityTitle"),description:s("authSecurityDescription")}),e.jsx(Z,{})]})}export{Q as SecurityConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as t}from"./vendor-BEQcLDx6.js";import{c as o}from"./index-
|
|
1
|
+
import{j as t}from"./vendor-BEQcLDx6.js";import{c as o}from"./index-D-wEIgPn.js";function m({className:e,...s}){return t.jsx("div",{className:o("animate-pulse rounded-md bg-slate-200",e),...s})}export{m as S};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./vendor-BEQcLDx6.js";import{c as a}from"./index-
|
|
1
|
+
import{j as e}from"./vendor-BEQcLDx6.js";import{c as a}from"./index-D-wEIgPn.js";const n={active:{dot:"bg-emerald-500",text:"text-emerald-600",bg:"bg-emerald-50"},ready:{dot:"bg-emerald-500",text:"text-emerald-600",bg:"bg-emerald-50"},inactive:{dot:"bg-gray-300",text:"text-gray-400",bg:"bg-gray-100/80"},setup:{dot:"bg-gray-300",text:"text-gray-400",bg:"bg-gray-100/80"},warning:{dot:"bg-amber-400",text:"text-amber-600",bg:"bg-amber-50"}};function m({status:r,label:s,className:g}){const t=n[r];return e.jsxs("div",{className:a("inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-2 py-0.5",t.bg,g),children:[e.jsx("span",{className:a("h-1.5 w-1.5 rounded-full",t.dot)}),e.jsx("span",{className:a("text-[11px] font-medium",t.text),children:s})]})}export{m as S};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e,j as i}from"./vendor-BEQcLDx6.js";import{c as t}from"./index-
|
|
1
|
+
import{r as e,j as i}from"./vendor-BEQcLDx6.js";import{c as t}from"./index-D-wEIgPn.js";const l=e.forwardRef(({className:o,checked:r=!1,onCheckedChange:s,...a},n)=>i.jsx("button",{type:"button",role:"switch","aria-checked":r,ref:n,className:t("peer inline-flex h-[22px] w-10 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-fast focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50",r?"bg-primary":"bg-gray-200/80 hover:bg-gray-300/80",o),onClick:()=>s==null?void 0:s(!r),...a,children:i.jsx("span",{className:t("pointer-events-none block h-5 w-5 rounded-full bg-white shadow-md ring-0 transition-transform duration-fast",r?"translate-x-5":"translate-x-0")})}));l.displayName="Switch";export{l as S};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./vendor-BEQcLDx6.js";import{aj as m,c as a}from"./index-
|
|
1
|
+
import{j as e}from"./vendor-BEQcLDx6.js";import{aj as m,c as a}from"./index-D-wEIgPn.js";function c({tabs:s,activeTab:i,onChange:o,className:n}){return e.jsx("div",{className:a("flex items-center gap-6 border-b border-gray-200/60 mb-6",n),children:s.map(t=>{const r=i===t.id;return e.jsxs("button",{onClick:()=>o(t.id),className:a("relative pb-3 text-[14px] font-medium transition-all duration-fast flex items-center gap-1.5",r?"text-gray-900":"text-gray-600 hover:text-gray-900"),children:[t.label,t.count!==void 0&&e.jsx("span",{className:a("text-[11px] font-medium","text-gray-500"),children:m(t.count)}),r&&e.jsx("div",{className:"absolute bottom-0 left-0 right-0 h-[2px] bg-primary rounded-full"})]},t.id)})})}export{c as T};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as a,r as t}from"./vendor-BEQcLDx6.js";import{ad as C,ae as h,af as p,ag as g,ah as x,ai as D,B as d,t as r}from"./index-
|
|
1
|
+
import{j as a,r as t}from"./vendor-BEQcLDx6.js";import{ad as C,ae as h,af as p,ag as g,ah as x,ai as D,B as d,t as r}from"./index-D-wEIgPn.js";const j=({open:l,onOpenChange:i,title:c,description:o,confirmLabel:s=r("confirm"),cancelLabel:e=r("cancel"),variant:n="default",onConfirm:f,onCancel:u})=>{const m=()=>{f(),i(!1)},v=()=>{u(),i(!1)};return a.jsx(C,{open:l,onOpenChange:i,children:a.jsxs(h,{className:"[&>:last-child]:hidden",onCloseAutoFocus:b=>b.preventDefault(),children:[a.jsxs(p,{children:[a.jsx(g,{children:c}),o?a.jsx(x,{children:o}):null]}),a.jsxs(D,{className:"gap-2 sm:gap-0",children:[a.jsx(d,{type:"button",variant:"outline",onClick:v,children:e}),a.jsx(d,{type:"button",variant:n==="destructive"?"destructive":"default",onClick:m,children:s})]})]})})},L={open:!1,title:"",description:"",confirmLabel:r("confirm"),cancelLabel:r("cancel"),variant:"default",resolve:null};function y(){const[l,i]=t.useState(L),c=t.useCallback(e=>new Promise(n=>{i({open:!0,title:e.title,description:e.description??"",confirmLabel:e.confirmLabel??r("confirm"),cancelLabel:e.cancelLabel??r("cancel"),variant:e.variant??"default",resolve:f=>{n(f),i(u=>({...u,open:!1,resolve:null}))}})}),[]),o=t.useCallback(e=>{i(n=>(!e&&n.resolve&&n.resolve(!1),{...n,open:e,resolve:e?n.resolve:null}))},[]),s=t.useCallback(()=>a.jsx(j,{open:l.open,onOpenChange:o,title:l.title,description:l.description||void 0,confirmLabel:l.confirmLabel,cancelLabel:l.cancelLabel,variant:l.variant,onConfirm:()=>{var e;return(e=l.resolve)==null?void 0:e.call(l,!0)},onCancel:()=>{var e;return(e=l.resolve)==null?void 0:e.call(l,!1)}}),[l,o]);return{confirm:c,ConfirmDialog:s}}export{y as u};
|
package/dist/index.html
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
8
|
<title>NextClaw</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-D-wEIgPn.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-BEQcLDx6.js">
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Bro-iRcb.css">
|
|
12
12
|
</head>
|
|
13
13
|
|
|
14
14
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ui",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"tailwind-merge": "^2.5.4",
|
|
29
29
|
"zod": "^3.23.8",
|
|
30
30
|
"zustand": "^5.0.2",
|
|
31
|
+
"@nextclaw/agent-chat-ui": "0.2.12",
|
|
32
|
+
"@nextclaw/ncp-react": "0.4.2",
|
|
31
33
|
"@nextclaw/ncp": "0.4.0",
|
|
32
|
-
"@nextclaw/agent-chat-ui": "0.2.11",
|
|
33
34
|
"@nextclaw/agent-chat": "0.1.3",
|
|
34
|
-
"@nextclaw/ncp-react": "0.4.1",
|
|
35
35
|
"@nextclaw/ncp-http-agent-client": "0.3.4"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { useRef } from
|
|
2
|
-
import { useStickyBottomScroll } from
|
|
3
|
-
import { Button } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { useStickyBottomScroll } from "@nextclaw/agent-chat-ui";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import {
|
|
5
|
+
ChatInputBarContainer,
|
|
6
|
+
ChatMessageListContainer,
|
|
7
|
+
} from "@/components/chat/nextclaw";
|
|
8
|
+
import { ChatWelcome } from "@/components/chat/ChatWelcome";
|
|
9
|
+
import { usePresenter } from "@/components/chat/presenter/chat-presenter-context";
|
|
10
|
+
import { useChatThreadStore } from "@/components/chat/stores/chat-thread.store";
|
|
11
|
+
import { t } from "@/lib/i18n";
|
|
12
|
+
import { cn } from "@/lib/utils";
|
|
13
|
+
import { Trash2 } from "lucide-react";
|
|
11
14
|
|
|
12
15
|
function ChatConversationSkeleton() {
|
|
13
16
|
return (
|
|
@@ -42,12 +45,21 @@ export function ChatConversationPanel() {
|
|
|
42
45
|
const snapshot = useChatThreadStore((state) => state.snapshot);
|
|
43
46
|
const fallbackThreadRef = useRef<HTMLDivElement | null>(null);
|
|
44
47
|
const threadRef = snapshot.threadRef ?? fallbackThreadRef;
|
|
45
|
-
const shouldShowSessionHeader = Boolean(
|
|
46
|
-
|
|
48
|
+
const shouldShowSessionHeader = Boolean(
|
|
49
|
+
snapshot.selectedSessionKey || snapshot.sessionTypeLabel,
|
|
50
|
+
);
|
|
51
|
+
const sessionHeaderTitle =
|
|
52
|
+
snapshot.sessionDisplayName ||
|
|
53
|
+
snapshot.selectedSessionKey ||
|
|
54
|
+
t("chatSidebarNewTask");
|
|
47
55
|
|
|
48
|
-
const showWelcome =
|
|
56
|
+
const showWelcome =
|
|
57
|
+
!snapshot.selectedSessionKey &&
|
|
58
|
+
snapshot.uiMessages.length === 0 &&
|
|
59
|
+
!snapshot.isSending;
|
|
49
60
|
const hasConfiguredModel = snapshot.modelOptions.length > 0;
|
|
50
|
-
const shouldShowProviderHint =
|
|
61
|
+
const shouldShowProviderHint =
|
|
62
|
+
snapshot.isProviderStateResolved && !hasConfiguredModel;
|
|
51
63
|
const hideEmptyHint =
|
|
52
64
|
snapshot.isHistoryLoading &&
|
|
53
65
|
snapshot.uiMessages.length === 0 &&
|
|
@@ -59,7 +71,7 @@ export function ChatConversationPanel() {
|
|
|
59
71
|
resetKey: snapshot.selectedSessionKey,
|
|
60
72
|
isLoading: snapshot.isHistoryLoading,
|
|
61
73
|
hasContent: snapshot.uiMessages.length > 0,
|
|
62
|
-
contentVersion: snapshot.uiMessages
|
|
74
|
+
contentVersion: snapshot.uiMessages[snapshot.uiMessages.length - 1] ?? null,
|
|
63
75
|
});
|
|
64
76
|
|
|
65
77
|
if (!snapshot.isProviderStateResolved) {
|
|
@@ -68,10 +80,14 @@ export function ChatConversationPanel() {
|
|
|
68
80
|
|
|
69
81
|
return (
|
|
70
82
|
<section className="flex-1 min-h-0 flex flex-col overflow-hidden bg-gradient-to-b from-gray-50/60 to-white">
|
|
71
|
-
<div
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
83
|
+
<div
|
|
84
|
+
className={cn(
|
|
85
|
+
"px-5 border-b border-gray-200/60 bg-white/80 backdrop-blur-sm flex items-center justify-between shrink-0 overflow-hidden transition-all duration-200",
|
|
86
|
+
shouldShowSessionHeader
|
|
87
|
+
? "py-3 opacity-100"
|
|
88
|
+
: "h-0 py-0 opacity-0 border-b-0",
|
|
89
|
+
)}
|
|
90
|
+
>
|
|
75
91
|
<div className="min-w-0 flex-1 flex items-center gap-2">
|
|
76
92
|
<span className="text-sm font-medium text-gray-700 truncate">
|
|
77
93
|
{sessionHeaderTitle}
|
|
@@ -97,22 +113,27 @@ export function ChatConversationPanel() {
|
|
|
97
113
|
|
|
98
114
|
{shouldShowProviderHint && (
|
|
99
115
|
<div className="px-5 py-2.5 border-b border-amber-200/70 bg-amber-50/70 flex items-center justify-between gap-3 shrink-0">
|
|
100
|
-
<span className="text-xs text-amber-800">
|
|
116
|
+
<span className="text-xs text-amber-800">
|
|
117
|
+
{t("chatModelNoOptions")}
|
|
118
|
+
</span>
|
|
101
119
|
<button
|
|
102
120
|
type="button"
|
|
103
121
|
onClick={presenter.chatThreadManager.goToProviders}
|
|
104
122
|
className="text-xs font-semibold text-amber-900 underline-offset-2 hover:underline"
|
|
105
123
|
>
|
|
106
|
-
{t(
|
|
124
|
+
{t("chatGoConfigureProvider")}
|
|
107
125
|
</button>
|
|
108
126
|
</div>
|
|
109
127
|
)}
|
|
110
128
|
|
|
111
|
-
{snapshot.sessionTypeUnavailable &&
|
|
112
|
-
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
{snapshot.sessionTypeUnavailable &&
|
|
130
|
+
snapshot.sessionTypeUnavailableMessage?.trim() && (
|
|
131
|
+
<div className="px-5 py-2.5 border-b border-amber-200/70 bg-amber-50/70 shrink-0">
|
|
132
|
+
<span className="text-xs text-amber-800">
|
|
133
|
+
{snapshot.sessionTypeUnavailableMessage}
|
|
134
|
+
</span>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
116
137
|
|
|
117
138
|
<div
|
|
118
139
|
ref={threadRef}
|
|
@@ -120,14 +141,23 @@ export function ChatConversationPanel() {
|
|
|
120
141
|
className="flex-1 min-h-0 overflow-y-auto custom-scrollbar"
|
|
121
142
|
>
|
|
122
143
|
{showWelcome ? (
|
|
123
|
-
<ChatWelcome
|
|
144
|
+
<ChatWelcome
|
|
145
|
+
onCreateSession={presenter.chatThreadManager.createSession}
|
|
146
|
+
/>
|
|
124
147
|
) : hideEmptyHint ? (
|
|
125
148
|
<div className="h-full" />
|
|
126
149
|
) : snapshot.uiMessages.length === 0 ? (
|
|
127
|
-
<div className="px-5 py-5 text-sm text-gray-500">
|
|
150
|
+
<div className="px-5 py-5 text-sm text-gray-500">
|
|
151
|
+
{t("chatNoMessages")}
|
|
152
|
+
</div>
|
|
128
153
|
) : (
|
|
129
154
|
<div className="mx-auto w-full max-w-[min(1120px,100%)] px-6 py-5">
|
|
130
|
-
<ChatMessageListContainer
|
|
155
|
+
<ChatMessageListContainer
|
|
156
|
+
uiMessages={snapshot.uiMessages}
|
|
157
|
+
isSending={
|
|
158
|
+
snapshot.isSending && snapshot.isAwaitingAssistantOutput
|
|
159
|
+
}
|
|
160
|
+
/>
|
|
131
161
|
</div>
|
|
132
162
|
)}
|
|
133
163
|
</div>
|
|
@@ -317,12 +317,16 @@ function toRenderableText(value: string): string | null {
|
|
|
317
317
|
return visible ? trimmed : null;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
|
|
321
|
-
uiMessages: ChatMessageSource[];
|
|
320
|
+
type ChatMessageAdapterParams = {
|
|
322
321
|
texts: ChatMessageAdapterTexts;
|
|
323
322
|
formatTimestamp: (value: string) => string;
|
|
324
|
-
}
|
|
325
|
-
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
export function adaptChatMessage(
|
|
326
|
+
message: ChatMessageSource,
|
|
327
|
+
params: ChatMessageAdapterParams,
|
|
328
|
+
): ChatMessageViewModel {
|
|
329
|
+
return {
|
|
326
330
|
id: message.id,
|
|
327
331
|
role: resolveUiRole(message.role),
|
|
328
332
|
roleLabel: resolveRoleLabel(message.role, params.texts.roleLabels),
|
|
@@ -421,5 +425,13 @@ export function adaptChatMessages(params: {
|
|
|
421
425
|
};
|
|
422
426
|
})
|
|
423
427
|
.filter((part) => part !== null),
|
|
424
|
-
}
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function adaptChatMessages(params: {
|
|
432
|
+
uiMessages: ChatMessageSource[];
|
|
433
|
+
texts: ChatMessageAdapterTexts;
|
|
434
|
+
formatTimestamp: (value: string) => string;
|
|
435
|
+
}): ChatMessageViewModel[] {
|
|
436
|
+
return params.uiMessages.map((message) => adaptChatMessage(message, params));
|
|
425
437
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
import type { UiMessage } from "@nextclaw/agent-chat";
|
|
3
|
+
import { beforeEach, expect, it, vi } from "vitest";
|
|
4
|
+
import { ChatMessageListContainer } from "./chat-message-list.container";
|
|
5
|
+
|
|
6
|
+
const captures = vi.hoisted(() => ({
|
|
7
|
+
renders: [] as Array<{ messages: unknown[] }>,
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
vi.mock("@nextclaw/agent-chat-ui", () => ({
|
|
11
|
+
ChatMessageList: (props: { messages: unknown[] }) => {
|
|
12
|
+
captures.renders.push(props);
|
|
13
|
+
return <div data-testid="chat-message-list" />;
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock("@/components/providers/I18nProvider", () => ({
|
|
18
|
+
useI18n: () => ({ language: "en" }),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock("@/lib/i18n", () => ({
|
|
22
|
+
formatDateTime: (value: string) => `formatted:${value}`,
|
|
23
|
+
t: (key: string) => key,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
captures.renders = [];
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("reuses adapted message references when the source message object is unchanged", () => {
|
|
31
|
+
const message = {
|
|
32
|
+
id: "assistant-1",
|
|
33
|
+
role: "assistant",
|
|
34
|
+
meta: {
|
|
35
|
+
timestamp: "2026-03-17T10:00:00.000Z",
|
|
36
|
+
status: "streaming",
|
|
37
|
+
},
|
|
38
|
+
parts: [{ type: "text", text: "hello" }],
|
|
39
|
+
} satisfies UiMessage;
|
|
40
|
+
|
|
41
|
+
const { rerender } = render(
|
|
42
|
+
<ChatMessageListContainer uiMessages={[message]} isSending={false} />,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const firstMessages =
|
|
46
|
+
captures.renders[captures.renders.length - 1]?.messages ?? [];
|
|
47
|
+
|
|
48
|
+
rerender(
|
|
49
|
+
<ChatMessageListContainer uiMessages={[message]} isSending={false} />,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const secondMessages =
|
|
53
|
+
captures.renders[captures.renders.length - 1]?.messages ?? [];
|
|
54
|
+
|
|
55
|
+
expect(secondMessages[0]).toBe(firstMessages[0]);
|
|
56
|
+
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { type UiMessage } from "@nextclaw/agent-chat";
|
|
3
|
-
import { ChatMessageList } from "@nextclaw/agent-chat-ui";
|
|
4
3
|
import {
|
|
5
|
-
|
|
4
|
+
type ChatMessageViewModel,
|
|
5
|
+
ChatMessageList,
|
|
6
|
+
} from "@nextclaw/agent-chat-ui";
|
|
7
|
+
import {
|
|
8
|
+
adaptChatMessage,
|
|
9
|
+
type ChatMessageAdapterTexts,
|
|
6
10
|
type ChatMessageSource,
|
|
7
11
|
} from "@/components/chat/adapters/chat-message.adapter";
|
|
8
12
|
import { useI18n } from "@/components/providers/I18nProvider";
|
|
@@ -14,11 +18,63 @@ type ChatMessageListContainerProps = {
|
|
|
14
18
|
className?: string;
|
|
15
19
|
};
|
|
16
20
|
|
|
21
|
+
const messageViewModelCache = new WeakMap<
|
|
22
|
+
UiMessage,
|
|
23
|
+
{ language: string; viewModel: ChatMessageViewModel }
|
|
24
|
+
>();
|
|
25
|
+
|
|
26
|
+
function buildChatMessageAdapterTexts(
|
|
27
|
+
language: string,
|
|
28
|
+
): ChatMessageAdapterTexts {
|
|
29
|
+
void language;
|
|
30
|
+
return {
|
|
31
|
+
roleLabels: {
|
|
32
|
+
user: t("chatRoleUser"),
|
|
33
|
+
assistant: t("chatRoleAssistant"),
|
|
34
|
+
tool: t("chatRoleTool"),
|
|
35
|
+
system: t("chatRoleSystem"),
|
|
36
|
+
fallback: t("chatRoleMessage"),
|
|
37
|
+
},
|
|
38
|
+
reasoningLabel: t("chatReasoning"),
|
|
39
|
+
toolCallLabel: t("chatToolCall"),
|
|
40
|
+
toolResultLabel: t("chatToolResult"),
|
|
41
|
+
toolNoOutputLabel: t("chatToolNoOutput"),
|
|
42
|
+
toolOutputLabel: t("chatToolOutput"),
|
|
43
|
+
toolStatusPreparingLabel: t("chatToolStatusPreparing"),
|
|
44
|
+
toolStatusRunningLabel: t("chatToolStatusRunning"),
|
|
45
|
+
toolStatusCompletedLabel: t("chatToolStatusCompleted"),
|
|
46
|
+
toolStatusFailedLabel: t("chatToolStatusFailed"),
|
|
47
|
+
toolStatusCancelledLabel: t("chatToolStatusCancelled"),
|
|
48
|
+
imageAttachmentLabel: t("chatImageAttachment"),
|
|
49
|
+
fileAttachmentLabel: t("chatFileAttachment"),
|
|
50
|
+
unknownPartLabel: t("chatUnknownPart"),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function buildChatMessageTexts(language: string) {
|
|
55
|
+
void language;
|
|
56
|
+
return {
|
|
57
|
+
copyCodeLabel: t("chatCodeCopy"),
|
|
58
|
+
copiedCodeLabel: t("chatCodeCopied"),
|
|
59
|
+
typingLabel: t("chatTyping"),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
17
63
|
export function ChatMessageListContainer(props: ChatMessageListContainerProps) {
|
|
18
64
|
const { language } = useI18n();
|
|
19
|
-
const
|
|
20
|
-
() =>
|
|
21
|
-
|
|
65
|
+
const texts = useMemo<ChatMessageAdapterTexts>(
|
|
66
|
+
() => buildChatMessageAdapterTexts(language),
|
|
67
|
+
[language],
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const messages = useMemo(() => {
|
|
71
|
+
return props.uiMessages.map((message) => {
|
|
72
|
+
const cached = messageViewModelCache.get(message);
|
|
73
|
+
if (cached && cached.language === language) {
|
|
74
|
+
return cached.viewModel;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const sourceMessage: ChatMessageSource = {
|
|
22
78
|
id: message.id,
|
|
23
79
|
role: message.role,
|
|
24
80
|
meta: {
|
|
@@ -26,57 +82,39 @@ export function ChatMessageListContainer(props: ChatMessageListContainerProps) {
|
|
|
26
82
|
status: message.meta?.status,
|
|
27
83
|
},
|
|
28
84
|
parts: message.parts as unknown as ChatMessageSource["parts"],
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
85
|
+
};
|
|
86
|
+
const viewModel = adaptChatMessage(sourceMessage, {
|
|
87
|
+
formatTimestamp: (value) => formatDateTime(value, language),
|
|
88
|
+
texts,
|
|
89
|
+
});
|
|
32
90
|
|
|
33
|
-
|
|
91
|
+
messageViewModelCache.set(message, { language, viewModel });
|
|
92
|
+
return viewModel;
|
|
93
|
+
});
|
|
94
|
+
}, [language, props.uiMessages, texts]);
|
|
95
|
+
|
|
96
|
+
const hasAssistantDraft = useMemo(
|
|
34
97
|
() =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
reasoningLabel: t("chatReasoning"),
|
|
47
|
-
toolCallLabel: t("chatToolCall"),
|
|
48
|
-
toolResultLabel: t("chatToolResult"),
|
|
49
|
-
toolNoOutputLabel: t("chatToolNoOutput"),
|
|
50
|
-
toolOutputLabel: t("chatToolOutput"),
|
|
51
|
-
toolStatusPreparingLabel: t("chatToolStatusPreparing"),
|
|
52
|
-
toolStatusRunningLabel: t("chatToolStatusRunning"),
|
|
53
|
-
toolStatusCompletedLabel: t("chatToolStatusCompleted"),
|
|
54
|
-
toolStatusFailedLabel: t("chatToolStatusFailed"),
|
|
55
|
-
toolStatusCancelledLabel: t("chatToolStatusCancelled"),
|
|
56
|
-
imageAttachmentLabel: t("chatImageAttachment"),
|
|
57
|
-
fileAttachmentLabel: t("chatFileAttachment"),
|
|
58
|
-
unknownPartLabel: t("chatUnknownPart"),
|
|
59
|
-
},
|
|
60
|
-
}),
|
|
61
|
-
[language, sourceMessages],
|
|
98
|
+
props.uiMessages.some(
|
|
99
|
+
(message) =>
|
|
100
|
+
message.role === "assistant" &&
|
|
101
|
+
(message.meta?.status === "streaming" ||
|
|
102
|
+
message.meta?.status === "pending"),
|
|
103
|
+
),
|
|
104
|
+
[props.uiMessages],
|
|
105
|
+
);
|
|
106
|
+
const messageTexts = useMemo(
|
|
107
|
+
() => buildChatMessageTexts(language),
|
|
108
|
+
[language],
|
|
62
109
|
);
|
|
63
110
|
|
|
64
111
|
return (
|
|
65
112
|
<ChatMessageList
|
|
66
113
|
messages={messages}
|
|
67
114
|
isSending={props.isSending}
|
|
68
|
-
hasAssistantDraft={
|
|
69
|
-
(message) =>
|
|
70
|
-
message.role === "assistant" &&
|
|
71
|
-
(message.meta?.status === "streaming" ||
|
|
72
|
-
message.meta?.status === "pending"),
|
|
73
|
-
)}
|
|
115
|
+
hasAssistantDraft={hasAssistantDraft}
|
|
74
116
|
className={props.className}
|
|
75
|
-
texts={
|
|
76
|
-
copyCodeLabel: t("chatCodeCopy"),
|
|
77
|
-
copiedCodeLabel: t("chatCodeCopied"),
|
|
78
|
-
typingLabel: t("chatTyping"),
|
|
79
|
-
}}
|
|
117
|
+
texts={messageTexts}
|
|
80
118
|
/>
|
|
81
119
|
);
|
|
82
120
|
}
|