UNPKG

heylock

Version:

Zero‑friction AI agent integration for JavaScript & TypeScript projects.

3 lines (2 loc) 24.6 kB
var d=class{constructor(e,t={}){this.agentKey=e;let r=typeof window<"u"&&typeof window.document<"u";if(this.useStorage=t.useStorage??r,this.useMessageHistory=t.useMessageHistory??!0,this.suppressWarnings=t.suppressWarnings??!1,typeof e!="string"||e.length<=0)throw new Error("Agent initialization failed: agentKey must be a non-empty string.");if(typeof this.useStorage!="boolean")throw new Error("Agent initialization failed: useStorage must be a boolean.");if(typeof this.useMessageHistory!="boolean")throw new Error("Agent initialization failed: useMessageHistory must be a boolean.");if(this.useStorage){let s=`heylock:${t.agentId||"default"}:context`;this.onContextChange(()=>{this.#u(s,this.context)});let n=this.#d(s);if(n)try{let a=JSON.parse(n);Array.isArray(a)&&a.every(i=>typeof i=="object"&&i!==null&&typeof i.content=="string"&&i.content.trim().length>0&&i.content.length<=2e3&&(i.timestamp===void 0||typeof i.timestamp=="number"&&i.timestamp>=0&&Number.isFinite(i.timestamp)))?this.#t=a.map(i=>({content:i.content.trim(),timestamp:i.timestamp??new Date().getTime()})):!this.suppressWarnings&&console.warn("Stored context is invalid. Context will not be restored.")}catch{!this.suppressWarnings&&console.warn("Failed to parse stored context. Context will not be restored.")}}this.#g(e)}async#g(e){try{let t=await fetch("https://heylock.dev/api/internal/verifyKey",{method:"POST",body:JSON.stringify({key:e})});if(t.status===500)throw new Error("Agent initialization failed: we are experiencing temporary server issues. Please try again later.");if(t.status!==200)throw new Error("Agent initialization failed: something went wrong. Please check your internet connection and try again.");let r=await t.json();if(typeof r.valid!="boolean")throw new Error("Agent initialization failed: received an unexpected response from the server. Please ensure you are using the correct version of the package.");if(r.valid===!1)throw new Error("Agent initialization failed: the provided agentKey is invalid. Please verify your key and try again.");this.#l=!0;try{await this.fetchUsageRemaining()}catch(s){!this.suppressWarnings&&console.warn("Initialization warning: failed to fetch usageRemaining:",s)}this.#f()}catch(t){this.#l=!1,!this.suppressWarnings&&console.warn(t?.message||t),this.#f()}}#l=!1;get isInitialized(){return this.#l??!1}#r={messages:null,sorts:null,rewrites:null};get usageRemaining(){let e=this.#r??{messages:null,sorts:null,rewrites:null};return Object.freeze({...e})}#e=[];get messageHistory(){let e=this.#e??[];return Object.freeze(e.map(t=>({content:t.content,role:t.role})))}#t=[];get context(){let e=this.#t??[];return Object.freeze(e.map(t=>({content:t.content,timestamp:t.timestamp})))}#i=[];onInitialized(e){if(typeof e!="function")throw new Error("onInitialized failed: callback must be a function.");return this.#i.push(e),()=>{let t=this.#i.indexOf(e);t!==-1&&this.#i.splice(t,1)}}#f(){[...this.#i].forEach(e=>{try{e(this.isInitialized)}catch(t){!this.suppressWarnings&&console.warn("onInitialized callback error:",t)}})}#a=[];onMessageHistoryChange(e){if(typeof e!="function")throw new Error("onMessageHistoryChange failed: callback must be a function.");return this.#a.push(e),()=>{let t=this.#a.indexOf(e);t!==-1&&this.#a.splice(t,1)}}#s(){this.#a.forEach(e=>{try{e(this.messageHistory)}catch(t){!this.suppressWarnings&&console.warn("onMessageHistoryChange callback error:",t)}})}#o=[];onContextChange(e){if(typeof e!="function")throw new Error("onContextChange failed: callback must be a function.");return this.#o.push(e),()=>{let t=this.#o.indexOf(e);t!==-1&&this.#o.splice(t,1)}}#n(){this.#o.forEach(e=>{try{e(this.context)}catch(t){!this.suppressWarnings&&console.warn("onContextChange callback error:",t)}})}addMessage(e,t="user"){if(typeof e!="string")throw new Error("addMessage failed: content must be a string.");if(e.length>1e4)throw new Error("addMessage failed: content exceeds maximum allowed length of 10000 characters.");if(t!=="user"&&t!=="assistant")throw new Error("addMessage failed: role must be either 'user' or 'assistant'.");let r=this.#e.push({content:e.trim(),role:t});return this.#s(),r-1}removeMessage(e){if(typeof e!="number"||e<0)throw new Error("removeMessage failed: index must be a number greater than or equal to 0.");if(e>this.#e.length-1)throw new Error(`removeMessage failed: index ${e} is out of bounds for message history of length ${this.#e.length}.`);this.#e.splice(e,1),this.#s()}modifyMessage(e,t,r){if(typeof e!="number"||e<0)throw new Error("modifyMessage failed: index must be a number greater than or equal to 0.");if(e>this.#e.length-1)throw new Error(`modifyMessage failed: index ${e} is out of bounds for message history of length ${this.#e.length}.`);if(typeof t!="string"||t.trim().length===0)throw new Error("modifyMessage failed: content must be a non-empty string.");if(t.length>1e4)throw new Error("modifyMessage failed: content exceeds maximum allowed length of 10000 characters.");if(r&&r!=="user"&&r!=="assistant")throw new Error("modifyMessage failed: role must be either 'user' or 'assistant'.");this.#e[e].content=t.trim(),this.#e[e].role=r||this.#e[e].role,this.#s()}setMessageHistory(e){if(!Array.isArray(e))throw new Error("setMessageHistory failed: messageHistory must be an array.");for(let t=0;t<e.length;t++){let r=e[t];if(typeof r!="object"||r===null||typeof r.content!="string"||r.content.length>1e4||r.role!=="user"&&r.role!=="assistant")throw new Error(`setMessageHistory failed: message at index ${t} is invalid. Each message must be an object with a string 'content' (max length 10000) and 'role' of either 'user' or 'assistant'.`)}this.#e=e.map(t=>({content:t.content.trim(),role:t.role})),this.#s()}clearMessageHistory(){this.#e=[],this.#s()}addContextEntry(e,t){if(typeof e!="string"||e.trim().length===0)throw new Error("addContextEntry failed: content must be a non-empty string.");if(e.length>2e3)throw new Error("addContextEntry failed: content exceeds maximum allowed length of 2000 characters.");if(t!==void 0&&(typeof t!="number"||t<0||!Number.isFinite(t)))throw new Error("addContextEntry failed: timestamp must be a finite, non-negative number if provided.");if(t!==void 0&&typeof t=="number"&&Number.isFinite(t)){let s=Date.now();t>s&&console.warn("addContextEntry warning: timestamp is in the future. This may lead to unexpected behavior.")}let r=this.#t.push({content:e.trim(),timestamp:t??new Date().getTime()});return this.#n(),r-1}removeContextEntry(e){if(typeof e!="number"||e<0)throw new Error("removeContextEntry failed: index must be a number greater than or equal to 0.");if(e>this.#t.length-1)throw new Error(`removeContextEntry failed: index ${e} is out of bounds for context of length ${this.#t.length}.`);this.#t.splice(e,1),this.#n()}modifyContextEntry(e,t,r){if(typeof e!="number"||e<0)throw new Error("modifyContextEntry failed: index must be a number greater than or equal to 0.");if(e>this.#t.length-1)throw new Error(`modifyContextEntry failed: index ${e} is out of bounds for context of length ${this.#t.length}.`);if(typeof t!="string"||t.trim().length===0)throw new Error("modifyContextEntry failed: content must be a non-empty string if provided.");if(t.length>2e3)throw new Error("modifyContextEntry failed: content exceeds maximum allowed length of 2000 characters.");if(r!==void 0&&(typeof r!="number"||r<0||!Number.isFinite(r)))throw new Error("modifyContextEntry failed: timestamp must be a finite, non-negative number if provided.");if(r!==void 0&&typeof r=="number"&&Number.isFinite(r)){let n=Date.now();r>n&&console.warn("modifyContextEntry warning: timestamp is in the future. This may lead to unexpected behavior.")}let s={content:t.trim()??this.#t[e].content,timestamp:r??this.#t[e].timestamp};this.#t[e]=s,this.#n()}setContext(e){if(!Array.isArray(e))throw new Error("setContext failed: contextArray must be an array.");for(let t=0;t<e.length;t++){let r=e[t];if(typeof r!="object"||r===null||typeof r.content!="string"||r.content.trim().length<=0||r.content.length>2e3||r.timestamp!==void 0&&(typeof r.timestamp!="number"||r.timestamp<0||!Number.isFinite(r.timestamp)))throw new Error(`setContext failed: entry at index ${t} is invalid. Each entry must be an object with a non-empty string 'content' (max length 2000) and an optional finite, non-negative 'timestamp'.`);if(r.timestamp!==void 0&&typeof r.timestamp=="number"&&Number.isFinite(r.timestamp)){let s=Date.now();r.timestamp>s&&!this.suppressWarnings&&console.warn(`setContext warning: timestamp at index ${t} is in the future. This may lead to unexpected behavior.`)}}this.#t=e.map(t=>({content:t.content.trim(),timestamp:t.timestamp??new Date().getTime()})),this.#n()}clearContext(){this.#t=[],this.#n()}getContextString(){let e="";function t(r){if(typeof r!="number"||!Number.isFinite(r)||r<0)return"";let n=Date.now()-r;if(n<0)return"in the future";let a=Math.floor(n/1e3);if(a<1)return"now";if(a<60)return`${a} second${a!==1?"s":""} ago`;let i=Math.floor(a/60);if(i<60)return`${i} minute${i!==1?"s":""} ago`;let o=Math.floor(i/60);if(o<24)return`${o} hour${o!==1?"s":""} ago`;let l=Math.floor(o/24);return`${l} day${l!==1?"s":""} ago`}return this.#t.forEach(r=>{e+=`${r.content} ${t(r.timestamp)}. `}),e}#u(e,t){if(typeof e!="string"||e.length===0)throw new Error("#setStorageItem failed: key must be a non-empty string.");if(typeof t>"u")throw new Error("#setStorageItem failed: value must not be undefined.");let r=typeof process<"u"&&process.versions!==null&&process.versions.node!==null,s=typeof window<"u"&&typeof window.document<"u";if(r&&!s){!this.suppressWarnings&&console.warn("Data can only be saved in a browser environment.");return}try{localStorage.setItem(e,JSON.stringify(t))}catch{!this.suppressWarnings&&console.warn("Data was not saved due to an unexpected error.")}}#d(e){if(typeof e!="string"||e.trim().length<=0)throw new Error("getStorageItem failed: key must be a non-empty string.");let t=typeof process<"u"&&process.versions!==null&&process.versions.node!==null,r=typeof window<"u"&&typeof window.document<"u";if(t&&!r){!this.suppressWarnings&&console.warn("Data can only be retrieved in a browser environment.");return}try{return localStorage.getItem(e)}catch{!this.suppressWarnings&&console.warn("Data was not retrieved due to an unexpected error.")}}async fetchUsageRemaining(){if(!this.isInitialized)throw new Error("fetchLimits failed: agent is not initialized. Please wait for initialization to complete.");try{let e=await fetch("https://heylock.dev/api/v1/limits",{method:"GET",headers:{Authorization:this.agentKey}});if(e.status===401)throw new Error("fetchUsageRemaining failed: authorization failed. Please check your agent key and try again.");if(e.status===500)throw new Error("fetchUsageRemaining failed: we are experiencing temporary server issues. Please try again later.");if(e.status===503)throw new Error("fetchUsageRemaining failed: the server is busy.");if(e.status!==200)throw new Error("fetchUsageRemaining failed: something went wrong. Please check your internet connection and ensure you are using the correct package version.");if(e.status===200){let t=await e.json(),r={messages:t.limits.messages.remaining,sorts:t.limits.sorts.remaining,rewrites:t.limits.rewrites.remaining};return this.#r=r,this.usageRemaining}}catch(e){throw e.message.includes("fetchUsageRemaining failed: ")?new Error(e.message):new Error(`fetchUsageRemaining failed: an unexpected error occurred. Please ensure you are using the correct version of the package. Error details: ${e}`)}}async message(e,t=!0,r=!0){if(!this.isInitialized)throw new Error("message failed: agent is not initialized. Please wait for initialization to complete.");if(typeof e!="string"||e.trim().length===0)throw new Error("message failed: content must be a non-empty string");if(e.length>1e4)throw new Error("message failed: content exceeds maximum allowed length of 10000 characters.");if(typeof r!="boolean")throw new Error("message failed: saveToMessageHistory must be a boolean.");if(typeof t!="boolean")throw new Error("message failed: useContext must be a boolean.");r&&this.addMessage(e,"user");let s;try{let n=await fetch("https://heylock.dev/api/v1/message",{method:"POST",headers:{Authorization:this.agentKey},body:JSON.stringify({content:e,stream:!1,...this.useMessageHistory&&this.#e.length>0?{history:this.messageHistory}:{},...t?{context:this.getContextString()}:{}})}),a=n.headers?.get?.("Plan-Remaining"),i=Number(a);a!=null&&!Number.isNaN(i)&&(this.#r.messages=i);let o;if(n.status===500)throw new Error("message failed: we are experiencing temporary server issues. Please try again later.");if(n.status===400)throw new Error("message failed: please check arguments. Refer to the documentation for more information (see documentation link).");if(n.status===401)throw new Error("message failed: authorization failed. Please check your agent key and try again.");if(n.status===429)throw rateLimitRemainingHeader!=null&&!Number.isNaN(rateLimitRemaining)&&rateLimitRemaining<=0?new Error("message failed: you have reached your message plan limit. Please upgrade your plan or wait for the limit to reset."):new Error("message failed: too many requests. Try again later.");if(n.status===502)throw new Error("message failed: we are experiencing unexpected external service errors. Please try again later.");if(n.status!==200)throw new Error("message failed: something went wrong. Please check your internet connection or ensure you are using the correct package version.");if(n.status===200){let f=(await n.json())?.message;if(typeof f!="string")throw new Error("message failed: received an unexpected response from the server. Please ensure you are using the correct version of the package.");return o=r&&this.addMessage(f,"assistant")||void 0,f}}catch(n){throw r&&typeof s=="number"&&this.modifyMessage(s,"An error occurred while processing your request. Please try again later."),n.message.includes("message failed: ")?new Error(n.message):new Error(`message failed: an unexpected error occurred. Please ensure you are using the correct version of the package. Error details: ${n}`)}}async*messageStream(e,t=!0,r=!0){if(!this.isInitialized)throw new Error("messageStream failed: agent is not initialized. Please wait for initialization to complete.");if(typeof e!="string"||e.trim().length===0)throw new Error("messageStream failed: content must be a non-empty string.");if(e.length>1e4)throw new Error("messageStream failed: content exceeds maximum allowed length of 10000 characters.");if(typeof t!="boolean")throw new Error("messageStream failed: useContext must be a boolean.");if(typeof r!="boolean")throw new Error("messageStream failed: saveToMessageHistory must be a boolean.");r&&this.addMessage(e,"user");let s=r?this.addMessage("","assistant"):void 0;try{let n=Array.isArray(this.messageHistory)?this.messageHistory.filter((l,f)=>f!==s):void 0,a=await fetch("https://heylock.dev/api/v1/message",{method:"POST",headers:{Authorization:this.agentKey},body:JSON.stringify({content:e,stream:!0,...this.useMessageHistory&&Array.isArray(n)&&n.length>0?{history:n}:{},...t?{context:this.getContextString()}:{}})}),i=a.headers?.get?.("Plan-Remaining"),o=Number(i);if(i!=null&&!Number.isNaN(o)&&(this.#r.messages=o),a.status===500)throw new Error("messageStream failed: we are experiencing temporary server issues. Please try again later.");if(a.status===400)throw new Error("messageStream failed: please check arguments. Refer to the documentation for more information (see documentation link).");if(a.status===401)throw new Error("messageStream failed: authorization failed. Please check your agent key and try again.");if(a.status===429)throw i!=null&&!Number.isNaN(o)&&o<=0?new Error("messageStream failed: you have reached your message plan limit. Please upgrade your plan or wait for the limit to reset."):new Error("messageStream failed: too many requests. Try again later.");if(a.status===502)throw new Error("messageStream failed: we are experiencing unexpected external service errors. Please try again later.");if(a.status!==200)throw new Error("messageStream failed: something went wrong. Please check your internet connection or ensure you are using the correct package version.");if(a.status===200){let l=a.body.getReader(),f=new TextDecoder,g="",u="";for(;;){let{done:w,value:y}=await l.read();if(w)break;g+=f.decode(y,{stream:!0});let c=g.split(` `);g=c.pop()||"";for(let E of c){let m=E.trim();if(m!=="")try{let h=JSON.parse(m);if(h.message&&!h.done)u+=h.message,r&&typeof s=="number"&&this.modifyMessage(s,u,"assistant"),yield h.message;else if(h.done)return u}catch{}}}}}catch(n){throw r&&typeof s=="number"&&this.modifyMessage(s,"An error occurred while processing your request. Please try again later."),n.message.includes("messageStream failed: ")?new Error(n.message):new Error(`messageStream failed: an unexpected error occurred. Please ensure you are using the correct version of the package. Error details: ${n}`)}}async greet(e,t=!0,r=!0){if((typeof e!="string"||e.trim().length===0)&&e!==void 0&&(typeof e!="string"||e.trim().length===0))throw new Error("greet failed: instructions must be a non-empty string if provided.");if(e&&e.length>1e4)throw new Error("greet failed: instructions exceeds maximum allowed length of 10000 characters.");if(typeof t!="boolean")throw new Error("greet failed: useContext must be a boolean.");if(typeof r!="boolean")throw new Error("greet failed: saveToMessageHistory must be a boolean.");let s="";e?s=`Write a short greeting message encouraging the visitor to interact with you. Use instructions: ${e}`:(s="Greet the visitor in one short, friendly sentence. Encourage interaction. Sound human.",t&&(s+=" Mention their interests or passions subtly.")),this.useMessageHistory&&this.#e.length>0&&(s+=" Take into account our previous conversation history to make the greeting more personalized and contextual");let n;try{let a=await this.message(s,t,!1);return r&&(n=this.addMessage(a,"assistant")),a}catch(a){throw r&&typeof n=="number"&&this.modifyMessage(n,"An error occurred while processing your request. Please try again later."),new Error(`greet failed - ${a}`)}}#h=0;async shouldEngage(e){let t=new Date().getTime();if(t-this.#h<15e3)return!this.suppressWarnings&&console.warn("shouldEngage ignored: throttling in effect (15000 ms). Please wait before calling again."),{shouldEngage:!1,reasoning:"",warning:"Throttling in effect (15000 ms). Please wait before calling again",fallback:!0};if(this.#h=t,e!==void 0){if(typeof e!="string"||e.trim().length===0)throw new Error("shouldEngage failed: instructions must be a non-empty string if provided.");if(e.length>1e4)throw new Error("shouldEngage failed: instructions exceeds maximum allowed length of 10000 characters.")}try{let r=await fetch("https://heylock.dev/api/v1/should-engage",{method:"POST",headers:{Authorization:this.agentKey},body:JSON.stringify({instructions:e,context:this.getContextString()})});if(r.status===400)throw new Error("shouldEngage failed: invalid arguments. Please check your instructions and try again.");if(r.status===401)throw new Error("shouldEngage failed: authorization failed. Please check your agent key and try again.");if(r.status===500)throw new Error("shouldEngage failed: we are experiencing server issues. Please try again later.");if(r.status===502)throw new Error("shouldEngage failed: external service error. Please try again later.");if(r.status!==200)throw new Error(`shouldEngage failed: unexpected error (HTTP ${r.status}).`);if(r.status===200){let s=await r.json();if(typeof s!="object"||s===null||typeof s.shouldEngage!="boolean"||typeof s.reasoning!="string"||typeof s.fallback!="boolean")throw new Error("shouldEngage failed: received an unexpected response from the server. Please ensure you are using the correct version of the package.");return s}}catch(r){throw r.message.includes("shouldEngage failed: ")?new Error(r.message):new Error(`shouldEngage failed: an unexpected error occurred. Please ensure you are using the correct version of the package. Error details: ${r}`)}}async rewrite(e,t,r=!0){if(typeof e!="string"||e.trim().length===0)throw new Error("rewrite failed: content must be a non-empty string.");if(e.length>1e4)throw new Error("rewrite failed: content exceeds maximum allowed length of 10000 characters.");if(typeof r!="boolean")throw new Error("rewrite failed: useContext must be a boolean.");if(t!==void 0){if(typeof t!="string")throw new Error("rewrite failed: instructions must be a string if provided.");if(t.length>1e4)throw new Error("rewrite failed: instructions exceeds maximum allowed length of 10000 characters.")}try{let s=await fetch("https://heylock.dev/api/v1/rewrite",{method:"POST",headers:{Authorization:this.agentKey},body:JSON.stringify({text:e,instructions:t,...r?{context:this.getContextString()}:{}})}),n=s.headers?.get?.("Plan-Remaining"),a=Number(n);if(n!=null&&!Number.isNaN(a)&&(this.#r.rewrites=a),s.status===400)throw new Error("rewrite failed: invalid arguments. Please check your content, instructions or context.");if(s.status===401)throw new Error("rewrite failed: authorization failed. Please check your agent key and try again.");if(s.status===429)throw n!=null&&!Number.isNaN(a)&&a<=0?new Error("rewrite failed: you have reached your rewrite plan limit. Please upgrade your plan or wait for the limit to reset."):new Error("rewrite failed: too many requests. Try again later.");if(s.status===500)throw new Error("rewrite failed: we are experiencing server issues. Please try again later.");if(s.status===502)throw new Error("rewrite failed: external service error. Please try again later.");if(s.status!==200)throw new Error(`rewrite failed: unexpected error (HTTP ${s.status}).`);if(s.status===200){let i=await s.json();if(typeof i!="object"||i===null||typeof i.text!="string")throw new Error("rewrite failed: received an unexpected response from the server. Please ensure you are using the correct version of the package.");return i.text}}catch(s){throw s.message.includes("rewrite failed: ")?new Error(s.message):new Error(`rewrite failed: an unexpected error occurred. Please ensure you are using the correct version of the package. Error details: ${s}`)}}async sort(e,t,r=!0){if(!Array.isArray(e)||e.length<2){let s=Array.isArray(e)?e:[];return{array:s,indexes:s.map((n,a)=>a),warning:"Input array is invalid or too short to sort. Returning original array.",fallback:!0}}if(t!==void 0&&typeof t!="string")throw new Error("sort failed: instructions must be a string if provided.");if(typeof r!="boolean")throw new Error("sort failed: useContext must be a boolean.");try{let s=await fetch("https://heylock.dev/api/v1/sort",{method:"POST",headers:{Authorization:this.agentKey},body:JSON.stringify({array:e,instructions:t,...r?{context:this.getContextString()}:{}})}),n=s.headers?.get?.("Plan-Remaining"),a=Number(n);if(n!=null&&!Number.isNaN(a)&&(this.#r.sorts=a),s.status===400)throw new Error("sort failed: invalid arguments. Please check your array, instructions, and context.");if(s.status===401)throw new Error("sort failed: authorization failed. Please check your agent key and try again.");if(s.status===429)throw n!=null&&!Number.isNaN(a)&&a<=0?new Error("sort failed: you have reached your sort plan limit. Please upgrade your plan or wait for the limit to reset."):new Error("sort failed: too many requests. Try again later.");if(s.status===500)throw new Error("sort failed: we are experiencing server issues. Please try again later.");if(s.status===502)throw new Error("sort failed: external service error. Please try again later.");if(s.status!==200)throw new Error(`sort failed: unexpected error (HTTP ${s.status}).`);if(s.status===200){let i=await s.json();if(typeof i!="object"||i===null||!Array.isArray(i.indexes)||i.indexes.some(l=>typeof l!="number"||!Number.isInteger(l)))throw new Error("sort failed: received an unexpected response from the server. Please ensure you are using the correct version of the package.");if(i.indexes.length!==e.length)throw new Error("sort failed: response indexes length does not match input array length. Possible server bug or data corruption.");return{array:i.indexes.map(l=>e[l]),indexes:i.indexes,reasoning:typeof i.reasoning=="string"?i.reasoning:void 0,fallback:typeof i.fallback=="boolean"?i.fallback:!1}}}catch(s){throw s.message.includes("sort failed: ")?new Error(s.message):new Error(`sort failed: an unexpected error occurred. Please ensure you are using the correct version of the package. Error details: ${s}`)}}};export{d as default};