@inkeep/agents-ui 0.17.6 → 0.17.7

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
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("../../hooks/use-inkeep-api-client.cjs");function s(t){const e=Number(t.code)||Number(t.statusCode);if(e&&!Number.isNaN(e))return e;try{const r=Number(JSON.parse(t.message??"").status);return r&&!Number.isNaN(r)?r:null}catch{return null}}function o(t){const e=s(t),r=n.parseAuthError(e??0,{detail:t.message??""});return r!==null?r:e===401?"session":e===403?"captcha":null}function a(t){const e=s(t);return e===400||e===429}const u=`Hmm..
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("../../hooks/use-inkeep-api-client.cjs");function n(t){const e=Number(t.code)||Number(t.statusCode);if(e&&!Number.isNaN(e))return e;try{const r=Number(JSON.parse(t.message??"").status);return r&&!Number.isNaN(r)?r:null}catch{return null}}function E(t){const e=n(t),r=o.parseAuthError(e??0,{detail:t.message??""});return r!==null?r:e===401?"session":e===403?"captcha":null}function a(t){const e=n(t);return e===400||e===413||e===429}function i(t){if(n(t)!==null)return!1;const e=(t.message??"").toLowerCase();return e.includes("failed to fetch")||e.includes("load failed")||e.includes("networkerror")||e.includes("network request failed")}const u="Something went wrong sending your message. Check your connection and try again.",c="Your message could not be sent. If you attached large files, try removing one. Otherwise, check your connection and try again.",_=`Hmm..
2
2
 
3
- It seems I might be having some issues right now. Please clear the chat and try again.`,i="Please try again.",E="You're sending requests too quickly. Please wait a moment and try again.",c=8e3;exports.DEFAULT_ERROR_MESSAGE=u;exports.RATE_LIMIT_MESSAGE=E;exports.RECOVERABLE_FALLBACK_MESSAGE=i;exports.RECOVERABLE_NOTIFICATION_DURATION_MS=c;exports.isRecoverableError=a;exports.resolveHttpStatusCode=s;exports.resolveStreamingAuthError=o;
3
+ It seems I might be having some issues right now. Please clear the chat and try again.`,l="Please try again.",R="You're sending requests too quickly. Please wait a moment and try again.",A="Your message or attachments are too large. Remove a file or shorten your message and try again.",S=43e5,s=4/3;function d(t){return new TextEncoder().encode(t.text).length+Math.ceil(t.rawFileBytes*s)+t.encodedPartsBytes}const O=8e3;exports.BASE64_SIZE_FACTOR=s;exports.DEFAULT_ERROR_MESSAGE=_;exports.MAX_REQUEST_BODY_BYTES=S;exports.NETWORK_ERROR_MESSAGE=u;exports.NETWORK_ERROR_WITH_FILES_MESSAGE=c;exports.PAYLOAD_TOO_LARGE_MESSAGE=A;exports.RATE_LIMIT_MESSAGE=R;exports.RECOVERABLE_FALLBACK_MESSAGE=l;exports.RECOVERABLE_NOTIFICATION_DURATION_MS=O;exports.estimateRequestBodyBytes=d;exports.isNetworkError=i;exports.isRecoverableError=a;exports.resolveHttpStatusCode=n;exports.resolveStreamingAuthError=E;
@@ -18,10 +18,47 @@ export declare function resolveStreamingAuthError(error: Error): 'captcha' | 'se
18
18
  * Recoverable errors are input-validation failures where the user can fix
19
19
  * their input and retry without clearing the conversation.
20
20
  *
21
+ * 413 (payload too large) is recoverable: the conversation is intact and the
22
+ * user can remove an attachment or shorten their message and resend.
23
+ *
21
24
  * Allowlist approach: unknown/unparseable errors default to non-recoverable (blocking).
22
25
  */
23
26
  export declare function isRecoverableError(error: Error): boolean;
27
+ /**
28
+ * Detects an opaque transport failure that arrived with no readable HTTP status —
29
+ * the fetch rejected before (or without) a usable response.
30
+ *
31
+ * The most common production cause is a platform-level 413: Vercel rejects any
32
+ * request body over ~4.5MB at the edge (base64-encoded file attachments inflate
33
+ * ~33%, so this is easy to hit), and that platform 413 carries no CORS headers
34
+ * because the app's cors() middleware never runs on it. The browser therefore
35
+ * blocks JS from reading the response and surfaces `TypeError: Failed to fetch`
36
+ * with no status. Genuine offline/DNS failures land here too — in both cases the
37
+ * conversation is intact and the user should get a non-blocking retry prompt.
38
+ *
39
+ * Matched on message signature (not error.name) so we don't swallow genuine
40
+ * programming TypeErrors as recoverable network failures.
41
+ */
42
+ export declare function isNetworkError(error: Error): boolean;
43
+ export declare const NETWORK_ERROR_MESSAGE = "Something went wrong sending your message. Check your connection and try again.";
44
+ export declare const NETWORK_ERROR_WITH_FILES_MESSAGE = "Your message could not be sent. If you attached large files, try removing one. Otherwise, check your connection and try again.";
24
45
  export declare const DEFAULT_ERROR_MESSAGE = "Hmm.. \n\nIt seems I might be having some issues right now. Please clear the chat and try again.";
25
46
  export declare const RECOVERABLE_FALLBACK_MESSAGE = "Please try again.";
26
47
  export declare const RATE_LIMIT_MESSAGE = "You're sending requests too quickly. Please wait a moment and try again.";
48
+ export declare const PAYLOAD_TOO_LARGE_MESSAGE = "Your message or attachments are too large. Remove a file or shorten your message and try again.";
49
+ export declare const MAX_REQUEST_BODY_BYTES = 4300000;
50
+ export declare const BASE64_SIZE_FACTOR: number;
51
+ /**
52
+ * Estimates the encoded byte size of the outgoing chat request body. Only the latest
53
+ * message is ever sent (the backend tracks history via conversationId), so file
54
+ * attachments in the current turn dominate — conversation history is irrelevant here.
55
+ */
56
+ export declare function estimateRequestBodyBytes(input: {
57
+ /** Message text. */
58
+ text: string;
59
+ /** Sum of `File.size` for freshly attached files (raw, pre-base64). */
60
+ rawFileBytes: number;
61
+ /** Sum of `.url.length` for already-encoded FileUIParts (data URLs). */
62
+ encodedPartsBytes: number;
63
+ }): number;
27
64
  export declare const RECOVERABLE_NOTIFICATION_DURATION_MS = 8000;
@@ -1,32 +1,51 @@
1
1
  "use client";
2
2
  import { parseAuthError as r } from "../../hooks/use-inkeep-api-client.js";
