@webority/mobile-chat 0.16.4 → 0.16.6

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 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatMessage=ChatMessage;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_labels=require("../labels.js"),_markdownParse=require("../markdownParse.js"),_ActionCard=require("./ActionCard.js"),_ChatMarkdown=require("./ChatMarkdown.js"),_ReplyRating=require("./ReplyRating.js"),_jsxRuntime=require("react/jsx-runtime");const inlineText=e=>e.map(e=>"text"===e.type||"code"===e.type?e.text:inlineText(e.children)).join(""),spokenText=e=>(0,_markdownParse.parseBlocks)(e).map(e=>{switch(e.type){case"paragraph":return inlineText((0,_markdownParse.parseInline)(e.lines.join(" ")));case"heading":return inlineText((0,_markdownParse.parseInline)(e.text));case"list":return e.items.map(e=>inlineText((0,_markdownParse.parseInline)(e))).join(". ");case"table":return[e.header,...e.rows].map(e=>e.join(", ")).join(". ");case"code":return e.text;default:return""}}).filter(Boolean).join("\n");function ChatMessage({turn:e,onRate:t,resolveLink:i,onLinkPress:n,confirmAction:r,onViewTicket:s,renderReply:a,labels:o,testID:l="chat-message"}){const m=(0,_labels.mergeLabels)(o),u=(0,_mobileUi.useTheme)(),c=e.streaming&&!e.answer,x=(0,_react.useMemo)(()=>e.streaming?e.answer:spokenText(e.answer),[e.streaming,e.answer]),_=(0,_react.useMemo)(()=>({you:m.you}),[m.you]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{gap:u.spacing.sm},testID:l,children:[""!==e.question&&(0,_jsxRuntime.jsx)(_mobileUi.MessageBubble,{side:"mine",text:e.question,labels:_,testID:`${l}-question`}),c?(0,_jsxRuntime.jsx)(_mobileUi.TypingIndicator,{label:m.thinking,testID:`${l}-thinking`}):null,""!==e.answer?(0,_jsxRuntime.jsx)(_mobileUi.MessageBubble,{side:"theirs",author:m.assistant,text:x,streaming:e.streaming,testID:`${l}-answer`,children:a?a(e,{streaming:e.streaming}):(0,_jsxRuntime.jsx)(_ChatMarkdown.ChatMarkdown,{text:e.answer,resolveLink:i,onLinkPress:n})}):null,e.error&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:e.error.message}),r&&!e.streaming&&e.actions.map(e=>(0,_jsxRuntime.jsx)(_ActionCard.ActionCard,{action:e,confirmAction:r,onViewTicket:s,labels:o},e.token)),t&&e.messageId&&!e.streaming&&(0,_jsxRuntime.jsx)(_ReplyRating.ReplyRating,{rating:e.rating,onRate:(i,n)=>t(e.id,i,n),labels:o})]})}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ChatMessage=void 0;var _mobileUi=require("@webority/mobile-ui"),_react=require("react"),_reactNative=require("react-native"),_labels=require("../labels.js"),_markdownParse=require("../markdownParse.js"),_ActionCard=require("./ActionCard.js"),_ChatMarkdown=require("./ChatMarkdown.js"),_ReplyRating=require("./ReplyRating.js"),_jsxRuntime=require("react/jsx-runtime");const inlineText=e=>e.map(e=>"text"===e.type||"code"===e.type?e.text:inlineText(e.children)).join(""),spokenText=e=>(0,_markdownParse.parseBlocks)(e).map(e=>{switch(e.type){case"paragraph":return inlineText((0,_markdownParse.parseInline)(e.lines.join(" ")));case"heading":return inlineText((0,_markdownParse.parseInline)(e.text));case"list":return e.items.map(e=>inlineText((0,_markdownParse.parseInline)(e))).join(". ");case"table":return[e.header,...e.rows].map(e=>e.join(", ")).join(". ");case"code":return e.text;default:return""}}).filter(Boolean).join("\n");function ChatMessageView({turn:e,onRate:t,resolveLink:i,onLinkPress:s,confirmAction:n,onViewTicket:r,renderReply:a,labels:o,testID:l="chat-message"}){const m=(0,_labels.mergeLabels)(o),u=(0,_mobileUi.useTheme)(),c=e.streaming&&!e.answer,x=(0,_react.useMemo)(()=>e.streaming?e.answer:spokenText(e.answer),[e.streaming,e.answer]),_=(0,_react.useMemo)(()=>({you:m.you}),[m.you]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{gap:u.spacing.sm},testID:l,children:[""!==e.question&&(0,_jsxRuntime.jsx)(_mobileUi.MessageBubble,{side:"mine",text:e.question,labels:_,testID:`${l}-question`}),c?(0,_jsxRuntime.jsx)(_mobileUi.TypingIndicator,{label:m.thinking,testID:`${l}-thinking`}):null,""!==e.answer?(0,_jsxRuntime.jsx)(_mobileUi.MessageBubble,{side:"theirs",author:m.assistant,text:x,streaming:e.streaming,testID:`${l}-answer`,children:a?a(e,{streaming:e.streaming}):(0,_jsxRuntime.jsx)(_ChatMarkdown.ChatMarkdown,{text:e.answer,resolveLink:i,onLinkPress:s})}):null,e.error&&(0,_jsxRuntime.jsx)(_mobileUi.Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:e.error.message}),n&&!e.streaming&&e.actions.map(e=>(0,_jsxRuntime.jsx)(_ActionCard.ActionCard,{action:e,confirmAction:n,onViewTicket:r,labels:o},e.token)),t&&e.messageId&&!e.streaming&&(0,_jsxRuntime.jsx)(_ReplyRating.ReplyRating,{rating:e.rating,onRate:(i,s)=>t(e.id,i,s),labels:o})]})}const ChatMessage=exports.ChatMessage=(0,_react.memo)(ChatMessageView);
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useChat=void 0;var _react=require("react");const toError=e=>{const t=e;return{code:"string"==typeof t?.code&&t.code?t.code:"unknown",message:"string"==typeof t?.message&&t.message?t.message:"Something went wrong. Please try again.",resetsAtUtc:"string"==typeof t?.resetsAtUtc?t.resetsAtUtc:null}},parseActions=e=>{if(!e)return[];const t=JSON.parse(e);return Array.isArray(t)?t:[]},emptyTurn=(e,t)=>({id:e,question:t,answer:"",streaming:!1,error:null,actions:[],messageId:null,rating:null,ratingNote:null}),turnsFromConversation=e=>{const t=[];for(const r of e??[]){if("User"===r.role){t.push(emptyTurn(r.publicId,r.content));continue}const e=t[t.length-1],n={answer:r.content,actions:parseActions(r.actionsJson),messageId:r.publicId,rating:r.rating??null,ratingNote:r.ratingNote??null};e&&null===e.messageId&&""===e.answer?Object.assign(e,n):t.push({...emptyTurn(r.publicId,""),...n})}return t},useChat=({client:e,pageContext:t})=>{const[r,n]=(0,_react.useState)([]),[s,a]=(0,_react.useState)(null),[c,o]=(0,_react.useState)(null),[u,l]=(0,_react.useState)(!1),[i,g]=(0,_react.useState)(null),d=(0,_react.useRef)(null),m=(0,_react.useRef)(0),f=(0,_react.useRef)(0),y=(0,_react.useRef)(t);y.current=t;const p=(0,_react.useRef)(null);p.current=s;const _=(0,_react.useRef)(r);_.current=r;const w=(0,_react.useCallback)(()=>{m.current+=1,d.current?.abort(),d.current=null},[]);(0,_react.useEffect)(()=>w,[w]);const C=(0,_react.useCallback)((e,t)=>{n(r=>r.map(r=>r.id===e?{...r,..."function"==typeof t?t(r):t}:r))},[]),b=(0,_react.useCallback)(async t=>{const r="string"==typeof t?t.trim():"";if(!r||d.current)return;const s=m.current,c=new AbortController;d.current=c,f.current+=1;const u=`turn-${f.current}`;n(e=>[...e,{...emptyTurn(u,r),streaming:!0}]);const live=()=>s===m.current&&!c.signal.aborted;try{const t=await e.sendMessage({message:r,conversationId:p.current,pageContext:y.current},{signal:c.signal,onEvent:(e,t)=>{if(!live())return;const r=t;"delta"===e?C(u,e=>({answer:e.answer+(r?.text??"")})):"reset"===e?C(u,{answer:""}):"actions"===e&&C(u,{actions:Array.isArray(r?.actions)?r.actions:[]})}});if(!live())return;C(u,{answer:t.reply,messageId:t.messageId??null,streaming:!1}),p.current=t.conversationId,a(t.conversationId),o(t.messagesLeftToday??null)}catch(e){if(!live())return;const t=toError(e);C(u,{answer:"",actions:[],streaming:!1,error:t}),"daily_limit"===t.code&&o(0),"conversation_not_found"===t.code&&(p.current=null,a(null))}finally{d.current===c&&(d.current=null)}},[e,C]),I=(0,_react.useCallback)(async t=>{w();const r=m.current;n([]),a(null),g(null),l(!0);try{const s=await e.getConversation(t);if(r!==m.current)return;n(turnsFromConversation(s.messages)),a(s.publicId)}catch(e){if(r!==m.current)return;g(toError(e))}finally{r===m.current&&l(!1)}},[w,e]),h=(0,_react.useCallback)(()=>{w(),n([]),a(null),g(null),l(!1)},[w]),v=(0,_react.useCallback)(()=>{w(),n([]),a(null),o(null),g(null),l(!1)},[w]),A=(0,_react.useCallback)(async()=>{const t=m.current,r=await e.getAllowance();t===m.current&&o(r?.messagesLeftToday??null)},[e]),k=(0,_react.useCallback)(async(t,r,n)=>{const s=_.current.find(e=>e.id===t),a=p.current;if(!s?.messageId||!a)throw new Error("Only a stored reply can be rated.");const c={rating:s.rating,ratingNote:s.ratingNote},o="string"==typeof n&&n.trim()?n.trim():null;C(t,{rating:r,ratingNote:o});try{await e.rateMessage(a,s.messageId,{rating:r,note:o})}catch(e){throw C(t,c),e}},[e,C]);return{turns:r,conversationId:s,messagesLeftToday:c,streaming:r.some(e=>e.streaming),loading:u,loadError:i,submit:b,openConversation:I,newConversation:h,rate:k,refreshAllowance:A,reset:v}};exports.useChat=useChat;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useChat=void 0;var _react=require("react");const toError=e=>{const t=e;return{code:"string"==typeof t?.code&&t.code?t.code:"unknown",message:"string"==typeof t?.message&&t.message?t.message:"Something went wrong. Please try again.",resetsAtUtc:"string"==typeof t?.resetsAtUtc?t.resetsAtUtc:null}},parseActions=e=>{if(!e)return[];const t=JSON.parse(e);return Array.isArray(t)?t:[]},emptyTurn=(e,t)=>({id:e,question:t,answer:"",streaming:!1,error:null,actions:[],messageId:null,rating:null,ratingNote:null}),turnsFromConversation=e=>{const t=[];for(const r of e??[]){if("User"===r.role){t.push(emptyTurn(r.publicId,r.content));continue}const e=t[t.length-1],n={answer:r.content,actions:parseActions(r.actionsJson),messageId:r.publicId,rating:r.rating??null,ratingNote:r.ratingNote??null};e&&null===e.messageId&&""===e.answer?Object.assign(e,n):t.push({...emptyTurn(r.publicId,""),...n})}return t},useChat=({client:e,pageContext:t})=>{const[r,n]=(0,_react.useState)([]),[a,s]=(0,_react.useState)(null),[c,u]=(0,_react.useState)(null),[o,l]=(0,_react.useState)(!1),[i,g]=(0,_react.useState)(null),d=(0,_react.useRef)(null),m=(0,_react.useRef)(0),f=(0,_react.useRef)(0),p=(0,_react.useRef)(t);p.current=t;const y=(0,_react.useRef)(null);y.current=a;const _=(0,_react.useRef)(r);_.current=r;const w=(0,_react.useRef)(new Map),C=(0,_react.useRef)(0),b=(0,_react.useRef)(!1),h=(0,_react.useCallback)(()=>{const e=w.current;0!==e.size&&(w.current=new Map,n(t=>t.map(t=>e.has(t.id)?{...t,answer:t.answer+(e.get(t.id)??"")}:t)))},[]),I=(0,_react.useCallback)((e,t)=>{w.current.set(e,(w.current.get(e)??"")+t),b.current||(b.current=!0,C.current=requestAnimationFrame(()=>{b.current=!1,h()}))},[h]),v=(0,_react.useCallback)(()=>{cancelAnimationFrame(C.current),b.current=!1,w.current=new Map},[]),A=(0,_react.useCallback)(()=>{m.current+=1,d.current?.abort(),d.current=null,v()},[v]);(0,_react.useEffect)(()=>A,[A]);const k=(0,_react.useCallback)((e,t)=>{n(r=>r.map(r=>r.id===e?{...r,..."function"==typeof t?t(r):t}:r))},[]),R=(0,_react.useCallback)(async t=>{const r="string"==typeof t?t.trim():"";if(!r||d.current)return;const a=m.current,c=new AbortController;d.current=c,f.current+=1;const o=`turn-${f.current}`;n(e=>[...e,{...emptyTurn(o,r),streaming:!0}]);const live=()=>a===m.current&&!c.signal.aborted;try{const t=await e.sendMessage({message:r,conversationId:y.current,pageContext:p.current},{signal:c.signal,onEvent:(e,t)=>{if(!live())return;const r=t;"delta"===e?I(o,r?.text??""):"reset"===e?(w.current.delete(o),k(o,{answer:""})):(h(),"actions"===e&&k(o,{actions:Array.isArray(r?.actions)?r.actions:[]}))}});if(!live())return;h(),k(o,{answer:t.reply,messageId:t.messageId??null,streaming:!1}),y.current=t.conversationId,s(t.conversationId),u(t.messagesLeftToday??null)}catch(e){if(!live())return;const t=toError(e);w.current.delete(o),k(o,{answer:"",actions:[],streaming:!1,error:t}),"daily_limit"===t.code&&u(0),"conversation_not_found"===t.code&&(y.current=null,s(null))}finally{d.current===c&&(d.current=null)}},[e,k,h,I]),E=(0,_react.useCallback)(async t=>{A();const r=m.current;n([]),s(null),g(null),l(!0);try{const a=await e.getConversation(t);if(r!==m.current)return;n(turnsFromConversation(a.messages)),s(a.publicId)}catch(e){if(r!==m.current)return;g(toError(e))}finally{r===m.current&&l(!1)}},[A,e]),N=(0,_react.useCallback)(()=>{A(),n([]),s(null),g(null),l(!1)},[A]),S=(0,_react.useCallback)(()=>{A(),n([]),s(null),u(null),g(null),l(!1)},[A]),T=(0,_react.useCallback)(async()=>{const t=m.current,r=await e.getAllowance();t===m.current&&u(r?.messagesLeftToday??null)},[e]),x=(0,_react.useCallback)(async(t,r,n)=>{const a=_.current.find(e=>e.id===t),s=y.current;if(!a?.messageId||!s)throw new Error("Only a stored reply can be rated.");const c={rating:a.rating,ratingNote:a.ratingNote},u="string"==typeof n&&n.trim()?n.trim():null;k(t,{rating:r,ratingNote:u});try{await e.rateMessage(s,a.messageId,{rating:r,note:u})}catch(e){throw k(t,c),e}},[e,k]);return{turns:r,conversationId:a,messagesLeftToday:c,streaming:r.some(e=>e.streaming),loading:o,loadError:i,submit:R,openConversation:E,newConversation:N,rate:x,refreshAllowance:T,reset:S}};exports.useChat=useChat;
@@ -1 +1 @@
1
- "use strict";import{MessageBubble,Text,TypingIndicator,useTheme}from"@webority/mobile-ui";import{useMemo}from"react";import{View}from"react-native";import{mergeLabels}from"../labels.js";import{parseBlocks,parseInline}from"../markdownParse.js";import{ActionCard}from"./ActionCard.js";import{ChatMarkdown}from"./ChatMarkdown.js";import{ReplyRating}from"./ReplyRating.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";const inlineText=e=>e.map(e=>"text"===e.type||"code"===e.type?e.text:inlineText(e.children)).join(""),spokenText=e=>parseBlocks(e).map(e=>{switch(e.type){case"paragraph":return inlineText(parseInline(e.lines.join(" ")));case"heading":return inlineText(parseInline(e.text));case"list":return e.items.map(e=>inlineText(parseInline(e))).join(". ");case"table":return[e.header,...e.rows].map(e=>e.join(", ")).join(". ");case"code":return e.text;default:return""}}).filter(Boolean).join("\n");export function ChatMessage({turn:e,onRate:t,resolveLink:s,onLinkPress:n,confirmAction:r,onViewTicket:i,renderReply:a,labels:o,testID:l="chat-message"}){const m=mergeLabels(o),c=useTheme(),p=e.streaming&&!e.answer,g=useMemo(()=>e.streaming?e.answer:spokenText(e.answer),[e.streaming,e.answer]),u=useMemo(()=>({you:m.you}),[m.you]);return _jsxs(View,{style:{gap:c.spacing.sm},testID:l,children:[""!==e.question&&_jsx(MessageBubble,{side:"mine",text:e.question,labels:u,testID:`${l}-question`}),p?_jsx(TypingIndicator,{label:m.thinking,testID:`${l}-thinking`}):null,""!==e.answer?_jsx(MessageBubble,{side:"theirs",author:m.assistant,text:g,streaming:e.streaming,testID:`${l}-answer`,children:a?a(e,{streaming:e.streaming}):_jsx(ChatMarkdown,{text:e.answer,resolveLink:s,onLinkPress:n})}):null,e.error&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:e.error.message}),r&&!e.streaming&&e.actions.map(e=>_jsx(ActionCard,{action:e,confirmAction:r,onViewTicket:i,labels:o},e.token)),t&&e.messageId&&!e.streaming&&_jsx(ReplyRating,{rating:e.rating,onRate:(s,n)=>t(e.id,s,n),labels:o})]})}
1
+ "use strict";import{MessageBubble,Text,TypingIndicator,useTheme}from"@webority/mobile-ui";import{memo,useMemo}from"react";import{View}from"react-native";import{mergeLabels}from"../labels.js";import{parseBlocks,parseInline}from"../markdownParse.js";import{ActionCard}from"./ActionCard.js";import{ChatMarkdown}from"./ChatMarkdown.js";import{ReplyRating}from"./ReplyRating.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";const inlineText=e=>e.map(e=>"text"===e.type||"code"===e.type?e.text:inlineText(e.children)).join(""),spokenText=e=>parseBlocks(e).map(e=>{switch(e.type){case"paragraph":return inlineText(parseInline(e.lines.join(" ")));case"heading":return inlineText(parseInline(e.text));case"list":return e.items.map(e=>inlineText(parseInline(e))).join(". ");case"table":return[e.header,...e.rows].map(e=>e.join(", ")).join(". ");case"code":return e.text;default:return""}}).filter(Boolean).join("\n");function ChatMessageView({turn:e,onRate:s,resolveLink:t,onLinkPress:n,confirmAction:i,onViewTicket:r,renderReply:a,labels:o,testID:l="chat-message"}){const m=mergeLabels(o),c=useTheme(),p=e.streaming&&!e.answer,g=useMemo(()=>e.streaming?e.answer:spokenText(e.answer),[e.streaming,e.answer]),u=useMemo(()=>({you:m.you}),[m.you]);return _jsxs(View,{style:{gap:c.spacing.sm},testID:l,children:[""!==e.question&&_jsx(MessageBubble,{side:"mine",text:e.question,labels:u,testID:`${l}-question`}),p?_jsx(TypingIndicator,{label:m.thinking,testID:`${l}-thinking`}):null,""!==e.answer?_jsx(MessageBubble,{side:"theirs",author:m.assistant,text:g,streaming:e.streaming,testID:`${l}-answer`,children:a?a(e,{streaming:e.streaming}):_jsx(ChatMarkdown,{text:e.answer,resolveLink:t,onLinkPress:n})}):null,e.error&&_jsx(Text,{variant:"bodySmall",color:"error",accessibilityLiveRegion:"polite",children:e.error.message}),i&&!e.streaming&&e.actions.map(e=>_jsx(ActionCard,{action:e,confirmAction:i,onViewTicket:r,labels:o},e.token)),s&&e.messageId&&!e.streaming&&_jsx(ReplyRating,{rating:e.rating,onRate:(t,n)=>s(e.id,t,n),labels:o})]})}export const ChatMessage=memo(ChatMessageView);
@@ -1 +1 @@
1
- "use strict";import{useCallback,useEffect,useRef,useState}from"react";const toError=e=>{const t=e;return{code:"string"==typeof t?.code&&t.code?t.code:"unknown",message:"string"==typeof t?.message&&t.message?t.message:"Something went wrong. Please try again.",resetsAtUtc:"string"==typeof t?.resetsAtUtc?t.resetsAtUtc:null}},parseActions=e=>{if(!e)return[];const t=JSON.parse(e);return Array.isArray(t)?t:[]},emptyTurn=(e,t)=>({id:e,question:t,answer:"",streaming:!1,error:null,actions:[],messageId:null,rating:null,ratingNote:null}),turnsFromConversation=e=>{const t=[];for(const n of e??[]){if("User"===n.role){t.push(emptyTurn(n.publicId,n.content));continue}const e=t[t.length-1],r={answer:n.content,actions:parseActions(n.actionsJson),messageId:n.publicId,rating:n.rating??null,ratingNote:n.ratingNote??null};e&&null===e.messageId&&""===e.answer?Object.assign(e,r):t.push({...emptyTurn(n.publicId,""),...r})}return t};export const useChat=({client:e,pageContext:t})=>{const[n,r]=useState([]),[s,a]=useState(null),[o,u]=useState(null),[c,l]=useState(!1),[i,g]=useState(null),f=useRef(null),m=useRef(0),d=useRef(0),y=useRef(t);y.current=t;const p=useRef(null);p.current=s;const w=useRef(n);w.current=n;const b=useCallback(()=>{m.current+=1,f.current?.abort(),f.current=null},[]);useEffect(()=>b,[b]);const C=useCallback((e,t)=>{r(n=>n.map(n=>n.id===e?{...n,..."function"==typeof t?t(n):t}:n))},[]),I=useCallback(async t=>{const n="string"==typeof t?t.trim():"";if(!n||f.current)return;const s=m.current,o=new AbortController;f.current=o,d.current+=1;const c=`turn-${d.current}`;r(e=>[...e,{...emptyTurn(c,n),streaming:!0}]);const live=()=>s===m.current&&!o.signal.aborted;try{const t=await e.sendMessage({message:n,conversationId:p.current,pageContext:y.current},{signal:o.signal,onEvent:(e,t)=>{if(!live())return;const n=t;"delta"===e?C(c,e=>({answer:e.answer+(n?.text??"")})):"reset"===e?C(c,{answer:""}):"actions"===e&&C(c,{actions:Array.isArray(n?.actions)?n.actions:[]})}});if(!live())return;C(c,{answer:t.reply,messageId:t.messageId??null,streaming:!1}),p.current=t.conversationId,a(t.conversationId),u(t.messagesLeftToday??null)}catch(e){if(!live())return;const t=toError(e);C(c,{answer:"",actions:[],streaming:!1,error:t}),"daily_limit"===t.code&&u(0),"conversation_not_found"===t.code&&(p.current=null,a(null))}finally{f.current===o&&(f.current=null)}},[e,C]),A=useCallback(async t=>{b();const n=m.current;r([]),a(null),g(null),l(!0);try{const s=await e.getConversation(t);if(n!==m.current)return;r(turnsFromConversation(s.messages)),a(s.publicId)}catch(e){if(n!==m.current)return;g(toError(e))}finally{n===m.current&&l(!1)}},[b,e]),h=useCallback(()=>{b(),r([]),a(null),g(null),l(!1)},[b]),v=useCallback(()=>{b(),r([]),a(null),u(null),g(null),l(!1)},[b]),k=useCallback(async()=>{const t=m.current,n=await e.getAllowance();t===m.current&&u(n?.messagesLeftToday??null)},[e]),E=useCallback(async(t,n,r)=>{const s=w.current.find(e=>e.id===t),a=p.current;if(!s?.messageId||!a)throw new Error("Only a stored reply can be rated.");const o={rating:s.rating,ratingNote:s.ratingNote},u="string"==typeof r&&r.trim()?r.trim():null;C(t,{rating:n,ratingNote:u});try{await e.rateMessage(a,s.messageId,{rating:n,note:u})}catch(e){throw C(t,o),e}},[e,C]);return{turns:n,conversationId:s,messagesLeftToday:o,streaming:n.some(e=>e.streaming),loading:c,loadError:i,submit:I,openConversation:A,newConversation:h,rate:E,refreshAllowance:k,reset:v}};
1
+ "use strict";import{useCallback,useEffect,useRef,useState}from"react";const toError=e=>{const t=e;return{code:"string"==typeof t?.code&&t.code?t.code:"unknown",message:"string"==typeof t?.message&&t.message?t.message:"Something went wrong. Please try again.",resetsAtUtc:"string"==typeof t?.resetsAtUtc?t.resetsAtUtc:null}},parseActions=e=>{if(!e)return[];const t=JSON.parse(e);return Array.isArray(t)?t:[]},emptyTurn=(e,t)=>({id:e,question:t,answer:"",streaming:!1,error:null,actions:[],messageId:null,rating:null,ratingNote:null}),turnsFromConversation=e=>{const t=[];for(const n of e??[]){if("User"===n.role){t.push(emptyTurn(n.publicId,n.content));continue}const e=t[t.length-1],r={answer:n.content,actions:parseActions(n.actionsJson),messageId:n.publicId,rating:n.rating??null,ratingNote:n.ratingNote??null};e&&null===e.messageId&&""===e.answer?Object.assign(e,r):t.push({...emptyTurn(n.publicId,""),...r})}return t};export const useChat=({client:e,pageContext:t})=>{const[n,r]=useState([]),[s,a]=useState(null),[u,c]=useState(null),[o,l]=useState(!1),[i,g]=useState(null),m=useRef(null),d=useRef(0),f=useRef(0),p=useRef(t);p.current=t;const y=useRef(null);y.current=s;const w=useRef(n);w.current=n;const b=useRef(new Map),C=useRef(0),I=useRef(!1),A=useCallback(()=>{const e=b.current;0!==e.size&&(b.current=new Map,r(t=>t.map(t=>e.has(t.id)?{...t,answer:t.answer+(e.get(t.id)??"")}:t)))},[]),k=useCallback((e,t)=>{b.current.set(e,(b.current.get(e)??"")+t),I.current||(I.current=!0,C.current=requestAnimationFrame(()=>{I.current=!1,A()}))},[A]),h=useCallback(()=>{cancelAnimationFrame(C.current),I.current=!1,b.current=new Map},[]),v=useCallback(()=>{d.current+=1,m.current?.abort(),m.current=null,h()},[h]);useEffect(()=>v,[v]);const R=useCallback((e,t)=>{r(n=>n.map(n=>n.id===e?{...n,..."function"==typeof t?t(n):t}:n))},[]),E=useCallback(async t=>{const n="string"==typeof t?t.trim():"";if(!n||m.current)return;const s=d.current,u=new AbortController;m.current=u,f.current+=1;const o=`turn-${f.current}`;r(e=>[...e,{...emptyTurn(o,n),streaming:!0}]);const live=()=>s===d.current&&!u.signal.aborted;try{const t=await e.sendMessage({message:n,conversationId:y.current,pageContext:p.current},{signal:u.signal,onEvent:(e,t)=>{if(!live())return;const n=t;"delta"===e?k(o,n?.text??""):"reset"===e?(b.current.delete(o),R(o,{answer:""})):(A(),"actions"===e&&R(o,{actions:Array.isArray(n?.actions)?n.actions:[]}))}});if(!live())return;A(),R(o,{answer:t.reply,messageId:t.messageId??null,streaming:!1}),y.current=t.conversationId,a(t.conversationId),c(t.messagesLeftToday??null)}catch(e){if(!live())return;const t=toError(e);b.current.delete(o),R(o,{answer:"",actions:[],streaming:!1,error:t}),"daily_limit"===t.code&&c(0),"conversation_not_found"===t.code&&(y.current=null,a(null))}finally{m.current===u&&(m.current=null)}},[e,R,A,k]),S=useCallback(async t=>{v();const n=d.current;r([]),a(null),g(null),l(!0);try{const s=await e.getConversation(t);if(n!==d.current)return;r(turnsFromConversation(s.messages)),a(s.publicId)}catch(e){if(n!==d.current)return;g(toError(e))}finally{n===d.current&&l(!1)}},[v,e]),N=useCallback(()=>{v(),r([]),a(null),g(null),l(!1)},[v]),T=useCallback(()=>{v(),r([]),a(null),c(null),g(null),l(!1)},[v]),M=useCallback(async()=>{const t=d.current,n=await e.getAllowance();t===d.current&&c(n?.messagesLeftToday??null)},[e]),x=useCallback(async(t,n,r)=>{const s=w.current.find(e=>e.id===t),a=y.current;if(!s?.messageId||!a)throw new Error("Only a stored reply can be rated.");const u={rating:s.rating,ratingNote:s.ratingNote},c="string"==typeof r&&r.trim()?r.trim():null;R(t,{rating:n,ratingNote:c});try{await e.rateMessage(a,s.messageId,{rating:n,note:c})}catch(e){throw R(t,u),e}},[e,R]);return{turns:n,conversationId:s,messagesLeftToday:u,streaming:n.some(e=>e.streaming),loading:o,loadError:i,submit:E,openConversation:S,newConversation:N,rate:x,refreshAllowance:M,reset:T}};
@@ -32,5 +32,7 @@ export interface ChatMessageProps<T = string> extends ChatReplyProps<T> {
32
32
  * leading side. The answer is announced once, when it finishes arriving. Support actions show
33
33
  * under the answer, and the rating once the reply is stored.
34
34
  */
35
- export declare function ChatMessage<T = string>({ turn, onRate, resolveLink, onLinkPress, confirmAction, onViewTicket, renderReply, labels: labelOverrides, testID }: ChatMessageProps<T>): React.ReactElement;
35
+ declare function ChatMessageView<T = string>({ turn, onRate, resolveLink, onLinkPress, confirmAction, onViewTicket, renderReply, labels: labelOverrides, testID }: ChatMessageProps<T>): React.ReactElement;
36
+ export declare const ChatMessage: typeof ChatMessageView;
37
+ export {};
36
38
  //# sourceMappingURL=ChatMessage.d.ts.map
@@ -32,5 +32,7 @@ export interface ChatMessageProps<T = string> extends ChatReplyProps<T> {
32
32
  * leading side. The answer is announced once, when it finishes arriving. Support actions show
33
33
  * under the answer, and the rating once the reply is stored.
34
34
  */
35
- export declare function ChatMessage<T = string>({ turn, onRate, resolveLink, onLinkPress, confirmAction, onViewTicket, renderReply, labels: labelOverrides, testID }: ChatMessageProps<T>): React.ReactElement;
35
+ declare function ChatMessageView<T = string>({ turn, onRate, resolveLink, onLinkPress, confirmAction, onViewTicket, renderReply, labels: labelOverrides, testID }: ChatMessageProps<T>): React.ReactElement;
36
+ export declare const ChatMessage: typeof ChatMessageView;
37
+ export {};
36
38
  //# sourceMappingURL=ChatMessage.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/mobile-chat",
3
- "version": "0.16.4",
3
+ "version": "0.16.6",
4
4
  "description": "AI assistant chat for Webority React Native apps: a streaming chat client, a store-agnostic chat hook, and the chat screen, thread, composer, past chats, reply rating and support action cards, built on @webority/mobile-ui.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -81,8 +81,8 @@
81
81
  ]
82
82
  },
83
83
  "devDependencies": {
84
- "@webority/mobile-ui": "0.16.4",
85
- "@webority/mobile-core": "0.16.4"
84
+ "@webority/mobile-core": "0.16.6",
85
+ "@webority/mobile-ui": "0.16.6"
86
86
  },
87
87
  "scripts": {
88
88
  "build": "bob build && node ../../scripts/minify-lib.mjs",