@useago/sdk 1.0.1 → 1.0.3
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.
- package/CHANGELOG.md +44 -0
- package/README.md +1 -1
- package/dist/{AgoClient-CZYNL25R.js → AgoClient-CBLJfu90.js} +173 -142
- package/dist/AgoClient-nYVPdI5x.cjs +6 -0
- package/dist/angular.cjs +1 -1
- package/dist/angular.d.cts +50 -7
- package/dist/angular.d.ts +50 -7
- package/dist/angular.js +1 -1
- package/dist/{createConversationSession-BLZvXMmM.cjs → createConversationSession-CnIchjFa.cjs} +1 -1
- package/dist/{createConversationSession-Bmqj2rSS.js → createConversationSession-D3aHSSir.js} +1 -1
- package/dist/createFormCollector-CQKfRjfj.cjs +1 -0
- package/dist/{createFormCollector-Bk0DRhUf.js → createFormCollector-CyD7KnjG.js} +2 -2
- package/dist/devtools.d.cts +50 -7
- package/dist/devtools.d.ts +50 -7
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +87 -10
- package/dist/index.d.ts +87 -10
- package/dist/index.js +60 -59
- package/dist/react.cjs +19 -19
- package/dist/react.d.cts +59 -13
- package/dist/react.d.ts +59 -13
- package/dist/react.js +1268 -1275
- package/dist/testing.d.cts +50 -7
- package/dist/testing.d.ts +50 -7
- package/dist/vue.cjs +1 -1
- package/dist/vue.d.cts +50 -7
- package/dist/vue.d.ts +50 -7
- package/dist/vue.js +1 -1
- package/dist/widget.cjs +4 -4
- package/dist/widget.d.cts +51 -8
- package/dist/widget.d.ts +51 -8
- package/dist/widget.js +194 -201
- package/package.json +2 -2
- package/dist/AgoClient-0x2Du_62.cjs +0 -6
- package/dist/createFormCollector-Ca8wRrxc.cjs +0 -1
|
@@ -0,0 +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 v extends h{constructor(t,s,r,n,i,a){super(t,s,r),this.type=n,this.param=i,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,s){const r=t.error;return new v(r.doc_url?`${r.message} See ${r.doc_url}`:r.message,r.code,s,r.type,r.param,r.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"}},A=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 A,p="ago_widget_id";function x(){if(typeof localStorage<"u"){const t=localStorage.getItem(p);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(p,e)}catch{}return e}var $=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 r=await fetch(s,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});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 postFormData(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (formData)",s);const r={...this.headers};try{const n=await fetch(s,{method:"POST",headers:r,body:t});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 request(e,t,s){const r=`${this.baseUrl}${t}`;o.debug(e,r,s);try{const n=await fetch(r,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0});return n.ok||await this.handleErrorResponse(n),n.status===204?void 0:n.json()}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 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")}},b=class{constructor(){this.functions=new Map}register(e,t,s){if(typeof e=="object"){const{name:n,handler:i,description:a,parameters:l}=e;return this.register(n,i,{description:a,parameters:l})}const r=e;if(!t||!s)throw new h(`registerFunction("${r}"): 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(r)&&o.warn(`Function "${r}" is being overwritten`),this.functions.set(r,{schema:{...s,name:r},handler:t}),o.log(`Registered function: ${r}`)}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 r=await s.handler(t);return o.log(`Function ${e} completed:`,r),r}catch(r){throw o.error(`Function ${e} failed:`,r),new m(`Function "${e}" execution failed: ${r instanceof Error?r.message:"Unknown error"}`,e,r instanceof Error?r:void 0)}}clear(){this.functions.clear(),o.log("Cleared all registered functions")}get size(){return this.functions.size}},C=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 r=s();r&&(e[t]=r)}catch(r){o.error(`DynamicContext provider "${t}" threw:`,r)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),o.log("ClientContext cleared")}},E=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1}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:r,value:n}=await t.read();if(r)break;const i=s.decode(n,{stream:!0});this.buffer+=i,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(r){const n=r instanceof Error?r:new g("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(n),n}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
|
|
2
|
+
|
|
3
|
+
`);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const s=t.split(`
|
|
4
|
+
`);for(const r of s)if(!r.startsWith(": ")&&r.startsWith("data: ")){const n=r.slice(6);try{const i=JSON.parse(n);this.handleChunk(i)}catch(i){o.warn("Failed to parse SSE data:",n,i)}}}}handleChunk(e){if(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&&this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}),e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(r=>r.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 R(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var _=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(r=>{try{r(t)}catch(n){console.error(`Error in event handler for ${String(e)}:`,n)}})}once(e,t){const s=(r=>{this.off(e,s),t(r)});this.on(e,s)}waitFor(e,t){return new Promise((s,r)=>{let n;const i=(a=>{n&&clearTimeout(n),s(a)});this.once(e,i),t?.timeout&&(n=setTimeout(()=>{this.off(e,i),r(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},y='`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).',I=/^[a-z][a-z0-9+.-]*:\/\//i,w=!1;function f(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new h(`${t}: ${y}`,"config_missing_base_url");const s=e.baseUrl;if(typeof s!="string"||s.trim()==="")throw new h(`${t}: ${y}`,"config_missing_base_url");!s.startsWith("/")&&!I.test(s)&&(w||(w=!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 S{constructor(t){this.warnedEmptyConversations=new Set,f(t,"AgoClient"),this.config=t,this.httpClient=new $(t),this.functionRegistry=new b,this.contextRegistry=new C,this.eventEmitter=new _,t.debug&&o.enable(),o.log("AgoClient initialized")}async sendMessage(t,s){const r=this.functionRegistry.getSchemas(),n=this.contextRegistry.getSnapshot(),i=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||i};r.length>0&&(a.client_functions=r),n&&(a.client_context=n);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||""),r.length>0&&c.append("client_functions",JSON.stringify(r)),n&&c.append("client_context",JSON.stringify(n));for(const k of s.files)c.append("files",k);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 r=await new E({onStart:n=>{this.eventEmitter.emit("message:start",n)},onChunk:n=>{this.eventEmitter.emit("message:chunk",n)},onToolCall:n=>{this.eventEmitter.emit("toolCall:received",n),n.type==="form"&&this.eventEmitter.emit("toolCall:form",n)},onClientFunction:async n=>{s=!0,this.eventEmitter.emit("function:invoke",n),await this.handleClientFunctionInvocation(n)},onAnswerComplete:n=>{this.eventEmitter.emit("message:answer-complete",n)},onComplete:n=>{this.eventEmitter.emit("message:complete",n)},onError:n=>{this.eventEmitter.emit("message:error",{error:n.message,code:n instanceof h?n.code:void 0})}}).processStream(t);return this.maybeFlagEmptyReply(r,s),r}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 r=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(r))return;this.warnedEmptyConversations.add(r);const n=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(n?`the agent "${n}" 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: "+(n?`the agent "${n}" 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,r;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(n){r=n instanceof Error?n.message:"Unknown error",o.error("Client function execution failed:",n)}if(t.invocationId)try{await this.submitToolCallForm(t.invocationId,{result:s,error:r,_type:"client_function_result"})}catch(n){o.error("Failed to submit function result:",n)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:r})}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}`),r={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_date),messages:s.messages.map(n=>({id:n.id,conversationId:s.id,content:n.content,role:n.role,status:n.status,createdAt:new Date(n.created_at),toolCalls:S.mapPersistedToolCalls(n.tool_call_data)}))};return this.eventEmitter.emit("conversation:loaded",r),r}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,r){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,r)}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 r=s.map(i=>i.name),n=s.map(i=>`- "${i.name}": ${i.description}`).join(`
|
|
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
|
+
${n}`,parameters:{type:"object",properties:{page:{type:"string",description:"The page to navigate to",enum:r}},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[n,i]of Object.entries(t))i!==void 0&&(s[n]=i);const r={...this.config,...s};f(r,"AgoClient.updateConfig"),this.config=r,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 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 C}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return b}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return E}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return R}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return o}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return f}});
|
package/dist/angular.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-nYVPdI5x.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;
|
package/dist/angular.d.cts
CHANGED
|
@@ -16,12 +16,26 @@ declare class AgoClient {
|
|
|
16
16
|
private contextRegistry;
|
|
17
17
|
private eventEmitter;
|
|
18
18
|
private config;
|
|
19
|
+
/** Conversations already warned about an empty reply (one warning each). */
|
|
20
|
+
private warnedEmptyConversations;
|
|
19
21
|
constructor(config: AgoConfig);
|
|
20
22
|
/**
|
|
21
23
|
* Send a message and receive a streaming response
|
|
22
24
|
*/
|
|
23
25
|
sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
|
|
24
26
|
private processSSEResponse;
|
|
27
|
+
/**
|
|
28
|
+
* Detect a reply that completed as DONE with no content and no activity —
|
|
29
|
+
* today's backend answers an unknown `agent` slug with an empty 200, which
|
|
30
|
+
* otherwise fails silently. Emits `message:empty` (always) and warns on the
|
|
31
|
+
* console once per conversation (unless `warnOnEmptyReply: false`).
|
|
32
|
+
*
|
|
33
|
+
* Deferred with setTimeout(0) so both land AFTER `sendMessage` resolves:
|
|
34
|
+
* `await client.sendMessage(...)` followed by `client.waitFor("message:empty")`
|
|
35
|
+
* must not race. TEMPORARY heuristic: remove once the backend returns an
|
|
36
|
+
* explicit error for unknown agents (see TODOS.md, backend issue).
|
|
37
|
+
*/
|
|
38
|
+
private maybeFlagEmptyReply;
|
|
25
39
|
private handleClientFunctionInvocation;
|
|
26
40
|
/**
|
|
27
41
|
* Get list of conversations
|
|
@@ -64,10 +78,11 @@ declare class AgoClient {
|
|
|
64
78
|
* Relay a completed form collector's values to a server-configured destination.
|
|
65
79
|
*
|
|
66
80
|
* Used by `createFormCollector` / `useFormCollector` in `{ via: "backend" }` mode:
|
|
67
|
-
* the browser never holds the destination URL or its secret — the backend
|
|
68
|
-
*
|
|
81
|
+
* the browser never holds the destination name, URL, or its secret — the backend
|
|
82
|
+
* resolves the destination from the named form's stored definition and forwards
|
|
83
|
+
* the values from the server.
|
|
69
84
|
*/
|
|
70
|
-
submitFormCollector(
|
|
85
|
+
submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
|
|
71
86
|
/**
|
|
72
87
|
* Submit feedback for a message
|
|
73
88
|
*/
|
|
@@ -194,6 +209,11 @@ declare class AgoClient {
|
|
|
194
209
|
}): Promise<AgoClientEvents[K]>;
|
|
195
210
|
/**
|
|
196
211
|
* Update client configuration
|
|
212
|
+
*
|
|
213
|
+
* Validates the MERGED config before committing: omitting a key (or passing
|
|
214
|
+
* it as `undefined`, common with spread-built partials) keeps the current
|
|
215
|
+
* value; an explicit empty/non-string `baseUrl` throws `config_missing_base_url`
|
|
216
|
+
* and leaves the client unchanged (no half-updated state).
|
|
197
217
|
*/
|
|
198
218
|
updateConfig(config: Partial<AgoConfig>): void;
|
|
199
219
|
/**
|
|
@@ -229,8 +249,23 @@ export declare interface AgoClientEvents {
|
|
|
229
249
|
*/
|
|
230
250
|
"message:answer-complete": AgoMessage;
|
|
231
251
|
"message:complete": AgoMessage;
|
|
252
|
+
/**
|
|
253
|
+
* A reply finished as `DONE` with empty content and no tool calls, client
|
|
254
|
+
* functions, or follow-up replies — usually an unknown `agent` slug (the
|
|
255
|
+
* backend currently answers those with an empty 200). Fires after
|
|
256
|
+
* `message:complete` AND after `sendMessage` resolves, so subscribing right
|
|
257
|
+
* after `await sendMessage(...)` still catches it. `messageId` and
|
|
258
|
+
* `conversationId` are empty strings when the stream completed without any
|
|
259
|
+
* message data at all (e.g. a proxy stripped the SSE stream).
|
|
260
|
+
*/
|
|
261
|
+
"message:empty": {
|
|
262
|
+
conversationId: string;
|
|
263
|
+
messageId: string;
|
|
264
|
+
};
|
|
232
265
|
"message:error": {
|
|
233
266
|
error: string;
|
|
267
|
+
/** Stable error code (see configuration.md#error-codes) when the failure was an AgoError. */
|
|
268
|
+
code?: string;
|
|
234
269
|
conversationId?: string;
|
|
235
270
|
messageId?: string;
|
|
236
271
|
};
|
|
@@ -259,7 +294,7 @@ export declare interface AgoClientEvents {
|
|
|
259
294
|
export declare interface AgoConfig {
|
|
260
295
|
/** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
|
|
261
296
|
baseUrl: string;
|
|
262
|
-
/**
|
|
297
|
+
/** Per-visitor anonymous ID (X-User-Anon-Id header). Auto-generated if not provided. */
|
|
263
298
|
widgetId?: string;
|
|
264
299
|
/** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
|
|
265
300
|
agent?: string;
|
|
@@ -273,6 +308,13 @@ export declare interface AgoConfig {
|
|
|
273
308
|
userJwt?: string;
|
|
274
309
|
/** Enable debug logging */
|
|
275
310
|
debug?: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Warn on the console when a reply completes with empty content and no tool
|
|
313
|
+
* calls (the usual cause is an unknown `agent` slug, which the backend
|
|
314
|
+
* currently answers with an empty 200). Default `true`. The `message:empty`
|
|
315
|
+
* event fires regardless of this setting.
|
|
316
|
+
*/
|
|
317
|
+
warnOnEmptyReply?: boolean;
|
|
276
318
|
}
|
|
277
319
|
|
|
278
320
|
declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
|
|
@@ -615,8 +657,9 @@ declare interface SendMessageOptions {
|
|
|
615
657
|
* POSTs the values to that URL.
|
|
616
658
|
* - `{ via: "client", url }` — same, written out.
|
|
617
659
|
* - `{ via: "client", handler }` — the browser runs your own submit logic.
|
|
618
|
-
* - `{ via: "backend"
|
|
619
|
-
*
|
|
660
|
+
* - `{ via: "backend" }` — the browser relays the values to the backend, which resolves
|
|
661
|
+
* the destination from the form's backend-stored definition (name, URL and secret all
|
|
662
|
+
* stay server-side). `destination` is deprecated and ignored.
|
|
620
663
|
* - `false` — collect only, no submit function.
|
|
621
664
|
*/
|
|
622
665
|
declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
@@ -627,7 +670,7 @@ declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
|
627
670
|
handler: (values: V) => Promise<unknown> | unknown;
|
|
628
671
|
} | {
|
|
629
672
|
via: "backend";
|
|
630
|
-
destination
|
|
673
|
+
destination?: string;
|
|
631
674
|
} | false;
|
|
632
675
|
|
|
633
676
|
/**
|
package/dist/angular.d.ts
CHANGED
|
@@ -16,12 +16,26 @@ declare class AgoClient {
|
|
|
16
16
|
private contextRegistry;
|
|
17
17
|
private eventEmitter;
|
|
18
18
|
private config;
|
|
19
|
+
/** Conversations already warned about an empty reply (one warning each). */
|
|
20
|
+
private warnedEmptyConversations;
|
|
19
21
|
constructor(config: AgoConfig);
|
|
20
22
|
/**
|
|
21
23
|
* Send a message and receive a streaming response
|
|
22
24
|
*/
|
|
23
25
|
sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
|
|
24
26
|
private processSSEResponse;
|
|
27
|
+
/**
|
|
28
|
+
* Detect a reply that completed as DONE with no content and no activity —
|
|
29
|
+
* today's backend answers an unknown `agent` slug with an empty 200, which
|
|
30
|
+
* otherwise fails silently. Emits `message:empty` (always) and warns on the
|
|
31
|
+
* console once per conversation (unless `warnOnEmptyReply: false`).
|
|
32
|
+
*
|
|
33
|
+
* Deferred with setTimeout(0) so both land AFTER `sendMessage` resolves:
|
|
34
|
+
* `await client.sendMessage(...)` followed by `client.waitFor("message:empty")`
|
|
35
|
+
* must not race. TEMPORARY heuristic: remove once the backend returns an
|
|
36
|
+
* explicit error for unknown agents (see TODOS.md, backend issue).
|
|
37
|
+
*/
|
|
38
|
+
private maybeFlagEmptyReply;
|
|
25
39
|
private handleClientFunctionInvocation;
|
|
26
40
|
/**
|
|
27
41
|
* Get list of conversations
|
|
@@ -64,10 +78,11 @@ declare class AgoClient {
|
|
|
64
78
|
* Relay a completed form collector's values to a server-configured destination.
|
|
65
79
|
*
|
|
66
80
|
* Used by `createFormCollector` / `useFormCollector` in `{ via: "backend" }` mode:
|
|
67
|
-
* the browser never holds the destination URL or its secret — the backend
|
|
68
|
-
*
|
|
81
|
+
* the browser never holds the destination name, URL, or its secret — the backend
|
|
82
|
+
* resolves the destination from the named form's stored definition and forwards
|
|
83
|
+
* the values from the server.
|
|
69
84
|
*/
|
|
70
|
-
submitFormCollector(
|
|
85
|
+
submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
|
|
71
86
|
/**
|
|
72
87
|
* Submit feedback for a message
|
|
73
88
|
*/
|
|
@@ -194,6 +209,11 @@ declare class AgoClient {
|
|
|
194
209
|
}): Promise<AgoClientEvents[K]>;
|
|
195
210
|
/**
|
|
196
211
|
* Update client configuration
|
|
212
|
+
*
|
|
213
|
+
* Validates the MERGED config before committing: omitting a key (or passing
|
|
214
|
+
* it as `undefined`, common with spread-built partials) keeps the current
|
|
215
|
+
* value; an explicit empty/non-string `baseUrl` throws `config_missing_base_url`
|
|
216
|
+
* and leaves the client unchanged (no half-updated state).
|
|
197
217
|
*/
|
|
198
218
|
updateConfig(config: Partial<AgoConfig>): void;
|
|
199
219
|
/**
|
|
@@ -229,8 +249,23 @@ export declare interface AgoClientEvents {
|
|
|
229
249
|
*/
|
|
230
250
|
"message:answer-complete": AgoMessage;
|
|
231
251
|
"message:complete": AgoMessage;
|
|
252
|
+
/**
|
|
253
|
+
* A reply finished as `DONE` with empty content and no tool calls, client
|
|
254
|
+
* functions, or follow-up replies — usually an unknown `agent` slug (the
|
|
255
|
+
* backend currently answers those with an empty 200). Fires after
|
|
256
|
+
* `message:complete` AND after `sendMessage` resolves, so subscribing right
|
|
257
|
+
* after `await sendMessage(...)` still catches it. `messageId` and
|
|
258
|
+
* `conversationId` are empty strings when the stream completed without any
|
|
259
|
+
* message data at all (e.g. a proxy stripped the SSE stream).
|
|
260
|
+
*/
|
|
261
|
+
"message:empty": {
|
|
262
|
+
conversationId: string;
|
|
263
|
+
messageId: string;
|
|
264
|
+
};
|
|
232
265
|
"message:error": {
|
|
233
266
|
error: string;
|
|
267
|
+
/** Stable error code (see configuration.md#error-codes) when the failure was an AgoError. */
|
|
268
|
+
code?: string;
|
|
234
269
|
conversationId?: string;
|
|
235
270
|
messageId?: string;
|
|
236
271
|
};
|
|
@@ -259,7 +294,7 @@ export declare interface AgoClientEvents {
|
|
|
259
294
|
export declare interface AgoConfig {
|
|
260
295
|
/** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
|
|
261
296
|
baseUrl: string;
|
|
262
|
-
/**
|
|
297
|
+
/** Per-visitor anonymous ID (X-User-Anon-Id header). Auto-generated if not provided. */
|
|
263
298
|
widgetId?: string;
|
|
264
299
|
/** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
|
|
265
300
|
agent?: string;
|
|
@@ -273,6 +308,13 @@ export declare interface AgoConfig {
|
|
|
273
308
|
userJwt?: string;
|
|
274
309
|
/** Enable debug logging */
|
|
275
310
|
debug?: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Warn on the console when a reply completes with empty content and no tool
|
|
313
|
+
* calls (the usual cause is an unknown `agent` slug, which the backend
|
|
314
|
+
* currently answers with an empty 200). Default `true`. The `message:empty`
|
|
315
|
+
* event fires regardless of this setting.
|
|
316
|
+
*/
|
|
317
|
+
warnOnEmptyReply?: boolean;
|
|
276
318
|
}
|
|
277
319
|
|
|
278
320
|
declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
|
|
@@ -615,8 +657,9 @@ declare interface SendMessageOptions {
|
|
|
615
657
|
* POSTs the values to that URL.
|
|
616
658
|
* - `{ via: "client", url }` — same, written out.
|
|
617
659
|
* - `{ via: "client", handler }` — the browser runs your own submit logic.
|
|
618
|
-
* - `{ via: "backend"
|
|
619
|
-
*
|
|
660
|
+
* - `{ via: "backend" }` — the browser relays the values to the backend, which resolves
|
|
661
|
+
* the destination from the form's backend-stored definition (name, URL and secret all
|
|
662
|
+
* stay server-side). `destination` is deprecated and ignored.
|
|
620
663
|
* - `false` — collect only, no submit function.
|
|
621
664
|
*/
|
|
622
665
|
declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
@@ -627,7 +670,7 @@ declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
|
627
670
|
handler: (values: V) => Promise<unknown> | unknown;
|
|
628
671
|
} | {
|
|
629
672
|
via: "backend";
|
|
630
|
-
destination
|
|
673
|
+
destination?: string;
|
|
631
674
|
} | false;
|
|
632
675
|
|
|
633
676
|
/**
|
package/dist/angular.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as o } from "./AgoClient-
|
|
1
|
+
import { t as o } from "./AgoClient-CBLJfu90.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");
|
package/dist/{createConversationSession-BLZvXMmM.cjs → createConversationSession-CnIchjFa.cjs}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
const d=require("./createFormCollector-
|
|
1
|
+
const d=require("./createFormCollector-CQKfRjfj.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 _}});
|
package/dist/{createConversationSession-Bmqj2rSS.js → createConversationSession-D3aHSSir.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as d } from "./createFormCollector-
|
|
1
|
+
import { i as d } from "./createFormCollector-CyD7KnjG.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 O=require("./AgoClient-nYVPdI5x.cjs");function _(o,e){const i=e?e.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let t=o;if(e&&i)try{const c=i.getItem(e.key);c!=null&&(t=JSON.parse(c))}catch{}const a=new Set,f=()=>a.forEach(c=>c(t));function d(){if(e&&i)try{i.setItem(e.key,JSON.stringify(t))}catch{}}return{get:()=>t,set:c=>{t=c,d(),f()},subscribe:c=>(a.add(c),()=>{a.delete(c)})}}var k=/^[a-zA-Z0-9_-]{1,40}$/,P=o=>o==null||o==="";function q(o,e){const i=e[o.property];if(P(i))return!1;if(Array.isArray(o.value))return o.value.some(f=>String(i)===String(f));if(!o.op)return String(i)===String(o.value);const t=Number(i),a=Number(o.value);if(Number.isNaN(t)||Number.isNaN(a))return!1;switch(o.op){case">=":return t>=a;case"<=":return t<=a;case">":return t>a;case"<":return t<a;default:return O.logger.warn(`Unknown requiredWhen op "${o.op}"; treating as not required.`),!1}}function p(o,e){const i=o.properties??{},t=new Set;for(const f of o.required??[]){const d=i[f]?.requiredWhen;(!d||q(d,e))&&t.add(f)}for(const[f,d]of Object.entries(i))d.requiredWhen&&q(d.requiredWhen,e)&&t.add(f);const a=[...t].filter(f=>P(e[f]));return{missing:a,complete:a.length===0}}function W(o){const e={};for(const[i,t]of Object.entries(o.properties??{}))e[i]={type:t.type,...t.description!=null&&{description:t.description},...t.enum&&{enum:t.enum},...t.default!==void 0&&{default:t.default}};return{type:"object",properties:e,required:[]}}function j(o){const{name:e,description:i,schema:t}=o;if(!k.test(e))throw new Error(`Invalid form collector name "${e}": must match ${k} (it becomes the update_/submit_ function names).`);const a=typeof o.submit=="string"?o.submit?{via:"client",url:o.submit}:!1:o.submit??!1,f=t.properties??{},d=r=>{const n={};for(const[u,s]of Object.entries(r)){const l=f[u];if(l)if(s==null)n[u]=s;else if(l.type==="number"||l.type==="integer"){const b=typeof s=="number"?s:Number(s);n[u]=Number.isNaN(b)?s:b}else l.type==="boolean"?n[u]=typeof s=="boolean"?s:s==="true"?!0:s==="false"?!1:!!s:n[u]=s}return n},c=o.initialValues??{},m=_({values:c,submitted:!1}),v=r=>{const n=m.get(),u={...n,values:{...n.values,...r}};return m.set(u),u};let h=null;const N=async()=>{const{values:r}=m.get(),{complete:n,missing:u}=p(t,r);if(!n)return{ok:!1,missing:u};if(!a)return{ok:!1,error:"No submit target configured for this form collector."};const s=r;try{let l;if(a.via==="client")if("handler"in a)l=await a.handler(s);else{const b=await fetch(a.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(s)});if(!b.ok)return{ok:!1,error:`Submit failed: HTTP ${b.status}`};l=await b.json().catch(()=>{})}else{if(!h)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};l=await h.submitFormCollector(e,s)}return m.set({...m.get(),submitted:!0}),{ok:!0,result:l}}catch(l){const b=l instanceof Error?l.message:"Submit failed";return O.logger.error(`FormCollector "${e}" submit failed:`,l),{ok:!1,error:b}}},S={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${i} 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:W(t),handler:r=>{const n=v(d(r)),{missing:u}=p(t,n.values);return{ok:!0,values:n.values,missing:u}}},g=[S];a&&g.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:()=>N()});const T="client__",C=a?`submit_${e}`:null,E=r=>{const n=r.functionName??r.toolName;if(n)return n.startsWith(T)?n.slice(8):n},$=r=>{let n={...c},u=!1;for(const s of r){const l=E(s);l===S.name?s.arguments&&(n={...n,...d(s.arguments)}):C&&l===C&&s.status?.toLowerCase()==="done"&&(u=!0)}m.set({values:n,submitted:u})},y=`form:${e}`,w=()=>{const{values:r,submitted:n}=m.get(),{missing:u,complete:s}=p(t,r),l=a?` When nothing is missing and the user confirms, call submit_${e}.`:"",b=n?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${b} ${i} 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(t)}. Data collected so far: ${JSON.stringify(r)}. Call update_${e} with any fields the user provides; ask only for what is still missing.${l}`,data:{values:r,missing:u,complete:s,submitted:n}}},F=r=>{$((r.messages??[]).flatMap(n=>n.toolCalls??[]))};return{name:e,store:m,functions:g,contextKey:y,contextProvider:w,install:r=>{h=r;for(const u of g)r.register(u);r.addDynamicContext(y,w);const n=m.subscribe(()=>r.notifyContextChanged());return r.on("conversation:loaded",F),()=>{n();for(const u of g)r.unregisterFunction(u.name);r.removeDynamicContext(y),r.off("conversation:loaded",F),h===r&&(h=null)}},hydrate:$,submit:N,getValues:()=>m.get().values,setValues:r=>{v(d(r))},reset:()=>{m.set({values:c,submitted:!1})},getStatus:()=>p(t,m.get().values)}}async function x(o,e){const i=await o.getFormCollector(e.name);return j({name:i.name,description:e.description??i.description,schema:e.schema??i.schema,submit:e.submit??i.submit,initialValues:e.initialValues})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return j}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return p}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return x}});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as _ } from "./AgoClient-CBLJfu90.js";
|
|
2
2
|
function E(n, e) {
|
|
3
3
|
const i = e ? e.storage ?? (typeof localStorage < "u" ? localStorage : void 0) : void 0;
|
|
4
4
|
let t = n;
|
|
@@ -137,7 +137,7 @@ function W(n) {
|
|
|
137
137
|
ok: !1,
|
|
138
138
|
error: "Backend submit requires install(client) (or useFormCollector) first."
|
|
139
139
|
};
|
|
140
|
-
l = await b.submitFormCollector(
|
|
140
|
+
l = await b.submitFormCollector(e, o);
|
|
141
141
|
}
|
|
142
142
|
return m.set({
|
|
143
143
|
...m.get(),
|
package/dist/devtools.d.cts
CHANGED
|
@@ -16,12 +16,26 @@ declare class AgoClient {
|
|
|
16
16
|
private contextRegistry;
|
|
17
17
|
private eventEmitter;
|
|
18
18
|
private config;
|
|
19
|
+
/** Conversations already warned about an empty reply (one warning each). */
|
|
20
|
+
private warnedEmptyConversations;
|
|
19
21
|
constructor(config: AgoConfig);
|
|
20
22
|
/**
|
|
21
23
|
* Send a message and receive a streaming response
|
|
22
24
|
*/
|
|
23
25
|
sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
|
|
24
26
|
private processSSEResponse;
|
|
27
|
+
/**
|
|
28
|
+
* Detect a reply that completed as DONE with no content and no activity —
|
|
29
|
+
* today's backend answers an unknown `agent` slug with an empty 200, which
|
|
30
|
+
* otherwise fails silently. Emits `message:empty` (always) and warns on the
|
|
31
|
+
* console once per conversation (unless `warnOnEmptyReply: false`).
|
|
32
|
+
*
|
|
33
|
+
* Deferred with setTimeout(0) so both land AFTER `sendMessage` resolves:
|
|
34
|
+
* `await client.sendMessage(...)` followed by `client.waitFor("message:empty")`
|
|
35
|
+
* must not race. TEMPORARY heuristic: remove once the backend returns an
|
|
36
|
+
* explicit error for unknown agents (see TODOS.md, backend issue).
|
|
37
|
+
*/
|
|
38
|
+
private maybeFlagEmptyReply;
|
|
25
39
|
private handleClientFunctionInvocation;
|
|
26
40
|
/**
|
|
27
41
|
* Get list of conversations
|
|
@@ -64,10 +78,11 @@ declare class AgoClient {
|
|
|
64
78
|
* Relay a completed form collector's values to a server-configured destination.
|
|
65
79
|
*
|
|
66
80
|
* Used by `createFormCollector` / `useFormCollector` in `{ via: "backend" }` mode:
|
|
67
|
-
* the browser never holds the destination URL or its secret — the backend
|
|
68
|
-
*
|
|
81
|
+
* the browser never holds the destination name, URL, or its secret — the backend
|
|
82
|
+
* resolves the destination from the named form's stored definition and forwards
|
|
83
|
+
* the values from the server.
|
|
69
84
|
*/
|
|
70
|
-
submitFormCollector(
|
|
85
|
+
submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
|
|
71
86
|
/**
|
|
72
87
|
* Submit feedback for a message
|
|
73
88
|
*/
|
|
@@ -194,6 +209,11 @@ declare class AgoClient {
|
|
|
194
209
|
}): Promise<AgoClientEvents[K]>;
|
|
195
210
|
/**
|
|
196
211
|
* Update client configuration
|
|
212
|
+
*
|
|
213
|
+
* Validates the MERGED config before committing: omitting a key (or passing
|
|
214
|
+
* it as `undefined`, common with spread-built partials) keeps the current
|
|
215
|
+
* value; an explicit empty/non-string `baseUrl` throws `config_missing_base_url`
|
|
216
|
+
* and leaves the client unchanged (no half-updated state).
|
|
197
217
|
*/
|
|
198
218
|
updateConfig(config: Partial<AgoConfig>): void;
|
|
199
219
|
/**
|
|
@@ -229,8 +249,23 @@ declare interface AgoClientEvents {
|
|
|
229
249
|
*/
|
|
230
250
|
"message:answer-complete": AgoMessage;
|
|
231
251
|
"message:complete": AgoMessage;
|
|
252
|
+
/**
|
|
253
|
+
* A reply finished as `DONE` with empty content and no tool calls, client
|
|
254
|
+
* functions, or follow-up replies — usually an unknown `agent` slug (the
|
|
255
|
+
* backend currently answers those with an empty 200). Fires after
|
|
256
|
+
* `message:complete` AND after `sendMessage` resolves, so subscribing right
|
|
257
|
+
* after `await sendMessage(...)` still catches it. `messageId` and
|
|
258
|
+
* `conversationId` are empty strings when the stream completed without any
|
|
259
|
+
* message data at all (e.g. a proxy stripped the SSE stream).
|
|
260
|
+
*/
|
|
261
|
+
"message:empty": {
|
|
262
|
+
conversationId: string;
|
|
263
|
+
messageId: string;
|
|
264
|
+
};
|
|
232
265
|
"message:error": {
|
|
233
266
|
error: string;
|
|
267
|
+
/** Stable error code (see configuration.md#error-codes) when the failure was an AgoError. */
|
|
268
|
+
code?: string;
|
|
234
269
|
conversationId?: string;
|
|
235
270
|
messageId?: string;
|
|
236
271
|
};
|
|
@@ -259,7 +294,7 @@ declare interface AgoClientEvents {
|
|
|
259
294
|
declare interface AgoConfig {
|
|
260
295
|
/** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
|
|
261
296
|
baseUrl: string;
|
|
262
|
-
/**
|
|
297
|
+
/** Per-visitor anonymous ID (X-User-Anon-Id header). Auto-generated if not provided. */
|
|
263
298
|
widgetId?: string;
|
|
264
299
|
/** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
|
|
265
300
|
agent?: string;
|
|
@@ -273,6 +308,13 @@ declare interface AgoConfig {
|
|
|
273
308
|
userJwt?: string;
|
|
274
309
|
/** Enable debug logging */
|
|
275
310
|
debug?: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Warn on the console when a reply completes with empty content and no tool
|
|
313
|
+
* calls (the usual cause is an unknown `agent` slug, which the backend
|
|
314
|
+
* currently answers with an empty 200). Default `true`. The `message:empty`
|
|
315
|
+
* event fires regardless of this setting.
|
|
316
|
+
*/
|
|
317
|
+
warnOnEmptyReply?: boolean;
|
|
276
318
|
}
|
|
277
319
|
|
|
278
320
|
declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
|
|
@@ -506,8 +548,9 @@ declare interface SendMessageOptions {
|
|
|
506
548
|
* POSTs the values to that URL.
|
|
507
549
|
* - `{ via: "client", url }` — same, written out.
|
|
508
550
|
* - `{ via: "client", handler }` — the browser runs your own submit logic.
|
|
509
|
-
* - `{ via: "backend"
|
|
510
|
-
*
|
|
551
|
+
* - `{ via: "backend" }` — the browser relays the values to the backend, which resolves
|
|
552
|
+
* the destination from the form's backend-stored definition (name, URL and secret all
|
|
553
|
+
* stay server-side). `destination` is deprecated and ignored.
|
|
511
554
|
* - `false` — collect only, no submit function.
|
|
512
555
|
*/
|
|
513
556
|
declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
@@ -518,7 +561,7 @@ declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
|
518
561
|
handler: (values: V) => Promise<unknown> | unknown;
|
|
519
562
|
} | {
|
|
520
563
|
via: "backend";
|
|
521
|
-
destination
|
|
564
|
+
destination?: string;
|
|
522
565
|
} | false;
|
|
523
566
|
|
|
524
567
|
/**
|
package/dist/devtools.d.ts
CHANGED
|
@@ -16,12 +16,26 @@ declare class AgoClient {
|
|
|
16
16
|
private contextRegistry;
|
|
17
17
|
private eventEmitter;
|
|
18
18
|
private config;
|
|
19
|
+
/** Conversations already warned about an empty reply (one warning each). */
|
|
20
|
+
private warnedEmptyConversations;
|
|
19
21
|
constructor(config: AgoConfig);
|
|
20
22
|
/**
|
|
21
23
|
* Send a message and receive a streaming response
|
|
22
24
|
*/
|
|
23
25
|
sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
|
|
24
26
|
private processSSEResponse;
|
|
27
|
+
/**
|
|
28
|
+
* Detect a reply that completed as DONE with no content and no activity —
|
|
29
|
+
* today's backend answers an unknown `agent` slug with an empty 200, which
|
|
30
|
+
* otherwise fails silently. Emits `message:empty` (always) and warns on the
|
|
31
|
+
* console once per conversation (unless `warnOnEmptyReply: false`).
|
|
32
|
+
*
|
|
33
|
+
* Deferred with setTimeout(0) so both land AFTER `sendMessage` resolves:
|
|
34
|
+
* `await client.sendMessage(...)` followed by `client.waitFor("message:empty")`
|
|
35
|
+
* must not race. TEMPORARY heuristic: remove once the backend returns an
|
|
36
|
+
* explicit error for unknown agents (see TODOS.md, backend issue).
|
|
37
|
+
*/
|
|
38
|
+
private maybeFlagEmptyReply;
|
|
25
39
|
private handleClientFunctionInvocation;
|
|
26
40
|
/**
|
|
27
41
|
* Get list of conversations
|
|
@@ -64,10 +78,11 @@ declare class AgoClient {
|
|
|
64
78
|
* Relay a completed form collector's values to a server-configured destination.
|
|
65
79
|
*
|
|
66
80
|
* Used by `createFormCollector` / `useFormCollector` in `{ via: "backend" }` mode:
|
|
67
|
-
* the browser never holds the destination URL or its secret — the backend
|
|
68
|
-
*
|
|
81
|
+
* the browser never holds the destination name, URL, or its secret — the backend
|
|
82
|
+
* resolves the destination from the named form's stored definition and forwards
|
|
83
|
+
* the values from the server.
|
|
69
84
|
*/
|
|
70
|
-
submitFormCollector(
|
|
85
|
+
submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
|
|
71
86
|
/**
|
|
72
87
|
* Submit feedback for a message
|
|
73
88
|
*/
|
|
@@ -194,6 +209,11 @@ declare class AgoClient {
|
|
|
194
209
|
}): Promise<AgoClientEvents[K]>;
|
|
195
210
|
/**
|
|
196
211
|
* Update client configuration
|
|
212
|
+
*
|
|
213
|
+
* Validates the MERGED config before committing: omitting a key (or passing
|
|
214
|
+
* it as `undefined`, common with spread-built partials) keeps the current
|
|
215
|
+
* value; an explicit empty/non-string `baseUrl` throws `config_missing_base_url`
|
|
216
|
+
* and leaves the client unchanged (no half-updated state).
|
|
197
217
|
*/
|
|
198
218
|
updateConfig(config: Partial<AgoConfig>): void;
|
|
199
219
|
/**
|
|
@@ -229,8 +249,23 @@ declare interface AgoClientEvents {
|
|
|
229
249
|
*/
|
|
230
250
|
"message:answer-complete": AgoMessage;
|
|
231
251
|
"message:complete": AgoMessage;
|
|
252
|
+
/**
|
|
253
|
+
* A reply finished as `DONE` with empty content and no tool calls, client
|
|
254
|
+
* functions, or follow-up replies — usually an unknown `agent` slug (the
|
|
255
|
+
* backend currently answers those with an empty 200). Fires after
|
|
256
|
+
* `message:complete` AND after `sendMessage` resolves, so subscribing right
|
|
257
|
+
* after `await sendMessage(...)` still catches it. `messageId` and
|
|
258
|
+
* `conversationId` are empty strings when the stream completed without any
|
|
259
|
+
* message data at all (e.g. a proxy stripped the SSE stream).
|
|
260
|
+
*/
|
|
261
|
+
"message:empty": {
|
|
262
|
+
conversationId: string;
|
|
263
|
+
messageId: string;
|
|
264
|
+
};
|
|
232
265
|
"message:error": {
|
|
233
266
|
error: string;
|
|
267
|
+
/** Stable error code (see configuration.md#error-codes) when the failure was an AgoError. */
|
|
268
|
+
code?: string;
|
|
234
269
|
conversationId?: string;
|
|
235
270
|
messageId?: string;
|
|
236
271
|
};
|
|
@@ -259,7 +294,7 @@ declare interface AgoClientEvents {
|
|
|
259
294
|
declare interface AgoConfig {
|
|
260
295
|
/** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
|
|
261
296
|
baseUrl: string;
|
|
262
|
-
/**
|
|
297
|
+
/** Per-visitor anonymous ID (X-User-Anon-Id header). Auto-generated if not provided. */
|
|
263
298
|
widgetId?: string;
|
|
264
299
|
/** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
|
|
265
300
|
agent?: string;
|
|
@@ -273,6 +308,13 @@ declare interface AgoConfig {
|
|
|
273
308
|
userJwt?: string;
|
|
274
309
|
/** Enable debug logging */
|
|
275
310
|
debug?: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Warn on the console when a reply completes with empty content and no tool
|
|
313
|
+
* calls (the usual cause is an unknown `agent` slug, which the backend
|
|
314
|
+
* currently answers with an empty 200). Default `true`. The `message:empty`
|
|
315
|
+
* event fires regardless of this setting.
|
|
316
|
+
*/
|
|
317
|
+
warnOnEmptyReply?: boolean;
|
|
276
318
|
}
|
|
277
319
|
|
|
278
320
|
declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
|
|
@@ -506,8 +548,9 @@ declare interface SendMessageOptions {
|
|
|
506
548
|
* POSTs the values to that URL.
|
|
507
549
|
* - `{ via: "client", url }` — same, written out.
|
|
508
550
|
* - `{ via: "client", handler }` — the browser runs your own submit logic.
|
|
509
|
-
* - `{ via: "backend"
|
|
510
|
-
*
|
|
551
|
+
* - `{ via: "backend" }` — the browser relays the values to the backend, which resolves
|
|
552
|
+
* the destination from the form's backend-stored definition (name, URL and secret all
|
|
553
|
+
* stay server-side). `destination` is deprecated and ignored.
|
|
511
554
|
* - `false` — collect only, no submit function.
|
|
512
555
|
*/
|
|
513
556
|
declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
@@ -518,7 +561,7 @@ declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
|
518
561
|
handler: (values: V) => Promise<unknown> | unknown;
|
|
519
562
|
} | {
|
|
520
563
|
via: "backend";
|
|
521
|
-
destination
|
|
564
|
+
destination?: string;
|
|
522
565
|
} | false;
|
|
523
566
|
|
|
524
567
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("./AgoClient-nYVPdI5x.cjs"),m=require("./createFormCollector-CQKfRjfj.cjs"),p=require("./createConversationSession-CnIchjFa.cjs"),w=require("./createMockClient-zHQ0cjUH.cjs");require("./testing.cjs");const g=require("./functions-DsmzgHjC.cjs");function h(e){return e}function E(e,o){return e.on("message:complete",o),()=>e.off("message:complete",o)}function S(e,o){return e.on("message:chunk",o),()=>e.off("message:chunk",o)}function y(e,o){return e.on("message:start",o),()=>e.off("message:start",o)}function v(e,o){return e.on("message:error",o),()=>e.off("message:error",o)}function b(e,o){return e.on("toolCall:received",o),()=>e.off("toolCall:received",o)}function F(e,o){return e.on("function:invoke",o),()=>e.off("function:invoke",o)}async function*M(e,o,l){const a=[];let r=null,s=!1;const c=i=>{a.push(i),r?.()},f=i=>c({type:"start",data:i}),t=i=>c({type:"chunk",data:i}),u=i=>{c({type:"complete",data:i}),s=!0,r?.()},d=i=>{c({type:"error",data:i}),s=!0,r?.()},C=i=>c({type:"toolCall",data:i});e.on("message:start",f),e.on("message:chunk",t),e.on("message:complete",u),e.on("message:error",d),e.on("toolCall:received",C),e.sendMessage(o,l).catch(()=>{s=!0,r?.()});try{for(;!s||a.length>0;)a.length>0?yield a.shift():(await new Promise(i=>{r=i}),r=null)}finally{e.off("message:start",f),e.off("message:chunk",t),e.off("message:complete",u),e.off("message:error",d),e.off("toolCall:received",C)}}function A(e){let o,l,a,r,s,c;if(typeof window<"u"&&window.AGO){const t=window.AGO;o=t.basepath,l=t.widgetId,a=t.agent||t.defaultAgent,r=t.permission,s=t.email,c=t.jwt}if(typeof document<"u"){const t=u=>document.querySelector(`meta[name="${u}"]`)?.getAttribute("content")||void 0;o=o||t("ago-base-url"),l=l||t("ago-widget-id"),a=a||t("ago-agent")||t("ago-agent-id"),r=r||t("ago-permission"),s=s||t("ago-user-email")}if(typeof document<"u"){const t=[document.body,...Array.from(document.querySelectorAll("script[data-ago-base-url]"))].filter(Boolean);for(const u of t)u&&(o=o||u.getAttribute("data-ago-base-url")||void 0,l=l||u.getAttribute("data-ago-widget-id")||void 0,a=a||u.getAttribute("data-ago-agent")||u.getAttribute("data-ago-agent-id")||void 0,r=r||u.getAttribute("data-ago-permission")||void 0,s=s||u.getAttribute("data-ago-user-email")||void 0)}o=e?.baseUrl||o,l=e?.widgetId||l,a=e?.agent||e?.defaultAgentId||a,r=e?.permission||r,s=e?.userEmail||s,c=e?.userJwt||c;const f=e?.debug;return o?{baseUrl:o,widgetId:l,agent:a,permission:r,userEmail:s,userJwt:c,debug:f}:null}function k(e){const o=A(e);if(!o)throw new n.AgoError('createAgo(): could not detect AGO configuration. Set window.AGO, add <meta name="ago-base-url">, or pass { baseUrl } explicitly.',"config_missing_base_url");return new n.AgoClient(o)}function q(e,o){return{...e,handler:o}}exports.AgoApiError=n.AgoApiError;exports.AgoClient=n.AgoClient;exports.AgoError=n.AgoError;exports.AgoFunctionError=n.AgoFunctionError;exports.AgoNetworkError=n.AgoNetworkError;exports.AgoStreamError=n.AgoStreamError;exports.ClientContextRegistry=n.ClientContextRegistry;exports.EventEmitter=n.EventEmitter;exports.FunctionRegistry=n.FunctionRegistry;exports.SSEHandler=n.SSEHandler;exports.autoDetectConfig=A;exports.copyToClipboard=g.copyToClipboard;exports.createAgo=k;exports.createConversationSession=p.createConversationSession;exports.createFormCollector=m.createFormCollector;exports.createMessageStream=M;exports.createMockClient=w.createMockClient;exports.createStore=m.createStore;exports.defineFunction=h;exports.deriveFormStatus=m.deriveFormStatus;exports.getLocalStorage=g.getLocalStorage;exports.getUserLocation=g.getUserLocation;exports.highlightElement=g.highlightElement;exports.isStreamNetworkError=n.isStreamNetworkError;exports.loadFormCollector=m.loadFormCollector;exports.logger=n.logger;exports.onFunctionInvoke=F;exports.onMessage=E;exports.onMessageChunk=S;exports.onMessageError=v;exports.onMessageStart=y;exports.onToolCall=b;exports.openUrl=g.openUrl;exports.scrollToElement=g.scrollToElement;exports.setLocalStorage=g.setLocalStorage;exports.setTheme=g.setTheme;exports.showConfirmDialog=g.showConfirmDialog;exports.showNotification=g.showNotification;exports.showToast=g.showToast;exports.submitForm=g.submitForm;exports.trackEvent=g.trackEvent;exports.validateConfig=n.validateConfig;exports.withHandler=q;
|