3
- function n(t) {
3
+ function s(t) {
4
4
  const e = Number(t.code) || Number(t.statusCode);
5
5
  if (e && !Number.isNaN(e)) return e;
6
6
  try {
7
- const s = Number(JSON.parse(t.message ?? "").status);
8
- return s && !Number.isNaN(s) ? s : null;
7
+ const n = Number(JSON.parse(t.message ?? "").status);
8
+ return n && !Number.isNaN(n) ? n : null;
9
9
  } catch {
10
10
  return null;
11
11
  }
12
12
  }
13
- function o(t) {
14
- const e = n(t), s = r(e ?? 0, { detail: t.message ?? "" });
15
- return s !== null ? s : e === 401 ? "session" : e === 403 ? "captcha" : null;
13
+ function c(t) {
14
+ const e = s(t), n = r(e ?? 0, { detail: t.message ?? "" });
15
+ return n !== null ? n : e === 401 ? "session" : e === 403 ? "captcha" : null;
16
+ }
17
+ function i(t) {
18
+ const e = s(t);
19
+ return e === 400 || e === 413 || e === 429;
16
20
  }
17
21
  function u(t) {
18
- const e = n(t);
19
- return e === 400 || e === 429;
22
+ if (s(t) !== null) return !1;
23
+ const e = (t.message ?? "").toLowerCase();
24
+ return e.includes("failed to fetch") || // Chromium
25
+ e.includes("load failed") || // Safari
26
+ e.includes("networkerror") || // Firefox
27
+ e.includes("network request failed");
20
28
  }
21
- const i = `Hmm..
29
+ const l = "Something went wrong sending your message. Check your connection and try again.", E = "Your message could not be sent. If you attached large files, try removing one. Otherwise, check your connection and try again.", d = `Hmm..
22
30
 
23
- It seems I might be having some issues right now. Please clear the chat and try again.`, c = "Please try again.", l = "You're sending requests too quickly. Please wait a moment and try again.", m = 8e3;
31
+ It seems I might be having some issues right now. Please clear the chat and try again.`, m = "Please try again.", g = "You're sending requests too quickly. Please wait a moment and try again.", R = "Your message or attachments are too large. Remove a file or shorten your message and try again.", _ = 43e5, o = 4 / 3;
32
+ function A(t) {
33
+ return new TextEncoder().encode(t.text).length + Math.ceil(t.rawFileBytes * o) + t.encodedPartsBytes;
34
+ }
35
+ const S = 8e3;
24
36
  export {
25
- i as DEFAULT_ERROR_MESSAGE,
26
- l as RATE_LIMIT_MESSAGE,
27
- c as RECOVERABLE_FALLBACK_MESSAGE,
28
- m as RECOVERABLE_NOTIFICATION_DURATION_MS,
29
- u as isRecoverableError,
30
- n as resolveHttpStatusCode,
31
- o as resolveStreamingAuthError
37
+ o as BASE64_SIZE_FACTOR,
38
+ d as DEFAULT_ERROR_MESSAGE,
39
+ _ as MAX_REQUEST_BODY_BYTES,
40
+ l as NETWORK_ERROR_MESSAGE,
41
+ E as NETWORK_ERROR_WITH_FILES_MESSAGE,
42
+ R as PAYLOAD_TOO_LARGE_MESSAGE,
43
+ g as RATE_LIMIT_MESSAGE,
44
+ m as RECOVERABLE_FALLBACK_MESSAGE,
45
+ S as RECOVERABLE_NOTIFICATION_DURATION_MS,
46
+ A as estimateRequestBodyBytes,
47
+ u as isNetworkError,
48
+ i as isRecoverableError,
49
+ s as resolveHttpStatusCode,
50
+ c as resolveStreamingAuthError
32
51
  };
@@ -1,2 +1,2 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Ze=require("@ai-sdk/react"),Xe=require("./file-upload-input.cjs"),Ye=require("ai"),t=require("react"),et=require("../../providers/config-provider.cjs"),tt=require("../../providers/chat-auth-provider.cjs"),st=require("../../hooks/use-media-query.cjs"),rt=require("../../hooks/use-conversation-loader.cjs"),nt=require("../../hooks/use-initial-conversation.cjs"),k=require("../../utils/generate-uid.cjs"),at=require("../../providers/base-events-provider.cjs"),ot=require("../../providers/chat-form-provider.cjs"),it=require("../../providers/widget-provider.cjs"),ct=require("@radix-ui/react-use-controllable-state"),ut=require("../../hooks/use-streaming-events.cjs"),lt=require("../../hooks/use-input-notification.cjs"),f=require("./chat-error-helpers.cjs"),dt=()=>{const{baseSettings:se,aiChatSettings:m}=et.useInkeepConfig(),[c="",v]=ct.useControllableState({prop:m.conversationIdOverride,defaultProp:m.conversationIdOverride??""}),{logEvent:h}=at.useBaseEvents(),{setConversationId:ke,emitToParent:F}=ut.useStreamingEvents(),re=t.useRef(c);t.useEffect(()=>{const e=re.current;re.current=c,e!==c&&h({eventName:"chat_conversation_changed",properties:{conversationId:c,previousConversationId:e}})},[c,h]);const[S,I]=t.useState(""),Fe=e=>I(e.target.value),{shouldBypassCaptcha:_e,filters:ne,userProperties:N,analyticsProperties:O}=se,{authToken:ae,isAuthenticated:y,isAuthConfigured:oe,refreshAuthToken:ie,sessionToken:ce,refreshSession:ue,getCaptchaHeader:_,invalidateCaptcha:d,effectiveAuthToken:le,applicableRefreshSession:Pe}=tt.useChatAuth(),{onInputMessageChange:xe,filters:de,baseUrl:fe,agentUrl:qe,context:pe,headers:ge,appId:P,apiKey:U,files:A}=m,he=t.useRef(_);he.current=_;const me=qe||`${fe}/run/api/chat`,{loadConversation:ve}=rt.useConversationLoader({baseUrl:fe,appId:P,authToken:le,getCaptchaHeader:_,invalidateCaptcha:d,refreshSession:Pe}),[Le,ye]=t.useState(!1),D=t.useRef(null);D.current=ce;const $=t.useRef(null);$.current=ae;const B=t.useRef(void 0);B.current=N&&Object.keys(N).length>0?N:void 0;const G=t.useRef(void 0);G.current=O&&Object.keys(O).length>0?O:void 0;const R=t.useRef(0),H=t.useRef(null),K=t.useRef(null),C=t.useRef(void 0),Ne=A?.map(e=>`${e.filename??""}:${e.mediaType}:${e.url.length}:${e.url.slice(0,64)}:${e.url.slice(-32)}`).join(`
2
- `)??"";t.useEffect(()=>{C.current=A?.length?A:void 0},[Ne]);const Re=t.useRef(ge);Re.current=ge;const z=t.useRef(void 0);z.current=ne||de?JSON.stringify({...ne,...de}):void 0;const Oe=e=>{switch(f.resolveHttpStatusCode(e)){case 400:try{const s=JSON.parse(e.message??"");return s.detail??s.error?.message??f.RECOVERABLE_FALLBACK_MESSAGE}catch{return e.message?.trim()||f.RECOVERABLE_FALLBACK_MESSAGE}case 401:return oe?"Authentication failed. Please try again.":f.DEFAULT_ERROR_MESSAGE;case 403:return`There seems to be a configuration error. Please contact ${se.organizationDisplayName??"Administrator"}`;case 429:return f.RATE_LIMIT_MESSAGE;default:return f.DEFAULT_ERROR_MESSAGE}},[b,j]=t.useState([]),Ue=t.useMemo(()=>new Ye.DefaultChatTransport({api:me,headers:()=>{const e=U??$.current??D.current;return{"x-inkeep-client-timezone":Intl.DateTimeFormat().resolvedOptions().timeZone,"x-inkeep-client-timestamp":new Date().toISOString(),"x-inkeep-invocation-type":"chat_widget",...P?{"x-inkeep-app-id":P}:{},...e?{Authorization:`Bearer ${e}`}:{},...z.current?{"inkeep-filters":z.current}:{},...Re.current}},prepareSendMessagesRequest:async e=>{const a=await he.current(),s=e.messages[e.messages.length-1];return s||console.warn("[useInkeepChat] prepareSendMessagesRequest called with empty messages array"),{body:{...e.body,id:e.id,messages:s?[s]:[],trigger:e.trigger,messageId:e.messageId,...B.current?{userProperties:B.current}:{},...G.current?{properties:G.current}:{}},headers:{...e.headers,...a}}},body:{requestContext:pe}}),[me,pe,P,U]),{messages:w,sendMessage:V,addToolApprovalResponse:J,status:Ce,setMessages:p,stop:x,error:q}=Ze.useChat({transport:Ue,onData(e){F(e.type,e.data)},async onFinish({message:e}){F("completion",{conversationId:c}),await h({eventName:"assistant_message_received",properties:{conversationId:c,messageId:e.id}}),h({eventName:"assistant_answer_displayed",properties:{conversationId:c,messageId:e.id}})},onError(e){console.error("onError",{code:e.code,message:e.message});const a=_e||U?null:f.resolveStreamingAuthError(e);if(a!==null&&R.current<1){R.current++;const n=K.current,r=H.current;(async()=>{if(a==="session"&&oe){const l=await ie();if(!l)throw new Error("Auth token refresh failed");$.current=l}else if(a==="session"){const l=await ue();l&&(D.current=l)}else d();if(n){J(n);return}r&&(p(l=>{let o=[...l];return o.at(-1)?.role==="assistant"&&(o=o.slice(0,-1)),o.at(-1)?.role==="user"&&(o=o.slice(0,-1)),o}),V({id:r.messageId,parts:[...r.content.trim()?[{type:"text",text:r.content}]:[],...r.files??[]]},{body:r.body}))})().catch(()=>{R.current=0,d(),p(l=>{const o=[...l],g=o[o.length-1];if(!g)return o;const L=f.DEFAULT_ERROR_MESSAGE;return g.role==="user"?o.push({id:k.generateUid(16),role:"assistant",parts:[{type:"text",text:L}]}):g.parts=[{type:"text",text:L}],o})});return}R.current=0,a!==null&&d();const s=f.isRecoverableError(e),u=Oe(e);if(h({eventName:"chat_error",properties:{conversationId:c,messageId:w.at(-1)?.id,error:e.message}}),s){Y({title:"Request failed",message:u},f.RECOVERABLE_NOTIFICATION_DURATION_MS),p(r=>{let i=[...r];return i.at(-1)?.role==="assistant"&&(i=i.slice(0,-1)),i.at(-1)?.role==="user"&&(i=i.slice(0,-1)),i});const n=H.current?.content;n&&I(n),X.current=e;return}p(n=>{const r=[...n],i=r[r.length-1];return i&&(i.role==="user"?r.push({id:k.generateUid(16),role:"assistant",parts:[{type:"text",text:u}]}):i.parts=[{type:"text",text:u}]),r})}}),Ee=t.useRef(y);t.useEffect(()=>{const e=Ee.current;Ee.current=y,e!==y&&(x(),M(null),p([]),v(""),I(""),j([]),d())},[y,x,p,v,d]);const Se=Ce==="submitted",Q=Ce==="streaming",De=t.useMemo(()=>{const e=n=>{if(!n||typeof n!="object")return!1;const r=n;return typeof r.type=="string"&&r.type.startsWith("tool-")},s=[...w??[]].reverse().find(n=>n.role==="assistant");if(!s)return!1;const u=s.parts?.at(-1);return!(!e(u)||u.state!=="output-available"||!u.approval?.id||Q)},[w,Q]),[$e,W]=t.useState(!1),Ie=Q||De&&!$e,Ae=Se||Ie,Be=w.length===0,Z=!S.trim()&&b.length===0||Ae,Ge=st.useMediaQuery("(max-width: 768px)"),[He,M]=t.useState(null),X=t.useRef(null);t.useEffect(()=>{if(q){if(X.current===q){X.current=null;return}M(q)}},[q]);const Ke=()=>M(null),{inputNotification:ze,showInputNotification:Y,clearInputNotification:je}=lt.useInputNotification(),be=t.useRef(null);t.useEffect(()=>{xe?.(S)},[S]);const Ve=e=>{e.key==="Enter"&&!e.shiftKey&&!Z&&!e.nativeEvent.isComposing&&(e.preventDefault(),ee())},ee=async(e=S)=>{if(Z&&(!e||e.trim().length===0)&&b.length===0||!e.trim()&&!b.length&&!C.current?.length)return;const a=b;j([]),I(""),R.current=0,K.current=null,W(!1);let s=c;s||(s=`conv_${k.generateUid(16)}`,v(s));const u=k.generateUid(21);ke(s),await h({eventName:"user_message_submitted",properties:{conversationId:s,messageId:u}});const n=C.current;C.current=void 0;let r=[];if(a.length>0)try{r=await Promise.all(a.map(o=>{const g=Xe.normalizeFileType(o);return new Promise((L,Te)=>{const T=new FileReader;T.onload=()=>{if(typeof T.result!="string"){Te(new Error(`Failed to read file "${g.name}"`));return}L({type:"file",url:T.result,mediaType:g.type,filename:g.name})},T.onerror=()=>Te(new Error(`Failed to read file "${g.name}"`)),T.readAsDataURL(g)})}))}catch{Y({title:"Failed to attach files",message:"Could not read one or more files. Please try again."});return}const i=r.length||n?.length?[...r,...n??[]]:void 0,l=[...e.trim()?[{type:"text",text:e}]:[],...i??[]];H.current={content:e,messageId:u,body:{conversationId:s},files:i},V({id:u,parts:l},{body:{conversationId:s}})},Je=t.useCallback(e=>{R.current=0,K.current=e,W(!1),J(e)},[J]),te=t.useCallback(()=>{W(!0),x().then(()=>{F("aborted",{conversationId:c})})},[x,c,F]),we=()=>{Ke(),p([]),v(""),d(),C.current=A?.length?A:void 0,h({eventName:"chat_clear_button_clicked",properties:{conversationId:c}})},E=t.useCallback((e,a)=>{M(null),p(a),v(e),d(),C.current=void 0},[p,v,d]),Me=t.useCallback(async(e,a)=>{te(),E(e,[]),ye(!0);try{const s=await ve(e,a);if(s===null)return!1;const n=s[s.length-1]?.role==="user"?[...s,{id:k.generateUid(16),role:"assistant",parts:[{type:"text",text:"This session was interrupted. Please check back in a few minutes or start a new conversation."}]}]:s;return E(e,n),!0}finally{a?.aborted||ye(!1)}},[E,ve,te]);nt.useInitialConversation({conversationId:m.conversationId,fetchedConversation:m.fetchedConversation,effectiveAuthToken:le,restoreSession:E,loadAndRestoreSession:Me,onLoadFailed:()=>E("",[])});const{openForm:Qe}=ot.useChatForm(),We=it.useWidget();return t.useImperativeHandle(m.chatFunctionsRef,()=>({submitMessage:ee,updateInputMessage(e){I(e)},clearChat:we,openForm:e=>{We?.setView("chat"),Qe(e,void 0)},focusInput:()=>{be.current?.focus()}})),{messages:w,sendMessage:V,addToolApprovalResponse:Je,isLoading:Se,isStreaming:Ie,isBusy:Ae,error:He,setError:M,isSubmitDisabled:Z,input:S,handleInputChange:Fe,handleInputKeyDown:Ve,handleSubmit:ee,stop:te,clear:we,inputRef:be,isMobile:Ge,files:b,setFiles:j,isNewChat:Be,conversationId:c,restoreSession:E,loadAndRestoreSession:Me,isSessionLoading:Le,authToken:y?ae:ce,refreshSession:y?ie:ue,getCaptchaHeader:_,invalidateCaptcha:d,inputNotification:ze,showInputNotification:Y,clearInputNotification:je}};exports.useInkeepChat=dt;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Xe=require("@ai-sdk/react"),Ze=require("./file-upload-input.cjs"),et=require("ai"),t=require("react"),tt=require("../../providers/config-provider.cjs"),st=require("../../providers/chat-auth-provider.cjs"),rt=require("../../hooks/use-media-query.cjs"),nt=require("../../hooks/use-conversation-loader.cjs"),at=require("../../hooks/use-initial-conversation.cjs"),O=require("../../utils/generate-uid.cjs"),ot=require("../../providers/base-events-provider.cjs"),it=require("../../providers/chat-form-provider.cjs"),ct=require("../../providers/widget-provider.cjs"),ut=require("@radix-ui/react-use-controllable-state"),lt=require("../../hooks/use-streaming-events.cjs"),dt=require("../../hooks/use-input-notification.cjs"),s=require("./chat-error-helpers.cjs"),ft=()=>{const{baseSettings:se,aiChatSettings:R}=tt.useInkeepConfig(),[u="",v]=ut.useControllableState({prop:R.conversationIdOverride,defaultProp:R.conversationIdOverride??""}),{logEvent:m}=ot.useBaseEvents(),{setConversationId:we,emitToParent:k}=lt.useStreamingEvents(),re=t.useRef(u);t.useEffect(()=>{const e=re.current;re.current=u,e!==u&&m({eventName:"chat_conversation_changed",properties:{conversationId:u,previousConversationId:e}})},[u,m]);const[_,C]=t.useState(""),Oe=e=>C(e.target.value),{shouldBypassCaptcha:ke,filters:ne,userProperties:B,analyticsProperties:D}=se,{authToken:ae,isAuthenticated:S,isAuthConfigured:oe,refreshAuthToken:ie,sessionToken:ce,refreshSession:ue,getCaptchaHeader:F,invalidateCaptcha:f,effectiveAuthToken:le,applicableRefreshSession:Fe}=st.useChatAuth(),{onInputMessageChange:Le,filters:de,baseUrl:fe,agentUrl:Ne,context:pe,headers:ge,appId:L,apiKey:U,files:T}=R,he=t.useRef(F);he.current=F;const me=Ne||`${fe}/run/api/chat`,{loadConversation:Ee}=nt.useConversationLoader({baseUrl:fe,appId:L,authToken:le,getCaptchaHeader:F,invalidateCaptcha:f,refreshSession:Fe}),[Pe,Re]=t.useState(!1),G=t.useRef(null);G.current=ce;const $=t.useRef(null);$.current=ae;const K=t.useRef(void 0);K.current=B&&Object.keys(B).length>0?B:void 0;const H=t.useRef(void 0);H.current=D&&Object.keys(D).length>0?D:void 0;const y=t.useRef(0),N=t.useRef(null),W=t.useRef(null),E=t.useRef(void 0),xe=T?.map(e=>`${e.filename??""}:${e.mediaType}:${e.url.length}:${e.url.slice(0,64)}:${e.url.slice(-32)}`).join(`
2
+ `)??"";t.useEffect(()=>{E.current=T?.length?T:void 0},[xe]);const ve=t.useRef(ge);ve.current=ge;const z=t.useRef(void 0);z.current=ne||de?JSON.stringify({...ne,...de}):void 0;const qe=e=>{if(s.isNetworkError(e))return N.current?.files?.length?s.NETWORK_ERROR_WITH_FILES_MESSAGE:s.NETWORK_ERROR_MESSAGE;switch(s.resolveHttpStatusCode(e)){case 400:try{const r=JSON.parse(e.message??"");return r.detail??r.error?.message??s.RECOVERABLE_FALLBACK_MESSAGE}catch{return e.message?.trim()||s.RECOVERABLE_FALLBACK_MESSAGE}case 401:return oe?"Authentication failed. Please try again.":s.DEFAULT_ERROR_MESSAGE;case 403:return`There seems to be a configuration error. Please contact ${se.organizationDisplayName??"Administrator"}`;case 413:return s.PAYLOAD_TOO_LARGE_MESSAGE;case 429:return s.RATE_LIMIT_MESSAGE;default:return s.DEFAULT_ERROR_MESSAGE}},[A,V]=t.useState([]),Be=t.useMemo(()=>new et.DefaultChatTransport({api:me,headers:()=>{const e=U??$.current??G.current;return{"x-inkeep-client-timezone":Intl.DateTimeFormat().resolvedOptions().timeZone,"x-inkeep-client-timestamp":new Date().toISOString(),"x-inkeep-invocation-type":"chat_widget",...L?{"x-inkeep-app-id":L}:{},...e?{Authorization:`Bearer ${e}`}:{},...z.current?{"inkeep-filters":z.current}:{},...ve.current}},prepareSendMessagesRequest:async e=>{const l=await he.current(),r=e.messages[e.messages.length-1];return r||console.warn("[useInkeepChat] prepareSendMessagesRequest called with empty messages array"),{body:{...e.body,id:e.id,messages:r?[r]:[],trigger:e.trigger,messageId:e.messageId,...K.current?{userProperties:K.current}:{},...H.current?{properties:H.current}:{}},headers:{...e.headers,...l}}},body:{requestContext:pe}}),[me,pe,L,U]),{messages:M,sendMessage:Y,addToolApprovalResponse:j,status:Se,setMessages:h,stop:P,error:x}=Xe.useChat({transport:Be,onData(e){k(e.type,e.data)},async onFinish({message:e}){k("completion",{conversationId:u}),await m({eventName:"assistant_message_received",properties:{conversationId:u,messageId:e.id}}),m({eventName:"assistant_answer_displayed",properties:{conversationId:u,messageId:e.id}})},onError(e){console.error("onError",{code:e.code,message:e.message});const l=ke||U?null:s.resolveStreamingAuthError(e);if(l!==null&&y.current<1){y.current++;const i=W.current,a=N.current;(async()=>{if(l==="session"&&oe){const o=await ie();if(!o)throw new Error("Auth token refresh failed");$.current=o}else if(l==="session"){const o=await ue();o&&(G.current=o)}else f();if(i){j(i);return}a&&(h(o=>{let c=[...o];return c.at(-1)?.role==="assistant"&&(c=c.slice(0,-1)),c.at(-1)?.role==="user"&&(c=c.slice(0,-1)),c}),Y({id:a.messageId,parts:[...a.content.trim()?[{type:"text",text:a.content}]:[],...a.files??[]]},{body:a.body}))})().catch(()=>{y.current=0,f(),h(o=>{const c=[...o],g=c[c.length-1];if(!g)return c;const d=s.DEFAULT_ERROR_MESSAGE;return g.role==="user"?c.push({id:O.generateUid(16),role:"assistant",parts:[{type:"text",text:d}]}):g.parts=[{type:"text",text:d}],c})});return}y.current=0,l!==null&&f();const r=s.isRecoverableError(e)||s.isNetworkError(e),n=qe(e);if(m({eventName:"chat_error",properties:{conversationId:u,messageId:M.at(-1)?.id,error:e.message}}),r){const i=n===s.PAYLOAD_TOO_LARGE_MESSAGE?"Message too large":n===s.RATE_LIMIT_MESSAGE?"Rate limit reached":n===s.NETWORK_ERROR_MESSAGE||n===s.NETWORK_ERROR_WITH_FILES_MESSAGE?"Connection error":"Request failed";q({title:i,message:n},s.RECOVERABLE_NOTIFICATION_DURATION_MS),h(p=>{let o=[...p];return o.at(-1)?.role==="assistant"&&(o=o.slice(0,-1)),o.at(-1)?.role==="user"&&(o=o.slice(0,-1)),o});const a=N.current?.content;a&&C(a),Z.current=e;return}h(i=>{const a=[...i],p=a[a.length-1];return p&&(p.role==="user"?a.push({id:O.generateUid(16),role:"assistant",parts:[{type:"text",text:n}]}):p.parts=[{type:"text",text:n}]),a})}}),ye=t.useRef(S);t.useEffect(()=>{const e=ye.current;ye.current=S,e!==S&&(P(),b(null),h([]),v(""),C(""),V([]),f())},[S,P,h,v,f]);const Ae=Se==="submitted",Q=Se==="streaming",De=t.useMemo(()=>{const e=i=>{if(!i||typeof i!="object")return!1;const a=i;return typeof a.type=="string"&&a.type.startsWith("tool-")},r=[...M??[]].reverse().find(i=>i.role==="assistant");if(!r)return!1;const n=r.parts?.at(-1);return!(!e(n)||n.state!=="output-available"||!n.approval?.id||Q)},[M,Q]),[Ue,J]=t.useState(!1),Ie=Q||De&&!Ue,_e=Ae||Ie,Ge=M.length===0,X=!_.trim()&&A.length===0||_e,$e=rt.useMediaQuery("(max-width: 768px)"),[Ke,b]=t.useState(null),Z=t.useRef(null);t.useEffect(()=>{if(x){if(Z.current===x){Z.current=null;return}b(x)}},[x]);const He=()=>b(null),{inputNotification:We,showInputNotification:q,clearInputNotification:ze}=dt.useInputNotification(),Ce=t.useRef(null);t.useEffect(()=>{Le?.(_)},[_]);const Ve=e=>{e.key==="Enter"&&!e.shiftKey&&!X&&!e.nativeEvent.isComposing&&(e.preventDefault(),ee())},ee=async(e=_)=>{if(X&&(!e||e.trim().length===0)&&A.length===0||!e.trim()&&!A.length&&!E.current?.length)return;if(s.estimateRequestBodyBytes({text:e,rawFileBytes:A.reduce((g,d)=>g+d.size,0),encodedPartsBytes:(E.current??[]).reduce((g,d)=>g+d.url.length,0)})>s.MAX_REQUEST_BODY_BYTES){q({title:"Message too large",message:s.PAYLOAD_TOO_LARGE_MESSAGE},s.RECOVERABLE_NOTIFICATION_DURATION_MS);return}const r=A;V([]),C(""),y.current=0,W.current=null,J(!1);let n=u;n||(n=`conv_${O.generateUid(16)}`,v(n));const i=O.generateUid(21);we(n),await m({eventName:"user_message_submitted",properties:{conversationId:n,messageId:i}});const a=E.current;E.current=void 0;let p=[];if(r.length>0)try{p=await Promise.all(r.map(g=>{const d=Ze.normalizeFileType(g);return new Promise((Je,be)=>{const w=new FileReader;w.onload=()=>{if(typeof w.result!="string"){be(new Error(`Failed to read file "${d.name}"`));return}Je({type:"file",url:w.result,mediaType:d.type,filename:d.name})},w.onerror=()=>be(new Error(`Failed to read file "${d.name}"`)),w.readAsDataURL(d)})}))}catch{q({title:"Failed to attach files",message:"Could not read one or more files. Please try again."});return}const o=p.length||a?.length?[...p,...a??[]]:void 0,c=[...e.trim()?[{type:"text",text:e}]:[],...o??[]];N.current={content:e,messageId:i,body:{conversationId:n},files:o},Y({id:i,parts:c},{body:{conversationId:n}})},Ye=t.useCallback(e=>{y.current=0,W.current=e,J(!1),j(e)},[j]),te=t.useCallback(()=>{J(!0),P().then(()=>{k("aborted",{conversationId:u})})},[P,u,k]),Te=()=>{He(),h([]),v(""),f(),E.current=T?.length?T:void 0,m({eventName:"chat_clear_button_clicked",properties:{conversationId:u}})},I=t.useCallback((e,l)=>{b(null),h(l),v(e),f(),E.current=void 0},[h,v,f]),Me=t.useCallback(async(e,l)=>{te(),I(e,[]),Re(!0);try{const r=await Ee(e,l);if(r===null)return!1;const i=r[r.length-1]?.role==="user"?[...r,{id:O.generateUid(16),role:"assistant",parts:[{type:"text",text:"This session was interrupted. Please check back in a few minutes or start a new conversation."}]}]:r;return I(e,i),!0}finally{l?.aborted||Re(!1)}},[I,Ee,te]);at.useInitialConversation({conversationId:R.conversationId,fetchedConversation:R.fetchedConversation,effectiveAuthToken:le,restoreSession:I,loadAndRestoreSession:Me,onLoadFailed:()=>I("",[])});const{openForm:je}=it.useChatForm(),Qe=ct.useWidget();return t.useImperativeHandle(R.chatFunctionsRef,()=>({submitMessage:ee,updateInputMessage(e){C(e)},clearChat:Te,openForm:e=>{Qe?.setView("chat"),je(e,void 0)},focusInput:()=>{Ce.current?.focus()}})),{messages:M,sendMessage:Y,addToolApprovalResponse:Ye,isLoading:Ae,isStreaming:Ie,isBusy:_e,error:Ke,setError:b,isSubmitDisabled:X,input:_,handleInputChange:Oe,handleInputKeyDown:Ve,handleSubmit:ee,stop:te,clear:Te,inputRef:Ce,isMobile:$e,files:A,setFiles:V,isNewChat:Ge,conversationId:u,restoreSession:I,loadAndRestoreSession:Me,isSessionLoading:Pe,authToken:S?ae:ce,refreshSession:S?ie:ue,getCaptchaHeader:F,invalidateCaptcha:f,inputNotification:We,showInputNotification:q,clearInputNotification:ze}};exports.useInkeepChat=ft;
@@ -1,113 +1,117 @@
1
1
  "use client";
2
- import { useChat as st } from "@ai-sdk/react";
3
- import { normalizeFileType as rt } from "./file-upload-input.js";
4
- import { DefaultChatTransport as nt } from "ai";
5
- import { useRef as i, useEffect as M, useState as k, useMemo as _e, useCallback as L, useImperativeHandle as ot } from "react";
6
- import { useInkeepConfig as at } from "../../providers/config-provider.js";
7
- import { useChatAuth as it } from "../../providers/chat-auth-provider.js";
8
- import { useMediaQuery as ct } from "../../hooks/use-media-query.js";
9
- import { useConversationLoader as lt } from "../../hooks/use-conversation-loader.js";
10
- import { useInitialConversation as ut } from "../../hooks/use-initial-conversation.js";
2
+ import { useChat as lt } from "@ai-sdk/react";
3
+ import { normalizeFileType as ut } from "./file-upload-input.js";
4
+ import { DefaultChatTransport as dt } from "ai";
5
+ import { useRef as i, useEffect as _, useState as k, useMemo as Oe, useCallback as $, useImperativeHandle as pt } from "react";
6
+ import { useInkeepConfig as ft } from "../../providers/config-provider.js";
7
+ import { useChatAuth as mt } from "../../providers/chat-auth-provider.js";
8
+ import { useMediaQuery as gt } from "../../hooks/use-media-query.js";
9
+ import { useConversationLoader as ht } from "../../hooks/use-conversation-loader.js";
10
+ import { useInitialConversation as vt } from "../../hooks/use-initial-conversation.js";
11
11
  import { generateUid as F } from "../../utils/generate-uid.js";
12
- import { useBaseEvents as pt } from "../../providers/base-events-provider.js";
13
- import { useChatForm as dt } from "../../providers/chat-form-provider.js";
14
- import { useWidget as ft } from "../../providers/widget-provider.js";
15
- import { useControllableState as mt } from "@radix-ui/react-use-controllable-state";
16
- import { useStreamingEvents as gt } from "../../hooks/use-streaming-events.js";
17
- import { useInputNotification as ht } from "../../hooks/use-input-notification.js";
18
- import { resolveStreamingAuthError as vt, DEFAULT_ERROR_MESSAGE as ne, isRecoverableError as yt, RECOVERABLE_NOTIFICATION_DURATION_MS as It, resolveHttpStatusCode as Ct, RATE_LIMIT_MESSAGE as Rt, RECOVERABLE_FALLBACK_MESSAGE as Ne } from "./chat-error-helpers.js";
19
- const Bt = () => {
20
- const { baseSettings: oe, aiChatSettings: g } = at(), [c = "", h] = mt({
21
- prop: g.conversationIdOverride,
22
- defaultProp: g.conversationIdOverride ?? ""
23
- }), { logEvent: m } = pt(), { setConversationId: Pe, emitToParent: x } = gt(), ae = i(c);
24
- M(() => {
25
- const e = ae.current;
26
- ae.current = c, e !== c && m({
12
+ import { useBaseEvents as yt } from "../../providers/base-events-provider.js";
13
+ import { useChatForm as Rt } from "../../providers/chat-form-provider.js";
14
+ import { useWidget as Et } from "../../providers/widget-provider.js";
15
+ import { useControllableState as It } from "@radix-ui/react-use-controllable-state";
16
+ import { useStreamingEvents as St } from "../../hooks/use-streaming-events.js";
17
+ import { useInputNotification as Ct } from "../../hooks/use-input-notification.js";
18
+ import { resolveStreamingAuthError as At, DEFAULT_ERROR_MESSAGE as ne, isRecoverableError as Tt, isNetworkError as Ne, RECOVERABLE_NOTIFICATION_DURATION_MS as Pe, PAYLOAD_TOO_LARGE_MESSAGE as oe, RATE_LIMIT_MESSAGE as Be, NETWORK_ERROR_MESSAGE as De, NETWORK_ERROR_WITH_FILES_MESSAGE as Le, resolveHttpStatusCode as wt, RECOVERABLE_FALLBACK_MESSAGE as $e, estimateRequestBodyBytes as bt, MAX_REQUEST_BODY_BYTES as Mt } from "./chat-error-helpers.js";
19
+ const Wt = () => {
20
+ const { baseSettings: ae, aiChatSettings: v } = ft(), [c = "", y] = It({
21
+ prop: v.conversationIdOverride,
22
+ defaultProp: v.conversationIdOverride ?? ""
23
+ }), { logEvent: g } = yt(), { setConversationId: Ue, emitToParent: x } = St(), ie = i(c);
24
+ _(() => {
25
+ const e = ie.current;
26
+ ie.current = c, e !== c && g({
27
27
  eventName: "chat_conversation_changed",
28
28
  properties: {
29
29
  conversationId: c,
30
30
  previousConversationId: e
31
31
  }
32
32
  });
33
- }, [c, m]);
34
- const [R, S] = k(""), Oe = (e) => S(e.target.value), {
35
- shouldBypassCaptcha: De,
36
- filters: ie,
37
- userProperties: $,
38
- analyticsProperties: B
39
- } = oe, {
40
- authToken: ce,
41
- isAuthenticated: v,
42
- isAuthConfigured: le,
43
- refreshAuthToken: ue,
33
+ }, [c, g]);
34
+ const [C, A] = k(""), Ge = (e) => A(e.target.value), {
35
+ shouldBypassCaptcha: Ke,
36
+ filters: ce,
37
+ userProperties: U,
38
+ analyticsProperties: G
39
+ } = ae, {
40
+ authToken: le,
41
+ isAuthenticated: R,
42
+ isAuthConfigured: ue,
43
+ refreshAuthToken: de,
44
44
  sessionToken: pe,
45
- refreshSession: de,
46
- getCaptchaHeader: _,
47
- invalidateCaptcha: p,
48
- effectiveAuthToken: fe,
49
- applicableRefreshSession: Le
50
- } = it(), {
51
- onInputMessageChange: $e,
52
- filters: me,
53
- baseUrl: ge,
54
- agentUrl: Be,
55
- context: he,
56
- headers: ve,
45
+ refreshSession: fe,
46
+ getCaptchaHeader: O,
47
+ invalidateCaptcha: d,
48
+ effectiveAuthToken: me,
49
+ applicableRefreshSession: ze
50
+ } = mt(), {
51
+ onInputMessageChange: He,
52
+ filters: ge,
53
+ baseUrl: he,
54
+ agentUrl: qe,
55
+ context: ve,
56
+ headers: ye,
57
57
  appId: N,
58
- apiKey: U,
59
- files: w
60
- } = g, ye = i(_);
61
- ye.current = _;
62
- const Ie = Be || `${ge}/run/api/chat`, { loadConversation: Ce } = lt({
63
- baseUrl: ge,
58
+ apiKey: K,
59
+ files: T
60
+ } = v, Re = i(O);
61
+ Re.current = O;
62
+ const Ee = qe || `${he}/run/api/chat`, { loadConversation: Ie } = ht({
63
+ baseUrl: he,
64
64
  appId: N,
65
- authToken: fe,
66
- getCaptchaHeader: _,
67
- invalidateCaptcha: p,
68
- refreshSession: Le
69
- }), [Ue, Re] = k(!1), z = i(null);
65
+ authToken: me,
66
+ getCaptchaHeader: O,
67
+ invalidateCaptcha: d,
68
+ refreshSession: ze
69
+ }), [We, Se] = k(!1), z = i(null);
70
70
  z.current = pe;
71
71
  const H = i(null);
72
- H.current = ce;
73
- const K = i(void 0);
74
- K.current = $ && Object.keys($).length > 0 ? $ : void 0;
72
+ H.current = le;
75
73
  const q = i(void 0);
76
- q.current = B && Object.keys(B).length > 0 ? B : void 0;
77
- const y = i(0), j = i(null), G = i(null), I = i(void 0), ze = w?.map(
74
+ q.current = U && Object.keys(U).length > 0 ? U : void 0;
75
+ const W = i(void 0);
76
+ W.current = G && Object.keys(G).length > 0 ? G : void 0;
77
+ const E = i(0), P = i(null), j = i(null), h = i(void 0), je = T?.map(
78
78
  (e) => `${e.filename ?? ""}:${e.mediaType}:${e.url.length}:${e.url.slice(0, 64)}:${e.url.slice(-32)}`
79
79
  ).join(`
80
80
  `) ?? "";
81
- M(() => {
82
- I.current = w?.length ? w : void 0;
83
- }, [ze]);
84
- const Se = i(ve);
85
- Se.current = ve;
81
+ _(() => {
82
+ h.current = T?.length ? T : void 0;
83
+ }, [je]);
84
+ const Ce = i(ye);
85
+ Ce.current = ye;
86
86
  const V = i(void 0);
87
- V.current = ie || me ? JSON.stringify({ ...ie, ...me }) : void 0;
88
- const He = (e) => {
89
- switch (Ct(e)) {
87
+ V.current = ce || ge ? JSON.stringify({ ...ce, ...ge }) : void 0;
88
+ const Ve = (e) => {
89
+ if (Ne(e))
90
+ return P.current?.files?.length ? Le : De;
91
+ switch (wt(e)) {
90
92
  case 400:
91
93
  try {
92
94
  const t = JSON.parse(e.message ?? "");
93
- return t.detail ?? t.error?.message ?? Ne;
95
+ return t.detail ?? t.error?.message ?? $e;
94
96
  } catch {
95
- return e.message?.trim() || Ne;
97
+ return e.message?.trim() || $e;
96
98
  }
97
99
  case 401:
98
- return le ? "Authentication failed. Please try again." : ne;
100
+ return ue ? "Authentication failed. Please try again." : ne;
99
101
  case 403:
100
- return `There seems to be a configuration error. Please contact ${oe.organizationDisplayName ?? "Administrator"}`;
102
+ return `There seems to be a configuration error. Please contact ${ae.organizationDisplayName ?? "Administrator"}`;
103
+ case 413:
104
+ return oe;
101
105
  case 429:
102
- return Rt;
106
+ return Be;
103
107
  default:
104
108
  return ne;
105
109
  }
106
- }, [A, J] = k([]), Ke = _e(
107
- () => new nt({
108
- api: Ie,
110
+ }, [I, Y] = k([]), Ye = Oe(
111
+ () => new dt({
112
+ api: Ee,
109
113
  headers: () => {
110
- const e = U ?? H.current ?? z.current;
114
+ const e = K ?? H.current ?? z.current;
111
115
  return {
112
116
  "x-inkeep-client-timezone": Intl.DateTimeFormat().resolvedOptions().timeZone,
113
117
  "x-inkeep-client-timestamp": (/* @__PURE__ */ new Date()).toISOString(),
@@ -115,11 +119,11 @@ const Bt = () => {
115
119
  ...N ? { "x-inkeep-app-id": N } : {},
116
120
  ...e ? { Authorization: `Bearer ${e}` } : {},
117
121
  ...V.current ? { "inkeep-filters": V.current } : {},
118
- ...Se.current
122
+ ...Ce.current
119
123
  };
120
124
  },
121
125
  prepareSendMessagesRequest: async (e) => {
122
- const n = await ye.current(), t = e.messages[e.messages.length - 1];
126
+ const l = await Re.current(), t = e.messages[e.messages.length - 1];
123
127
  return t || console.warn(
124
128
  "[useInkeepChat] prepareSendMessagesRequest called with empty messages array"
125
129
  ), {
@@ -129,41 +133,41 @@ const Bt = () => {
129
133
  messages: t ? [t] : [],
130
134
  trigger: e.trigger,
131
135
  messageId: e.messageId,
132
- ...K.current ? { userProperties: K.current } : {},
133
- ...q.current ? { properties: q.current } : {}
136
+ ...q.current ? { userProperties: q.current } : {},
137
+ ...W.current ? { properties: W.current } : {}
134
138
  },
135
139
  headers: {
136
140
  ...e.headers,
137
- ...n
141
+ ...l
138
142
  }
139
143
  };
140
144
  },
141
145
  body: {
142
- requestContext: he
146
+ requestContext: ve
143
147
  }
144
148
  }),
145
- [Ie, he, N, U]
149
+ [Ee, ve, N, K]
146
150
  ), {
147
- messages: b,
148
- sendMessage: W,
151
+ messages: w,
152
+ sendMessage: J,
149
153
  addToolApprovalResponse: Q,
150
- status: we,
151
- setMessages: d,
152
- stop: P,
153
- error: O
154
- } = st({
155
- transport: Ke,
154
+ status: Ae,
155
+ setMessages: m,
156
+ stop: B,
157
+ error: D
158
+ } = lt({
159
+ transport: Ye,
156
160
  onData(e) {
157
161
  x(e.type, e.data);
158
162
  },
159
163
  async onFinish({ message: e }) {
160
- x("completion", { conversationId: c }), await m({
164
+ x("completion", { conversationId: c }), await g({
161
165
  eventName: "assistant_message_received",
162
166
  properties: {
163
167
  conversationId: c,
164
168
  messageId: e.id
165
169
  }
166
- }), m({
170
+ }), g({
167
171
  eventName: "assistant_answer_displayed",
168
172
  properties: {
169
173
  conversationId: c,
@@ -173,196 +177,210 @@ const Bt = () => {
173
177
  },
174
178
  onError(e) {
175
179
  console.error("onError", { code: e.code, message: e.message });
176
- const n = De || U ? null : vt(e);
177
- if (n !== null && y.current < 1) {
178
- y.current++;
179
- const r = G.current, s = j.current;
180
+ const l = Ke || K ? null : At(e);
181
+ if (l !== null && E.current < 1) {
182
+ E.current++;
183
+ const o = j.current, r = P.current;
180
184
  (async () => {
181
- if (n === "session" && le) {
182
- const u = await ue();
183
- if (!u) throw new Error("Auth token refresh failed");
184
- H.current = u;
185
- } else if (n === "session") {
186
- const u = await de();
187
- u && (z.current = u);
185
+ if (l === "session" && ue) {
186
+ const n = await de();
187
+ if (!n) throw new Error("Auth token refresh failed");
188
+ H.current = n;
189
+ } else if (l === "session") {
190
+ const n = await fe();
191
+ n && (z.current = n);
188
192
  } else
189
- p();
190
- if (r) {
191
- Q(r);
193
+ d();
194
+ if (o) {
195
+ Q(o);
192
196
  return;
193
197
  }
194
- s && (d((u) => {
195
- let o = [...u];
196
- return o.at(-1)?.role === "assistant" && (o = o.slice(0, -1)), o.at(-1)?.role === "user" && (o = o.slice(0, -1)), o;
197
- }), W(
198
+ r && (m((n) => {
199
+ let a = [...n];
200
+ return a.at(-1)?.role === "assistant" && (a = a.slice(0, -1)), a.at(-1)?.role === "user" && (a = a.slice(0, -1)), a;
201
+ }), J(
198
202
  {
199
- id: s.messageId,
203
+ id: r.messageId,
200
204
  parts: [
201
- ...s.content.trim() ? [{ type: "text", text: s.content }] : [],
202
- ...s.files ?? []
205
+ ...r.content.trim() ? [{ type: "text", text: r.content }] : [],
206
+ ...r.files ?? []
203
207
  ]
204
208
  },
205
- { body: s.body }
209
+ { body: r.body }
206
210
  ));
207
211
  })().catch(() => {
208
- y.current = 0, p(), d((u) => {
209
- const o = [...u], f = o[o.length - 1];
210
- if (!f) return o;
211
- const D = ne;
212
- return f.role === "user" ? o.push({
212
+ E.current = 0, d(), m((n) => {
213
+ const a = [...n], f = a[a.length - 1];
214
+ if (!f) return a;
215
+ const u = ne;
216
+ return f.role === "user" ? a.push({
213
217
  id: F(16),
214
218
  role: "assistant",
215
- parts: [{ type: "text", text: D }]
216
- }) : f.parts = [{ type: "text", text: D }], o;
219
+ parts: [{ type: "text", text: u }]
220
+ }) : f.parts = [{ type: "text", text: u }], a;
217
221
  });
218
222
  });
219
223
  return;
220
224
  }
221
- y.current = 0, n !== null && p();
222
- const t = yt(e), l = He(e);
223
- if (m({
225
+ E.current = 0, l !== null && d();
226
+ const t = Tt(e) || Ne(e), s = Ve(e);
227
+ if (g({
224
228
  eventName: "chat_error",
225
229
  properties: {
226
230
  conversationId: c,
227
- messageId: b.at(-1)?.id,
231
+ messageId: w.at(-1)?.id,
228
232
  error: e.message
229
233
  }
230
234
  }), t) {
231
- te(
232
- { title: "Request failed", message: l },
233
- It
234
- ), d((s) => {
235
- let a = [...s];
236
- return a.at(-1)?.role === "assistant" && (a = a.slice(0, -1)), a.at(-1)?.role === "user" && (a = a.slice(0, -1)), a;
235
+ L(
236
+ { title: s === oe ? "Message too large" : s === Be ? "Rate limit reached" : s === De || s === Le ? "Connection error" : "Request failed", message: s },
237
+ Pe
238
+ ), m((p) => {
239
+ let n = [...p];
240
+ return n.at(-1)?.role === "assistant" && (n = n.slice(0, -1)), n.at(-1)?.role === "user" && (n = n.slice(0, -1)), n;
237
241
  });
238
- const r = j.current?.content;
239
- r && S(r), ee.current = e;
242
+ const r = P.current?.content;
243
+ r && A(r), te.current = e;
240
244
  return;
241
245
  }
242
- d((r) => {
243
- const s = [...r], a = s[s.length - 1];
244
- return a && (a.role === "user" ? s.push({
246
+ m((o) => {
247
+ const r = [...o], p = r[r.length - 1];
248
+ return p && (p.role === "user" ? r.push({
245
249
  id: F(16),
246
250
  role: "assistant",
247
- parts: [{ type: "text", text: l }]
248
- }) : a.parts = [{ type: "text", text: l }]), s;
251
+ parts: [{ type: "text", text: s }]
252
+ }) : p.parts = [{ type: "text", text: s }]), r;
249
253
  });
250
254
  }
251
- }), Ae = i(v);
252
- M(() => {
253
- const e = Ae.current;
254
- Ae.current = v, e !== v && (P(), E(null), d([]), h(""), S(""), J([]), p());
255
- }, [v, P, d, h, p]);
256
- const be = we === "submitted", Z = we === "streaming", qe = _e(() => {
257
- const e = (r) => {
258
- if (!r || typeof r != "object") return !1;
259
- const s = r;
260
- return typeof s.type == "string" && s.type.startsWith("tool-");
261
- }, t = [...b ?? []].reverse().find((r) => r.role === "assistant");
255
+ }), Te = i(R);
256
+ _(() => {
257
+ const e = Te.current;
258
+ Te.current = R, e !== R && (B(), b(null), m([]), y(""), A(""), Y([]), d());
259
+ }, [R, B, m, y, d]);
260
+ const we = Ae === "submitted", X = Ae === "streaming", Je = Oe(() => {
261
+ const e = (o) => {
262
+ if (!o || typeof o != "object") return !1;
263
+ const r = o;
264
+ return typeof r.type == "string" && r.type.startsWith("tool-");
265
+ }, t = [...w ?? []].reverse().find((o) => o.role === "assistant");
262
266
  if (!t) return !1;
263
- const l = t.parts?.at(-1);
264
- return !(!e(l) || l.state !== "output-available" || !l.approval?.id || Z);
265
- }, [b, Z]), [je, X] = k(!1), Ee = Z || qe && !je, Te = be || Ee, Ge = b.length === 0, Y = !R.trim() && A.length === 0 || Te, Ve = ct("(max-width: 768px)"), [Je, E] = k(null), ee = i(null);
266
- M(() => {
267
- if (O) {
268
- if (ee.current === O) {
269
- ee.current = null;
267
+ const s = t.parts?.at(-1);
268
+ return !(!e(s) || s.state !== "output-available" || !s.approval?.id || X);
269
+ }, [w, X]), [Qe, Z] = k(!1), be = X || Je && !Qe, Me = we || be, Xe = w.length === 0, ee = !C.trim() && I.length === 0 || Me, Ze = gt("(max-width: 768px)"), [et, b] = k(null), te = i(null);
270
+ _(() => {
271
+ if (D) {
272
+ if (te.current === D) {
273
+ te.current = null;
270
274
  return;
271
275
  }
272
- E(O);
276
+ b(D);
273
277
  }
274
- }, [O]);
275
- const We = () => E(null), { inputNotification: Qe, showInputNotification: te, clearInputNotification: Ze } = ht(), Me = i(null);
276
- M(() => {
277
- $e?.(R);
278
- }, [R]);
279
- const Xe = (e) => {
280
- e.key === "Enter" && !e.shiftKey && !Y && !e.nativeEvent.isComposing && (e.preventDefault(), se());
281
- }, se = async (e = R) => {
282
- if (Y && (!e || e.trim().length === 0) && A.length === 0 || !e.trim() && !A.length && !I.current?.length)
278
+ }, [D]);
279
+ const tt = () => b(null), { inputNotification: st, showInputNotification: L, clearInputNotification: rt } = Ct(), _e = i(null);
280
+ _(() => {
281
+ He?.(C);
282
+ }, [C]);
283
+ const nt = (e) => {
284
+ e.key === "Enter" && !e.shiftKey && !ee && !e.nativeEvent.isComposing && (e.preventDefault(), se());
285
+ }, se = async (e = C) => {
286
+ if (ee && (!e || e.trim().length === 0) && I.length === 0 || !e.trim() && !I.length && !h.current?.length)
283
287
  return;
284
- const n = A;
285
- J([]), S(""), y.current = 0, G.current = null, X(!1);
286
- let t = c;
287
- t || (t = `conv_${F(16)}`, h(t));
288
- const l = F(21);
289
- Pe(t), await m({
288
+ if (bt({
289
+ text: e,
290
+ rawFileBytes: I.reduce((f, u) => f + u.size, 0),
291
+ encodedPartsBytes: (h.current ?? []).reduce(
292
+ (f, u) => f + u.url.length,
293
+ 0
294
+ )
295
+ }) > Mt) {
296
+ L(
297
+ { title: "Message too large", message: oe },
298
+ Pe
299
+ );
300
+ return;
301
+ }
302
+ const t = I;
303
+ Y([]), A(""), E.current = 0, j.current = null, Z(!1);
304
+ let s = c;
305
+ s || (s = `conv_${F(16)}`, y(s));
306
+ const o = F(21);
307
+ Ue(s), await g({
290
308
  eventName: "user_message_submitted",
291
309
  properties: {
292
- conversationId: t,
293
- messageId: l
310
+ conversationId: s,
311
+ messageId: o
294
312
  }
295
313
  });
296
- const r = I.current;
297
- I.current = void 0;
298
- let s = [];
299
- if (n.length > 0)
314
+ const r = h.current;
315
+ h.current = void 0;
316
+ let p = [];
317
+ if (t.length > 0)
300
318
  try {
301
- s = await Promise.all(
302
- n.map((o) => {
303
- const f = rt(o);
304
- return new Promise((D, xe) => {
305
- const T = new FileReader();
306
- T.onload = () => {
307
- if (typeof T.result != "string") {
308
- xe(new Error(`Failed to read file "${f.name}"`));
319
+ p = await Promise.all(
320
+ t.map((f) => {
321
+ const u = ut(f);
322
+ return new Promise((ct, xe) => {
323
+ const M = new FileReader();
324
+ M.onload = () => {
325
+ if (typeof M.result != "string") {
326
+ xe(new Error(`Failed to read file "${u.name}"`));
309
327
  return;
310
328
  }
311
- D({
329
+ ct({
312
330
  type: "file",
313
- url: T.result,
314
- mediaType: f.type,
315
- filename: f.name
331
+ url: M.result,
332
+ mediaType: u.type,
333
+ filename: u.name
316
334
  });
317
- }, T.onerror = () => xe(new Error(`Failed to read file "${f.name}"`)), T.readAsDataURL(f);
335
+ }, M.onerror = () => xe(new Error(`Failed to read file "${u.name}"`)), M.readAsDataURL(u);
318
336
  });
319
337
  })
320
338
  );
321
339
  } catch {
322
- te({
340
+ L({
323
341
  title: "Failed to attach files",
324
342
  message: "Could not read one or more files. Please try again."
325
343
  });
326
344
  return;
327
345
  }
328
- const a = s.length || r?.length ? [...s, ...r ?? []] : void 0, u = [
346
+ const n = p.length || r?.length ? [...p, ...r ?? []] : void 0, a = [
329
347
  ...e.trim() ? [{ type: "text", text: e }] : [],
330
- ...a ?? []
348
+ ...n ?? []
331
349
  ];
332
- j.current = {
350
+ P.current = {
333
351
  content: e,
334
- messageId: l,
335
- body: { conversationId: t },
336
- files: a
337
- }, W({ id: l, parts: u }, { body: { conversationId: t } });
338
- }, Ye = L(
352
+ messageId: o,
353
+ body: { conversationId: s },
354
+ files: n
355
+ }, J({ id: o, parts: a }, { body: { conversationId: s } });
356
+ }, ot = $(
339
357
  (e) => {
340
- y.current = 0, G.current = e, X(!1), Q(e);
358
+ E.current = 0, j.current = e, Z(!1), Q(e);
341
359
  },
342
360
  [Q]
343
- ), re = L(() => {
344
- X(!0), P().then(() => {
361
+ ), re = $(() => {
362
+ Z(!0), B().then(() => {
345
363
  x("aborted", { conversationId: c });
346
364
  });
347
- }, [P, c, x]), ke = () => {
348
- We(), d([]), h(""), p(), I.current = w?.length ? w : void 0, m({
365
+ }, [B, c, x]), ke = () => {
366
+ tt(), m([]), y(""), d(), h.current = T?.length ? T : void 0, g({
349
367
  eventName: "chat_clear_button_clicked",
350
368
  properties: {
351
369
  conversationId: c
352
370
  }
353
371
  });
354
- }, C = L(
355
- (e, n) => {
356
- E(null), d(n), h(e), p(), I.current = void 0;
372
+ }, S = $(
373
+ (e, l) => {
374
+ b(null), m(l), y(e), d(), h.current = void 0;
357
375
  },
358
- [d, h, p]
359
- ), Fe = L(
360
- async (e, n) => {
361
- re(), C(e, []), Re(!0);
376
+ [m, y, d]
377
+ ), Fe = $(
378
+ async (e, l) => {
379
+ re(), S(e, []), Se(!0);
362
380
  try {
363
- const t = await Ce(e, n);
381
+ const t = await Ie(e, l);
364
382
  if (t === null) return !1;
365
- const r = t[t.length - 1]?.role === "user" ? [
383
+ const o = t[t.length - 1]?.role === "user" ? [
366
384
  ...t,
367
385
  {
368
386
  id: F(16),
@@ -375,68 +393,68 @@ const Bt = () => {
375
393
  ]
376
394
  }
377
395
  ] : t;
378
- return C(e, r), !0;
396
+ return S(e, o), !0;
379
397
  } finally {
380
- n?.aborted || Re(!1);
398
+ l?.aborted || Se(!1);
381
399
  }
382
400
  },
383
- [C, Ce, re]
401
+ [S, Ie, re]
384
402
  );
385
- ut({
386
- conversationId: g.conversationId,
387
- fetchedConversation: g.fetchedConversation,
388
- effectiveAuthToken: fe,
389
- restoreSession: C,
403
+ vt({
404
+ conversationId: v.conversationId,
405
+ fetchedConversation: v.fetchedConversation,
406
+ effectiveAuthToken: me,
407
+ restoreSession: S,
390
408
  loadAndRestoreSession: Fe,
391
- onLoadFailed: () => C("", [])
409
+ onLoadFailed: () => S("", [])
392
410
  });
393
- const { openForm: et } = dt(), tt = ft();
394
- return ot(g.chatFunctionsRef, () => ({
411
+ const { openForm: at } = Rt(), it = Et();
412
+ return pt(v.chatFunctionsRef, () => ({
395
413
  submitMessage: se,
396
414
  updateInputMessage(e) {
397
- S(e);
415
+ A(e);
398
416
  },
399
417
  clearChat: ke,
400
418
  openForm: (e) => {
401
- tt?.setView("chat"), et(e, void 0);
419
+ it?.setView("chat"), at(e, void 0);
402
420
  },
403
421
  focusInput: () => {
404
- Me.current?.focus();
422
+ _e.current?.focus();
405
423
  }
406
424
  })), {
407
- messages: b,
408
- sendMessage: W,
409
- addToolApprovalResponse: Ye,
410
- isLoading: be,
411
- isStreaming: Ee,
412
- isBusy: Te,
413
- error: Je,
414
- setError: E,
415
- isSubmitDisabled: Y,
416
- input: R,
417
- handleInputChange: Oe,
418
- handleInputKeyDown: Xe,
425
+ messages: w,
426
+ sendMessage: J,
427
+ addToolApprovalResponse: ot,
428
+ isLoading: we,
429
+ isStreaming: be,
430
+ isBusy: Me,
431
+ error: et,
432
+ setError: b,
433
+ isSubmitDisabled: ee,
434
+ input: C,
435
+ handleInputChange: Ge,
436
+ handleInputKeyDown: nt,
419
437
  handleSubmit: se,
420
438
  stop: re,
421
439
  clear: ke,
422
- inputRef: Me,
423
- isMobile: Ve,
424
- files: A,
425
- setFiles: J,
426
- isNewChat: Ge,
440
+ inputRef: _e,
441
+ isMobile: Ze,
442
+ files: I,
443
+ setFiles: Y,
444
+ isNewChat: Xe,
427
445
  conversationId: c,
428
- restoreSession: C,
446
+ restoreSession: S,
429
447
  loadAndRestoreSession: Fe,
430
- isSessionLoading: Ue,
431
- authToken: v ? ce : pe,
432
- refreshSession: v ? ue : de,
433
- getCaptchaHeader: _,
434
- invalidateCaptcha: p,
435
- inputNotification: Qe,
436
- showInputNotification: te,
437
- clearInputNotification: Ze
448
+ isSessionLoading: We,
449
+ authToken: R ? le : pe,
450
+ refreshSession: R ? de : fe,
451
+ getCaptchaHeader: O,
452
+ invalidateCaptcha: d,
453
+ inputNotification: st,
454
+ showInputNotification: L,
455
+ clearInputNotification: rt
438
456
  };
439
457
  };
440
458
  export {
441
- Bt as useInkeepChat
459
+ Wt as useInkeepChat
442
460
  };
@@ -1 +1 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),t=require("react"),p=require("./config-provider.cjs"),n=t.createContext(void 0),g=({children:e})=>{const{baseSettings:s,componentType:o}=p.useInkeepConfig(),{tags:r,analyticsProperties:i}=s,c="0.17.6",a=t.useMemo(()=>({widgetLibraryVersion:c,componentType:o,tags:r}),[o,r,c]),v={logEvent:t.useCallback(async u=>{const E={...a,...u.properties,...i},d={eventName:u.eventName,properties:E};return s.onEvent?.(d)},[s,a,i])};return l.jsx(n.Provider,{value:v,children:e})},m=()=>{const e=t.useContext(n);if(!e)throw new Error("useBaseEvents must be used within a BaseEventsProvider");return e};exports.BaseEventsContext=n;exports.BaseEventsProvider=g;exports.useBaseEvents=m;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),t=require("react"),p=require("./config-provider.cjs"),n=t.createContext(void 0),g=({children:e})=>{const{baseSettings:s,componentType:o}=p.useInkeepConfig(),{tags:r,analyticsProperties:i}=s,c="0.17.7",a=t.useMemo(()=>({widgetLibraryVersion:c,componentType:o,tags:r}),[o,r,c]),v={logEvent:t.useCallback(async u=>{const E={...a,...u.properties,...i},d={eventName:u.eventName,properties:E};return s.onEvent?.(d)},[s,a,i])};return l.jsx(n.Provider,{value:v,children:e})},m=()=>{const e=t.useContext(n);if(!e)throw new Error("useBaseEvents must be used within a BaseEventsProvider");return e};exports.BaseEventsContext=n;exports.BaseEventsProvider=g;exports.useBaseEvents=m;
@@ -3,7 +3,7 @@ import { jsx as u } from "react/jsx-runtime";
3
3
  import { createContext as E, useMemo as d, useCallback as l, useContext as g } from "react";
4
4
  import { useInkeepConfig as x } from "./config-provider.js";
5
5
  const c = E(void 0), b = ({ children: e }) => {
6
- const { baseSettings: t, componentType: o } = x(), { tags: s, analyticsProperties: n } = t, r = "0.17.6", i = d(
6
+ const { baseSettings: t, componentType: o } = x(), { tags: s, analyticsProperties: n } = t, r = "0.17.7", i = d(
7
7
  () => ({
8
8
  widgetLibraryVersion: r,
9
9
  componentType: o,
@@ -1 +1 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("react/jsx-runtime"),u=require("react"),B=require("./config-provider.cjs"),O=require("./chat-auth-provider.cjs"),U=require("../hooks/use-events-api.cjs"),x=require("./base-events-provider.cjs"),M=({children:g})=>{const{baseSettings:n,aiChatSettings:h,componentType:i}=B.useInkeepConfig(),{tags:t,analyticsProperties:r,privacyPreferences:y,userProperties:o}=n,c="0.17.6",a=u.useMemo(()=>({widgetLibraryVersion:c,componentType:i}),[i,c]),{effectiveAuthToken:b,applicableRefreshSession:f,getCaptchaHeader:E,invalidateCaptcha:P}=O.useChatAuth(),{baseUrl:m,appId:A,analyticsApiBaseUrl:C,headers:I}=h,p=y?.optOutAllAnalytics??!1,{logEvent:l}=U.useEventsApi({baseUrl:C??m,appId:A,authToken:b,getCaptchaHeader:E,invalidateCaptcha:P,refreshSession:f,headers:I}),k={logEvent:u.useCallback(async s=>{const q={eventName:s.eventName,properties:{...a,...t?{tags:t}:{},...s.properties,...r}};if(!p){const e=s.properties??{},v=typeof e.conversationId=="string"?e.conversationId:void 0,d=typeof e.messageId=="string"?e.messageId:void 0,S=!!o&&Object.keys(o).length>0,w={...t?{tags:t}:{},...r??{}},T={...a,...s.properties};l({body:{type:s.eventName,...v?{conversationId:v}:{},...d?{messageId:d}:{},...S?{userProperties:o}:{},properties:w,metadata:T}})}try{return await n.onEvent?.(q)}catch(e){console.warn("[events] onEvent callback threw",e)}},[n,a,t,r,l,p,o])};return j.jsx(x.BaseEventsContext.Provider,{value:k,children:g})};exports.ChatBaseEventsProvider=M;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("react/jsx-runtime"),u=require("react"),B=require("./config-provider.cjs"),O=require("./chat-auth-provider.cjs"),U=require("../hooks/use-events-api.cjs"),x=require("./base-events-provider.cjs"),M=({children:g})=>{const{baseSettings:n,aiChatSettings:h,componentType:i}=B.useInkeepConfig(),{tags:t,analyticsProperties:r,privacyPreferences:y,userProperties:o}=n,c="0.17.7",a=u.useMemo(()=>({widgetLibraryVersion:c,componentType:i}),[i,c]),{effectiveAuthToken:b,applicableRefreshSession:f,getCaptchaHeader:E,invalidateCaptcha:P}=O.useChatAuth(),{baseUrl:m,appId:A,analyticsApiBaseUrl:C,headers:I}=h,p=y?.optOutAllAnalytics??!1,{logEvent:l}=U.useEventsApi({baseUrl:C??m,appId:A,authToken:b,getCaptchaHeader:E,invalidateCaptcha:P,refreshSession:f,headers:I}),k={logEvent:u.useCallback(async s=>{const q={eventName:s.eventName,properties:{...a,...t?{tags:t}:{},...s.properties,...r}};if(!p){const e=s.properties??{},v=typeof e.conversationId=="string"?e.conversationId:void 0,d=typeof e.messageId=="string"?e.messageId:void 0,S=!!o&&Object.keys(o).length>0,w={...t?{tags:t}:{},...r??{}},T={...a,...s.properties};l({body:{type:s.eventName,...v?{conversationId:v}:{},...d?{messageId:d}:{},...S?{userProperties:o}:{},properties:w,metadata:T}})}try{return await n.onEvent?.(q)}catch(e){console.warn("[events] onEvent callback threw",e)}},[n,a,t,r,l,p,o])};return j.jsx(x.BaseEventsContext.Provider,{value:k,children:g})};exports.ChatBaseEventsProvider=M;
@@ -6,7 +6,7 @@ import { useChatAuth as O } from "./chat-auth-provider.js";
6
6
  import { useEventsApi as j } from "../hooks/use-events-api.js";
7
7
  import { BaseEventsContext as M } from "./base-events-provider.js";
8
8
  const F = ({ children: m }) => {
9
- const { baseSettings: r, aiChatSettings: g, componentType: i } = N(), { tags: t, analyticsProperties: n, privacyPreferences: f, userProperties: o } = r, c = "0.17.6", a = x(
9
+ const { baseSettings: r, aiChatSettings: g, componentType: i } = N(), { tags: t, analyticsProperties: n, privacyPreferences: f, userProperties: o } = r, c = "0.17.7", a = x(
10
10
  () => ({
11
11
  widgetLibraryVersion: c,
12
12
  componentType: i
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-ui",
3
- "version": "0.17.6",
3
+ "version": "0.17.7",
4
4
  "description": "",
5
5
  "homepage": "",
6
6
  "repository": {