@useago/sdk 1.0.0 → 1.0.2

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/dist/vue.d.ts CHANGED
@@ -24,12 +24,26 @@ declare class AgoClient {
24
24
  private contextRegistry;
25
25
  private eventEmitter;
26
26
  private config;
27
+ /** Conversations already warned about an empty reply (one warning each). */
28
+ private warnedEmptyConversations;
27
29
  constructor(config: AgoConfig);
28
30
  /**
29
31
  * Send a message and receive a streaming response
30
32
  */
31
33
  sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
32
34
  private processSSEResponse;
35
+ /**
36
+ * Detect a reply that completed as DONE with no content and no activity —
37
+ * today's backend answers an unknown `agent` slug with an empty 200, which
38
+ * otherwise fails silently. Emits `message:empty` (always) and warns on the
39
+ * console once per conversation (unless `warnOnEmptyReply: false`).
40
+ *
41
+ * Deferred with setTimeout(0) so both land AFTER `sendMessage` resolves:
42
+ * `await client.sendMessage(...)` followed by `client.waitFor("message:empty")`
43
+ * must not race. TEMPORARY heuristic: remove once the backend returns an
44
+ * explicit error for unknown agents (see TODOS.md, backend issue).
45
+ */
46
+ private maybeFlagEmptyReply;
33
47
  private handleClientFunctionInvocation;
34
48
  /**
35
49
  * Get list of conversations
@@ -61,6 +75,13 @@ declare class AgoClient {
61
75
  * Reject a tool call
62
76
  */
63
77
  rejectToolCall(toolCallId: string): Promise<void>;
78
+ /**
79
+ * Fetch a backend-stored form collector definition by name (the single source
80
+ * of truth for the form's description, schema, and submit target). Used by
81
+ * `loadFormCollector` / the name-only form of `useFormCollector` so the schema
82
+ * lives in the backend instead of being hardcoded in client code.
83
+ */
84
+ getFormCollector(name: string): Promise<FormCollectorDefinition>;
64
85
  /**
65
86
  * Relay a completed form collector's values to a server-configured destination.
66
87
  *
@@ -195,6 +216,11 @@ declare class AgoClient {
195
216
  }): Promise<AgoClientEvents[K]>;
196
217
  /**
197
218
  * Update client configuration
219
+ *
220
+ * Validates the MERGED config before committing: omitting a key (or passing
221
+ * it as `undefined`, common with spread-built partials) keeps the current
222
+ * value; an explicit empty/non-string `baseUrl` throws `config_missing_base_url`
223
+ * and leaves the client unchanged (no half-updated state).
198
224
  */
199
225
  updateConfig(config: Partial<AgoConfig>): void;
200
226
  /**
@@ -230,8 +256,23 @@ declare interface AgoClientEvents {
230
256
  */
231
257
  "message:answer-complete": AgoMessage;
232
258
  "message:complete": AgoMessage;
259
+ /**
260
+ * A reply finished as `DONE` with empty content and no tool calls, client
261
+ * functions, or follow-up replies — usually an unknown `agent` slug (the
262
+ * backend currently answers those with an empty 200). Fires after
263
+ * `message:complete` AND after `sendMessage` resolves, so subscribing right
264
+ * after `await sendMessage(...)` still catches it. `messageId` and
265
+ * `conversationId` are empty strings when the stream completed without any
266
+ * message data at all (e.g. a proxy stripped the SSE stream).
267
+ */
268
+ "message:empty": {
269
+ conversationId: string;
270
+ messageId: string;
271
+ };
233
272
  "message:error": {
234
273
  error: string;
274
+ /** Stable error code (see configuration.md#error-codes) when the failure was an AgoError. */
275
+ code?: string;
235
276
  conversationId?: string;
236
277
  messageId?: string;
237
278
  };
@@ -260,7 +301,7 @@ declare interface AgoClientEvents {
260
301
  export declare interface AgoConfig {
261
302
  /** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
262
303
  baseUrl: string;
263
- /** Widget ID (X-Widget-Id header). Auto-generated if not provided. */
304
+ /** Per-visitor anonymous ID (X-User-Anon-Id header). Auto-generated if not provided. */
264
305
  widgetId?: string;
265
306
  /** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
266
307
  agent?: string;
@@ -274,6 +315,13 @@ export declare interface AgoConfig {
274
315
  userJwt?: string;
275
316
  /** Enable debug logging */
276
317
  debug?: boolean;
318
+ /**
319
+ * Warn on the console when a reply completes with empty content and no tool
320
+ * calls (the usual cause is an unknown `agent` slug, which the backend
321
+ * currently answers with an empty 200). Default `true`. The `message:empty`
322
+ * event fires regardless of this setting.
323
+ */
324
+ warnOnEmptyReply?: boolean;
277
325
  }
278
326
 
279
327
  declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
@@ -417,6 +465,30 @@ export declare interface Conversation {
417
465
  */
418
466
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
419
467
 
468
+ /**
469
+ * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
470
+ * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
471
+ * {@link CreateFormCollectorOptions}: the `submit` here is never the client-only
472
+ * `handler` variant (a function can't be stored server-side).
473
+ */
474
+ declare interface FormCollectorDefinition<V = Record<string, unknown>> {
475
+ name: string;
476
+ description: string;
477
+ schema: FormCollectorSchema;
478
+ /** Server-stored submit target, if any. Absent means collect-only. */
479
+ submit?: SubmitConfig<V>;
480
+ }
481
+
482
+ /**
483
+ * Shape of a form's fields. Mirrors a client function's `parameters` (so the same
484
+ * object feeds the store, the update function, and the dynamic context). Additionally allows the SDK-only per-field `requiredWhen`, which {@link toWireParameters} removes before the schema reaches the LLM.
485
+ */
486
+ declare interface FormCollectorSchema {
487
+ type: "object";
488
+ properties: Record<string, FormFieldSchema>;
489
+ required?: string[];
490
+ }
491
+
420
492
  declare interface FormField {
421
493
  type: "string" | "number" | "boolean" | "array";
422
494
  title?: string;
@@ -433,6 +505,43 @@ declare interface FormField_2 {
433
505
  default?: unknown;
434
506
  }
435
507
 
508
+ /**
509
+ * A field's conditional-requiredness rule. The field becomes required exactly
510
+ * when the controlling `property` matches `value` against the answers collected
511
+ * so far:
512
+ * - a single `value`, no `op` — equality (compared as strings);
513
+ * - a single `value` with `op` — numeric comparison (both sides coerced to numbers);
514
+ * - an array `value`, no `op` — "one of": matches when the property equals any
515
+ * listed value.
516
+ *
517
+ * SDK-only — it is stripped from the schema before it reaches the LLM tool
518
+ */
519
+ declare interface FormFieldCondition {
520
+ /** The controlling field whose value the rule tests. */
521
+ property: string;
522
+ /** Comparison operator; omitted means equality. Ignored when `value` is an array. */
523
+ op?: ">=" | "<=" | ">" | "<";
524
+ /**
525
+ * The value(s) to test the controlling field against. A single value is an
526
+ * equality (or, with `op`, a numeric comparison); an array is an "is one of"
527
+ * membership test, e.g. `value: ["1", "2", "3"]`.
528
+ */
529
+ value: string | number | Array<string | number>;
530
+ }
531
+
532
+ /** A single field's schema: the wire-legal keys plus the SDK-only `requiredWhen`. */
533
+ declare interface FormFieldSchema {
534
+ type: string;
535
+ description?: string;
536
+ enum?: string[];
537
+ default?: unknown;
538
+ /**
539
+ * Makes the field required only while this condition holds. Drives the dynamic
540
+ * `missing` list; stripped before the LLM tool — see {@link toWireParameters}.
541
+ */
542
+ requiredWhen?: FormFieldCondition;
543
+ }
544
+
436
545
  /**
437
546
  * Form schema for tool calls requiring user input
438
547
  */
@@ -479,6 +588,27 @@ declare interface Store<T> {
479
588
  subscribe(listener: (state: T) => void): () => void;
480
589
  }
481
590
 
591
+ /**
592
+ * Where a completed form is sent.
593
+ * - `"https://..."` (a bare string) — shorthand for `{ via: "client", url }`: the browser
594
+ * POSTs the values to that URL.
595
+ * - `{ via: "client", url }` — same, written out.
596
+ * - `{ via: "client", handler }` — the browser runs your own submit logic.
597
+ * - `{ via: "backend", destination }` — the browser relays the values to the backend,
598
+ * which forwards them to the server-configured destination (URL + secret stay server-side).
599
+ * - `false` — collect only, no submit function.
600
+ */
601
+ declare type SubmitConfig<V = Record<string, unknown>> = string | {
602
+ via: "client";
603
+ url: string;
604
+ } | {
605
+ via: "client";
606
+ handler: (values: V) => Promise<unknown> | unknown;
607
+ } | {
608
+ via: "backend";
609
+ destination: string;
610
+ } | false;
611
+
482
612
  /**
483
613
  * Tool call data from SSE stream
484
614
  */
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as A } from "./AgoClient-BrYhSO5M.js";
1
+ import { t as A } from "./AgoClient-bQozE6-A.js";
2
2
  import { computed as y, inject as F, onMounted as g, onScopeDispose as N, onUnmounted as I, ref as c, shallowRef as D } from "vue";
3
3
  var L = /* @__PURE__ */ Symbol("ago-client"), b = { install(t, n) {
4
4
  const e = new A(n);
package/dist/widget.cjs CHANGED
@@ -1,5 +1,5 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Ie=require("./AgoClient-CPqPT5s6.cjs"),Te=require("./createFormCollector-DaWZsBsI.cjs"),Ne=require("./createConversationSession-CGRO0bs2.cjs");var Oe={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function H(o){return o.replace(/[&<>"']/g,n=>Oe[n])}function ce(o){const n=o.trim();return/^(https?:|mailto:|tel:|#|\/|\.\/|\.\.\/)/i.test(n)||!/^[a-z][a-z0-9+.-]*:/i.test(n)?n:null}var ge='"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace',q="";function L(o){const n=[],r=u=>(n.push(u),`${q}${n.length-1}${q}`);let e=o;return e=e.replace(/`([^`]+)`/g,(u,a)=>r(`<code style="background:#f0f2f5;padding:2px 5px;border-radius:4px;font-size:13px;font-family:${ge}">${H(a)}</code>`)),e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(u,a,p)=>{const i=ce(p);return i?r(`<img alt="${H(a)}" src="${H(i)}" style="max-width:100%;border-radius:8px;margin:4px 0" />`):u}),e=e.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(u,a,p)=>{const i=ce(p);return i?r(`<a href="${H(i)}" target="_blank" rel="noopener noreferrer" style="color:#1b5fc4;text-decoration:underline">${L(a)}</a>`):u}),e=H(e),e=e.replace(/\*\*([^*]+?)\*\*/g,"<strong>$1</strong>").replace(/__([^_]+?)__/g,"<strong>$1</strong>").replace(/~~([^~]+?)~~/g,"<del>$1</del>").replace(/(^|[^*])\*(?!\s)([^*]+?)\*/g,"$1<em>$2</em>").replace(/(^|[^\w_])_(?!\s)([^_]+?)_/g,"$1<em>$2</em>"),e=e.replace(new RegExp(`${q}(\\d+)${q}`,"g"),(u,a)=>n[Number(a)]),e}function w(o,n,r){const e=document.createElement(o);return Object.assign(e.style,n),r!==void 0&&(e.innerHTML=r),e}var he=/^ {0,3}([-*_])( *\1){2,} *$/,me=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/,xe=/^ {0,3}(```+|~~~+)/,X=/^ {0,3}>\s?/,B=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/,Ae=["20px","18px","16px","15px","14px","13px"],J=o=>o.match(/^\s*/)?.[0].length??0;function Le(o){return o.trim()===""||he.test(o)||me.test(o)||xe.test(o)||X.test(o)||B.test(o)}function be(o){const n=o[0].match(B),r=n[1].length,e=/\d/.test(n[2]),u=w(e?"ol":"ul",{margin:"0 0 8px 0",paddingLeft:"20px",listStyleType:e?"decimal":"disc",listStylePosition:"outside"});let a=0;for(;a<o.length;){const p=o[a].match(B),i=[];for(a++;a<o.length&&J(o[a])>r;)i.push(o[a]),a++;const f=w("li",{display:"list-item",margin:"2px 0",lineHeight:"1.6"}),d=p[3].match(/^\[([ xX])\]\s+(.*)$/);d?(f.style.listStyleType="none",f.style.marginLeft="-20px",f.innerHTML=`<span style="margin-right:6px">${d[1].toLowerCase()==="x"?"☑":"☐"}</span>${L(d[2])}`):f.innerHTML=L(p[3]),i.filter(b=>B.test(b)).length>0&&f.appendChild(be(i.filter(b=>b.trim()!==""))),u.appendChild(f)}return u}function De(o){const n=i=>i.replace(/^\s*\|?/,"").replace(/\|?\s*$/,"").split("|").map(f=>f.trim()),r=w("div",{overflowX:"auto",margin:"0 0 8px 0"}),e=w("table",{borderCollapse:"collapse",width:"100%",fontSize:"13px"}),u=document.createElement("thead"),a=document.createElement("tr");for(const i of n(o[0]))a.appendChild(w("th",{border:"1px solid #dee3e8",padding:"6px 10px",textAlign:"left",backgroundColor:"#f5f7fa",fontWeight:"600"},L(i)));u.appendChild(a),e.appendChild(u);const p=document.createElement("tbody");for(const i of o.slice(2)){const f=document.createElement("tr");for(const d of n(i))f.appendChild(w("td",{border:"1px solid #dee3e8",padding:"6px 10px"},L(d)));p.appendChild(f)}return e.appendChild(p),r.appendChild(e),r}var Me=o=>!!o&&/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o);function ee(o){const n=document.createDocumentFragment(),r=o.replace(/\r\n?/g,`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ke=require("./AgoClient-_fig8FoN.cjs"),$e=require("./createFormCollector-CdQjGAl_.cjs"),Ke=require("./createConversationSession-DJUFgOXy.cjs");var Ve={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function U(o){return o.replace(/[&<>"']/g,n=>Ve[n])}function Ae(o){const n=o.trim();return/^(https?:|mailto:|tel:|#|\/|\.\/|\.\.\/)/i.test(n)||!/^[a-z][a-z0-9+.-]*:/i.test(n)?n:null}var Te='"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace',Q="";function M(o){const n=[],r=u=>(n.push(u),`${Q}${n.length-1}${Q}`);let t=o;return t=t.replace(/`([^`]+)`/g,(u,i)=>r(`<code style="background:#f0f2f5;padding:2px 5px;border-radius:4px;font-size:13px;font-family:${Te}">${U(i)}</code>`)),t=t.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(u,i,f)=>{const s=Ae(f);return s?r(`<img alt="${U(i)}" src="${U(s)}" style="max-width:100%;border-radius:8px;margin:4px 0" />`):u}),t=t.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(u,i,f)=>{const s=Ae(f);return s?r(`<a href="${U(s)}" target="_blank" rel="noopener noreferrer" style="color:#1b5fc4;text-decoration:underline">${M(i)}</a>`):u}),t=U(t),t=t.replace(/\*\*([^*]+?)\*\*/g,"<strong>$1</strong>").replace(/__([^_]+?)__/g,"<strong>$1</strong>").replace(/~~([^~]+?)~~/g,"<del>$1</del>").replace(/(^|[^*])\*(?!\s)([^*]+?)\*/g,"$1<em>$2</em>").replace(/(^|[^\w_])_(?!\s)([^_]+?)_/g,"$1<em>$2</em>"),t=t.replace(new RegExp(`${Q}(\\d+)${Q}`,"g"),(u,i)=>n[Number(i)]),t}function _(o,n,r){const t=document.createElement(o);return Object.assign(t.style,n),r!==void 0&&(t.innerHTML=r),t}var De=/^ {0,3}([-*_])( *\1){2,} *$/,Me=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/,Be=/^ {0,3}(```+|~~~+)/,Z=/^ {0,3}>\s?/,P=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/,Qe=["20px","18px","16px","15px","14px","13px"],fe=o=>o.match(/^\s*/)?.[0].length??0;function Ye(o){return o.trim()===""||De.test(o)||Me.test(o)||Be.test(o)||Z.test(o)||P.test(o)}function ze(o){const n=o[0].match(P),r=n[1].length,t=/\d/.test(n[2]),u=_(t?"ol":"ul",{margin:"0 0 8px 0",paddingLeft:"20px",listStyleType:t?"decimal":"disc",listStylePosition:"outside"});let i=0;for(;i<o.length;){const f=o[i].match(P),s=[];for(i++;i<o.length&&fe(o[i])>r;)s.push(o[i]),i++;const p=_("li",{display:"list-item",margin:"2px 0",lineHeight:"1.6"}),c=f[3].match(/^\[([ xX])\]\s+(.*)$/);c?(p.style.listStyleType="none",p.style.marginLeft="-20px",p.innerHTML=`<span style="margin-right:6px">${c[1].toLowerCase()==="x"?"☑":"☐"}</span>${M(c[2])}`):p.innerHTML=M(f[3]),s.filter(h=>P.test(h)).length>0&&p.appendChild(ze(s.filter(h=>h.trim()!==""))),u.appendChild(p)}return u}function Ze(o){const n=s=>s.replace(/^\s*\|?/,"").replace(/\|?\s*$/,"").split("|").map(p=>p.trim()),r=_("div",{overflowX:"auto",margin:"0 0 8px 0"}),t=_("table",{borderCollapse:"collapse",width:"100%",fontSize:"13px"}),u=document.createElement("thead"),i=document.createElement("tr");for(const s of n(o[0]))i.appendChild(_("th",{border:"1px solid #dee3e8",padding:"6px 10px",textAlign:"left",backgroundColor:"#f5f7fa",fontWeight:"600"},M(s)));u.appendChild(i),t.appendChild(u);const f=document.createElement("tbody");for(const s of o.slice(2)){const p=document.createElement("tr");for(const c of n(s))p.appendChild(_("td",{border:"1px solid #dee3e8",padding:"6px 10px"},M(c)));f.appendChild(p)}return t.appendChild(f),r.appendChild(t),r}var Je=o=>!!o&&/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o);function J(o){const n=document.createDocumentFragment(),r=o.replace(/\r\n?/g,`
2
2
  `).split(`
3
- `);let e=0;for(;e<r.length;){const a=r[e];if(a.trim()===""){e++;continue}const p=a.match(xe);if(p){const d=p[1][0],b=[];for(e++;e<r.length&&!new RegExp(`^ {0,3}${d==="`"?"`{3,}":"~{3,}"}\\s*$`).test(r[e]);)b.push(r[e]),e++;e++;const N=w("pre",{margin:"0 0 8px 0"});N.appendChild(w("code",{display:"block",background:"#f5f5f5",padding:"8px 12px",borderRadius:"6px",fontSize:"13px",overflowX:"auto",fontFamily:ge,whiteSpace:"pre"},H(b.join(`
4
- `)))),n.appendChild(N);continue}if(he.test(a)){n.appendChild(w("hr",{border:"none",borderTop:"1px solid #dee3e8",margin:"12px 0"})),e++;continue}const i=a.match(me);if(i){const d=i[1].length;n.appendChild(w(`h${d}`,{margin:"16px 0 8px 0",fontSize:Ae[d-1],fontWeight:"600",lineHeight:"1.3"},L(i[2]))),e++;continue}if(X.test(a)){const d=[];for(;e<r.length&&X.test(r[e]);)d.push(r[e].replace(X,"")),e++;const b=w("blockquote",{borderLeft:"4px solid #dee3e8",paddingLeft:"12px",margin:"0 0 8px 0",fontStyle:"italic",color:"#6b6d6f"});b.appendChild(ee(d.join(`
5
- `))),n.appendChild(b);continue}if(a.includes("|")&&Me(r[e+1])){const d=[a,r[e+1]];for(e+=2;e<r.length&&r[e].includes("|")&&r[e].trim();)d.push(r[e]),e++;n.appendChild(De(d));continue}if(B.test(a)){const d=[],b=J(a);for(;e<r.length&&r[e].trim()!=="";)if(B.test(r[e])||J(r[e])>b)d.push(r[e]),e++;else break;n.appendChild(be(d));continue}const f=[a];for(e++;e<r.length&&!Le(r[e]);)f.push(r[e]),e++;n.appendChild(w("p",{margin:"0 0 8px 0",lineHeight:"1.6"},f.map(d=>L(d)).join("<br>")))}const u=n.lastElementChild;return u&&(u.style.marginBottom="0"),n}var Ce='var(--ago-font, "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)',pe={font:"--ago-font",radius:"--ago-radius",messageRadius:"--ago-message-radius",brand:"--ago-brand-color",brandText:"--ago-brand-text-color",headerBg:"--ago-header-background",headerText:"--ago-header-text-color",panelBg:"--ago-panel-background",messagesBg:"--ago-messages-background",text:"--ago-text-color",mutedText:"--ago-muted-text-color",border:"--ago-border-color",accent:"--ago-accent-color"},ve="var(--ago-brand-color, #03182f)",ye="var(--ago-brand-text-color, #fff)",He="var(--ago-header-background, var(--ago-brand-color, #03182f))",Be="var(--ago-header-text-color, #e8f0fe)",z="var(--ago-panel-background, #fff)",Ue="var(--ago-messages-background, #fbfbfb)",j="var(--ago-text-color, #30373e)",ze="var(--ago-muted-text-color, #6b6d6f)",$="var(--ago-border-color, #dee3e8)",Z="var(--ago-accent-color, #1b5fc4)",Fe="var(--ago-radius, 16px)",fe="var(--ago-message-radius, 16px)";function We(o,n){if(n)for(const r of Object.keys(pe)){const e=n[r];e!=null&&o.style.setProperty(pe[r],e)}}function S(o,n){Object.assign(o.style,n)}function x(o={}){const n=document.createElement("div");return S(n,o),n}var ue="ago-chat-widget-keyframes";function Pe(){if(typeof document>"u"||document.getElementById(ue))return;const o=document.createElement("style");o.id=ue,o.textContent="@keyframes ago-pulse { 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } 40% { opacity: 1; transform: scale(1); } }",document.head.appendChild(o)}function Ge(o){const n=typeof o=="string"?document.querySelector(o):o;if(!n)throw new Error(`mountChatWidget: target "${String(o)}" not found.`);return n}function qe(o,n){const{title:r="Chat",welcomeMessage:e="Hello! How can I help you today?",placeholder:u="Type a message...",allowFiles:a=!1,height:p=500,logoUrl:i,showAgentName:f=!1,theme:d,loadThreads:b=!1,forms:N,onFollowUpClick:g,onMessageSent:_,onMessageReceived:F}=n;if(!n.client&&!n.config?.baseUrl)throw new Error("mountChatWidget requires either `client` or `config` (with a baseUrl).");const m=n.client??new Ie.AgoClient(n.config),O=Ge(o),W=n.persistConversation,D=W?Ne.createConversationSession(W===!0?{}:W):void 0;let R=n.conversationId??D?.getLastActiveThread()??void 0,l=[],I=!1,U=null;const P=[],M=x({display:"flex",flexDirection:"column",height:typeof p=="number"?`${p}px`:p,border:`1px solid ${$}`,borderRadius:Fe,overflow:"hidden",backgroundColor:z,fontFamily:Ce,textAlign:"left",boxShadow:"rgba(15, 15, 15, 0.08) 0px 2px 16px 0px"});M.className="ago-chat-widget",We(M,d);const G=x({padding:"14px 16px",borderBottom:`1px solid ${$}`,backgroundColor:He,color:Be,display:"flex",alignItems:"center",gap:"10px"});if(G.className="ago-chat-widget__header",i){const t=document.createElement("img");t.src=i,t.alt="Logo",S(t,{height:"24px",width:"auto"}),G.appendChild(t)}const K=document.createElement("h3");K.textContent=r,S(K,{margin:"0",fontSize:"15px",fontWeight:"600"}),G.appendChild(K);const T=x({flex:"1",overflow:"auto",padding:"16px",backgroundColor:Ue});T.className="ago-chat-widget__messages";const{inputRow:Ee,setDisabled:we,focus:Se}=je({placeholder:u,allowFiles:a,onSend:(t,s)=>{V(t,s)}});Pe(),M.append(G,T,Ee),O.appendChild(M);const te=g!==!1,ne=g===!1?void 0:g??(t=>{V(t)});function Re(t,s){const c=t.role==="user",E=x({display:"flex",flexDirection:"column",alignItems:c?"flex-end":"flex-start",marginBottom:"16px"});if(E.className=`ago-message ago-message--${t.role}`,!c&&f&&t.agent){const h=x({fontSize:"13px",fontWeight:"500",color:j,marginBottom:"6px",padding:"0 4px"});h.className="ago-message__agent",h.textContent=t.agent.displayName||t.agent.name,E.appendChild(h)}if(!c&&t.sources&&t.sources.length>0){const h=x({display:"grid",gridTemplateColumns:"1fr 1fr",gap:"6px",marginBottom:"10px",width:"100%",maxWidth:"85%"});h.className="ago-message__sources",t.sources.forEach((C,y)=>{const A=C.url?document.createElement("a"):document.createElement("div");C.url&&A instanceof HTMLAnchorElement&&(A.href=C.url,A.target="_blank",A.rel="noopener noreferrer"),S(A,{display:"flex",alignItems:"center",gap:"8px",padding:"8px 10px",border:`1px solid ${$}`,borderRadius:"8px",backgroundColor:z,textDecoration:"none",color:j,fontSize:"12px",overflow:"hidden"});const de=x({flexShrink:"0",width:"18px",height:"18px",borderRadius:"3px",border:`1px solid ${Z}`,color:Z,fontSize:"11px",fontWeight:"500",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"#f0f4ff"});de.textContent=String(y+1);const Y=x({overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});Y.textContent=C.title,Y.title=C.title,A.append(de,Y),h.appendChild(A)}),E.appendChild(h)}const v=x({maxWidth:c?"75%":"100%",padding:c?"10px 14px":"2px 8px",borderRadius:c?fe:"0",backgroundColor:c?ve:"transparent",color:c?ye:j,wordBreak:"break-word",fontSize:"14px",lineHeight:"1.6"});if(v.className="ago-message__content",t.content?v.appendChild(ee(t.content)):t.status==="IN_PROGRESS"&&v.appendChild(le()),E.appendChild(v),s&&I&&t.role==="assistant"&&t.status==="DONE"&&!(t.followUpReplies&&t.followUpReplies.length>0)){const h=x({marginTop:"10px",paddingLeft:"8px"});h.className="ago-message__followups-loading",h.appendChild(le()),E.appendChild(h)}if(s&&t.followUpReplies&&t.followUpReplies.length>0){const h=x({display:"flex",flexWrap:"wrap",gap:"8px",marginTop:"10px"});h.className="ago-message__followups";for(const C of t.followUpReplies){const y=document.createElement("button");y.type="button",y.className="ago-message__followup-btn",y.textContent=C,y.disabled=!te,S(y,{padding:"6px 14px",fontSize:"13px",borderRadius:fe,border:`1px solid ${$}`,backgroundColor:z,color:j,cursor:te?"pointer":"default",transition:"border-color 0.15s"}),ne&&y.addEventListener("click",()=>ne(C)),y.addEventListener("mouseenter",()=>{y.style.borderColor=Z}),y.addEventListener("mouseleave",()=>{y.style.borderColor=$}),h.appendChild(y)}E.appendChild(h)}return E}function k(){if(T.replaceChildren(),l.length===0){const s=x({textAlign:"center",color:ze,padding:"24px 16px",fontSize:"14px",lineHeight:"1.5"});s.textContent=e,T.appendChild(s)}else l.forEach((s,c)=>{T.appendChild(Re(s,c===l.length-1))});if(U){const s=x({padding:"10px 14px",backgroundColor:"#fef2f2",color:"#dc2626",borderRadius:"12px",marginTop:"8px",fontSize:"13px",border:"1px solid #fecaca"});s.textContent=U,T.appendChild(s)}T.scrollTop=T.scrollHeight;const t=l[l.length-1];we(I&&t?.role==="assistant"&&t.status==="IN_PROGRESS")}function _e(){for(let t=l.length-1;t>=0;t--){const s=l[t];if(s.role==="assistant"&&s.status==="IN_PROGRESS")return s}}const oe=t=>{R||(R=t.conversationId)},re=t=>{const s=_e();s&&(s.content+=t.content,k())},ae=t=>{const s=l.findIndex(c=>c.id===t.id||c.role==="assistant"&&c.status==="IN_PROGRESS");s>=0?l[s]=t:l.push(t),k()},se=t=>{const s=l.findIndex(c=>c.id===t.id||c.role==="assistant"&&c.status==="IN_PROGRESS");s>=0?l[s]=t:l.push(t),I=!1,k(),t.status==="DONE"&&F?.({id:t.id,content:t.content})},ie=t=>{U=t.error,I=!1,l=l.filter(s=>!s.id.startsWith("temp-")),k()};m.on("message:start",oe),m.on("message:chunk",re),m.on("message:answer-complete",ae),m.on("message:complete",se),m.on("message:error",ie);const ke=(N??[]).map(t=>Te.createFormCollector(t).install(m));async function V(t,s){const c=t.trim();if(!c&&!s?.length||I)return;_?.(c),I=!0,U=null;const E=Date.now();l.push({id:`temp-user-${E}`,conversationId:R||"",content:c,role:"user",status:"DONE",createdAt:new Date}),l.push({id:`temp-assistant-${E}`,conversationId:R||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date}),k();try{const v=await m.sendMessage(c,{conversationId:R,files:s});v.conversationId&&(R||(R=v.conversationId),D?.setActiveThread(v.conversationId,v.createdAt));const h=l.find(C=>C.id===`temp-user-${E}`);if(h&&(h.id=`user-${E}`,h.conversationId=v.conversationId),!l.some(C=>C.id===v.id)){const C=l.findIndex(y=>y.id===`temp-assistant-${E}`);C>=0?l[C]=v:l.push(v)}l=l.filter(C=>!C.id.startsWith("temp-")),I=!1,k(),b&&Q()}catch(v){U=v instanceof Error?v.message:"Failed to send message",I=!1,l=l.filter(h=>!h.id.startsWith("temp-")),k()}}async function Q(){try{const t=await m.getConversations();P.splice(0,P.length,...t)}catch{}return P}async function $e(t){try{const s=(await m.getConversation(t))?.messages??[];s.length>0&&l.length===0&&(l=s,k())}catch{l.length===0&&(D?.clear(),R=void 0)}}return k(),Se(),R&&$e(R),b&&Q(),{client:m,element:M,sendMessage:V,session:D,threads:P,refreshThreads:Q,destroy(){m.off("message:start",oe),m.off("message:chunk",re),m.off("message:answer-complete",ae),m.off("message:complete",se),m.off("message:error",ie),ke.forEach(t=>t()),M.remove(),n.client||m.destroy()}};function le(){const t=x({display:"flex",gap:"4px",padding:"4px 0"});for(let s=0;s<3;s++){const c=x({width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"#b5bfc8",animation:"ago-pulse 1.2s ease-in-out infinite",animationDelay:`${s*.2}s`});t.appendChild(c)}return t}}function je(o){let n=[];const r=document.createElement("form");S(r,{display:"flex",flexDirection:"column",gap:"8px",padding:"12px",borderTop:`1px solid ${$}`,backgroundColor:z}),r.className="ago-chat-input";const e=x({display:"flex",flexWrap:"wrap",gap:"6px"}),u=x({display:"flex",gap:"8px",alignItems:"flex-end"}),a=document.createElement("textarea");a.placeholder=o.placeholder,a.rows=1,S(a,{flex:"1",resize:"none",padding:"10px 12px",border:`1px solid ${$}`,borderRadius:"12px",fontSize:"14px",fontFamily:Ce,lineHeight:"1.4",maxHeight:"120px",outline:"none"});const p=document.createElement("button");p.type="submit",p.textContent="Send",S(p,{padding:"10px 16px",border:"none",borderRadius:"12px",backgroundColor:ve,color:ye,fontSize:"14px",fontWeight:"500",cursor:"pointer"});let i=null,f=null;o.allowFiles&&(i=document.createElement("input"),i.type="file",i.multiple=!0,S(i,{display:"none"}),f=document.createElement("button"),f.type="button",f.textContent="📎",S(f,{padding:"10px 12px",border:`1px solid ${$}`,borderRadius:"12px",backgroundColor:z,cursor:"pointer",fontSize:"14px"}),f.addEventListener("click",()=>i?.click()),i.addEventListener("change",()=>{n=[...n,...Array.from(i?.files??[])],d()}));function d(){e.replaceChildren(),n.forEach((g,_)=>{const F=x({display:"flex",alignItems:"center",gap:"4px",padding:"4px 8px",backgroundColor:"#f0f4ff",border:`1px solid ${$}`,borderRadius:"8px",fontSize:"12px"}),m=document.createElement("span");m.textContent=g.name;const O=document.createElement("button");O.type="button",O.textContent="×",S(O,{border:"none",background:"transparent",cursor:"pointer",fontSize:"14px",lineHeight:"1"}),O.addEventListener("click",()=>{n=n.filter((W,D)=>D!==_),d()}),F.append(m,O),e.appendChild(F)})}const b=()=>{const g=a.value,_=n;return a.value="",n=[],d(),{content:g,files:_}},N=()=>{const{content:g,files:_}=b();(g.trim()||_.length>0)&&o.onSend(g.trim(),_.length>0?_:void 0)};return r.addEventListener("submit",g=>{g.preventDefault(),N()}),a.addEventListener("keydown",g=>{g.key==="Enter"&&!g.shiftKey&&(g.preventDefault(),N())}),f&&u.appendChild(f),u.append(a,p),i&&r.appendChild(i),r.append(e,u),{inputRow:r,getValueAndClear:b,setDisabled:g=>{a.disabled=g,p.disabled=g,p.style.opacity=g?"0.6":"1",p.style.cursor=g?"not-allowed":"pointer"},focus:()=>a.focus()}}exports.mountChatWidget=qe;exports.renderMarkdown=ee;
3
+ `);let t=0;for(;t<r.length;){const i=r[t];if(i.trim()===""){t++;continue}const f=i.match(Be);if(f){const c=f[1][0],h=[];for(t++;t<r.length&&!new RegExp(`^ {0,3}${c==="`"?"`{3,}":"~{3,}"}\\s*$`).test(r[t]);)h.push(r[t]),t++;t++;const L=_("pre",{margin:"0 0 8px 0"});L.appendChild(_("code",{display:"block",background:"#f5f5f5",padding:"8px 12px",borderRadius:"6px",fontSize:"13px",overflowX:"auto",fontFamily:Te,whiteSpace:"pre"},U(h.join(`
4
+ `)))),n.appendChild(L);continue}if(De.test(i)){n.appendChild(_("hr",{border:"none",borderTop:"1px solid #dee3e8",margin:"12px 0"})),t++;continue}const s=i.match(Me);if(s){const c=s[1].length;n.appendChild(_(`h${c}`,{margin:"16px 0 8px 0",fontSize:Qe[c-1],fontWeight:"600",lineHeight:"1.3"},M(s[2]))),t++;continue}if(Z.test(i)){const c=[];for(;t<r.length&&Z.test(r[t]);)c.push(r[t].replace(Z,"")),t++;const h=_("blockquote",{borderLeft:"4px solid #dee3e8",paddingLeft:"12px",margin:"0 0 8px 0",fontStyle:"italic",color:"#6b6d6f"});h.appendChild(J(c.join(`
5
+ `))),n.appendChild(h);continue}if(i.includes("|")&&Je(r[t+1])){const c=[i,r[t+1]];for(t+=2;t<r.length&&r[t].includes("|")&&r[t].trim();)c.push(r[t]),t++;n.appendChild(Ze(c));continue}if(P.test(i)){const c=[],h=fe(i);for(;t<r.length&&r[t].trim()!=="";)if(P.test(r[t])||fe(r[t])>h)c.push(r[t]),t++;else break;n.appendChild(ze(c));continue}const p=[i];for(t++;t<r.length&&!Ye(r[t]);)p.push(r[t]),t++;n.appendChild(_("p",{margin:"0 0 8px 0",lineHeight:"1.6"},p.map(c=>M(c)).join("<br>")))}const u=n.lastElementChild;return u&&(u.style.marginBottom="0"),n}var ue='var(--ago-font, "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)',Ie={font:"--ago-font",radius:"--ago-radius",messageRadius:"--ago-message-radius",brand:"--ago-brand-color",brandText:"--ago-brand-text-color",headerBg:"--ago-header-background",headerText:"--ago-header-text-color",panelBg:"--ago-panel-background",messagesBg:"--ago-messages-background",text:"--ago-text-color",mutedText:"--ago-muted-text-color",border:"--ago-border-color",accent:"--ago-accent-color"},ge="var(--ago-brand-color, #03182f)",he="var(--ago-brand-text-color, #fff)",et="var(--ago-header-background, var(--ago-brand-color, #03182f))",Le="var(--ago-header-text-color, #e8f0fe)",j="var(--ago-panel-background, #fff)",tt="var(--ago-messages-background, #fbfbfb)",Y="var(--ago-text-color, #30373e)",nt="var(--ago-muted-text-color, #6b6d6f)",$="var(--ago-border-color, #dee3e8)",pe="var(--ago-accent-color, #1b5fc4)",ot="var(--ago-radius, 16px)",Ne="var(--ago-message-radius, 16px)";function rt(o,n){if(n)for(const r of Object.keys(Ie)){const t=n[r];t!=null&&o.style.setProperty(Ie[r],t)}}function y(o,n){Object.assign(o.style,n)}function x(o={}){const n=document.createElement("div");return y(n,o),n}var Oe="ago-chat-widget-keyframes";function at(){if(typeof document>"u"||document.getElementById(Oe))return;const o=document.createElement("style");o.id=Oe,o.textContent="@keyframes ago-pulse { 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } 40% { opacity: 1; transform: scale(1); } }",document.head.appendChild(o)}function it(o){const n=typeof o=="string"?document.querySelector(o):o;if(!n)throw new Error(`mountChatWidget: target "${String(o)}" not found.`);return n}function st(o,n){const{title:r="Chat",welcomeMessage:t="Hello! How can I help you today?",placeholder:u="Type a message...",allowFiles:i=!1,height:f=500,placement:s="inline",width:p=400,defaultOpen:c=!1,logoUrl:h,showAgentName:L=!1,theme:m,loadThreads:R=!1,forms:q,onFollowUpClick:B,onMessageSent:N,onMessageReceived:me}=n;if(!n.client&&!n.config?.baseUrl)throw new ke.AgoError("mountChatWidget requires either `client` or `config` (with a baseUrl).","config_missing_base_url");const g=n.client??new ke.AgoClient(n.config),xe=it(o),z=s==="left"||s==="right",He=z&&(n.launcher??!0);let H=z?c:!0;const ee=n.persistConversation,X=ee?Ke.createConversationSession(ee===!0?{}:ee):void 0;let k=n.conversationId??X?.getLastActiveThread()??void 0,d=[],O=!1,W=null;const K=[],F=x({display:"flex",flexDirection:"column",height:z?"100%":typeof f=="number"?`${f}px`:f,border:`1px solid ${$}`,borderRadius:ot,overflow:"hidden",backgroundColor:j,fontFamily:ue,textAlign:"left",boxShadow:"rgba(15, 15, 15, 0.08) 0px 2px 16px 0px"});F.className="ago-chat-widget",rt(F,m);const G=x({padding:"14px 16px",borderBottom:`1px solid ${$}`,backgroundColor:et,color:Le,display:"flex",alignItems:"center",gap:"10px"});if(G.className="ago-chat-widget__header",h){const e=document.createElement("img");e.src=h,e.alt="Logo",y(e,{height:"24px",width:"auto"}),G.appendChild(e)}const te=document.createElement("h3");if(te.textContent=r,y(te,{margin:"0",fontSize:"15px",fontWeight:"600"}),G.appendChild(te),z){const e=document.createElement("button");e.type="button",e.className="ago-chat-widget__close",e.setAttribute("aria-label","Close"),e.textContent="×",y(e,{marginLeft:"auto",background:"transparent",border:"none",color:Le,fontSize:"22px",lineHeight:"1",cursor:"pointer",padding:"0 2px"}),e.addEventListener("click",()=>de()),G.appendChild(e)}const I=x({flex:"1",overflow:"auto",padding:"16px",backgroundColor:tt});I.className="ago-chat-widget__messages";const{inputRow:Fe,setDisabled:Ue,focus:ne}=lt({placeholder:u,allowFiles:i,onSend:(e,a)=>{ae(e,a)}});at(),F.append(G,I,Fe);let V=F,T,E;const oe=s==="left"?"left":"right";if(z&&(T=x({position:"fixed",top:"0",bottom:"0",[oe]:"0",width:typeof p=="number"?`${p}px`:p,maxWidth:"100vw",display:"flex",zIndex:"2147483000",transition:"transform 0.3s ease",boxShadow:"rgba(15, 15, 15, 0.18) 0px 0px 24px 0px"}),T.className="ago-chat-widget-panel",y(F,{height:"100%",width:"100%",borderRadius:"0",border:"none",boxShadow:"none",[oe==="left"?"borderRight":"borderLeft"]:`1px solid ${$}`}),T.appendChild(F),V=T),He){if(E=document.createElement("button"),E.type="button",E.className="ago-chat-widget-launcher",E.setAttribute("aria-label",`Open ${r}`),y(E,{position:"fixed",bottom:"20px",[oe]:"20px",width:"56px",height:"56px",borderRadius:"50%",border:"none",backgroundColor:ge,color:he,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",zIndex:"2147483000",boxShadow:"rgba(15, 15, 15, 0.2) 0px 4px 14px 0px",fontFamily:ue}),h){const e=document.createElement("img");e.src=h,e.alt="",y(e,{width:"26px",height:"26px",objectFit:"contain"}),E.appendChild(e)}else E.appendChild(qe());E.addEventListener("click",()=>le())}xe.appendChild(V),E&&xe.appendChild(E),se();const be=B!==!1,Ce=B===!1?void 0:B??(e=>{ae(e)});function Pe(e,a){const l=e.role==="user",S=x({display:"flex",flexDirection:"column",alignItems:l?"flex-end":"flex-start",marginBottom:"16px"});if(S.className=`ago-message ago-message--${e.role}`,!l&&L&&e.agent){const b=x({fontSize:"13px",fontWeight:"500",color:Y,marginBottom:"6px",padding:"0 4px"});b.className="ago-message__agent",b.textContent=e.agent.displayName||e.agent.name,S.appendChild(b)}if(!l&&e.sources&&e.sources.length>0){const b=x({display:"grid",gridTemplateColumns:"1fr 1fr",gap:"6px",marginBottom:"10px",width:"100%",maxWidth:"85%"});b.className="ago-message__sources",e.sources.forEach((C,w)=>{const D=C.url?document.createElement("a"):document.createElement("div");C.url&&D instanceof HTMLAnchorElement&&(D.href=C.url,D.target="_blank",D.rel="noopener noreferrer"),y(D,{display:"flex",alignItems:"center",gap:"8px",padding:"8px 10px",border:`1px solid ${$}`,borderRadius:"8px",backgroundColor:j,textDecoration:"none",color:Y,fontSize:"12px",overflow:"hidden"});const Re=x({flexShrink:"0",width:"18px",height:"18px",borderRadius:"3px",border:`1px solid ${pe}`,color:pe,fontSize:"11px",fontWeight:"500",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"#f0f4ff"});Re.textContent=String(w+1);const ce=x({overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});ce.textContent=C.title,ce.title=C.title,D.append(Re,ce),b.appendChild(D)}),S.appendChild(b)}const v=x({maxWidth:l?"75%":"100%",padding:l?"10px 14px":"2px 8px",borderRadius:l?Ne:"0",backgroundColor:l?ge:"transparent",color:l?he:Y,wordBreak:"break-word",fontSize:"14px",lineHeight:"1.6"});if(v.className="ago-message__content",e.content?v.appendChild(J(e.content)):e.status==="IN_PROGRESS"&&v.appendChild(Xe()),S.appendChild(v),a&&e.followUpReplies&&e.followUpReplies.length>0){const b=x({display:"flex",flexWrap:"wrap",gap:"8px",marginTop:"10px"});b.className="ago-message__followups";for(const C of e.followUpReplies){const w=document.createElement("button");w.type="button",w.className="ago-message__followup-btn",w.textContent=C,w.disabled=!be,y(w,{padding:"6px 14px",fontSize:"14px",borderRadius:Ne,border:`1px solid ${$}`,backgroundColor:j,color:Y,cursor:be?"pointer":"default",transition:"border-color 0.15s"}),Ce&&w.addEventListener("click",()=>Ce(C)),w.addEventListener("mouseenter",()=>{w.style.borderColor=pe}),w.addEventListener("mouseleave",()=>{w.style.borderColor=$}),b.appendChild(w)}S.appendChild(b)}return S}function A(){if(I.replaceChildren(),d.length===0){const a=x({textAlign:"center",color:nt,padding:"24px 16px",fontSize:"14px",lineHeight:"1.5"});a.appendChild(J(t)),I.appendChild(a)}else d.forEach((a,l)=>{I.appendChild(Pe(a,l===d.length-1))});if(W){const a=x({padding:"10px 14px",backgroundColor:"#fef2f2",color:"#dc2626",borderRadius:"12px",marginTop:"8px",fontSize:"13px",border:"1px solid #fecaca"});a.textContent=W,I.appendChild(a)}I.scrollTop=I.scrollHeight;const e=d[d.length-1];Ue(O&&e?.role==="assistant"&&e.status==="IN_PROGRESS")}function We(){for(let e=d.length-1;e>=0;e--){const a=d[e];if(a.role==="assistant"&&a.status==="IN_PROGRESS")return a}}const ve=e=>{k||(k=e.conversationId)},we=e=>{const a=We();a&&(a.content+=e.content,A())},ye=e=>{const a=d.findIndex(l=>l.id===e.id||l.role==="assistant"&&l.status==="IN_PROGRESS");a>=0?d[a]=e:d.push(e),A(),ne()},Ee=e=>{const a=d.findIndex(l=>l.id===e.id||l.role==="assistant"&&l.status==="IN_PROGRESS");a>=0?d[a]=e:d.push(e),O=!1,A(),e.status==="DONE"&&me?.({id:e.id,content:e.content})},Se=e=>{W=e.error,O=!1,d=d.filter(a=>!a.id.startsWith("temp-")),A()};g.on("message:start",ve),g.on("message:chunk",we),g.on("message:answer-complete",ye),g.on("message:complete",Ee),g.on("message:error",Se);const re=[];let _e=!1;for(const e of q??[])e.schema!=null?re.push($e.createFormCollector(e).install(g)):$e.loadFormCollector(g,e).then(a=>{_e||re.push(a.install(g))}).catch(()=>{});async function ae(e,a){const l=e.trim();if(!l&&!a?.length||O)return;N?.(l),O=!0,W=null;const S=Date.now();d.push({id:`temp-user-${S}`,conversationId:k||"",content:l,role:"user",status:"DONE",createdAt:new Date}),d.push({id:`temp-assistant-${S}`,conversationId:k||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date}),A();try{const v=await g.sendMessage(l,{conversationId:k,files:a});v.conversationId&&(k||(k=v.conversationId),X?.setActiveThread(v.conversationId,v.createdAt));const b=d.find(C=>C.id===`temp-user-${S}`);if(b&&(b.id=`user-${S}`,b.conversationId=v.conversationId),!d.some(C=>C.id===v.id)){const C=d.findIndex(w=>w.id===`temp-assistant-${S}`);C>=0?d[C]=v:d.push(v)}d=d.filter(C=>!C.id.startsWith("temp-")),O=!1,A(),R&&ie()}catch(v){W=v instanceof Error?v.message:"Failed to send message",O=!1,d=d.filter(b=>!b.id.startsWith("temp-")),A()}}async function ie(){try{const e=await g.getConversations();K.splice(0,K.length,...e)}catch{}return K}async function Ge(e){try{const a=(await g.getConversation(e))?.messages??[];a.length>0&&d.length===0&&(d=a,A())}catch{d.length===0&&(X?.clear(),k=void 0)}}return A(),ne(),k&&Ge(k),R&&ie(),{client:g,element:V,sendMessage:ae,...z?{open:le,close:de,toggle:je}:{},session:X,threads:K,refreshThreads:ie,destroy(){g.off("message:start",ve),g.off("message:chunk",we),g.off("message:answer-complete",ye),g.off("message:complete",Ee),g.off("message:error",Se),_e=!0,re.forEach(e=>e()),V.remove(),E?.remove(),n.client||g.destroy()}};function se(){if(!T)return;const e=s==="left"?"translateX(-100%)":"translateX(100%)";T.style.transform=H?"translateX(0)":e,T.setAttribute("aria-hidden",H?"false":"true"),E&&(E.style.display=H?"none":"flex")}function le(){H=!0,se(),ne()}function de(){H=!1,se()}function je(){H?de():le()}function qe(){const e="http://www.w3.org/2000/svg",a=document.createElementNS(e,"svg");a.setAttribute("width","26"),a.setAttribute("height","26"),a.setAttribute("viewBox","0 0 24 24"),a.setAttribute("fill","none");const l=document.createElementNS(e,"path");return l.setAttribute("d","M21 11.5a8.38 8.38 0 0 1-8.5 8.5 8.5 8.5 0 0 1-3.8-.9L3 21l1.9-5.7a8.5 8.5 0 0 1-.9-3.8 8.38 8.38 0 0 1 8.5-8.5 8.38 8.38 0 0 1 8.5 8.5z"),l.setAttribute("stroke","currentColor"),l.setAttribute("stroke-width","2"),l.setAttribute("stroke-linecap","round"),l.setAttribute("stroke-linejoin","round"),a.appendChild(l),a}function Xe(){const e=x({display:"flex",gap:"4px",padding:"4px 0"});for(let a=0;a<3;a++){const l=x({width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"#b5bfc8",animation:"ago-pulse 1.2s ease-in-out infinite",animationDelay:`${a*.2}s`});e.appendChild(l)}return e}}function lt(o){let n=[];const r=document.createElement("form");y(r,{display:"flex",flexDirection:"column",gap:"8px",padding:"12px",borderTop:`1px solid ${$}`,backgroundColor:j}),r.className="ago-chat-input";const t=x({display:"flex",flexWrap:"wrap",gap:"6px"}),u=x({display:"flex",gap:"8px",alignItems:"flex-end"}),i=document.createElement("textarea");i.placeholder=o.placeholder,i.rows=1,y(i,{flex:"1",resize:"none",padding:"10px 12px",border:`1px solid ${$}`,borderRadius:"12px",fontSize:"14px",fontFamily:ue,lineHeight:"1.4",maxHeight:"120px",outline:"none"});const f=document.createElement("button");f.type="submit",f.textContent="Send",y(f,{padding:"10px 16px",border:"none",borderRadius:"12px",backgroundColor:ge,color:he,fontSize:"14px",fontWeight:"500",cursor:"pointer"});let s=null,p=null;o.allowFiles&&(s=document.createElement("input"),s.type="file",s.multiple=!0,y(s,{display:"none"}),p=document.createElement("button"),p.type="button",p.textContent="📎",y(p,{padding:"10px 12px",border:`1px solid ${$}`,borderRadius:"12px",backgroundColor:j,cursor:"pointer",fontSize:"14px"}),p.addEventListener("click",()=>s?.click()),s.addEventListener("change",()=>{n=[...n,...Array.from(s?.files??[])],c()}));function c(){t.replaceChildren(),n.forEach((m,R)=>{const q=x({display:"flex",alignItems:"center",gap:"4px",padding:"4px 8px",backgroundColor:"#f0f4ff",border:`1px solid ${$}`,borderRadius:"8px",fontSize:"12px"}),B=document.createElement("span");B.textContent=m.name;const N=document.createElement("button");N.type="button",N.textContent="×",y(N,{border:"none",background:"transparent",cursor:"pointer",fontSize:"14px",lineHeight:"1"}),N.addEventListener("click",()=>{n=n.filter((me,g)=>g!==R),c()}),q.append(B,N),t.appendChild(q)})}const h=()=>{const m=i.value,R=n;return i.value="",n=[],c(),{content:m,files:R}},L=()=>{const{content:m,files:R}=h();(m.trim()||R.length>0)&&o.onSend(m.trim(),R.length>0?R:void 0)};return r.addEventListener("submit",m=>{m.preventDefault(),L()}),i.addEventListener("keydown",m=>{m.key==="Enter"&&!m.shiftKey&&(m.preventDefault(),L())}),p&&u.appendChild(p),u.append(i,f),s&&r.appendChild(s),r.append(t,u),{inputRow:r,getValueAndClear:h,setDisabled:m=>{i.disabled=m,f.disabled=m,f.style.opacity=m?"0.6":"1",f.style.cursor=m?"not-allowed":"pointer"},focus:()=>i.focus()}}exports.mountChatWidget=st;exports.renderMarkdown=J;
package/dist/widget.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
@@ -53,6 +67,13 @@ declare class AgoClient {
53
67
  * Reject a tool call
54
68
  */
55
69
  rejectToolCall(toolCallId: string): Promise<void>;
70
+ /**
71
+ * Fetch a backend-stored form collector definition by name (the single source
72
+ * of truth for the form's description, schema, and submit target). Used by
73
+ * `loadFormCollector` / the name-only form of `useFormCollector` so the schema
74
+ * lives in the backend instead of being hardcoded in client code.
75
+ */
76
+ getFormCollector(name: string): Promise<FormCollectorDefinition>;
56
77
  /**
57
78
  * Relay a completed form collector's values to a server-configured destination.
58
79
  *
@@ -187,6 +208,11 @@ declare class AgoClient {
187
208
  }): Promise<AgoClientEvents[K]>;
188
209
  /**
189
210
  * Update client configuration
211
+ *
212
+ * Validates the MERGED config before committing: omitting a key (or passing
213
+ * it as `undefined`, common with spread-built partials) keeps the current
214
+ * value; an explicit empty/non-string `baseUrl` throws `config_missing_base_url`
215
+ * and leaves the client unchanged (no half-updated state).
190
216
  */
191
217
  updateConfig(config: Partial<AgoConfig>): void;
192
218
  /**
@@ -222,8 +248,23 @@ declare interface AgoClientEvents {
222
248
  */
223
249
  "message:answer-complete": AgoMessage;
224
250
  "message:complete": AgoMessage;
251
+ /**
252
+ * A reply finished as `DONE` with empty content and no tool calls, client
253
+ * functions, or follow-up replies — usually an unknown `agent` slug (the
254
+ * backend currently answers those with an empty 200). Fires after
255
+ * `message:complete` AND after `sendMessage` resolves, so subscribing right
256
+ * after `await sendMessage(...)` still catches it. `messageId` and
257
+ * `conversationId` are empty strings when the stream completed without any
258
+ * message data at all (e.g. a proxy stripped the SSE stream).
259
+ */
260
+ "message:empty": {
261
+ conversationId: string;
262
+ messageId: string;
263
+ };
225
264
  "message:error": {
226
265
  error: string;
266
+ /** Stable error code (see configuration.md#error-codes) when the failure was an AgoError. */
267
+ code?: string;
227
268
  conversationId?: string;
228
269
  messageId?: string;
229
270
  };
@@ -252,7 +293,7 @@ declare interface AgoClientEvents {
252
293
  declare interface AgoConfig {
253
294
  /** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
254
295
  baseUrl: string;
255
- /** Widget ID (X-Widget-Id header). Auto-generated if not provided. */
296
+ /** Per-visitor anonymous ID (X-User-Anon-Id header). Auto-generated if not provided. */
256
297
  widgetId?: string;
257
298
  /** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
258
299
  agent?: string;
@@ -266,6 +307,13 @@ declare interface AgoConfig {
266
307
  userJwt?: string;
267
308
  /** Enable debug logging */
268
309
  debug?: boolean;
310
+ /**
311
+ * Warn on the console when a reply completes with empty content and no tool
312
+ * calls (the usual cause is an unknown `agent` slug, which the backend
313
+ * currently answers with an empty 200). Default `true`. The `message:empty`
314
+ * event fires regardless of this setting.
315
+ */
316
+ warnOnEmptyReply?: boolean;
269
317
  }
270
318
 
271
319
  declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
@@ -345,6 +393,13 @@ export declare interface ChatWidgetHandle {
345
393
  element: HTMLElement;
346
394
  /** Programmatically send a message (same path as the input). */
347
395
  sendMessage: (content: string, files?: File[]) => Promise<void>;
396
+ /**
397
+ * Open / close / toggle the side panel. Present only for
398
+ * `placement: "left" | "right"` (an inline panel is always visible).
399
+ */
400
+ open?: () => void;
401
+ close?: () => void;
402
+ toggle?: () => void;
348
403
  /**
349
404
  * The conversation-persistence session, present only when `persistConversation`
350
405
  * is set — exposes the stable `widgetId` and `session.clear()` to start a new thread.
@@ -520,6 +575,20 @@ export declare interface CreateFormCollectorOptions<V = Record<string, unknown>>
520
575
  */
521
576
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
522
577
 
578
+ /**
579
+ * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
580
+ * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
581
+ * {@link CreateFormCollectorOptions}: the `submit` here is never the client-only
582
+ * `handler` variant (a function can't be stored server-side).
583
+ */
584
+ declare interface FormCollectorDefinition<V = Record<string, unknown>> {
585
+ name: string;
586
+ description: string;
587
+ schema: FormCollectorSchema;
588
+ /** Server-stored submit target, if any. Absent means collect-only. */
589
+ submit?: SubmitConfig<V>;
590
+ }
591
+
523
592
  /**
524
593
  * Shape of a form's fields. Mirrors a client function's `parameters` (so the same
525
594
  * object feeds the store, the update function, and the dynamic context). Additionally allows the SDK-only per-field `requiredWhen`, which {@link toWireParameters} removes before the schema reaches the LLM.
@@ -584,6 +653,16 @@ declare interface FormSchema {
584
653
  required?: string[];
585
654
  }
586
655
 
656
+ /**
657
+ * Options for {@link loadFormCollector} / the name-only form of `useFormCollector`:
658
+ * the `name` is required and the definition is fetched from the backend, while any
659
+ * field here overrides the fetched one — notably a client-only `submit` handler,
660
+ * which can't be stored server-side.
661
+ */
662
+ declare interface LoadFormCollectorOptions<V = Record<string, unknown>> extends Partial<Omit<CreateFormCollectorOptions<V>, "name">> {
663
+ name: string;
664
+ }
665
+
587
666
  declare type MessageStatus = "IN_PROGRESS" | "DONE" | "ERROR" | "TODO" | "CANCELED";
588
667
 
589
668
  /**
@@ -646,9 +725,37 @@ export declare interface MountChatWidgetOptions {
646
725
  placeholder?: string;
647
726
  /** Enable file attachments. */
648
727
  allowFiles?: boolean;
649
- /** Widget height (number → px). */
728
+ /** Widget height (number → px). Ignored when `placement` is `"left"`/`"right"`
729
+ * (a side panel is always full-height). */
650
730
  height?: string | number;
651
- /** URL of a logo shown in the header. */
731
+ /**
732
+ * Where the panel renders. `"inline"` (default) mounts it directly into the
733
+ * target element, filling it. `"left"` / `"right"` instead pin a **fixed,
734
+ * full-height side panel** to that edge of the viewport that slides open and
735
+ * closed; the target is only used as the DOM parent (pass `document.body` for
736
+ * a true page overlay). In side mode `height` is ignored and the width comes
737
+ * from {@link MountChatWidgetOptions.width}.
738
+ */
739
+ placement?: "inline" | "left" | "right";
740
+ /**
741
+ * Width of the side panel for `placement: "left" | "right"` (number → px).
742
+ * Capped at the viewport width so it never overflows on mobile. Ignored when
743
+ * `placement` is `"inline"`. Defaults to `400`.
744
+ */
745
+ width?: string | number;
746
+ /**
747
+ * For side placements, render the built-in floating launcher button that opens
748
+ * the panel (plus a close "×" in the header). Set `false` to drive open/close
749
+ * yourself via the handle's `open()`/`close()`/`toggle()`. Ignored when
750
+ * `placement` is `"inline"`. Defaults to `true`.
751
+ */
752
+ launcher?: boolean;
753
+ /**
754
+ * For side placements, whether the panel starts open. Ignored when `placement`
755
+ * is `"inline"` (an inline panel is always visible). Defaults to `false`.
756
+ */
757
+ defaultOpen?: boolean;
758
+ /** URL of a logo shown in the header (and on the launcher button, if shown). */
652
759
  logoUrl?: string;
653
760
  /** Show the agent name above assistant messages. Defaults to `false`. */
654
761
  showAgentName?: boolean;
@@ -665,10 +772,13 @@ export declare interface MountChatWidgetOptions {
665
772
  loadThreads?: boolean;
666
773
  /**
667
774
  * Conversational forms the agent can fill and submit during the chat. Each
668
- * config is installed as a {@link createFormCollector} for the lifetime of the
775
+ * entry is installed as a {@link createFormCollector} for the lifetime of the
669
776
  * widget (removed on `destroy()`).
777
+ *
778
+ * Pass a full config (with `schema`) to define it inline, or just `{ name }` to
779
+ * fetch the definition from the backend ({@link loadFormCollector}).
670
780
  */
671
- forms?: CreateFormCollectorOptions[];
781
+ forms?: Array<CreateFormCollectorOptions | LoadFormCollectorOptions>;
672
782
  /**
673
783
  * How clicking a suggested follow-up reply behaves. Defaults to sending the
674
784
  * reply as a new user message. Pass a handler to override, or `false` to