@useago/sdk 1.0.7 → 1.0.8

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,6 +1,6 @@
1
- var h=class extends Error{constructor(e,t,s){super(e),this.code=t,this.statusCode=s,this.name="AgoError"}},u=class b extends h{constructor(t,s,n,r,i,a){super(t,s,n),this.type=r,this.param=i,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,s){const n=t.error;return new b(n.doc_url?`${n.message} See ${n.doc_url}`:n.message,n.code,s,n.type,n.param,n.doc_url)}},d=class extends h{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},g=class extends h{constructor(e,t="stream_error"){super(e,t),this.name="AgoStreamError"}},m=class extends h{constructor(e,t,s){super(e,"function_error"),this.functionName=t,this.originalError=s,this.name="AgoFunctionError"}},$=class{constructor(e=!1){this.enabled=e}enable(){this.enabled=!0}disable(){this.enabled=!1}log(...e){this.enabled&&console.log("[AGO SDK]",...e)}warn(...e){this.enabled&&console.warn("[AGO SDK]",...e)}error(...e){console.error("[AGO SDK]",...e)}debug(...e){this.enabled&&console.debug("[AGO SDK]",...e)}},o=new $,y="ago_widget_id";function x(){if(typeof localStorage<"u"){const t=localStorage.getItem(y);if(t)return t}const e=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`;if(typeof localStorage<"u")try{localStorage.setItem(y,e)}catch{}return e}var R=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||x()},e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission&&(this.headers["X-Widget-Permission"]=e.permission)}updateConfig(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),e.widgetId&&(this.headers["X-User-Anon-Id"]=e.widgetId),e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission!==void 0&&(e.permission?this.headers["X-Widget-Permission"]=e.permission:delete this.headers["X-Widget-Permission"])}async get(e){return this.request("GET",e)}async post(e,t){return this.request("POST",e,t)}async postStream(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (stream)",s,t);try{const n=await fetch(s,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return n.ok||await this.handleErrorResponse(n),n}catch(n){throw n instanceof u?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,n instanceof Error?n:void 0)}}async postFormData(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (formData)",s);const n={...this.headers};try{const r=await fetch(s,{method:"POST",headers:n,body:t});return r.ok||await this.handleErrorResponse(r),r}catch(r){throw r instanceof u?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async request(e,t,s){const n=`${this.baseUrl}${t}`;o.debug(e,n,s);try{const r=await fetch(n,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0});return r.ok||await this.handleErrorResponse(r),r.status===204?void 0:r.json()}catch(r){throw r instanceof u?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw u.fromResponse(t,e.status);let s="";throw e.status===401||e.status===403?s=" Check `userJwt` (and that it has not expired).":e.status===404&&(s=" Check that `baseUrl` points at your AGO API root."),new u(`HTTP ${e.status}: ${e.statusText}.${s}`,"http_error",e.status,"api_error")}},C=class{constructor(){this.functions=new Map}register(e,t,s){if(typeof e=="object"){const{name:r,handler:i,description:a,parameters:l}=e;return this.register(r,i,{description:a,parameters:l})}const n=e;if(!t||!s)throw new h(`registerFunction("${n}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`,"function_invalid_registration");this.functions.has(n)&&o.warn(`Function "${n}" is being overwritten`),this.functions.set(n,{schema:{...s,name:n},handler:t}),o.log(`Registered function: ${n}`)}unregister(e){const t=this.functions.delete(e);return t&&o.log(`Unregistered function: ${e}`),t}get(e){return this.functions.get(e)}has(e){return this.functions.has(e)}getSchemas(){return Array.from(this.functions.values()).map(e=>e.schema)}async execute(e,t){const s=this.functions.get(e);if(!s)throw new m(`Function "${e}" is not registered`,e);o.log(`Executing function: ${e}`,t);try{const n=await s.handler(t);return o.log(`Function ${e} completed:`,n),n}catch(n){throw o.error(`Function ${e} failed:`,n),new m(`Function "${e}" execution failed: ${n instanceof Error?n.message:"Unknown error"}`,e,n instanceof Error?n:void 0)}}clear(){this.functions.clear(),o.log("Cleared all registered functions")}get size(){return this.functions.size}},E=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),o.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&o.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),o.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&o.log(`DynamicContext provider removed: ${e}`),t}getSnapshot(){if(this.entries.size===0&&this.dynamicProviders.size===0)return null;const e={};for(const[t,s]of this.entries)e[t]=s;for(const[t,s]of this.dynamicProviders)try{const n=s();n&&(e[t]=n)}catch(n){o.error(`DynamicContext provider "${t}" threw:`,n)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),o.log("ClientContext cleared")}};function f(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(f).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${f(e[t])}`).join(",")}}`}var _=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.firedClientFunctions=new Set}async processStream(e){if(!e.body)throw new g("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.","stream_no_body");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:n,value:r}=await t.read();if(n)break;const i=s.decode(r,{stream:!0});this.buffer+=i,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(n){const r=n instanceof Error?n:new g("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(r),r}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
1
+ var h=class extends Error{constructor(e,t,s){super(e),this.code=t,this.statusCode=s,this.name="AgoError"}},u=class b extends h{constructor(t,s,n,r,i,a){super(t,s,n),this.type=r,this.param=i,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,s){const n=t.error;return new b(n.doc_url?`${n.message} See ${n.doc_url}`:n.message,n.code,s,n.type,n.param,n.doc_url)}},d=class extends h{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},m=class extends h{constructor(e,t="stream_error"){super(e,t),this.name="AgoStreamError"}},g=class extends h{constructor(e,t,s){super(e,"function_error"),this.functionName=t,this.originalError=s,this.name="AgoFunctionError"}},$=class{constructor(e=!1){this.enabled=e}enable(){this.enabled=!0}disable(){this.enabled=!1}log(...e){this.enabled&&console.log("[AGO SDK]",...e)}warn(...e){this.enabled&&console.warn("[AGO SDK]",...e)}error(...e){console.error("[AGO SDK]",...e)}debug(...e){this.enabled&&console.debug("[AGO SDK]",...e)}},o=new $,y="ago_widget_id";function x(){if(typeof localStorage<"u"){const t=localStorage.getItem(y);if(t)return t}const e=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`;if(typeof localStorage<"u")try{localStorage.setItem(y,e)}catch{}return e}var R=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||x()},e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission&&(this.headers["X-Widget-Permission"]=e.permission)}updateConfig(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),e.widgetId&&(this.headers["X-User-Anon-Id"]=e.widgetId),e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission!==void 0&&(e.permission?this.headers["X-Widget-Permission"]=e.permission:delete this.headers["X-Widget-Permission"])}async get(e){return this.request("GET",e)}async post(e,t){return this.request("POST",e,t)}async postStream(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (stream)",s,t);try{const n=await fetch(s,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return n.ok||await this.handleErrorResponse(n),n}catch(n){throw n instanceof u?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,n instanceof Error?n:void 0)}}async postFormData(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (formData)",s);const n={...this.headers};try{const r=await fetch(s,{method:"POST",headers:n,body:t});return r.ok||await this.handleErrorResponse(r),r}catch(r){throw r instanceof u?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async request(e,t,s){const n=`${this.baseUrl}${t}`;o.debug(e,n,s);try{const r=await fetch(n,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0});return r.ok||await this.handleErrorResponse(r),r.status===204?void 0:r.json()}catch(r){throw r instanceof u?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw u.fromResponse(t,e.status);let s="";throw e.status===401||e.status===403?s=" Check `userJwt` (and that it has not expired).":e.status===404&&(s=" Check that `baseUrl` points at your AGO API root."),new u(`HTTP ${e.status}: ${e.statusText}.${s}`,"http_error",e.status,"api_error")}},C=class{constructor(){this.functions=new Map}register(e,t,s){if(typeof e=="object"){const{name:r,handler:i,description:a,parameters:l}=e;return this.register(r,i,{description:a,parameters:l})}const n=e;if(!t||!s)throw new h(`registerFunction("${n}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`,"function_invalid_registration");this.functions.has(n)&&o.warn(`Function "${n}" is being overwritten`),this.functions.set(n,{schema:{...s,name:n},handler:t}),o.log(`Registered function: ${n}`)}unregister(e){const t=this.functions.delete(e);return t&&o.log(`Unregistered function: ${e}`),t}get(e){return this.functions.get(e)}has(e){return this.functions.has(e)}getSchemas(){return Array.from(this.functions.values()).map(e=>e.schema)}async execute(e,t){const s=this.functions.get(e);if(!s)throw new g(`Function "${e}" is not registered`,e);o.log(`Executing function: ${e}`,t);try{const n=await s.handler(t);return o.log(`Function ${e} completed:`,n),n}catch(n){throw o.error(`Function ${e} failed:`,n),new g(`Function "${e}" execution failed: ${n instanceof Error?n.message:"Unknown error"}`,e,n instanceof Error?n:void 0)}}clear(){this.functions.clear(),o.log("Cleared all registered functions")}get size(){return this.functions.size}},E=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),o.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&o.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),o.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&o.log(`DynamicContext provider removed: ${e}`),t}getSnapshot(){if(this.entries.size===0&&this.dynamicProviders.size===0)return null;const e={};for(const[t,s]of this.entries)e[t]=s;for(const[t,s]of this.dynamicProviders)try{const n=s();n&&(e[t]=n)}catch(n){o.error(`DynamicContext provider "${t}" threw:`,n)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),o.log("ClientContext cleared")}};function f(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(f).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${f(e[t])}`).join(",")}}`}var _=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.firedClientFunctions=new Set}async processStream(e){if(!e.body)throw new m("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.","stream_no_body");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:n,value:r}=await t.read();if(n)break;const i=s.decode(r,{stream:!0});this.buffer+=i,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(n){const r=n instanceof Error?n:new m("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(r),r}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
2
2
 
3
3
  `);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const s=t.split(`
4
- `);for(const n of s)if(!n.startsWith(": ")&&n.startsWith("data: ")){const r=n.slice(6);try{const i=JSON.parse(r);this.handleChunk(i)}catch(i){o.warn("Failed to parse SSE data:",r,i)}}}}handleChunk(e){if(this.callbacks.onRawChunk?.(e),e.message_id&&!this.message.id&&(this.message.id=e.message_id),e.thread?.id&&(this.message.conversationId=e.thread.id,this.isFirstChunk&&this.message.id&&(this.isFirstChunk=!1,this.callbacks.onStart?.({conversationId:this.message.conversationId,messageId:this.message.id}))),e.content!==void 0&&(this.message.content=(this.message.content||"")+e.content,this.message.conversationId&&this.message.id&&this.callbacks.onChunk?.({content:e.content,conversationId:this.message.conversationId,messageId:this.message.id})),e.full_content!==void 0&&(this.message.content=e.full_content),e.status&&(this.message.status=e.status),e.agent&&(this.message.agent={id:e.agent.id,name:e.agent.name,displayName:e.agent.display_name}),e.knowledge_sources&&(this.sources=e.knowledge_sources.map(t=>{const s=t.knowledge_document;return{id:s.id,title:s.title,url:s.use_external_link?s.external_link_url:s.internal_link_url}})),e.type==="client_function"&&e.function_name){const t=`${e.function_name}::${f(e.arguments??{})}`;this.firedClientFunctions.has(t)||(this.firedClientFunctions.add(t),this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}))}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(n=>n.id===t.id);s>=0?this.toolCalls[s]=t:this.toolCalls.push(t)}e.follow_up_replies&&(this.followUpReplies=e.follow_up_replies),this.message.status==="DONE"&&!this.answerCompleteEmitted&&this.message.id&&(this.answerCompleteEmitted=!0,this.callbacks.onAnswerComplete?.(this.buildMessage()))}parseToolCall(e){return{id:e.id||"",type:e.type||"status_message",status:e.status||"unknown",toolName:e.tool_name||"",toolDisplayName:e.tool_display_name,message:e.message,formSchema:e.form_schema,data:e.data,functionName:e.function_name,arguments:e.arguments}}buildMessage(){return{id:this.message.id||"",conversationId:this.message.conversationId||"",content:this.message.content||"",role:"assistant",status:this.message.status||"DONE",agent:this.message.agent,sources:this.sources.length>0?this.sources:void 0,toolCalls:this.toolCalls.length>0?this.toolCalls:void 0,followUpReplies:this.followUpReplies.length>0?this.followUpReplies:void 0,createdAt:new Date}}buildFinalMessage(){const e=this.buildMessage();return this.callbacks.onComplete?.(e),e}};function I(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var S=class{constructor(){this.handlers=new Map}on(e,t){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(t)}off(e,t){const s=this.handlers.get(e);s&&s.delete(t)}emit(e,t){const s=this.handlers.get(e);s&&s.forEach(n=>{try{n(t)}catch(r){console.error(`Error in event handler for ${String(e)}:`,r)}})}once(e,t){const s=(n=>{this.off(e,s),t(n)});this.on(e,s)}waitFor(e,t){return new Promise((s,n)=>{let r;const i=(a=>{r&&clearTimeout(r),s(a)});this.once(e,i),t?.timeout&&(r=setTimeout(()=>{this.off(e,i),n(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},w='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).',U=/^[a-z][a-z0-9+.-]*:\/\//i,v=!1;function p(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new h(`${t}: ${w}`,"config_missing_base_url");const s=e.baseUrl;if(typeof s!="string"||s.trim()==="")throw new h(`${t}: ${w}`,"config_missing_base_url");!s.startsWith("/")&&!U.test(s)&&(v||(v=!0,console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)))}var F=class k{constructor(t){this.warnedEmptyConversations=new Set,p(t,"AgoClient"),this.config=t,this.httpClient=new R(t),this.functionRegistry=new C,this.contextRegistry=new E,this.eventEmitter=new S,t.debug&&o.enable(),o.log("AgoClient initialized")}async sendMessage(t,s){const n=this.functionRegistry.getSchemas(),r=this.contextRegistry.getSnapshot(),i=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||i};n.length>0&&(a.client_functions=n),r&&(a.client_context=r);let l;if(s?.files&&s.files.length>0){const c=new FormData;c.append("content",t),s.conversationId&&c.append("conversation_id",s.conversationId),(s.agentId||i)&&c.append("agent_id",s.agentId||i||""),n.length>0&&c.append("client_functions",JSON.stringify(n)),r&&c.append("client_context",JSON.stringify(r));for(const A of s.files)c.append("files",A);l=await this.httpClient.postFormData("/api/sdk/v1/messages",c)}else l=await this.httpClient.postStream("/api/sdk/v1/messages",a);return this.processSSEResponse(l)}async processSSEResponse(t){let s=!1;const n=await new _({onRawChunk:r=>{this.eventEmitter.emit("stream:message",r)},onStart:r=>{this.eventEmitter.emit("message:start",r)},onChunk:r=>{this.eventEmitter.emit("message:chunk",r)},onToolCall:r=>{this.eventEmitter.emit("toolCall:received",r),r.type==="form"&&this.eventEmitter.emit("toolCall:form",r)},onClientFunction:async r=>{s=!0,this.eventEmitter.emit("function:invoke",r),await this.handleClientFunctionInvocation(r)},onAnswerComplete:r=>{this.eventEmitter.emit("message:answer-complete",r)},onComplete:r=>{this.eventEmitter.emit("message:complete",r)},onError:r=>{this.eventEmitter.emit("message:error",{error:r.message,code:r instanceof h?r.code:void 0})}}).processStream(t);return this.maybeFlagEmptyReply(n,s),n}maybeFlagEmptyReply(t,s){t.status==="DONE"&&(t.content??"").trim()===""&&!s&&!(t.toolCalls&&t.toolCalls.length>0)&&!(t.followUpReplies&&t.followUpReplies.length>0)&&setTimeout(()=>{if(this.eventEmitter.emit("message:empty",{conversationId:t.conversationId??"",messageId:t.id??""}),this.config.warnOnEmptyReply===!1)return;const n=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(n))return;this.warnedEmptyConversations.add(n);const r=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(r?`the agent "${r}" may not exist for this tenant, `:"an unknown `agent` slug, ")+"or the agent replied with no text. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`."):console.warn("[AGO] The stream completed without any message data. Possible causes: "+(r?`the agent "${r}" may not exist for this tenant, or `:"")+"`baseUrl` does not point at an AGO endpoint that returns server-sent events. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`.")},0)}async handleClientFunctionInvocation(t){let s,n;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(r){n=r instanceof Error?r.message:"Unknown error",o.error("Client function execution failed:",r)}if(t.invocationId)try{await this.submitToolCallForm(t.invocationId,{result:s,error:n,_type:"client_function_result"})}catch(r){o.error("Failed to submit function result:",r)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:n})}async getConversations(){return(await this.httpClient.get("/api/sdk/v1/conversations")).items.map(t=>({id:t.id,title:t.title,lastMessageDate:new Date(t.last_message_date)}))}async getConversation(t){const s=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),n={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_date),messages:s.messages.map(r=>({id:r.id,conversationId:s.id,content:r.content,role:r.role,status:r.status,createdAt:new Date(r.created_at),toolCalls:k.mapPersistedToolCalls(r.tool_call_data)}))};return this.eventEmitter.emit("conversation:loaded",n),n}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(s=>({id:String(s.id??""),type:s.type??"status_message",status:String(s.status??"unknown"),toolName:s.tool_name??"",toolDisplayName:s.tool_display_name,message:s.message,formSchema:s.form_schema,data:s.data,functionName:s.function_name,arguments:s.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async submitToolCallForm(t,s){await this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:s})}async confirmToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/confirm/`)}async rejectToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/reject/`)}async getFormCollector(t){const s=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:s.name,description:s.description,schema:s.schema,submit:s.submit??void 0}}async submitFormCollector(t,s){return this.httpClient.post("/api/sdk/v1/forms/submit",{name:t,values:s})}async submitFeedback(t,s){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:s})}registerFunction(t,s,n){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,n)}register(t){if(Array.isArray(t))for(const s of t)this.functionRegistry.register(s);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}registerNavigationFunction(t,s){const n=s.map(i=>i.name),r=s.map(i=>`- "${i.name}": ${i.description}`).join(`
4
+ `);for(const n of s)if(!n.startsWith(": ")&&n.startsWith("data: ")){const r=n.slice(6);try{const i=JSON.parse(r);this.handleChunk(i)}catch(i){o.warn("Failed to parse SSE data:",r,i)}}}}handleChunk(e){if(this.callbacks.onRawChunk?.(e),e.message_id&&!this.message.id&&(this.message.id=e.message_id),e.thread?.id&&(this.message.conversationId=e.thread.id,this.isFirstChunk&&this.message.id&&(this.isFirstChunk=!1,this.callbacks.onStart?.({conversationId:this.message.conversationId,messageId:this.message.id}))),e.content!==void 0&&(this.message.content=(this.message.content||"")+e.content,this.message.conversationId&&this.message.id&&this.callbacks.onChunk?.({content:e.content,conversationId:this.message.conversationId,messageId:this.message.id})),e.full_content!==void 0&&(this.message.content=e.full_content),e.status&&(this.message.status=e.status),e.agent&&(this.message.agent={id:e.agent.id,name:e.agent.name,displayName:e.agent.display_name}),e.knowledge_sources&&(this.sources=e.knowledge_sources.map(t=>{const s=t.knowledge_document;return{id:s.id,title:s.title,url:s.use_external_link?s.external_link_url:s.internal_link_url}})),e.type==="client_function"&&e.function_name){const t=`${e.function_name}::${f(e.arguments??{})}`;this.firedClientFunctions.has(t)||(this.firedClientFunctions.add(t),this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}))}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(n=>n.id===t.id);s>=0?this.toolCalls[s]=t:this.toolCalls.push(t)}e.follow_up_replies&&(this.followUpReplies=e.follow_up_replies),this.message.status==="DONE"&&!this.answerCompleteEmitted&&this.message.id&&(this.answerCompleteEmitted=!0,this.callbacks.onAnswerComplete?.(this.buildMessage()))}parseToolCall(e){return{id:e.id||"",type:e.type||"status_message",status:e.status||"unknown",toolName:e.tool_name||"",toolDisplayName:e.tool_display_name,message:e.message,formSchema:e.form_schema,data:e.data,functionName:e.function_name,arguments:e.arguments}}buildMessage(){return{id:this.message.id||"",conversationId:this.message.conversationId||"",content:this.message.content||"",role:"assistant",status:this.message.status||"DONE",agent:this.message.agent,sources:this.sources.length>0?this.sources:void 0,toolCalls:this.toolCalls.length>0?this.toolCalls:void 0,followUpReplies:this.followUpReplies.length>0?this.followUpReplies:void 0,createdAt:new Date}}buildFinalMessage(){const e=this.buildMessage();return this.callbacks.onComplete?.(e),e}};function I(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var S=class{constructor(){this.handlers=new Map}on(e,t){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(t)}off(e,t){const s=this.handlers.get(e);s&&s.delete(t)}emit(e,t){const s=this.handlers.get(e);s&&s.forEach(n=>{try{n(t)}catch(r){console.error(`Error in event handler for ${String(e)}:`,r)}})}once(e,t){const s=(n=>{this.off(e,s),t(n)});this.on(e,s)}waitFor(e,t){return new Promise((s,n)=>{let r;const i=(a=>{r&&clearTimeout(r),s(a)});this.once(e,i),t?.timeout&&(r=setTimeout(()=>{this.off(e,i),n(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},w='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).',F=/^[a-z][a-z0-9+.-]*:\/\//i,v=!1;function p(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new h(`${t}: ${w}`,"config_missing_base_url");const s=e.baseUrl;if(typeof s!="string"||s.trim()==="")throw new h(`${t}: ${w}`,"config_missing_base_url");!s.startsWith("/")&&!F.test(s)&&(v||(v=!0,console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)))}var U=class k{constructor(t){this.warnedEmptyConversations=new Set,p(t,"AgoClient"),this.config=t,this.httpClient=new R(t),this.functionRegistry=new C,this.contextRegistry=new E,this.eventEmitter=new S,t.debug&&o.enable(),o.log("AgoClient initialized")}async sendMessage(t,s){const n=this.functionRegistry.getSchemas(),r=this.contextRegistry.getSnapshot(),i=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||i};n.length>0&&(a.client_functions=n),r&&(a.client_context=r);let l;if(s?.files&&s.files.length>0){const c=new FormData;c.append("content",t),s.conversationId&&c.append("conversation_id",s.conversationId),(s.agentId||i)&&c.append("agent_id",s.agentId||i||""),n.length>0&&c.append("client_functions",JSON.stringify(n)),r&&c.append("client_context",JSON.stringify(r));for(const A of s.files)c.append("files",A);l=await this.httpClient.postFormData("/api/sdk/v1/messages",c)}else l=await this.httpClient.postStream("/api/sdk/v1/messages",a);return this.processSSEResponse(l)}async processSSEResponse(t){let s=!1;const n=await new _({onRawChunk:r=>{this.eventEmitter.emit("stream:message",r)},onStart:r=>{this.eventEmitter.emit("message:start",r)},onChunk:r=>{this.eventEmitter.emit("message:chunk",r)},onToolCall:r=>{this.eventEmitter.emit("toolCall:received",r),r.type==="form"&&this.eventEmitter.emit("toolCall:form",r)},onClientFunction:async r=>{s=!0,this.eventEmitter.emit("function:invoke",r),await this.handleClientFunctionInvocation(r)},onAnswerComplete:r=>{this.eventEmitter.emit("message:answer-complete",r)},onComplete:r=>{this.eventEmitter.emit("message:complete",r)},onError:r=>{this.eventEmitter.emit("message:error",{error:r.message,code:r instanceof h?r.code:void 0})}}).processStream(t);return this.maybeFlagEmptyReply(n,s),n}maybeFlagEmptyReply(t,s){t.status==="DONE"&&(t.content??"").trim()===""&&!s&&!(t.toolCalls&&t.toolCalls.length>0)&&!(t.followUpReplies&&t.followUpReplies.length>0)&&setTimeout(()=>{if(this.eventEmitter.emit("message:empty",{conversationId:t.conversationId??"",messageId:t.id??""}),this.config.warnOnEmptyReply===!1)return;const n=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(n))return;this.warnedEmptyConversations.add(n);const r=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(r?`the agent "${r}" may not exist for this tenant, `:"an unknown `agent` slug, ")+"or the agent replied with no text. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`."):console.warn("[AGO] The stream completed without any message data. Possible causes: "+(r?`the agent "${r}" may not exist for this tenant, or `:"")+"`baseUrl` does not point at an AGO endpoint that returns server-sent events. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`.")},0)}async handleClientFunctionInvocation(t){let s,n;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(r){n=r instanceof Error?r.message:"Unknown error",o.error("Client function execution failed:",r)}if(t.invocationId)try{await this.submitToolCallForm(t.invocationId,{result:s,error:n,_type:"client_function_result"})}catch(r){o.error("Failed to submit function result:",r)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:n})}async getConversations(){return(await this.httpClient.get("/api/sdk/v1/conversations")).items.map(t=>({id:t.id,title:t.title,lastMessageDate:new Date(t.last_message_date)}))}async getConversation(t){const s=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),n={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_date),messages:s.messages.map(r=>({id:r.id,conversationId:s.id,content:r.content,role:r.role,status:r.status,createdAt:new Date(r.created_at),toolCalls:k.mapPersistedToolCalls(r.tool_call_data)}))};return this.eventEmitter.emit("conversation:loaded",n),n}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(s=>({id:String(s.id??""),type:s.type??"status_message",status:String(s.status??"unknown"),toolName:s.tool_name??"",toolDisplayName:s.tool_display_name,message:s.message,formSchema:s.form_schema,data:s.data,functionName:s.function_name,arguments:s.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async submitToolCallForm(t,s){await this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:s})}async confirmToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/confirm/`)}async rejectToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/reject/`)}async getFormCollector(t){const s=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:s.name,description:s.description,schema:s.schema,submit:s.submit??void 0}}async submitFormCollector(t,s){return this.httpClient.post("/api/sdk/v1/forms/submit",{name:t,values:s})}async submitFeedback(t,s){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:s})}registerFunction(t,s,n){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,n)}register(t){if(Array.isArray(t))for(const s of t)this.functionRegistry.register(s);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}registerNavigationFunction(t,s){const n=s.map(i=>i.name),r=s.map(i=>`- "${i.name}": ${i.description}`).join(`
5
5
  `);this.registerFunction("navigateToPage",async i=>{const a=i.page,l=s.find(c=>c.name===a);return l?(t(l.path),{success:!0,navigatedTo:l.path}):{success:!1,error:`Unknown page: ${a}`}},{description:`Navigate the user to a page in the application. Available pages:
6
- ${r}`,parameters:{type:"object",properties:{page:{type:"string",description:"The page to navigate to",enum:n}},required:["page"]}})}setContext(t,s){this.contextRegistry.set(t,s),this.notifyContextChanged()}removeContext(t){const s=this.contextRegistry.remove(t);return s&&this.notifyContextChanged(),s}addDynamicContext(t,s){this.contextRegistry.addDynamicProvider(t,s),this.notifyContextChanged()}removeDynamicContext(t){const s=this.contextRegistry.removeDynamicProvider(t);return s&&this.notifyContextChanged(),s}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}enableAutoPageContext(){this.addDynamicContext("browser-page",()=>{const t=typeof window<"u"?window.location.href:void 0,s=typeof document<"u"?document.title:void 0;return!t&&!s?null:{name:"Browser page",description:"Current page the user is viewing",data:{url:t,title:s}}})}getContextSnapshot(){return this.contextRegistry.getSnapshot()}on(t,s){this.eventEmitter.on(t,s)}off(t,s){this.eventEmitter.off(t,s)}once(t,s){this.eventEmitter.once(t,s)}waitFor(t,s){return this.eventEmitter.waitFor(t,s)}updateConfig(t){const s={};for(const[r,i]of Object.entries(t))i!==void 0&&(s[r]=i);const n={...this.config,...s};p(n,"AgoClient.updateConfig"),this.config=n,this.httpClient.updateConfig(s),s.debug!==void 0&&(s.debug?o.enable():o.disable())}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),o.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return u}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return F}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"AgoFunctionError",{enumerable:!0,get:function(){return m}});Object.defineProperty(exports,"AgoNetworkError",{enumerable:!0,get:function(){return d}});Object.defineProperty(exports,"AgoStreamError",{enumerable:!0,get:function(){return g}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return E}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return S}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return C}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return I}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return o}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return p}});
6
+ ${r}`,parameters:{type:"object",properties:{page:{type:"string",description:"The page to navigate to",enum:n}},required:["page"]}})}setContext(t,s){this.contextRegistry.set(t,s),this.notifyContextChanged()}removeContext(t){const s=this.contextRegistry.remove(t);return s&&this.notifyContextChanged(),s}addDynamicContext(t,s){this.contextRegistry.addDynamicProvider(t,s),this.notifyContextChanged()}removeDynamicContext(t){const s=this.contextRegistry.removeDynamicProvider(t);return s&&this.notifyContextChanged(),s}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}emitFormEvent(t,s){this.eventEmitter.emit(t,s)}enableAutoPageContext(){this.addDynamicContext("browser-page",()=>{const t=typeof window<"u"?window.location.href:void 0,s=typeof document<"u"?document.title:void 0;return!t&&!s?null:{name:"Browser page",description:"Current page the user is viewing",data:{url:t,title:s}}})}getContextSnapshot(){return this.contextRegistry.getSnapshot()}on(t,s){this.eventEmitter.on(t,s)}off(t,s){this.eventEmitter.off(t,s)}once(t,s){this.eventEmitter.once(t,s)}waitFor(t,s){return this.eventEmitter.waitFor(t,s)}updateConfig(t){const s={};for(const[r,i]of Object.entries(t))i!==void 0&&(s[r]=i);const n={...this.config,...s};p(n,"AgoClient.updateConfig"),this.config=n,this.httpClient.updateConfig(s),s.debug!==void 0&&(s.debug?o.enable():o.disable())}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),o.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return u}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return U}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"AgoFunctionError",{enumerable:!0,get:function(){return g}});Object.defineProperty(exports,"AgoNetworkError",{enumerable:!0,get:function(){return d}});Object.defineProperty(exports,"AgoStreamError",{enumerable:!0,get:function(){return m}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return E}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return S}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return C}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return I}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return o}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return p}});
@@ -595,6 +595,9 @@ ${i}`,
595
595
  notifyContextChanged() {
596
596
  this.eventEmitter.emit("context:changed", this.contextRegistry.getSnapshot());
597
597
  }
598
+ emitFormEvent(t, s) {
599
+ this.eventEmitter.emit(t, s);
600
+ }
598
601
  enableAutoPageContext() {
599
602
  this.addDynamicContext("browser-page", () => {
600
603
  const t = typeof window < "u" ? window.location.href : void 0, s = typeof document < "u" ? document.title : void 0;
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient--y10UXUV.cjs");var n=class{constructor(e){this.client=new o.AgoClient(e),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(e){const t=this.client;return{subscribe(i){const s=r=>{i.next?.(r)};return t.on(e,s),{unsubscribe:()=>t.off(e,s)}}}}sendMessage(e,t){return this.client.sendMessage(e,t)}getConversations(){return this.client.getConversations()}getConversation(e){return this.client.getConversation(e)}getMessages(e){return this.client.getMessages(e)}submitToolCallForm(e,t){return this.client.submitToolCallForm(e,t)}confirmToolCall(e){return this.client.confirmToolCall(e)}rejectToolCall(e){return this.client.rejectToolCall(e)}submitFeedback(e,t){return this.client.submitFeedback(e,t)}registerFunction(e,t,i){typeof e=="object"?this.client.registerFunction(e):this.client.registerFunction(e,t,i)}unregisterFunction(e){return this.client.unregisterFunction(e)}registerNavigationFunction(e,t){this.client.registerNavigationFunction(e,t)}on(e,t){this.client.on(e,t)}off(e,t){this.client.off(e,t)}updateConfig(e){this.client.updateConfig(e)}getClient(){return this.client}destroy(){this.client.destroy()}};function c(e){return{provide:n,useValue:new n(e)}}exports.AgoService=n;exports.provideAgo=c;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-B3-WGVne.cjs");var n=class{constructor(e){this.client=new o.AgoClient(e),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(e){const t=this.client;return{subscribe(i){const s=r=>{i.next?.(r)};return t.on(e,s),{unsubscribe:()=>t.off(e,s)}}}}sendMessage(e,t){return this.client.sendMessage(e,t)}getConversations(){return this.client.getConversations()}getConversation(e){return this.client.getConversation(e)}getMessages(e){return this.client.getMessages(e)}submitToolCallForm(e,t){return this.client.submitToolCallForm(e,t)}confirmToolCall(e){return this.client.confirmToolCall(e)}rejectToolCall(e){return this.client.rejectToolCall(e)}submitFeedback(e,t){return this.client.submitFeedback(e,t)}registerFunction(e,t,i){typeof e=="object"?this.client.registerFunction(e):this.client.registerFunction(e,t,i)}unregisterFunction(e){return this.client.unregisterFunction(e)}registerNavigationFunction(e,t){this.client.registerNavigationFunction(e,t)}on(e,t){this.client.on(e,t)}off(e,t){this.client.off(e,t)}updateConfig(e){this.client.updateConfig(e)}getClient(){return this.client}destroy(){this.client.destroy()}};function c(e){return{provide:n,useValue:new n(e)}}exports.AgoService=n;exports.provideAgo=c;
@@ -176,6 +176,7 @@ declare class AgoClient {
176
176
  * call it when their store updates so observers like the dev panel stay live.
177
177
  */
178
178
  notifyContextChanged(): void;
179
+ /* Excluded from this release type: emitFormEvent */
179
180
  /**
180
181
  * Enable automatic capture of the current browser page (URL + title).
181
182
  * Injected as a dynamic context entry named `browser-page`.
@@ -290,6 +291,27 @@ export declare interface AgoClientEvents {
290
291
  result: unknown;
291
292
  error?: string;
292
293
  };
294
+ /**
295
+ * A form collector submitted successfully. `result` is the raw submit response
296
+ * (POST body / handler return value / backend relay result) — the third-party
297
+ * API's answer. `values` is the submitted field set, `name` the collector name.
298
+ */
299
+ "form:submitted": {
300
+ name: string;
301
+ values: Record<string, unknown>;
302
+ result: unknown;
303
+ };
304
+ /**
305
+ * A form collector submit was attempted and failed at the network/server level
306
+ * (HTTP non-2xx, or a thrown handler/fetch). `error` is the message. Validation
307
+ * pre-checks (missing required fields, no submit target) are NOT errors and do
308
+ * not fire this — they are returned to the caller as `{ ok: false }`.
309
+ */
310
+ "form:error": {
311
+ name: string;
312
+ values: Record<string, unknown>;
313
+ error: string;
314
+ };
293
315
  "connection:status": {
294
316
  connected: boolean;
295
317
  };
package/dist/angular.d.ts CHANGED
@@ -176,6 +176,7 @@ declare class AgoClient {
176
176
  * call it when their store updates so observers like the dev panel stay live.
177
177
  */
178
178
  notifyContextChanged(): void;
179
+ /* Excluded from this release type: emitFormEvent */
179
180
  /**
180
181
  * Enable automatic capture of the current browser page (URL + title).
181
182
  * Injected as a dynamic context entry named `browser-page`.
@@ -290,6 +291,27 @@ export declare interface AgoClientEvents {
290
291
  result: unknown;
291
292
  error?: string;
292
293
  };
294
+ /**
295
+ * A form collector submitted successfully. `result` is the raw submit response
296
+ * (POST body / handler return value / backend relay result) — the third-party
297
+ * API's answer. `values` is the submitted field set, `name` the collector name.
298
+ */
299
+ "form:submitted": {
300
+ name: string;
301
+ values: Record<string, unknown>;
302
+ result: unknown;
303
+ };
304
+ /**
305
+ * A form collector submit was attempted and failed at the network/server level
306
+ * (HTTP non-2xx, or a thrown handler/fetch). `error` is the message. Validation
307
+ * pre-checks (missing required fields, no submit target) are NOT errors and do
308
+ * not fire this — they are returned to the caller as `{ ok: false }`.
309
+ */
310
+ "form:error": {
311
+ name: string;
312
+ values: Record<string, unknown>;
313
+ error: string;
314
+ };
293
315
  "connection:status": {
294
316
  connected: boolean;
295
317
  };
package/dist/angular.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as o } from "./AgoClient-DYdIe_R4.js";
1
+ import { t as o } from "./AgoClient-QcTtrN7u.js";
2
2
  var n = class {
3
3
  constructor(t) {
4
4
  this.client = new o(t), this.messages$ = this.fromEvent("message:complete"), this.chunks$ = this.fromEvent("message:chunk"), this.errors$ = this.fromEvent("message:error"), this.messageStart$ = this.fromEvent("message:start");
@@ -1 +1 @@
1
- const d=require("./createFormCollector-DWzGKDwO.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),c=o.get();c.value!==null&&s(c.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function s(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||s(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
1
+ const d=require("./createFormCollector-BHHEW6uX.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),c=o.get();c.value!==null&&s(c.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function s(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||s(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
@@ -1,4 +1,4 @@
1
- import { i as d } from "./createFormCollector-BwM7qTrp.js";
1
+ import { i as d } from "./createFormCollector-QyojCH_-.js";
2
2
  var f = "ago_widget_id", g = "ago_last_thread", y = 7200 * 1e3;
3
3
  function v() {
4
4
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
@@ -0,0 +1 @@
1
+ const w=require("./AgoClient-B3-WGVne.cjs");function W(s,e){const a=e?e.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let n=s;if(e&&a)try{const m=a.getItem(e.key);m!=null&&(n=JSON.parse(m))}catch{}const i=new Set,c=()=>i.forEach(m=>m(n));function b(){if(e&&a)try{a.setItem(e.key,JSON.stringify(n))}catch{}}return{get:()=>n,set:m=>{n=m,b(),c()},subscribe:m=>(i.add(m),()=>{i.delete(m)})}}var T=/^[a-zA-Z0-9_-]{1,40}$/,x=s=>s==null||s==="";function j(s,e){const a=e[s.property];if(x(a))return!1;if(Array.isArray(s.value))return s.value.some(c=>String(a)===String(c));if(!s.op)return String(a)===String(s.value);const n=Number(a),i=Number(s.value);if(Number.isNaN(n)||Number.isNaN(i))return!1;switch(s.op){case">=":return n>=i;case"<=":return n<=i;case">":return n>i;case"<":return n<i;default:return w.logger.warn(`Unknown requiredWhen op "${s.op}"; treating as not required.`),!1}}function h(s,e){const a=s.properties??{},n=new Set;for(const c of s.required??[]){const b=a[c]?.requiredWhen;(!b||j(b,e))&&n.add(c)}for(const[c,b]of Object.entries(a))b.requiredWhen&&j(b.requiredWhen,e)&&n.add(c);const i=[...n].filter(c=>x(e[c]));return{missing:i,complete:i.length===0}}function R(s){const e={};for(const[a,n]of Object.entries(s.properties??{}))e[a]={type:n.type,...n.description!=null&&{description:n.description},...n.enum&&{enum:n.enum},...n.default!==void 0&&{default:n.default}};return{type:"object",properties:e,required:[]}}function A(s){const{name:e,description:a,schema:n}=s;if(!T.test(e))throw new Error(`Invalid form collector name "${e}": must match ${T} (it becomes the update_/submit_ function names).`);const i=typeof s.submit=="string"?s.submit?{via:"client",url:s.submit}:!1:s.submit??!1;s.autoSubmit===!0&&!i&&w.logger.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);const c=(s.autoSubmit??!0)&&!!i,b=n.properties??{},m=t=>{const r={};for(const[u,o]of Object.entries(t)){const l=b[u];if(l)if(o==null)r[u]=o;else if(l.type==="number"||l.type==="integer"){const d=typeof o=="number"?o:Number(o);r[u]=Number.isNaN(d)?o:d}else l.type==="boolean"?r[u]=typeof o=="boolean"?o:o==="true"?!0:o==="false"?!1:!!o:r[u]=o}return r},v=s.initialValues??{},f=W({values:v,submitted:!1}),C=t=>{const r=f.get(),u={...r,values:{...r.values,...t}};return f.set(u),u};let g=null;const $=(t,r)=>{g?.emitFormEvent("form:error",{name:e,values:t,error:r})};let p=null;const I=async()=>{const{values:t}=f.get(),{complete:r,missing:u}=h(n,t);if(!r)return{ok:!1,missing:u};if(!i)return{ok:!1,error:"No submit target configured for this form collector."};const o=t;try{let l;if(i.via==="client")if("handler"in i)l=await i.handler(o);else{const d=await fetch(i.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(o)});if(!d.ok){const P=`Submit failed: HTTP ${d.status}`;return $(o,P),{ok:!1,error:P}}l=await d.json().catch(()=>{})}else{if(!g)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};l=await g.submitFormCollector(e,o)}return f.set({...f.get(),submitted:!0,submitResult:l}),g?.emitFormEvent("form:submitted",{name:e,values:o,result:l}),{ok:!0,result:l}}catch(l){const d=l instanceof Error?l.message:"Submit failed";return w.logger.error(`FormCollector "${e}" submit failed:`,l),$(o,d),{ok:!1,error:d}}},S=()=>p||(p=(async()=>{try{return await I()}finally{p=null}})(),p),F=async()=>{if(!c||!i)return null;const{values:t,submitted:r}=f.get();return r||!h(n,t).complete?null:S()},k={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${a} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,parameters:R(n),handler:async t=>{const r=C(m(t)),{missing:u}=h(n,r.values),o=await F();return o?o.ok?{ok:!0,values:r.values,missing:u,submitted:!0}:{ok:!0,values:r.values,missing:u,submitted:!1,submitError:o.error}:{ok:!0,values:r.values,missing:u}}},y=[k];i&&!c&&y.push({name:`submit_${e}`,description:`Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,parameters:{type:"object",properties:{}},handler:()=>S()});const V="client__",q=i?`submit_${e}`:null,J=t=>{const r=t.functionName??t.toolName;if(r)return r.startsWith(V)?r.slice(8):r},O=t=>{let r={...v},u=!1;for(const o of t){const l=J(o);l===k.name?o.arguments&&(r={...r,...m(o.arguments)}):q&&l===q&&o.status?.toLowerCase()==="done"&&(u=!0)}f.set({values:r,submitted:u})},N=`form:${e}`,_=()=>{const{values:t,submitted:r}=f.get(),{missing:u,complete:o}=h(n,t),l=i?c?" The form is submitted automatically as soon as every required field is filled, so there is no submit function to call.":` When nothing is missing and the user confirms, call submit_${e}.`:"",d=r?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${d} ${a} There are conditionnals questions/values to collected, you can find this information with the requiredWhen field in the form. The form schema is the following: ${JSON.stringify(n)}. Data collected so far: ${JSON.stringify(t)}. Call update_${e} with any fields the user provides; ask only for what is still missing.${l}`,data:{values:t,missing:u,complete:o,submitted:r}}},E=t=>{O((t.messages??[]).flatMap(r=>r.toolCalls??[]))};return{name:e,store:f,functions:y,contextKey:N,contextProvider:_,install:t=>{g=t;for(const u of y)t.register(u);t.addDynamicContext(N,_);const r=f.subscribe(()=>t.notifyContextChanged());return t.on("conversation:loaded",E),()=>{r();for(const u of y)t.unregisterFunction(u.name);t.removeDynamicContext(N),t.off("conversation:loaded",E),g===t&&(g=null)}},hydrate:O,submit:S,getValues:()=>f.get().values,setValues:t=>{C(m(t)),F()},reset:()=>{f.set({values:v,submitted:!1})},getStatus:()=>h(n,f.get().values)}}async function B(s,e){const a=await s.getFormCollector(e.name);return A({name:a.name,description:e.description??a.description,schema:e.schema??a.schema,submit:e.submit??a.submit,initialValues:e.initialValues,autoSubmit:e.autoSubmit??a.autoSubmit})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return A}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return W}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return B}});
@@ -1,13 +1,13 @@
1
- import { c as N } from "./AgoClient-DYdIe_R4.js";
2
- function W(n, e) {
1
+ import { c as w } from "./AgoClient-QcTtrN7u.js";
2
+ function A(o, e) {
3
3
  const a = e ? e.storage ?? (typeof localStorage < "u" ? localStorage : void 0) : void 0;
4
- let s = n;
4
+ let s = o;
5
5
  if (e && a) try {
6
- const f = a.getItem(e.key);
7
- f != null && (s = JSON.parse(f));
6
+ const m = a.getItem(e.key);
7
+ m != null && (s = JSON.parse(m));
8
8
  } catch {
9
9
  }
10
- const i = /* @__PURE__ */ new Set(), c = () => i.forEach((f) => f(s));
10
+ const i = /* @__PURE__ */ new Set(), c = () => i.forEach((m) => m(s));
11
11
  function b() {
12
12
  if (e && a) try {
13
13
  a.setItem(e.key, JSON.stringify(s));
@@ -16,23 +16,23 @@ function W(n, e) {
16
16
  }
17
17
  return {
18
18
  get: () => s,
19
- set: (f) => {
20
- s = f, b(), c();
19
+ set: (m) => {
20
+ s = m, b(), c();
21
21
  },
22
- subscribe: (f) => (i.add(f), () => {
23
- i.delete(f);
22
+ subscribe: (m) => (i.add(m), () => {
23
+ i.delete(m);
24
24
  })
25
25
  };
26
26
  }
27
- var T = /^[a-zA-Z0-9_-]{1,40}$/, E = (n) => n == null || n === "";
28
- function O(n, e) {
29
- const a = e[n.property];
30
- if (E(a)) return !1;
31
- if (Array.isArray(n.value)) return n.value.some((c) => String(a) === String(c));
32
- if (!n.op) return String(a) === String(n.value);
33
- const s = Number(a), i = Number(n.value);
27
+ var x = /^[a-zA-Z0-9_-]{1,40}$/, W = (o) => o == null || o === "";
28
+ function P(o, e) {
29
+ const a = e[o.property];
30
+ if (W(a)) return !1;
31
+ if (Array.isArray(o.value)) return o.value.some((c) => String(a) === String(c));
32
+ if (!o.op) return String(a) === String(o.value);
33
+ const s = Number(a), i = Number(o.value);
34
34
  if (Number.isNaN(s) || Number.isNaN(i)) return !1;
35
- switch (n.op) {
35
+ switch (o.op) {
36
36
  case ">=":
37
37
  return s >= i;
38
38
  case "<=":
@@ -42,25 +42,25 @@ function O(n, e) {
42
42
  case "<":
43
43
  return s < i;
44
44
  default:
45
- return N.warn(`Unknown requiredWhen op "${n.op}"; treating as not required.`), !1;
45
+ return w.warn(`Unknown requiredWhen op "${o.op}"; treating as not required.`), !1;
46
46
  }
47
47
  }
48
- function p(n, e) {
49
- const a = n.properties ?? {}, s = /* @__PURE__ */ new Set();
50
- for (const c of n.required ?? []) {
48
+ function g(o, e) {
49
+ const a = o.properties ?? {}, s = /* @__PURE__ */ new Set();
50
+ for (const c of o.required ?? []) {
51
51
  const b = a[c]?.requiredWhen;
52
- (!b || O(b, e)) && s.add(c);
52
+ (!b || P(b, e)) && s.add(c);
53
53
  }
54
- for (const [c, b] of Object.entries(a)) b.requiredWhen && O(b.requiredWhen, e) && s.add(c);
55
- const i = [...s].filter((c) => E(e[c]));
54
+ for (const [c, b] of Object.entries(a)) b.requiredWhen && P(b.requiredWhen, e) && s.add(c);
55
+ const i = [...s].filter((c) => W(e[c]));
56
56
  return {
57
57
  missing: i,
58
58
  complete: i.length === 0
59
59
  };
60
60
  }
61
- function j(n) {
61
+ function J(o) {
62
62
  const e = {};
63
- for (const [a, s] of Object.entries(n.properties ?? {})) e[a] = {
63
+ for (const [a, s] of Object.entries(o.properties ?? {})) e[a] = {
64
64
  type: s.type,
65
65
  ...s.description != null && { description: s.description },
66
66
  ...s.enum && { enum: s.enum },
@@ -72,42 +72,50 @@ function j(n) {
72
72
  required: []
73
73
  };
74
74
  }
75
- function I(n) {
76
- const { name: e, description: a, schema: s } = n;
77
- if (!T.test(e)) throw new Error(`Invalid form collector name "${e}": must match ${T} (it becomes the update_/submit_ function names).`);
78
- const i = typeof n.submit == "string" ? n.submit ? {
75
+ function R(o) {
76
+ const { name: e, description: a, schema: s } = o;
77
+ if (!x.test(e)) throw new Error(`Invalid form collector name "${e}": must match ${x} (it becomes the update_/submit_ function names).`);
78
+ const i = typeof o.submit == "string" ? o.submit ? {
79
79
  via: "client",
80
- url: n.submit
81
- } : !1 : n.submit ?? !1;
82
- n.autoSubmit === !0 && !i && N.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);
83
- const c = (n.autoSubmit ?? !0) && !!i, b = s.properties ?? {}, f = (t) => {
80
+ url: o.submit
81
+ } : !1 : o.submit ?? !1;
82
+ o.autoSubmit === !0 && !i && w.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);
83
+ const c = (o.autoSubmit ?? !0) && !!i, b = s.properties ?? {}, m = (t) => {
84
84
  const r = {};
85
- for (const [u, o] of Object.entries(t)) {
85
+ for (const [u, n] of Object.entries(t)) {
86
86
  const l = b[u];
87
87
  if (l)
88
- if (o == null) r[u] = o;
88
+ if (n == null) r[u] = n;
89
89
  else if (l.type === "number" || l.type === "integer") {
90
- const d = typeof o == "number" ? o : Number(o);
91
- r[u] = Number.isNaN(d) ? o : d;
92
- } else l.type === "boolean" ? r[u] = typeof o == "boolean" ? o : o === "true" ? !0 : o === "false" ? !1 : !!o : r[u] = o;
90
+ const d = typeof n == "number" ? n : Number(n);
91
+ r[u] = Number.isNaN(d) ? n : d;
92
+ } else l.type === "boolean" ? r[u] = typeof n == "boolean" ? n : n === "true" ? !0 : n === "false" ? !1 : !!n : r[u] = n;
93
93
  }
94
94
  return r;
95
- }, y = n.initialValues ?? {}, m = W({
96
- values: y,
95
+ }, v = o.initialValues ?? {}, f = A({
96
+ values: v,
97
97
  submitted: !1
98
98
  }), $ = (t) => {
99
- const r = m.get(), u = {
99
+ const r = f.get(), u = {
100
100
  ...r,
101
101
  values: {
102
102
  ...r.values,
103
103
  ...t
104
104
  }
105
105
  };
106
- return m.set(u), u;
106
+ return f.set(u), u;
107
107
  };
108
108
  let h = null;
109
- const v = async () => {
110
- const { values: t } = m.get(), { complete: r, missing: u } = p(s, t);
109
+ const C = (t, r) => {
110
+ h?.emitFormEvent("form:error", {
111
+ name: e,
112
+ values: t,
113
+ error: r
114
+ });
115
+ };
116
+ let p = null;
117
+ const j = async () => {
118
+ const { values: t } = f.get(), { complete: r, missing: u } = g(s, t);
111
119
  if (!r) return {
112
120
  ok: !1,
113
121
  missing: u
@@ -116,21 +124,24 @@ function I(n) {
116
124
  ok: !1,
117
125
  error: "No submit target configured for this form collector."
118
126
  };
119
- const o = t;
127
+ const n = t;
120
128
  try {
121
129
  let l;
122
- if (i.via === "client") if ("handler" in i) l = await i.handler(o);
130
+ if (i.via === "client") if ("handler" in i) l = await i.handler(n);
123
131
  else {
124
132
  const d = await fetch(i.url, {
125
133
  method: "POST",
126
134
  headers: { "Content-Type": "application/json" },
127
135
  credentials: "include",
128
- body: JSON.stringify(o)
136
+ body: JSON.stringify(n)
129
137
  });
130
- if (!d.ok) return {
131
- ok: !1,
132
- error: `Submit failed: HTTP ${d.status}`
133
- };
138
+ if (!d.ok) {
139
+ const O = `Submit failed: HTTP ${d.status}`;
140
+ return C(n, O), {
141
+ ok: !1,
142
+ error: O
143
+ };
144
+ }
134
145
  l = await d.json().catch(() => {
135
146
  });
136
147
  }
@@ -139,34 +150,44 @@ function I(n) {
139
150
  ok: !1,
140
151
  error: "Backend submit requires install(client) (or useFormCollector) first."
141
152
  };
142
- l = await h.submitFormCollector(e, o);
153
+ l = await h.submitFormCollector(e, n);
143
154
  }
144
- return m.set({
145
- ...m.get(),
155
+ return f.set({
156
+ ...f.get(),
146
157
  submitted: !0,
147
158
  submitResult: l
159
+ }), h?.emitFormEvent("form:submitted", {
160
+ name: e,
161
+ values: n,
162
+ result: l
148
163
  }), {
149
164
  ok: !0,
150
165
  result: l
151
166
  };
152
167
  } catch (l) {
153
168
  const d = l instanceof Error ? l.message : "Submit failed";
154
- return N.error(`FormCollector "${e}" submit failed:`, l), {
169
+ return w.error(`FormCollector "${e}" submit failed:`, l), C(n, d), {
155
170
  ok: !1,
156
171
  error: d
157
172
  };
158
173
  }
159
- }, w = async () => {
174
+ }, S = () => p || (p = (async () => {
175
+ try {
176
+ return await j();
177
+ } finally {
178
+ p = null;
179
+ }
180
+ })(), p), k = async () => {
160
181
  if (!c || !i) return null;
161
- const { values: t, submitted: r } = m.get();
162
- return r || !p(s, t).complete ? null : v();
163
- }, C = {
182
+ const { values: t, submitted: r } = f.get();
183
+ return r || !g(s, t).complete ? null : S();
184
+ }, F = {
164
185
  name: `update_${e}`,
165
186
  description: `Fill or update fields of the "${e}" form. ${a} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,
166
- parameters: j(s),
187
+ parameters: J(s),
167
188
  handler: async (t) => {
168
- const r = $(f(t)), { missing: u } = p(s, r.values), o = await w();
169
- return o ? o.ok ? {
189
+ const r = $(m(t)), { missing: u } = g(s, r.values), n = await k();
190
+ return n ? n.ok ? {
170
191
  ok: !0,
171
192
  values: r.values,
172
193
  missing: u,
@@ -176,90 +197,90 @@ function I(n) {
176
197
  values: r.values,
177
198
  missing: u,
178
199
  submitted: !1,
179
- submitError: o.error
200
+ submitError: n.error
180
201
  } : {
181
202
  ok: !0,
182
203
  values: r.values,
183
204
  missing: u
184
205
  };
185
206
  }
186
- }, g = [C];
187
- i && !c && g.push({
207
+ }, y = [F];
208
+ i && !c && y.push({
188
209
  name: `submit_${e}`,
189
210
  description: `Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,
190
211
  parameters: {
191
212
  type: "object",
192
213
  properties: {}
193
214
  },
194
- handler: () => v()
215
+ handler: () => S()
195
216
  });
196
- const x = "client__", k = i ? `submit_${e}` : null, P = (t) => {
217
+ const I = "client__", q = i ? `submit_${e}` : null, V = (t) => {
197
218
  const r = t.functionName ?? t.toolName;
198
219
  if (r)
199
- return r.startsWith(x) ? r.slice(8) : r;
200
- }, F = (t) => {
201
- let r = { ...y }, u = !1;
202
- for (const o of t) {
203
- const l = P(o);
204
- l === C.name ? o.arguments && (r = {
220
+ return r.startsWith(I) ? r.slice(8) : r;
221
+ }, _ = (t) => {
222
+ let r = { ...v }, u = !1;
223
+ for (const n of t) {
224
+ const l = V(n);
225
+ l === F.name ? n.arguments && (r = {
205
226
  ...r,
206
- ...f(o.arguments)
207
- }) : k && l === k && o.status?.toLowerCase() === "done" && (u = !0);
227
+ ...m(n.arguments)
228
+ }) : q && l === q && n.status?.toLowerCase() === "done" && (u = !0);
208
229
  }
209
- m.set({
230
+ f.set({
210
231
  values: r,
211
232
  submitted: u
212
233
  });
213
- }, S = `form:${e}`, q = () => {
214
- const { values: t, submitted: r } = m.get(), { missing: u, complete: o } = p(s, t), l = i ? c ? " The form is submitted automatically as soon as every required field is filled, so there is no submit function to call." : ` When nothing is missing and the user confirms, call submit_${e}.` : "", d = r ? `The "${e}" form has been submitted.` : `You are currently collecting information from the user to fill the "${e}" form.`;
234
+ }, N = `form:${e}`, E = () => {
235
+ const { values: t, submitted: r } = f.get(), { missing: u, complete: n } = g(s, t), l = i ? c ? " The form is submitted automatically as soon as every required field is filled, so there is no submit function to call." : ` When nothing is missing and the user confirms, call submit_${e}.` : "", d = r ? `The "${e}" form has been submitted.` : `You are currently collecting information from the user to fill the "${e}" form.`;
215
236
  return {
216
237
  name: `Form: ${e}`,
217
238
  description: `${d} ${a} There are conditionnals questions/values to collected, you can find this information with the requiredWhen field in the form. The form schema is the following: ${JSON.stringify(s)}. Data collected so far: ${JSON.stringify(t)}. Call update_${e} with any fields the user provides; ask only for what is still missing.${l}`,
218
239
  data: {
219
240
  values: t,
220
241
  missing: u,
221
- complete: o,
242
+ complete: n,
222
243
  submitted: r
223
244
  }
224
245
  };
225
- }, _ = (t) => {
226
- F((t.messages ?? []).flatMap((r) => r.toolCalls ?? []));
246
+ }, T = (t) => {
247
+ _((t.messages ?? []).flatMap((r) => r.toolCalls ?? []));
227
248
  };
228
249
  return {
229
250
  name: e,
230
- store: m,
231
- functions: g,
232
- contextKey: S,
233
- contextProvider: q,
251
+ store: f,
252
+ functions: y,
253
+ contextKey: N,
254
+ contextProvider: E,
234
255
  install: (t) => {
235
256
  h = t;
236
- for (const u of g) t.register(u);
237
- t.addDynamicContext(S, q);
238
- const r = m.subscribe(() => t.notifyContextChanged());
239
- return t.on("conversation:loaded", _), () => {
257
+ for (const u of y) t.register(u);
258
+ t.addDynamicContext(N, E);
259
+ const r = f.subscribe(() => t.notifyContextChanged());
260
+ return t.on("conversation:loaded", T), () => {
240
261
  r();
241
- for (const u of g) t.unregisterFunction(u.name);
242
- t.removeDynamicContext(S), t.off("conversation:loaded", _), h === t && (h = null);
262
+ for (const u of y) t.unregisterFunction(u.name);
263
+ t.removeDynamicContext(N), t.off("conversation:loaded", T), h === t && (h = null);
243
264
  };
244
265
  },
245
- hydrate: F,
246
- submit: v,
247
- getValues: () => m.get().values,
266
+ hydrate: _,
267
+ submit: S,
268
+ getValues: () => f.get().values,
248
269
  setValues: (t) => {
249
- $(f(t)), w();
270
+ $(m(t)), k();
250
271
  },
251
272
  reset: () => {
252
- m.set({
253
- values: y,
273
+ f.set({
274
+ values: v,
254
275
  submitted: !1
255
276
  });
256
277
  },
257
- getStatus: () => p(s, m.get().values)
278
+ getStatus: () => g(s, f.get().values)
258
279
  };
259
280
  }
260
- async function J(n, e) {
261
- const a = await n.getFormCollector(e.name);
262
- return I({
281
+ async function L(o, e) {
282
+ const a = await o.getFormCollector(e.name);
283
+ return R({
263
284
  name: a.name,
264
285
  description: e.description ?? a.description,
265
286
  schema: e.schema ?? a.schema,
@@ -269,8 +290,8 @@ async function J(n, e) {
269
290
  });
270
291
  }
271
292
  export {
272
- W as i,
273
- p as n,
274
- J as r,
275
- I as t
293
+ A as i,
294
+ g as n,
295
+ L as r,
296
+ R as t
276
297
  };