@useago/sdk 0.4.5 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@ var d = class extends Error {
22
22
  constructor(e, t, s) {
23
23
  super(e, "function_error"), this.functionName = t, this.originalError = s, this.name = "AgoFunctionError";
24
24
  }
25
- }, w = class {
25
+ }, y = class {
26
26
  constructor(e = !1) {
27
27
  this.enabled = e;
28
28
  }
@@ -44,7 +44,7 @@ var d = class extends Error {
44
44
  debug(...e) {
45
45
  this.enabled && console.debug("[AGO SDK]", ...e);
46
46
  }
47
- }, n = new w(), f = "ago_widget_id";
47
+ }, n = new y(), f = "ago_widget_id";
48
48
  function C() {
49
49
  if (typeof localStorage < "u") {
50
50
  const t = localStorage.getItem(f);
@@ -133,10 +133,10 @@ var E = class {
133
133
  }
134
134
  register(e, t, s) {
135
135
  if (typeof e == "object") {
136
- const { name: i, handler: o, description: a, parameters: c } = e;
136
+ const { name: i, handler: o, description: a, parameters: l } = e;
137
137
  return this.register(i, o, {
138
138
  description: a,
139
- parameters: c
139
+ parameters: l
140
140
  });
141
141
  }
142
142
  const r = e;
@@ -212,9 +212,9 @@ var E = class {
212
212
  clear() {
213
213
  this.entries.clear(), this.dynamicProviders.clear(), n.log("ClientContext cleared");
214
214
  }
215
- }, S = class {
215
+ }, k = class {
216
216
  constructor(e) {
217
- this.callbacks = e, this.buffer = "", this.message = {}, this.toolCalls = [], this.sources = [], this.followUpReplies = [], this.isFirstChunk = !0;
217
+ this.callbacks = e, this.buffer = "", this.message = {}, this.toolCalls = [], this.sources = [], this.followUpReplies = [], this.isFirstChunk = !0, this.answerCompleteEmitted = !1;
218
218
  }
219
219
  async processStream(e) {
220
220
  if (!e.body) throw new g("Response has no body");
@@ -285,7 +285,7 @@ var E = class {
285
285
  const s = this.toolCalls.findIndex((r) => r.id === t.id);
286
286
  s >= 0 ? this.toolCalls[s] = t : this.toolCalls.push(t);
287
287
  }
288
- e.follow_up_replies && (this.followUpReplies = e.follow_up_replies);
288
+ 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()));
289
289
  }
290
290
  parseToolCall(e) {
291
291
  return {
@@ -301,8 +301,8 @@ var E = class {
301
301
  arguments: e.arguments
302
302
  };
303
303
  }
304
- buildFinalMessage() {
305
- const e = {
304
+ buildMessage() {
305
+ return {
306
306
  id: this.message.id || "",
307
307
  conversationId: this.message.conversationId || "",
308
308
  content: this.message.content || "",
@@ -314,6 +314,9 @@ var E = class {
314
314
  followUpReplies: this.followUpReplies.length > 0 ? this.followUpReplies : void 0,
315
315
  createdAt: /* @__PURE__ */ new Date()
316
316
  };
317
+ }
318
+ buildFinalMessage() {
319
+ const e = this.buildMessage();
317
320
  return this.callbacks.onComplete?.(e), e;
318
321
  }
319
322
  };
@@ -321,7 +324,7 @@ function x(e) {
321
324
  const t = e.message.toLowerCase();
322
325
  return t.includes("load failed") || t.includes("failed to fetch") || t.includes("network") || t.includes("abort");
323
326
  }
324
- var k = class {
327
+ var S = class {
325
328
  constructor() {
326
329
  this.handlers = /* @__PURE__ */ new Map();
327
330
  }
@@ -362,9 +365,9 @@ var k = class {
362
365
  removeAllListeners(e) {
363
366
  e ? this.handlers.delete(e) : this.handlers.clear();
364
367
  }
365
- }, $ = class v {
368
+ }, $ = class w {
366
369
  constructor(t) {
367
- this.config = t, this.httpClient = new E(t), this.functionRegistry = new b(), this.contextRegistry = new _(), this.eventEmitter = new k(), t.debug && n.enable(), n.log("AgoClient initialized");
370
+ this.config = t, this.httpClient = new E(t), this.functionRegistry = new b(), this.contextRegistry = new _(), this.eventEmitter = new S(), t.debug && n.enable(), n.log("AgoClient initialized");
368
371
  }
369
372
  async sendMessage(t, s) {
370
373
  const r = this.functionRegistry.getSchemas(), i = this.contextRegistry.getSnapshot(), o = this.config.agent || this.config.defaultAgentId, a = {
@@ -373,17 +376,17 @@ var k = class {
373
376
  agent_id: s?.agentId || o
374
377
  };
375
378
  r.length > 0 && (a.client_functions = r), i && (a.client_context = i);
376
- let c;
379
+ let l;
377
380
  if (s?.files && s.files.length > 0) {
378
- const l = new FormData();
379
- l.append("content", t), s.conversationId && l.append("conversation_id", s.conversationId), (s.agentId || o) && l.append("agent_id", s.agentId || o || ""), r.length > 0 && l.append("client_functions", JSON.stringify(r)), i && l.append("client_context", JSON.stringify(i));
380
- for (const y of s.files) l.append("files", y);
381
- c = await this.httpClient.postFormData("/api/sdk/v1/messages", l);
382
- } else c = await this.httpClient.postStream("/api/sdk/v1/messages", a);
383
- return this.processSSEResponse(c);
381
+ const c = new FormData();
382
+ c.append("content", t), s.conversationId && c.append("conversation_id", s.conversationId), (s.agentId || o) && c.append("agent_id", s.agentId || o || ""), r.length > 0 && c.append("client_functions", JSON.stringify(r)), i && c.append("client_context", JSON.stringify(i));
383
+ for (const v of s.files) c.append("files", v);
384
+ l = await this.httpClient.postFormData("/api/sdk/v1/messages", c);
385
+ } else l = await this.httpClient.postStream("/api/sdk/v1/messages", a);
386
+ return this.processSSEResponse(l);
384
387
  }
385
388
  async processSSEResponse(t) {
386
- return new S({
389
+ return new k({
387
390
  onStart: (s) => {
388
391
  this.eventEmitter.emit("message:start", s);
389
392
  },
@@ -396,6 +399,9 @@ var k = class {
396
399
  onClientFunction: async (s) => {
397
400
  this.eventEmitter.emit("function:invoke", s), await this.handleClientFunctionInvocation(s);
398
401
  },
402
+ onAnswerComplete: (s) => {
403
+ this.eventEmitter.emit("message:answer-complete", s);
404
+ },
399
405
  onComplete: (s) => {
400
406
  this.eventEmitter.emit("message:complete", s);
401
407
  },
@@ -445,7 +451,7 @@ var k = class {
445
451
  role: i.role,
446
452
  status: i.status,
447
453
  createdAt: new Date(i.created_at),
448
- toolCalls: v.mapPersistedToolCalls(i.tool_call_data)
454
+ toolCalls: w.mapPersistedToolCalls(i.tool_call_data)
449
455
  }))
450
456
  };
451
457
  return this.eventEmitter.emit("conversation:loaded", r), r;
@@ -503,10 +509,10 @@ var k = class {
503
509
  const r = s.map((o) => o.name), i = s.map((o) => `- "${o.name}": ${o.description}`).join(`
504
510
  `);
505
511
  this.registerFunction("navigateToPage", async (o) => {
506
- const a = o.page, c = s.find((l) => l.name === a);
507
- return c ? (t(c.path), {
512
+ const a = o.page, l = s.find((c) => c.name === a);
513
+ return l ? (t(l.path), {
508
514
  success: !0,
509
- navigatedTo: c.path
515
+ navigatedTo: l.path
510
516
  }) : {
511
517
  success: !1,
512
518
  error: `Unknown page: ${a}`
@@ -587,9 +593,9 @@ export {
587
593
  g as f,
588
594
  x as i,
589
595
  d as l,
590
- k as n,
596
+ S as n,
591
597
  b as o,
592
- S as r,
598
+ k as r,
593
599
  n as s,
594
600
  $ as t,
595
601
  m as u
@@ -0,0 +1,6 @@
1
+ var u=class extends Error{constructor(e,t,s){super(e),this.code=t,this.statusCode=s,this.name="AgoError"}},h=class p extends u{constructor(t,s,r,n,o,a){super(t,s,r),this.type=n,this.param=o,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,s){const r=t.error;return new p(r.message,r.code,s,r.type,r.param,r.doc_url)}},d=class extends u{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},g=class extends u{constructor(e){super(e,"stream_error"),this.name="AgoStreamError"}},m=class extends u{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)}},i=new _,f="ago_widget_id";function S(){if(typeof localStorage<"u"){const t=localStorage.getItem(f);if(t)return t}const e=crypto.randomUUID();if(typeof localStorage<"u")try{localStorage.setItem(f,e)}catch{}return e}var k=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-Widget-Id":e.widgetId||S()},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-Widget-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}`;i.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 h?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}`,r instanceof Error?r:void 0)}}async postFormData(e,t){const s=`${this.baseUrl}${e}`;i.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 h?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}`,n instanceof Error?n:void 0)}}async request(e,t,s){const r=`${this.baseUrl}${t}`;i.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 h?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}`,n instanceof Error?n:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}throw t?.error?h.fromResponse(t,e.status):new h(`HTTP ${e.status}: ${e.statusText}`,"http_error",e.status,"api_error")}},y=class{constructor(){this.functions=new Map}register(e,t,s){if(typeof e=="object"){const{name:n,handler:o,description:a,parameters:c}=e;return this.register(n,o,{description:a,parameters:c})}const r=e;if(!t||!s)throw new Error("handler and schema are required");this.functions.has(r)&&i.warn(`Function "${r}" is being overwritten`),this.functions.set(r,{schema:{...s,name:r},handler:t}),i.log(`Registered function: ${r}`)}unregister(e){const t=this.functions.delete(e);return t&&i.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);i.log(`Executing function: ${e}`,t);try{const r=await s.handler(t);return i.log(`Function ${e} completed:`,r),r}catch(r){throw i.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(),i.log("Cleared all registered functions")}get size(){return this.functions.size}},w=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),i.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&i.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),i.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&i.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){i.error(`DynamicContext provider "${t}" threw:`,r)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),i.log("ClientContext cleared")}},v=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");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:r,value:n}=await t.read();if(r)break;const o=s.decode(n,{stream:!0});this.buffer+=o,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(r){const n=r instanceof Error?r:new g("Stream processing failed");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 o=JSON.parse(n);this.handleChunk(o)}catch(o){i.warn("Failed to parse SSE data:",n,o)}}}}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 x(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var C=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 o=(a=>{n&&clearTimeout(n),s(a)});this.once(e,o),t?.timeout&&(n=setTimeout(()=>{this.off(e,o),r(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},A=class b{constructor(t){this.config=t,this.httpClient=new k(t),this.functionRegistry=new y,this.contextRegistry=new w,this.eventEmitter=new C,t.debug&&i.enable(),i.log("AgoClient initialized")}async sendMessage(t,s){const r=this.functionRegistry.getSchemas(),n=this.contextRegistry.getSnapshot(),o=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||o};r.length>0&&(a.client_functions=r),n&&(a.client_context=n);let c;if(s?.files&&s.files.length>0){const l=new FormData;l.append("content",t),s.conversationId&&l.append("conversation_id",s.conversationId),(s.agentId||o)&&l.append("agent_id",s.agentId||o||""),r.length>0&&l.append("client_functions",JSON.stringify(r)),n&&l.append("client_context",JSON.stringify(n));for(const E of s.files)l.append("files",E);c=await this.httpClient.postFormData("/api/sdk/v1/messages",l)}else c=await this.httpClient.postStream("/api/sdk/v1/messages",a);return this.processSSEResponse(c)}async processSSEResponse(t){return new v({onStart:s=>{this.eventEmitter.emit("message:start",s)},onChunk:s=>{this.eventEmitter.emit("message:chunk",s)},onToolCall:s=>{this.eventEmitter.emit("toolCall:received",s),s.type==="form"&&this.eventEmitter.emit("toolCall:form",s)},onClientFunction:async s=>{this.eventEmitter.emit("function:invoke",s),await this.handleClientFunctionInvocation(s)},onAnswerComplete:s=>{this.eventEmitter.emit("message:answer-complete",s)},onComplete:s=>{this.eventEmitter.emit("message:complete",s)},onError:s=>{this.eventEmitter.emit("message:error",{error:s.message})}}).processStream(t)}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",i.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){i.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:b.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 submitFormCollector(t,s){return this.httpClient.post("/api/sdk/v1/forms/submit",{destination: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(o=>o.name),n=s.map(o=>`- "${o.name}": ${o.description}`).join(`
5
+ `);this.registerFunction("navigateToPage",async o=>{const a=o.page,c=s.find(l=>l.name===a);return c?(t(c.path),{success:!0,navigatedTo:c.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){this.config={...this.config,...t},this.httpClient.updateConfig(t),t.debug!==void 0&&(t.debug?i.enable():i.disable())}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),i.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return A}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return u}});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 w}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return C}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return y}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return v}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return x}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return i}});
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-D4EL6nva.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-CPqPT5s6.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;
@@ -216,6 +216,11 @@ export declare interface AgoClientEvents {
216
216
  conversationId: string;
217
217
  messageId: string;
218
218
  };
219
+ /**
220
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
221
+ * replies may still be pending. Fires once, before `message:complete`.
222
+ */
223
+ "message:answer-complete": AgoMessage;
219
224
  "message:complete": AgoMessage;
220
225
  "message:error": {
221
226
  error: string;
package/dist/angular.d.ts CHANGED
@@ -216,6 +216,11 @@ export declare interface AgoClientEvents {
216
216
  conversationId: string;
217
217
  messageId: string;
218
218
  };
219
+ /**
220
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
221
+ * replies may still be pending. Fires once, before `message:complete`.
222
+ */
223
+ "message:answer-complete": AgoMessage;
219
224
  "message:complete": AgoMessage;
220
225
  "message:error": {
221
226
  error: string;
package/dist/angular.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as o } from "./AgoClient-rvTz2thR.js";
1
+ import { t as o } from "./AgoClient-BrYhSO5M.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-BMTdfhHg.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-DaWZsBsI.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 { r as d } from "./createFormCollector-Cujr7hW4.js";
1
+ import { r as d } from "./createFormCollector-CPS2phYq.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,245 @@
1
+ import { s as _ } from "./AgoClient-BrYhSO5M.js";
2
+ function E(n, e) {
3
+ const l = e ? e.storage ?? (typeof localStorage < "u" ? localStorage : void 0) : void 0;
4
+ let r = n;
5
+ if (e && l) try {
6
+ const c = l.getItem(e.key);
7
+ c != null && (r = JSON.parse(c));
8
+ } catch {
9
+ }
10
+ const i = /* @__PURE__ */ new Set(), f = () => i.forEach((c) => c(r));
11
+ function m() {
12
+ if (e && l) try {
13
+ l.setItem(e.key, JSON.stringify(r));
14
+ } catch {
15
+ }
16
+ }
17
+ return {
18
+ get: () => r,
19
+ set: (c) => {
20
+ r = c, m(), f();
21
+ },
22
+ subscribe: (c) => (i.add(c), () => {
23
+ i.delete(c);
24
+ })
25
+ };
26
+ }
27
+ var q = /^[a-zA-Z0-9_-]{1,40}$/, O = (n) => n == null || n === "";
28
+ function F(n, e) {
29
+ const l = e[n.property];
30
+ if (O(l)) return !1;
31
+ if (Array.isArray(n.value)) return n.value.some((f) => String(l) === String(f));
32
+ if (!n.op) return String(l) === String(n.value);
33
+ const r = Number(l), i = Number(n.value);
34
+ if (Number.isNaN(r) || Number.isNaN(i)) return !1;
35
+ switch (n.op) {
36
+ case ">=":
37
+ return r >= i;
38
+ case "<=":
39
+ return r <= i;
40
+ case ">":
41
+ return r > i;
42
+ case "<":
43
+ return r < i;
44
+ default:
45
+ return _.warn(`Unknown requiredWhen op "${n.op}"; treating as not required.`), !1;
46
+ }
47
+ }
48
+ function y(n, e) {
49
+ const l = n.properties ?? {}, r = /* @__PURE__ */ new Set();
50
+ for (const f of n.required ?? []) {
51
+ const m = l[f]?.requiredWhen;
52
+ (!m || F(m, e)) && r.add(f);
53
+ }
54
+ for (const [f, m] of Object.entries(l)) m.requiredWhen && F(m.requiredWhen, e) && r.add(f);
55
+ const i = [...r].filter((f) => O(e[f]));
56
+ return {
57
+ missing: i,
58
+ complete: i.length === 0
59
+ };
60
+ }
61
+ function P(n) {
62
+ const e = {};
63
+ for (const [l, r] of Object.entries(n.properties ?? {})) e[l] = {
64
+ type: r.type,
65
+ ...r.description != null && { description: r.description },
66
+ ...r.enum && { enum: r.enum },
67
+ ...r.default !== void 0 && { default: r.default }
68
+ };
69
+ return {
70
+ type: "object",
71
+ properties: e,
72
+ required: []
73
+ };
74
+ }
75
+ function I(n) {
76
+ const { name: e, description: l, schema: r } = n;
77
+ if (!q.test(e)) throw new Error(`Invalid form collector name "${e}": must match ${q} (it becomes the update_/submit_ function names).`);
78
+ const i = typeof n.submit == "string" ? n.submit ? {
79
+ via: "client",
80
+ url: n.submit
81
+ } : !1 : n.submit ?? !1, f = r.properties ?? {}, m = (t) => {
82
+ const s = {};
83
+ for (const [a, o] of Object.entries(t)) {
84
+ const u = f[a];
85
+ if (u)
86
+ if (o == null) s[a] = o;
87
+ else if (u.type === "number" || u.type === "integer") {
88
+ const p = typeof o == "number" ? o : Number(o);
89
+ s[a] = Number.isNaN(p) ? o : p;
90
+ } else u.type === "boolean" ? s[a] = typeof o == "boolean" ? o : o === "true" ? !0 : o === "false" ? !1 : !!o : s[a] = o;
91
+ }
92
+ return s;
93
+ }, c = n.initialValues ?? {}, d = E({
94
+ values: c,
95
+ submitted: !1
96
+ }), v = (t) => {
97
+ const s = d.get(), a = {
98
+ ...s,
99
+ values: {
100
+ ...s.values,
101
+ ...t
102
+ }
103
+ };
104
+ return d.set(a), a;
105
+ };
106
+ let h = null;
107
+ const N = async () => {
108
+ const { values: t } = d.get(), { complete: s, missing: a } = y(r, t);
109
+ if (!s) return {
110
+ ok: !1,
111
+ missing: a
112
+ };
113
+ if (!i) return {
114
+ ok: !1,
115
+ error: "No submit target configured for this form collector."
116
+ };
117
+ const o = t;
118
+ try {
119
+ let u;
120
+ if (i.via === "client") if ("handler" in i) u = await i.handler(o);
121
+ else {
122
+ const p = await fetch(i.url, {
123
+ method: "POST",
124
+ headers: { "Content-Type": "application/json" },
125
+ credentials: "include",
126
+ body: JSON.stringify(o)
127
+ });
128
+ if (!p.ok) return {
129
+ ok: !1,
130
+ error: `Submit failed: HTTP ${p.status}`
131
+ };
132
+ u = await p.json().catch(() => {
133
+ });
134
+ }
135
+ else {
136
+ if (!h) return {
137
+ ok: !1,
138
+ error: "Backend submit requires install(client) (or useFormCollector) first."
139
+ };
140
+ u = await h.submitFormCollector(i.destination, o);
141
+ }
142
+ return d.set({
143
+ ...d.get(),
144
+ submitted: !0
145
+ }), {
146
+ ok: !0,
147
+ result: u
148
+ };
149
+ } catch (u) {
150
+ const p = u instanceof Error ? u.message : "Submit failed";
151
+ return _.error(`FormCollector "${e}" submit failed:`, u), {
152
+ ok: !1,
153
+ error: p
154
+ };
155
+ }
156
+ }, $ = {
157
+ name: `update_${e}`,
158
+ description: `Fill or update fields of the "${e}" form. ${l} 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.`,
159
+ parameters: P(r),
160
+ handler: (t) => {
161
+ const s = v(m(t)), { missing: a } = y(r, s.values);
162
+ return {
163
+ ok: !0,
164
+ values: s.values,
165
+ missing: a
166
+ };
167
+ }
168
+ }, b = [$];
169
+ i && b.push({
170
+ name: `submit_${e}`,
171
+ 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.`,
172
+ parameters: {
173
+ type: "object",
174
+ properties: {}
175
+ },
176
+ handler: () => N()
177
+ });
178
+ const T = "client__", S = i ? `submit_${e}` : null, x = (t) => {
179
+ const s = t.functionName ?? t.toolName;
180
+ if (s)
181
+ return s.startsWith(T) ? s.slice(8) : s;
182
+ }, w = (t) => {
183
+ let s = { ...c }, a = !1;
184
+ for (const o of t) {
185
+ const u = x(o);
186
+ u === $.name ? o.arguments && (s = {
187
+ ...s,
188
+ ...m(o.arguments)
189
+ }) : S && u === S && o.status?.toLowerCase() === "done" && (a = !0);
190
+ }
191
+ d.set({
192
+ values: s,
193
+ submitted: a
194
+ });
195
+ }, g = `form:${e}`, C = () => {
196
+ const { values: t, submitted: s } = d.get(), { missing: a, complete: o } = y(r, t), u = i ? ` When nothing is missing and the user confirms, call submit_${e}.` : "", p = s ? `The "${e}" form has been submitted.` : `You are currently collecting information from the user to fill the "${e}" form.`;
197
+ return {
198
+ name: `Form: ${e}`,
199
+ description: `${p} ${l} 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(r)}. Data collected so far: ${JSON.stringify(t)}. Call update_${e} with any fields the user provides; ask only for what is still missing.${u}`,
200
+ data: {
201
+ values: t,
202
+ missing: a,
203
+ complete: o,
204
+ submitted: s
205
+ }
206
+ };
207
+ }, k = (t) => {
208
+ w((t.messages ?? []).flatMap((s) => s.toolCalls ?? []));
209
+ };
210
+ return {
211
+ name: e,
212
+ store: d,
213
+ functions: b,
214
+ contextKey: g,
215
+ contextProvider: C,
216
+ install: (t) => {
217
+ h = t;
218
+ for (const a of b) t.register(a);
219
+ t.addDynamicContext(g, C);
220
+ const s = d.subscribe(() => t.notifyContextChanged());
221
+ return t.on("conversation:loaded", k), () => {
222
+ s();
223
+ for (const a of b) t.unregisterFunction(a.name);
224
+ t.removeDynamicContext(g), t.off("conversation:loaded", k), h === t && (h = null);
225
+ };
226
+ },
227
+ hydrate: w,
228
+ submit: N,
229
+ getValues: () => d.get().values,
230
+ setValues: (t) => {
231
+ v(m(t));
232
+ },
233
+ reset: () => {
234
+ d.set({
235
+ values: c,
236
+ submitted: !1
237
+ });
238
+ }
239
+ };
240
+ }
241
+ export {
242
+ y as n,
243
+ E as r,
244
+ I as t
245
+ };
@@ -0,0 +1 @@
1
+ const O=require("./AgoClient-CPqPT5s6.cjs");function _(o,e){const l=e?e.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let r=o;if(e&&l)try{const c=l.getItem(e.key);c!=null&&(r=JSON.parse(c))}catch{}const i=new Set,f=()=>i.forEach(c=>c(r));function m(){if(e&&l)try{l.setItem(e.key,JSON.stringify(r))}catch{}}return{get:()=>r,set:c=>{r=c,m(),f()},subscribe:c=>(i.add(c),()=>{i.delete(c)})}}var q=/^[a-zA-Z0-9_-]{1,40}$/,P=o=>o==null||o==="";function F(o,e){const l=e[o.property];if(P(l))return!1;if(Array.isArray(o.value))return o.value.some(f=>String(l)===String(f));if(!o.op)return String(l)===String(o.value);const r=Number(l),i=Number(o.value);if(Number.isNaN(r)||Number.isNaN(i))return!1;switch(o.op){case">=":return r>=i;case"<=":return r<=i;case">":return r>i;case"<":return r<i;default:return O.logger.warn(`Unknown requiredWhen op "${o.op}"; treating as not required.`),!1}}function g(o,e){const l=o.properties??{},r=new Set;for(const f of o.required??[]){const m=l[f]?.requiredWhen;(!m||F(m,e))&&r.add(f)}for(const[f,m]of Object.entries(l))m.requiredWhen&&F(m.requiredWhen,e)&&r.add(f);const i=[...r].filter(f=>P(e[f]));return{missing:i,complete:i.length===0}}function E(o){const e={};for(const[l,r]of Object.entries(o.properties??{}))e[l]={type:r.type,...r.description!=null&&{description:r.description},...r.enum&&{enum:r.enum},...r.default!==void 0&&{default:r.default}};return{type:"object",properties:e,required:[]}}function W(o){const{name:e,description:l,schema:r}=o;if(!q.test(e))throw new Error(`Invalid form collector name "${e}": must match ${q} (it becomes the update_/submit_ function names).`);const i=typeof o.submit=="string"?o.submit?{via:"client",url:o.submit}:!1:o.submit??!1,f=r.properties??{},m=t=>{const n={};for(const[a,s]of Object.entries(t)){const u=f[a];if(u)if(s==null)n[a]=s;else if(u.type==="number"||u.type==="integer"){const b=typeof s=="number"?s:Number(s);n[a]=Number.isNaN(b)?s:b}else u.type==="boolean"?n[a]=typeof s=="boolean"?s:s==="true"?!0:s==="false"?!1:!!s:n[a]=s}return n},c=o.initialValues??{},d=_({values:c,submitted:!1}),v=t=>{const n=d.get(),a={...n,values:{...n.values,...t}};return d.set(a),a};let p=null;const N=async()=>{const{values:t}=d.get(),{complete:n,missing:a}=g(r,t);if(!n)return{ok:!1,missing:a};if(!i)return{ok:!1,error:"No submit target configured for this form collector."};const s=t;try{let u;if(i.via==="client")if("handler"in i)u=await i.handler(s);else{const b=await fetch(i.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}`};u=await b.json().catch(()=>{})}else{if(!p)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};u=await p.submitFormCollector(i.destination,s)}return d.set({...d.get(),submitted:!0}),{ok:!0,result:u}}catch(u){const b=u instanceof Error?u.message:"Submit failed";return O.logger.error(`FormCollector "${e}" submit failed:`,u),{ok:!1,error:b}}},S={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${l} 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:E(r),handler:t=>{const n=v(m(t)),{missing:a}=g(r,n.values);return{ok:!0,values:n.values,missing:a}}},h=[S];i&&h.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__",$=i?`submit_${e}`:null,j=t=>{const n=t.functionName??t.toolName;if(n)return n.startsWith(T)?n.slice(8):n},w=t=>{let n={...c},a=!1;for(const s of t){const u=j(s);u===S.name?s.arguments&&(n={...n,...m(s.arguments)}):$&&u===$&&s.status?.toLowerCase()==="done"&&(a=!0)}d.set({values:n,submitted:a})},y=`form:${e}`,C=()=>{const{values:t,submitted:n}=d.get(),{missing:a,complete:s}=g(r,t),u=i?` 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} ${l} 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(r)}. Data collected so far: ${JSON.stringify(t)}. Call update_${e} with any fields the user provides; ask only for what is still missing.${u}`,data:{values:t,missing:a,complete:s,submitted:n}}},k=t=>{w((t.messages??[]).flatMap(n=>n.toolCalls??[]))};return{name:e,store:d,functions:h,contextKey:y,contextProvider:C,install:t=>{p=t;for(const a of h)t.register(a);t.addDynamicContext(y,C);const n=d.subscribe(()=>t.notifyContextChanged());return t.on("conversation:loaded",k),()=>{n();for(const a of h)t.unregisterFunction(a.name);t.removeDynamicContext(y),t.off("conversation:loaded",k),p===t&&(p=null)}},hydrate:w,submit:N,getValues:()=>d.get().values,setValues:t=>{v(m(t))},reset:()=>{d.set({values:c,submitted:!1})}}}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return W}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return g}});
package/dist/devtools.cjs CHANGED
@@ -1,17 +1,17 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var c,d,v=()=>({});function i(){c&&(c.textContent=JSON.stringify(v(),null,2))}function s(l,e){if(!d)return;const o=document.createElement("div");o.className=`dev-log-line dev-log-${e}`,o.textContent=`${new Date().toLocaleTimeString()} ${l}`,d.appendChild(o),d.scrollTop=d.scrollHeight}var x="ago_dev_panel_collapsed";function r(l,e){l.classList.toggle("collapsed",e);const o=l.querySelector(".dev-toggle");o&&(o.textContent=e?"▢":"—",o.title=e?"Expand dev tools":"Collapse dev tools",o.setAttribute("aria-expanded",String(!e)));try{localStorage.setItem(x,e?"1":"0")}catch{}}function h(l){const{client:e,target:o}=l;v=()=>e.getContextSnapshot()?.entries??{},b();const u=typeof o=="string"?document.querySelector(o):o instanceof Element?o:document.body,t=document.createElement("aside");t.id="ago-dev-panel",(u??document.body).appendChild(t),t.innerHTML=`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var p,d,x=()=>({});function i(){p&&(p.textContent=JSON.stringify(x(),null,2))}function s(n,e){if(!d)return;const o=document.createElement("div");o.className=`dev-log-line dev-log-${e}`,o.textContent=`${new Date().toLocaleTimeString()} ${n}`,d.appendChild(o),d.scrollTop=d.scrollHeight}var u="ago_dev_panel_collapsed";function c(n,e){n.classList.toggle("collapsed",e);const o=n.querySelector(".dev-toggle");o&&(o.textContent=e?"▢":"—",o.title=e?"Expand dev tools":"Collapse dev tools",o.setAttribute("aria-expanded",String(!e)));try{localStorage.setItem(u,e?"1":"0")}catch{}}function h(n){const{client:e,target:o}=n;x=()=>{const t=e.getContextSnapshot()?.entries??{};return Object.fromEntries(Object.entries(t).map(([l,{name:r,data:b}])=>[l,{name:r,data:b}]))},m();const f=typeof o=="string"?document.querySelector(o):o instanceof Element?o:document.body,a=document.createElement("aside");a.id="ago-dev-panel",(f??document.body).appendChild(a),a.innerHTML=`
2
2
  <div class="dev-head">
3
3
  <span class="dev-badge">DEV</span>
4
4
  <span class="dev-title">DEV TOOLS · client-side function state — not for production</span>
5
5
  <button type="button" class="dev-toggle" aria-label="Toggle dev tools">—</button>
6
6
  </div>
7
7
  <div class="dev-body">
8
- <div class="dev-fns">Registered functions: <code>${(e.getRegisteredFunctions?.()??[]).map(a=>a.name).join(", ")||"—"}</code></div>
8
+ <div class="dev-fns">Registered functions: <code>${(e.getRegisteredFunctions?.()??[]).map(t=>t.name).join(", ")||"—"}</code></div>
9
9
  <div class="dev-section-label">JSON object (built by the agent)</div>
10
10
  <pre class="dev-state" id="ago-dev-state"></pre>
11
11
  <div class="dev-section-label">Function calls</div>
12
12
  <div class="dev-log" id="ago-dev-log"></div>
13
13
  </div>
14
- `,c=t.querySelector("#ago-dev-state"),d=t.querySelector("#ago-dev-log"),t.querySelector(".dev-toggle")?.addEventListener("click",a=>{a.stopPropagation(),r(t,!t.classList.contains("collapsed"))}),t.addEventListener("click",()=>{t.classList.contains("collapsed")&&r(t,!1)});let p=!1;try{p=localStorage.getItem(x)==="1"}catch{}r(t,p),e.on("function:invoke",({functionName:a,arguments:n})=>{s(`→ ${a}(${JSON.stringify(n??{})})`,"invoke")}),e.on("function:result",({result:a,error:n})=>{s(n?`✗ error: ${n}`:`← ${JSON.stringify(a)}`,n?"error":"result"),i()}),e.on("context:changed",i),e.on("conversation:loaded",a=>{const n=(a.messages??[]).flatMap(f=>f.toolCalls??[]);s(`⟳ hydrated "${a.title||a.id}" — replayed ${n.length} tool call${n.length===1?"":"s"}`,"hydrate"),i()}),i()}var g="ago-dev-panel-styles";function b(){if(document.getElementById(g))return;const l=document.createElement("style");l.id=g,l.textContent=m,document.head.appendChild(l)}var m=`
14
+ `,p=a.querySelector("#ago-dev-state"),d=a.querySelector("#ago-dev-log"),a.querySelector(".dev-toggle")?.addEventListener("click",t=>{t.stopPropagation(),c(a,!a.classList.contains("collapsed"))}),a.addEventListener("click",()=>{a.classList.contains("collapsed")&&c(a,!1)});let g=!1;try{g=localStorage.getItem(u)==="1"}catch{}c(a,g),e.on("function:invoke",({functionName:t,arguments:l})=>{s(`→ ${t}(${JSON.stringify(l??{})})`,"invoke")}),e.on("function:result",({result:t,error:l})=>{s(l?`✗ error: ${l}`:`← ${JSON.stringify(t)}`,l?"error":"result"),i()}),e.on("context:changed",i),e.on("conversation:loaded",t=>{const l=(t.messages??[]).flatMap(r=>r.toolCalls??[]);s(`⟳ hydrated "${t.title||t.id}" — replayed ${l.length} tool call${l.length===1?"":"s"}`,"hydrate"),i()}),i()}var v="ago-dev-panel-styles";function m(){if(document.getElementById(v))return;const n=document.createElement("style");n.id=v,n.textContent=y,document.head.appendChild(n)}var y=`
15
15
  #ago-dev-panel {
16
16
  position: fixed;
17
17
  top: 16px;
@@ -216,6 +216,11 @@ declare interface AgoClientEvents {
216
216
  conversationId: string;
217
217
  messageId: string;
218
218
  };
219
+ /**
220
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
221
+ * replies may still be pending. Fires once, before `message:complete`.
222
+ */
223
+ "message:answer-complete": AgoMessage;
219
224
  "message:complete": AgoMessage;
220
225
  "message:error": {
221
226
  error: string;
@@ -379,8 +384,8 @@ declare interface Conversation {
379
384
  export declare interface DevPanelOptions {
380
385
  /**
381
386
  * The AGO client to debug. The panel lists its registered functions, logs its
382
- * function events, and renders its live context snapshot
383
- * (`client.getContextSnapshot()`)
387
+ * function events, and renders the name + data of each entry in its live context
388
+ * snapshot (`client.getContextSnapshot()`)
384
389
  */
385
390
  client: Pick<AgoClient, "on" | "getRegisteredFunctions" | "getContextSnapshot">;
386
391
  /** Where to mount: a CSS selector, an Element, or `document.body` (default). */
@@ -216,6 +216,11 @@ declare interface AgoClientEvents {
216
216
  conversationId: string;
217
217
  messageId: string;
218
218
  };
219
+ /**
220
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
221
+ * replies may still be pending. Fires once, before `message:complete`.
222
+ */
223
+ "message:answer-complete": AgoMessage;
219
224
  "message:complete": AgoMessage;
220
225
  "message:error": {
221
226
  error: string;
@@ -379,8 +384,8 @@ declare interface Conversation {
379
384
  export declare interface DevPanelOptions {
380
385
  /**
381
386
  * The AGO client to debug. The panel lists its registered functions, logs its
382
- * function events, and renders its live context snapshot
383
- * (`client.getContextSnapshot()`)
387
+ * function events, and renders the name + data of each entry in its live context
388
+ * snapshot (`client.getContextSnapshot()`)
384
389
  */
385
390
  client: Pick<AgoClient, "on" | "getRegisteredFunctions" | "getContextSnapshot">;
386
391
  /** Where to mount: a CSS selector, an Element, or `document.body` (default). */