@mencraft/lore-headless
Version:
A headless library for chat streaming functionality
3 lines (2 loc) • 12.1 kB
JavaScript
;var t,e,a,r,n,s=require("react");exports.EventType=void 0,(t=exports.EventType||(exports.EventType={})).BatchDataIntermediate="batch_data_intermediate",t.TextBatchIntermediate="text_batch_intermediate",t.TextStreamIntermediate="text_stream_intermediate",t.ToolCallIntermediate="tool_call_intermediate",t.BatchDataOutput="batch_data_output",t.TextBatchOutput="text_batch_output",t.TextStreamOutput="text_stream_output",t.ToolCallOutput="tool_call_output",t.End="end",t.Error="error",function(t){t.HYDE_PROMPT="HydePromptNode",t.PROMPT="PromptNode",t.BOOL_PROMPT="BoolPromptNode",t.DEFAULT_RESPONSE="DefaultResponseNode",t.QUERY="QueryNode",t.ROUTER="RouterNode",t.REACT="ReactNode",t.CONDITIONAL="ConditionalNode",t.SEARCH="SearchNode"}(e||(e={})),function(t){t.HYDE_PROMPT="HydePromptNode",t.PROMPT="PromptNode",t.BOOL_PROMPT="BoolPromptNode",t.DEFAULT_RESPONSE="DefaultResponseNode",t.QUERY="QueryNode",t.ROUTER="RouterNode",t.REACT="ReactNode",t.CONDITIONAL="ConditionalNode",t.SEARCH="SearchNode"}(a||(a={})),function(t){t.ASSISTANT="assistant",t.USER="user",t.SYSTEM="system",t.DEVELOPER="developer"}(r||(r={})),exports.ToolParameterType=void 0,(n=exports.ToolParameterType||(exports.ToolParameterType={})).STRING="string",n.NUMBER="number",n.INTEGER="integer",n.BOOLEAN="boolean",n.OBJECT="object",n.ARRAY="array";class o{constructor(t,e,a={}){this.readerRef=null,this.loreClient=t,this.auth=e,this.callbacks=a}setCallbacks(t){this.callbacks={...this.callbacks,...t}}async processChatStream(t){var e,a,r,n,s,o;const i=t.getReader();this.readerRef=i;const l=new TextDecoder;let c="";try{for(;;){const{done:t,value:r}=await i.read();if(t){if(c.trim())try{const t=JSON.parse(c.trim());await this.processEvent(t)}catch(t){}null===(a=(e=this.callbacks).onEnd)||void 0===a||a.call(e);break}for(c+=l.decode(r,{stream:!0});;){const t=c.indexOf("\n");if(-1===t)break;const e=c.slice(0,t).trim();if(c=c.slice(t+1),e)try{const t=JSON.parse(e);await this.processEvent(t)}catch(t){continue}}}}catch(t){null===(n=(r=this.callbacks).onError)||void 0===n||n.call(r,t instanceof Error?t:new Error("Stream processing error"))}finally{i.cancel(),null===(o=(s=this.callbacks).onEnd)||void 0===o||o.call(s)}}handleGraphValidationErrors(t){var e,a,r,n,s,o,i,l,c;return t.test_failure&&(null===(a=(e=this.callbacks).onSystemMessage)||void 0===a||a.call(e,"Graph validation failed due to test failures.")),t.too_many_graphs&&(null===(n=(r=this.callbacks).onSystemMessage)||void 0===n||n.call(r,"Error: Too many graphs detected.")),(null===(s=t.validation_errors)||void 0===s?void 0:s.length)&&(t.validation_errors.forEach((t=>{var e,a;const r=`Validation error in node ${t.node_id}: ${t.message} (${t.error_type})`;null===(a=(e=this.callbacks).onSystemMessage)||void 0===a||a.call(e,r)})),null===(i=(o=this.callbacks).onSystemMessage)||void 0===i||i.call(o,"This graph is not able to run. [Click to go to graph](/graph?graphId="+this.callbacks.graphId+") , load the graph to fix the graph error.")),(null===(l=t.tests)||void 0===l?void 0:l.length)&&t.tests.forEach((t=>{var e,a,r,n,s;if(t.error){const o=t.error_text||(null===(r=null===(a=null===(e=t.events)||void 0===e?void 0:e[0])||void 0===a?void 0:a.event_data)||void 0===r?void 0:r.error)||"Unknown test error";null===(s=(n=this.callbacks).onSystemMessage)||void 0===s||s.call(n,`Test error: ${o}`)}})),!((null===(c=t.validation_errors)||void 0===c?void 0:c.length)||t.test_failure||t.too_many_graphs)}async processEvent(t){var e,a,r,n,s,o,i,l,c,d,u,h,p;switch(null===(a=(e=this.callbacks).onEvent)||void 0===a||a.call(e,t),t.event_type){case exports.EventType.TextStreamOutput:void 0!==(null===(r=t.event_data)||void 0===r?void 0:r.text)&&(null===(s=(n=this.callbacks).onTextStream)||void 0===s||s.call(n,t.event_data.text));break;case exports.EventType.ToolCallOutput:t.event_data&&(null===(i=(o=this.callbacks).onToolCall)||void 0===i||i.call(o,t.event_data));break;case exports.EventType.BatchDataOutput:null===(c=(l=this.callbacks).onBatchData)||void 0===c||c.call(l,t.event_data);break;case exports.EventType.TextBatchOutput:null===(u=(d=this.callbacks).onTextBatch)||void 0===u||u.call(d,t.event_data);break;case exports.EventType.End:null===(p=(h=this.callbacks).onEnd)||void 0===p||p.call(h)}}async startGraphChatStream(t,e,a=!1){var r,n;try{if(!a){if(!await this.validateGraph(t,e))return}const r=await this.loreClient.chatPost("/chat_stream",this.auth,t,{headers:{Accept:"text/event-stream","Graph-Id":this.callbacks.graphId||e||"personal"}});if(!r.data)throw new Error("No stream data received");await this.processChatStream(r.data)}catch(t){null===(n=(r=this.callbacks).onError)||void 0===n||n.call(r,t instanceof Error?t:new Error("Failed to start chat stream"))}}async startChatStream(t,e,a=!1){let r=null;if(a?r=await this.loreClient.adminPost("/chat/chat_stream",this.auth,t,{headers:{Accept:"text/event-stream","Graph-Id":this.callbacks.graphId||e||"personal"}}):a||(r=await this.loreClient.chatPost("/chat_stream",this.auth,t,{headers:{Accept:"text/event-stream","Graph-Id":this.callbacks.graphId||e||"personal"}})),!r)throw new Error("No response received");if(!r.data)throw new Error("No stream data received");await this.processChatStream(r.data)}cancelStream(){this.readerRef&&(this.readerRef.cancel(),this.readerRef=null)}async sendFeedback(t,e){return this.loreClient.post("/feedback",this.auth,t,{headers:{...e&&{"Graph-Id":e}},useValidationUrl:!1})}async validateGraph(t,e){var a,r,n,s,o,i,l,c;try{null===(r=(a=this.callbacks).onSystemMessage)||void 0===r||r.call(a,"Verifying graph structure...");const l={graphID:e,tests:[t.query]},c=await this.loreClient.post("/graph/verify",this.auth,l,{headers:{Accept:"text/event-stream","Graph-Id":e},useValidationUrl:!0});if(!c.data)return null===(s=(n=this.callbacks).onSystemMessage)||void 0===s||s.call(n,"Validation failed: No response received"),!1;const d=this.handleGraphValidationErrors(c.data);return d&&(null===(i=(o=this.callbacks).onSystemMessage)||void 0===i||i.call(o,"Graph structure verified successfully.")),d}catch(t){return null===(c=(l=this.callbacks).onError)||void 0===c||c.call(l,t instanceof Error?t:new Error("Graph validation error")),!1}}}const i=()=>Date.now().toString(36)+Math.random().toString(36).substring(2);exports.LoreClient=class{constructor(t="production",e,a){if(e||a){if(!e||!a)throw new Error("Both customChatUrl and customValidationUrl must be provided together");this.chatUrl=e,this.validationUrl=a}else"staging"===t?(this.chatUrl="https://staging-chat.lore.center",this.validationUrl="https://staging-api.lore.center"):"development"===t?(this.chatUrl="http://127.0.0.1:8002",this.validationUrl="http://127.0.0.1:8000"):(this.chatUrl="https://chat-cloudrun-service-778776159944.us-central1.run.app",this.validationUrl="https://api.lore.center")}async post(t,e,a,r={}){if(!e.clientId||!e.token)throw new Error(`Authentication error: ${e.clientId?"Token":"Client ID"} missing`);const n={"Content-Type":"application/json",Accept:"application/json","client-id":e.clientId,"firebase-id-token":e.token},s={...r,method:"POST",headers:{...n,...r.headers},body:a?JSON.stringify(a):void 0},o=!0===r.useValidationUrl?this.validationUrl:this.chatUrl,i=await fetch(`${o}${t}`,s);if(!i.ok)throw new Error(`HTTP error! status: ${i.status}`);const l={status:i.status,statusText:i.statusText,headers:i.headers},c=i.headers.get("content-type");if(null==c?void 0:c.includes("text/event-stream"))return{...l,data:i.body};if(null==c?void 0:c.includes("application/json")){const t=await i.text();if(t)return{...l,data:JSON.parse(t)}}return l}async chatPost(t,e,a,r={}){return this.post(t,e,a,{...r,useValidationUrl:!1})}async adminPost(t,e,a,r={}){if(!e.clientId||!e.token)throw new Error(`Authentication error: ${e.clientId?"Firebase token":"Client ID"} missing`);const n={"Content-Type":"application/json",Accept:"application/json","client-id":e.clientId,"firebase-id-token":e.token},s={...r,method:"POST",headers:{...n,...r.headers},body:a?JSON.stringify(a):void 0},o=this.validationUrl,i=await fetch(`${o}${t}`,s);if(!i.ok)throw new Error(`HTTP error! status: ${i.status}`);const l={status:i.status,statusText:i.statusText,headers:i.headers},c=i.headers.get("content-type");if(null==c?void 0:c.includes("text/event-stream"))return{...l,data:i.body};if(null==c?void 0:c.includes("application/json")){const t=await i.text();if(t)return{...l,data:JSON.parse(t)}}return l}},exports.useChatStream=(t,e,n={})=>{const[l,c]=s.useState([]),[d,u]=s.useState(!1),h=s.useRef(null),p=s.useRef(null);if(h.current)h.current.setCallbacks(n);else{const s={...n,onToolCall:t=>{c((e=>{const a=e[e.length-1],n=[...e];"assistant"===(null==a?void 0:a.role)&&"content"in a&&a.content;const s={id:i(),content:`Tool called: ${t.tool_name}`,role:r.ASSISTANT,timestamp:new Date};return n.push(s),n}))},onBatchData:t=>{var e;switch(t.node_type){case a.QUERY:{const e=t;Object.entries(Object.keys(e.query_result).filter((t=>t.startsWith("image."))).reduce(((t,a)=>{const[,r,n]=a.split(".");return t[r]||(t[r]={image_name:"",storage_type:"",url:"",uuid:""}),t[r][n]=e.query_result[a][0],t}),{})).map((([,t])=>t)).forEach((t=>{"bucket"===t.storage_type&&c((e=>[...e,{id:i(),imageId:t.uuid,storageType:t.storage_type,role:r.ASSISTANT,timestamp:new Date,url:t.url}]))}));Object.entries(Object.keys(e.query_result).filter((t=>t.startsWith("file."))).reduce(((t,a)=>{const r=a.replace("file.","");return Object.prototype.hasOwnProperty.call(t,"file")||(t.file={}),t.file[r]=e.query_result[a][0],t}),{})).map((([,t])=>t)).forEach((t=>{t.filename&&t.media_type&&c((e=>[...e,{id:i(),filename:t.filename,mediaType:t.media_type,role:r.ASSISTANT,timestamp:new Date}]))}));break}}null===(e=n.onBatchData)||void 0===e||e.call(n,t)},onTextStream:t=>{var e;c((e=>{const a=[...e];if(p.current){const e=a.findIndex((t=>t.id===p.current));if(-1!==e){const r=a[e];return"content"in r&&(a[e]={...r,content:r.content+t}),a}}const n=i();return p.current=n,[...a,{id:n,role:r.ASSISTANT,content:t,timestamp:new Date,isStreaming:!1}]})),null===(e=n.onTextStream)||void 0===e||e.call(n,t)},onSystemMessage:t=>{var e;c((e=>[...e,{id:i(),role:r.SYSTEM,content:t,timestamp:new Date}])),null===(e=n.onSystemMessage)||void 0===e||e.call(n,t)},onError:t=>{var e;c((e=>[...e,{id:i(),role:"error",content:t.message,timestamp:new Date}])),u(!1),p.current=null,null===(e=n.onError)||void 0===e||e.call(n,t)},onEnd:()=>{var t;u(!1),p.current&&(c((t=>{const e=[...t],a=e.findIndex((t=>t.id===p.current));if(-1!==a){const t=e[a];"isStreaming"in t&&(e[a]={...t,isStreaming:!1})}return e})),p.current=null),null===(t=n.onEnd)||void 0===t||t.call(n)}};h.current=new o(t,e,s)}const m=s.useCallback(((t,e,a=!1)=>h.current?(c((e=>[...e,{id:i(),role:r.USER,content:t.query,timestamp:new Date}])),u(!0),h.current.startGraphChatStream(t,e,a)):Promise.reject(new Error("Chat stream manager not initialized"))),[c]),v=s.useCallback(((t,e,a)=>h.current?(c((e=>[...e,{id:i(),role:r.USER,content:t.query,timestamp:new Date}])),u(!0),h.current.startChatStream(t,e,a)):Promise.reject(new Error("Chat stream manager not initialized"))),[c]),f=s.useCallback((async(t,e)=>h.current?h.current.validateGraph(t,e):Promise.reject(new Error("Chat stream manager not initialized"))),[]);return{messages:l,isStreaming:d,startChatStream:v,cancelStream:s.useCallback((()=>{h.current&&(h.current.cancelStream(),u(!1),p.current&&(c((t=>{const e=[...t],a=e.findIndex((t=>t.id===p.current));if(-1!==a){const t=e[a];"content"in t&&(e[a]={...t,isStreaming:!1,content:t.content+" [cancelled]"})}return e})),p.current=null))}),[c]),startGraphChatStream:m,clearMessages:s.useCallback((()=>{c([])}),[c]),startVerification:f}},exports.useFeedback=(t,e,a)=>{const[r,n]=s.useState(!1),[i,l]=s.useState(null),[c,d]=s.useState(null),u=s.useCallback((async r=>{n(!0),l(null);try{const n=new o(t,e),s=await n.sendFeedback(r,a);return d(s.data),s}catch(t){const e=t instanceof Error?t:new Error("Failed to send feedback");throw l(e),e}finally{n(!1)}}),[t,e,a]);return{sendFeedback:u,loading:r,error:i,data:c}};
//# sourceMappingURL=react.js.map