@useago/sdk 1.7.2 → 1.9.0

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +43 -1
  3. package/dist/angular.cjs +1 -1
  4. package/dist/angular.d.cts +89 -5
  5. package/dist/angular.d.ts +89 -5
  6. package/dist/angular.js +11 -7
  7. package/dist/{createConversationSession-DP90nY71.js → createConversationSession-BaaXBQ5b.js} +3 -3
  8. package/dist/createConversationSession-CU0b-t1W.cjs +1 -0
  9. package/dist/{createFormCollector-BivHRIAe.js → createFormCollector-Cf7kGhCB.js} +1 -1
  10. package/dist/createFormCollector-DfN1xZBy.cjs +1 -0
  11. package/dist/{createMockClient-BDLW6tVc.js → createMockClient-5YF-ZbVu.js} +22 -21
  12. package/dist/createMockClient-BZbOe-23.cjs +1 -0
  13. package/dist/devtools.cjs +61 -12
  14. package/dist/devtools.d.cts +90 -5
  15. package/dist/devtools.d.ts +90 -5
  16. package/dist/devtools.js +225 -73
  17. package/dist/errors-BLfjXnLB.js +32 -0
  18. package/dist/errors-o1IB5fEu.cjs +1 -0
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.cts +100 -3
  21. package/dist/index.d.ts +100 -3
  22. package/dist/index.js +77 -75
  23. package/dist/react.cjs +4 -4
  24. package/dist/react.d.cts +197 -3
  25. package/dist/react.d.ts +197 -3
  26. package/dist/react.js +1034 -752
  27. package/dist/testing.cjs +1 -1
  28. package/dist/testing.d.cts +80 -3
  29. package/dist/testing.d.ts +80 -3
  30. package/dist/testing.js +1 -1
  31. package/dist/{AgoClient-DTkBRGFE.js → types-CPga11Of.js} +489 -386
  32. package/dist/types-D3YQl1jx.cjs +9 -0
  33. package/dist/vue.cjs +1 -1
  34. package/dist/vue.d.cts +110 -3
  35. package/dist/vue.d.ts +110 -3
  36. package/dist/vue.js +202 -154
  37. package/dist/widget.cjs +4 -4
  38. package/dist/widget.d.cts +148 -3
  39. package/dist/widget.d.ts +148 -3
  40. package/dist/widget.js +871 -651
  41. package/llms-full.txt +139 -25
  42. package/package.json +1 -1
  43. package/dist/AgoClient-7yXQ6R3O.cjs +0 -9
  44. package/dist/createConversationSession-Bv6a15E0.cjs +0 -1
  45. package/dist/createFormCollector-CwfiYn0V.cjs +0 -1
  46. package/dist/createMockClient-BSNuN3ys.cjs +0 -1
@@ -0,0 +1,9 @@
1
+ const d=require("./errors-o1IB5fEu.cjs");var pe=10,L=1e3;function me(e){if(typeof e!="object"||e===null)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function k(e,t){if(typeof e=="string"){if(e.length<=1e3)return e;const s=e.length-L;return e.slice(0,L)+`…[truncated ${s} chars]`}if(Array.isArray(e)){if(t.has(e))return"…[circular]";t.add(e);const s=e.slice(0,50).map(i=>k(i,t));return e.length>50&&s.push(`…[+${e.length-50} more]`),t.delete(e),s}if(me(e)){if(t.has(e))return"…[circular]";t.add(e);const s={};for(const[i,n]of Object.entries(e))s[i]=k(n,t);return t.delete(e),s}return e}function ye(e){return k(e,new WeakSet)}var ee=class{constructor(e=10){this.entries=[];const t=Math.floor(e);this.maxEntries=Number.isFinite(t)?Math.max(1,t):10}add(e){const t={ts:e.ts??Date.now(),actor:e.actor??"user",name:e.name,summary:e.summary,...e.data!==void 0?{data:ye(e.data)}:{}};this.entries.push(t);const s=this.entries.length-this.maxEntries;return s>0&&this.entries.splice(0,s),t}getRecent(){return[...this.entries]}get size(){return this.entries.length}clear(){this.entries=[]}},ve=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)}},l=new ve,B="ago_widget_id";function T(e){return typeof DOMException<"u"&&e instanceof DOMException&&e.name==="AbortError"||e instanceof Error&&e.name==="AbortError"}function we(){if(typeof localStorage<"u"){const t=localStorage.getItem(B);if(t)return t}const e=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`;if(typeof localStorage<"u")try{localStorage.setItem(B,e)}catch{}return e}var Se=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||we()},e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission&&(this.headers["X-Widget-Permission"]=e.permission)}updateConfig(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),e.widgetId&&(this.headers["X-User-Anon-Id"]=e.widgetId),e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission!==void 0&&(e.permission?this.headers["X-Widget-Permission"]=e.permission:delete this.headers["X-Widget-Permission"])}async get(e){return this.request("GET",e)}async post(e,t,s){return this.request("POST",e,t,s)}async postStream(e,t,s){const i=`${this.baseUrl}${e}`;l.debug("POST (stream)",i,t);try{const n=await fetch(i,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0,signal:s?.signal});return n.ok||await this.handleErrorResponse(n),n}catch(n){throw n instanceof d.AgoApiError||T(n)?n:new d.AgoNetworkError(`Network error: ${n instanceof Error?n.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,n instanceof Error?n:void 0)}}async postFormData(e,t,s){const i=`${this.baseUrl}${e}`;l.debug("POST (formData)",i);const n={...this.headers};try{const r=await fetch(i,{method:"POST",headers:n,body:t,signal:s?.signal});return r.ok||await this.handleErrorResponse(r),r}catch(r){throw r instanceof d.AgoApiError||T(r)?r:new d.AgoNetworkError(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async request(e,t,s,i){const n=`${this.baseUrl}${t}`;l.debug(e,n,s);try{const r=await fetch(n,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0,...i?.keepalive?{keepalive:!0}:{}});return r.ok||await this.handleErrorResponse(r),r.status===204?void 0:r.json()}catch(r){throw r instanceof d.AgoApiError?r:new d.AgoNetworkError(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw d.AgoApiError.fromResponse(t,e.status);let s="";throw e.status===401||e.status===403?s=" Check `userJwt` (and that it has not expired).":e.status===404&&(s=" Check that `baseUrl` points at your AGO API root."),new d.AgoApiError(`HTTP ${e.status}: ${e.statusText}.${s}`,"http_error",e.status,"api_error")}},Ae=5e4,Ce=2e4,be=2e3,te=class{constructor(e){this.functions=new Map,this.defaultMaxResultBytes=e?.maxResultBytes??Ae}setDefaultMaxResultBytes(e){this.defaultMaxResultBytes=e}getDefaultMaxResultBytes(){return this.defaultMaxResultBytes}register(e,t,s){if(typeof e=="object"){const{name:o,handler:c,description:h,parameters:u,maxResultBytes:f,requiresApproval:y}=e;return this.register(o,c,{description:h,parameters:u,maxResultBytes:f,requiresApproval:y})}const i=e;if(!t||!s)throw new d.AgoError(`registerFunction("${i}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`,"function_invalid_registration");this.functions.has(i)&&l.warn(`Function "${i}" is being overwritten`);const{maxResultBytes:n,requiresApproval:r,...a}=s;this.functions.set(i,{schema:{...a,name:i},handler:t,maxResultBytes:n,requiresApproval:r}),l.log(`Registered function: ${i}`)}unregister(e){const t=this.functions.delete(e);return t&&l.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 d.AgoFunctionError(`Function "${e}" is not registered`,e);l.log(`Executing function: ${e}`,t);try{const i=await s.handler(t);return l.log(`Function ${e} completed:`,i),this.guardResultSize(e,i,s.maxResultBytes)}catch(i){throw l.error(`Function ${e} failed:`,i),new d.AgoFunctionError(`Function "${e}" execution failed: ${i instanceof Error?i.message:"Unknown error"}`,e,i instanceof Error?i:void 0)}}guardResultSize(e,t,s){let i;try{i=JSON.stringify(t)}catch{return t}if(i===void 0)return t;const n=new TextEncoder().encode(i).length,r=s??this.defaultMaxResultBytes;return n>r?(l.warn(`Function "${e}" result is ${n} bytes, over the ${r}-byte limit; a truncated preview was sent to the agent instead. Return fewer fields, paginate, or raise maxResultBytes for this function.`),{truncated:!0,originalBytes:n,maxBytes:r,preview:i.slice(0,be),hint:`The result of "${e}" exceeded the ${r}-byte limit and was truncated. Request less data (use limit or filter parameters if available), or tell the user the result is too large to process.`}):(n>Ce&&l.warn(`Function "${e}" returned a large result (${Math.round(n/1024)} KB). Large results consume LLM context: return fewer fields, paginate, or push the data to the UI and return a summary.`),t)}clear(){this.functions.clear(),l.log("Cleared all registered functions")}get size(){return this.functions.size}},Ee=new TextEncoder;function m(e){return Ee.encode(e).length}function x(e){return m(JSON.stringify(e))-2}function se(e,t){if(t<=0)return"";let s="",i=0;for(const n of e){const r=x(n);if(i+r>t)break;s+=n,i+=r}return s}var _e=50,Re=2;var Ie=2e3;function C(e){try{return JSON.stringify(e)}catch{return}}var F=Symbol("ago.pageData.timeout");function ke(e,t){return t<=0?Promise.resolve(F):new Promise((s,i)=>{const n=setTimeout(()=>s(F),t);e.then(r=>{clearTimeout(n),s(r)},r=>{clearTimeout(n),i(r)})})}async function Te(e,t){const s=Date.now()+t;let i=0;for(;Date.now()<s&&i<Re;)i=e().isLoading?.()?0:i+1,await new Promise(o=>setTimeout(o,_e));const n=e().get();if(!q(n))return n;const r=await ke(Promise.resolve(n),s-Date.now());if(r!==F)return r;l.warn("Page data did not resolve within the settle timeout; returning what the page has now. Raise settleTimeoutMs if the work legitimately takes longer.");const a=e().get();if(!q(a))return a;Promise.resolve(a).catch(()=>{})}function q(e){return typeof e=="object"&&e!==null&&typeof e.then=="function"}function xe(e){if(typeof e!="object"||e===null||Array.isArray(e))return;const t=e;let s;for(const i of Object.keys(t)){const n=t[i];Array.isArray(n)&&(s===void 0||n.length>t[s].length)&&(s=i)}return s}function Fe(e,t){let s=2,i=0;for(const n of e){const r=m(C(n)??"null")+(i>0?1:0);if(s+r>t)break;s+=r,i++}return i}function P(e){return`The page data returned by "${e}" was too large to send in full. Only the first items are included: ask for fewer rows or narrow the filters to see the rest.`}function Pe(e,t,s,i){const n={truncated:!0,originalBytes:s,maxBytes:i,preview:"",hint:P(e)},r=m(C(n)??"{}");return{...n,preview:se(t,Math.min(Ie,i-r))}}function Oe(e,t,s,i,n){const r=s===void 0?{}:{...t},a=s??"items",o=m(C({...r,[a]:[],truncation:{truncated:!0,returnedItems:i.length,totalItems:i.length,hint:P(e)}})??"{}")-2;if(o>=n)return;const c=i.slice(0,Fe(i,n-o));return{...r,[a]:c,truncation:{truncated:!0,returnedItems:c.length,totalItems:i.length,hint:P(e)}}}function G(e,t,s){const i=C(t);if(i===void 0)return t;const n=m(i);if(n<=s)return t;l.warn(`Page data for "${e}" is ${n} bytes, over the ${s}-byte limit; it was truncated to the first items that fit. Return fewer fields per item, paginate, or raise maxResultBytes on the data source.`);const r=xe(t),a=Array.isArray(t)?t:r!==void 0?t[r]:void 0;if(a){const o=Oe(e,t,r,a,s),c=m(C(o)??"");if(o!==void 0&&c<=s)return o}return Pe(e,i,n,s)}function E(e,t){if(e===t)return!0;if(e===null||t===null||typeof e!="object"||typeof t!="object"||Array.isArray(e)!==Array.isArray(t))return!1;if(Array.isArray(e))return e.length!==t.length?!1:e.every((n,r)=>E(n,t[r]));const s=Object.keys(e),i=Object.keys(t);return s.length!==i.length?!1:s.every(n=>n in t&&E(e[n],t[n]))}var W=100,_=" … [truncated]",ie={truncated:!0},$e=m(',"data":'+JSON.stringify(ie));function O(e){return m(JSON.stringify(e))}function K(e,t){if(O(e)<=t||!e.rejected)return e;const s=Object.entries(e.rejected),i=Object.fromEntries(s.map(([o])=>[o,_])),n={...e,rejected:i};let r=O(n);if(r>t)return n;const a=x(_);for(const[o,c]of s){const h=x(c),u=t-r+a;if(h<=u){i[o]=c,r+=h-a;continue}i[o]=se(c,u-a)+_;break}return n}function S(e){return Array.isArray(e)?"array":typeof e}function J(e){return typeof e!="number"?`Expected type "number", got "${S(e)}".`:Number.isFinite(e)?null:"Expected a finite number."}function ne(e){const t=e.slice(0,W).map(i=>JSON.stringify(i)),s=e.length-W;return s>0?`${t.join(", ")} (${s} more not shown)`:t.join(", ")}function H(e,t){return t.includes(e)?null:`${JSON.stringify(e)} is not an allowed value. Allowed values: ${ne(t)}.`}function De(e,t){const{schema:s}=t;if(s.type==="array"){if(!Array.isArray(e))return`Expected type "array", got "${S(e)}".`;for(let n=0;n<e.length;n++){const r=e[n];if(s.items?.type){const a=s.items.type==="number"?J(r):S(r)!==s.items.type?`Expected type "${s.items.type}", got "${S(r)}".`:null;if(a)return`Array item at index ${n}: ${a[0].toLowerCase()}${a.slice(1)}`}if(s.items?.enum){const a=H(r,s.items.enum);if(a)return`Array item ${a}`}}return null}if(s.type==="number"){const n=J(e);if(n)return n}else if(S(e)!==s.type)return`Expected type "${s.type}", got "${S(e)}".`;const i=re(t);return i?H(e,i):null}function M(e){return e.clearable===!0&&e.schema.type==="string"}function re(e){const t=e.schema.enum;if(t)return M(e)&&!t.includes("")?[...t,""]:t}function Ne(e){const t={...e.schema,description:e.description};M(e)&&(t.description=`${e.description} Pass "" to clear it.`);const s=re(e);return s&&(t.enum=s),t}function Me(e,t){const s=new Map(e.map(r=>[r.name,r])),i=e.map(r=>r.name),n=e.map(r=>`- "${r.name}": ${r.description}`).join(`
2
+ `);return{name:t.name,handler:async r=>{const a=[],o=[],c={};for(const[g,v]of Object.entries(r)){const w=s.get(g);if(!w){c[g]=`"${g}" is not a registered control. Available controls: ${ne(i)}.`;continue}if(v==null||v===""&&!M(w))continue;const U=De(v,w);if(U){c[g]=U;continue}if(w.get&&E(v,w.get())){o.push(g);continue}const b=await w.set(v);b?b.result==="rejected"?c[g]=b.reason||"The page rejected this field's update.":b.result==="unchanged"?o.push(g):a.push(g):a.push(g)}const h=Object.keys(c).length>0,u={success:!h,applied:a,unchanged:o,...h?{rejected:c}:{}},f=t.getResultBudget();if(!t.data)return K(u,f);const y=K(u,f-$e),A=await t.data.read(y),p={...y,data:A};return O(p)<=f?p:{...y,data:ie}},description:(e.length>0?`Change the state of the current page. Set ONLY the controls the user explicitly asked for; leave the others unset. Available controls:
3
+ ${n}`:"The current page has no editable state — nothing to change here.")+(t.data?`
4
+ Returns the resulting page data once it has loaded: ${t.data.description}`:""),parameters:{type:"object",properties:Object.fromEntries(e.map(r=>[r.name,Ne(r)])),required:[]},requiresApproval:t.requiresApproval,maxResultBytes:t.data?.maxResultBytes}}var je=250,Ue=3,Le=1e3,Be=24,qe=10,Ge=50,We=["mousemove","mousedown","keydown","scroll","touchstart"],oe=class{constructor(e={}){this.started=!1,this.teardowns=[],this.route="",this.routeEnteredAt=0,this.lastActivityAt=0,this.lastHeavyActivityAt=0,this.recentRoutes=[],this.routeBounces=0,this.rageClicks=0,this.fieldErrors={},this.recentClicks=[],this.signals=[],this.listeners=new Set,this.getPageState=e.getPageState,this.activityThrottleMs=e.activityThrottleMs??je,this.rageClickCount=e.rageClickCount??Ue,this.rageClickWindowMs=e.rageClickWindowMs??Le,this.rageClickRadiusPx=e.rageClickRadiusPx??Be,this.maxRecentRoutes=e.maxRecentRoutes??qe,this.maxSignals=e.maxSignals??Ge}start(){if(this.started||typeof window>"u"||typeof document>"u")return;this.started=!0;const e=Date.now();this.route=this.currentPathname(),this.routeEnteredAt=e,this.lastActivityAt=e,this.recentRoutes=[this.route];const t=(i,n,r)=>{i.addEventListener(n,r,{passive:!0}),this.teardowns.push(()=>i.removeEventListener(n,r))},s=()=>this.recordActivity();for(const i of We)t(window,i,s);t(document,"visibilitychange",()=>{document.visibilityState==="visible"&&this.recordActivity()}),t(window,"popstate",()=>this.checkRoute()),t(window,"hashchange",()=>this.checkRoute()),t(window,"click",i=>this.onClick(i)),l.log("SignalCollector started")}destroy(){for(const e of this.teardowns)e();this.teardowns=[],this.listeners.clear(),this.recentClicks=[],this.started=!1,l.log("SignalCollector destroyed")}signalFieldError(e){this.checkRoute();const t=(this.fieldErrors[e]??0)+1;this.fieldErrors[e]=t,this.pushSignal({type:"field_error",route:this.route,at:Date.now(),count:t,meta:{field:e}})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getSignals(){return[...this.signals]}getSnapshot(e){this.checkRoute();const t=Date.now();return{route:this.route,dwellMs:this.started?t-this.routeEnteredAt:0,idleMs:this.started?t-this.lastActivityAt:0,rageClicks:this.rageClicks,routeBounces:this.routeBounces,fieldErrors:{...this.fieldErrors},recentRoutes:[...this.recentRoutes],pageState:e?.pageState===!1?null:this.readPageState()}}currentPathname(){return typeof window<"u"&&window.location?window.location.pathname:""}readPageState(){if(!this.getPageState)return null;try{return this.getPageState()??null}catch(e){return l.warn("SignalCollector getPageState threw:",e),null}}recordActivity(){const e=Date.now();this.lastActivityAt=e,e-this.lastHeavyActivityAt>=this.activityThrottleMs&&(this.lastHeavyActivityAt=e,this.checkRoute())}checkRoute(){if(!this.started)return;const e=this.currentPathname();if(e===this.route)return;const t=Date.now(),s=this.route;this.route=e,this.routeEnteredAt=t,this.rageClicks=0,this.fieldErrors={},this.recentClicks=[],this.recentRoutes.push(e),this.recentRoutes.length>this.maxRecentRoutes&&this.recentRoutes.splice(0,this.recentRoutes.length-this.maxRecentRoutes),this.pushSignal({type:"route_change",route:e,at:t,meta:{from:s}});const i=this.recentRoutes,n=i.length;n>=4&&i[n-1]===i[n-3]&&i[n-2]===i[n-4]&&i[n-1]!==i[n-2]&&(this.routeBounces+=1,this.pushSignal({type:"route_bounce",route:e,at:t,count:this.routeBounces,meta:{between:`${i[n-2]}↔${i[n-1]}`}}))}onClick(e){this.recordActivity();const t=Date.now(),s=this.pageStateKey(),i={at:t,x:e.clientX,y:e.clientY,stateKey:s};this.recentClicks=this.recentClicks.filter(o=>t-o.at<=this.rageClickWindowMs);const n=this.recentClicks[0],r=!n||Math.abs(i.x-n.x)<=this.rageClickRadiusPx&&Math.abs(i.y-n.y)<=this.rageClickRadiusPx,a=!n||n.stateKey===s;if(!r||!a){this.recentClicks=[i];return}this.recentClicks.push(i),this.recentClicks.length>=this.rageClickCount&&(this.rageClicks+=1,this.recentClicks=[],this.pushSignal({type:"rage_click",route:this.route,at:t,count:this.rageClicks}))}pageStateKey(){const e=this.readPageState();if(!e)return"";try{return JSON.stringify(e)}catch{return""}}pushSignal(e){this.signals.push(e),this.signals.length>this.maxSignals&&this.signals.splice(0,this.signals.length-this.maxSignals);for(const t of this.listeners)try{t(e)}catch(s){l.error("Signal listener threw:",s)}}};function ae(e,t){const s=t?t.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let i=e;if(t&&s)try{const o=s.getItem(t.key);o!=null&&(i=JSON.parse(o))}catch{}const n=new Set,r=()=>n.forEach(o=>o(i));function a(){if(t&&s)try{s.setItem(t.key,JSON.stringify(i))}catch{}}return{get:()=>i,set:o=>{i=o,a(),r()},subscribe:o=>(n.add(o),()=>{n.delete(o)})}}var Ke=6e4,Je=1440*60*1e3,He="ago_proactive";function R(e){const t=new Date(e),s=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0");return`${t.getFullYear()}-${s}-${i}`}var ze=class{constructor(e={}){this.killSwitchEnabled=!1,this.engaged=!1,this.turnInFlight=!1,this.slotOccupied=!1,this.sessionCount=0,this.perSessionCap=e.frequencyCap?.perSession,this.perDayCap=e.frequencyCap?.perDay,this.store=ae({optOut:!1,lastFiredAt:{},dismissedAt:{},day:{date:R(Date.now()),count:0}},{key:e.storageKey??He,storage:e.storage})}setKillSwitch(e){this.killSwitchEnabled=e}optOut(){this.store.set({...this.store.get(),optOut:!0})}optIn(){this.store.set({...this.store.get(),optOut:!1})}isOptedOut(){return this.store.get().optOut}setEngaged(e){this.engaged=e}setTurnInFlight(e){this.turnInFlight=e}isSlotOccupied(){return this.slotOccupied}occupySlot(){this.slotOccupied=!0}releaseSlot(){this.slotOccupied=!1}canFire(e,t=Date.now()){if(!this.killSwitchEnabled)return this.deny(e,"kill-switch (proactive disabled server-side)");const s=this.store.get();if(s.optOut)return this.deny(e,"user opted out");if(this.engaged)return this.deny(e,"user engaged (widget open)");if(this.turnInFlight)return this.deny(e,"message turn in flight");if(this.slotOccupied)return this.deny(e,"nudge slot occupied");const i=s.lastFiredAt[e.id],n=e.cooldownMs??Ke;if(i!==void 0&&t-i<n)return this.deny(e,"cooldown");const r=s.dismissedAt[e.id],a=e.resurfaceAfterMs??Je;return r!==void 0&&t-r<a?this.deny(e,"dismissed recently"):this.perSessionCap!==void 0&&this.sessionCount>=this.perSessionCap?this.deny(e,"perSession cap"):this.perDayCap!==void 0&&this.dayCount(t)>=this.perDayCap?this.deny(e,"perDay cap"):!0}recordFired(e,t=Date.now()){const s=this.store.get();this.store.set({...s,lastFiredAt:{...s.lastFiredAt,[e]:t}})}recordNudgeShown(e=Date.now()){this.sessionCount+=1;const t=this.store.get(),s=R(e),i=t.day.date===s?{date:s,count:t.day.count+1}:{date:s,count:1};this.store.set({...t,day:i})}recordDismissed(e,t=Date.now()){const s=this.store.get();this.store.set({...s,dismissedAt:{...s.dismissedAt,[e]:t}})}dayCount(e){const t=this.store.get();return t.day.date===R(e)?t.day.count:0}deny(e,t){return l.debug(`NudgeGovernor: trigger "${e.id}" blocked — ${t}`),!1}};function z(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.floor(Math.random()*16);return(e==="x"?t:t&3|8).toString(16)})}function Xe(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ce(e,t){if(e==="*"||e===t)return!0;const s=e.split("/"),i=s.map((n,r)=>{const a=r===s.length-1;return n==="*"?a?"[^/]+(?:/[^/]+)*":"[^/]+":n.startsWith(":")?"[^/]+":Xe(n)});return new RegExp("^"+i.join("/")+"/?$").test(t)}function j(e,t){return e===t?!0:e===null||t===null?!1:Array.isArray(e)?!Array.isArray(t)||t.length!==e.length?!1:e.every((s,i)=>E(s,t[i])):typeof e=="object"?typeof t!="object"||Array.isArray(t)?!1:Object.entries(e).every(([s,i])=>j(i,t[s])):!1}function le(e,t){if(e.route!==void 0&&!ce(e.route,t.route)||e.idleMs!==void 0&&t.idleMs<e.idleMs||e.dwellMs!==void 0&&t.dwellMs<e.dwellMs||e.rageClicks!==void 0&&t.rageClicks<e.rageClicks||e.routeBounces!==void 0&&t.routeBounces<e.routeBounces)return!1;if(e.fieldErrors!==void 0){for(const[s,i]of Object.entries(e.fieldErrors))if((t.fieldErrors[s]??0)<i)return!1}return!(e.pageState!==void 0&&!j(e.pageState,t.pageState??{}))}var Ve=1e3,Ye="/api/sdk/v1/config",Qe="/api/sdk/v1/proactive/evaluate",Ze=class{constructor(e){this.tickTimer=null,this.teardowns=[],this.started=!1,this.activeNudge=null,this.lastConversationId=null,this.shownIds=new Set,this.resolvedIds=new Set,this.lastEvaluationAt=0,this.client=e.client,this.collector=e.collector,this.governor=e.governor,this.tracker=e.tracker,this.options=e.options,this.tickMs=e.options.tickMs??Ve}start(){if(this.started)return;this.started=!0,this.options.enabledOverride!==void 0?this.governor.setKillSwitch(this.options.enabledOverride):this.loadKillSwitch();const e=n=>{n.conversationId&&(this.lastConversationId=n.conversationId),this.governor.setTurnInFlight(!0)},t=()=>this.governor.setTurnInFlight(!1),s=()=>this.governor.setTurnInFlight(!1),i=n=>{n?.id&&(this.lastConversationId=n.id)};this.client.on("message:start",e),this.client.on("message:complete",t),this.client.on("message:error",s),this.client.on("conversation:loaded",i),this.teardowns.push(()=>{this.client.off("message:start",e),this.client.off("message:complete",t),this.client.off("message:error",s),this.client.off("conversation:loaded",i)}),this.tickTimer=setInterval(()=>this.evaluate(),this.tickMs),this.teardowns.push(this.collector.subscribe(()=>{Date.now()-this.lastEvaluationAt>=this.tickMs&&this.evaluate()}))}stop(){this.tickTimer!==null&&(clearInterval(this.tickTimer),this.tickTimer=null);for(const e of this.teardowns)e();this.teardowns=[],this.started=!1}getActiveNudge(){return this.activeNudge}async loadKillSwitch(){try{const e=await this.client.getHttp().get(Ye);this.governor.setKillSwitch(e?.proactive?.enabled===!0)}catch(e){l.debug("Proactive config fetch failed; staying disabled:",e),this.governor.setKillSwitch(!1)}}evaluate(){if(this.lastEvaluationAt=Date.now(),typeof document<"u"&&document.visibilityState==="hidden"||this.governor.isSlotOccupied())return;const e=this.collector.getSnapshot();for(const t of this.options.triggers)if(le(t.when,e)&&this.governor.canFire(t)){this.fire(t);return}}fire(e){if(this.governor.recordFired(e.id),this.governor.occupySlot(),e.intervene==="agent"){this.evaluateWithAgent(e);return}this.setReady({id:z(),triggerId:e.id,source:"static",message:e.intervene.message,action:e.intervene.action,goal:e.goal,kickoff:e.kickoff,createdAt:new Date})}async evaluateWithAgent(e){const t=z(),s={client_nudge_id:t,trigger_id:e.id,goal:e.goal??"",agent:this.client.getConfiguredAgent(),signals:this.collector.getSnapshot(),client_context:this.client.getContextSnapshot()??{entries:{}},client_functions:this.client.getRegisteredFunctions()};let i;try{i=await this.client.getHttp().post(Qe,s)}catch(n){l.debug("Proactive evaluate failed (treated as no-intervene):",n),this.governor.releaseSlot();return}if(!i?.intervene||!i.message){this.governor.releaseSlot();return}this.setReady({id:t,triggerId:e.id,source:"agent",message:i.message,action:et(i.action),goal:e.goal,kickoff:e.kickoff,createdAt:new Date,serverNudgeId:i.nudge_id})}setReady(e){this.activeNudge=e,this.client.emitProactiveEvent("nudge:ready",e)}shown(e){this.shownIds.has(e.id)||(this.shownIds.add(e.id),this.governor.recordNudgeShown(),this.tracker.track({clientNudgeId:e.id,triggerId:e.triggerId,source:e.source,type:"shown",message:e.message,occurredAt:Date.now()}),this.client.emitProactiveEvent("nudge:shown",{nudge:e}))}dismiss(e){this.resolvedIds.has(e.id)||(this.resolvedIds.add(e.id),this.governor.recordDismissed(e.triggerId),this.tracker.track({clientNudgeId:e.id,triggerId:e.triggerId,source:e.source,type:"dismissed",occurredAt:Date.now()}),this.clearActive(e),this.client.emitProactiveEvent("nudge:dismissed",{nudge:e}))}async accept(e){this.resolvedIds.has(e.id)||(this.resolvedIds.add(e.id),this.tracker.track({clientNudgeId:e.id,triggerId:e.triggerId,source:e.source,type:"accepted",occurredAt:Date.now()}),this.clearActive(e),this.client.emitProactiveEvent("nudge:accepted",{nudge:e}),(e.source==="agent"||e.goal)&&(this.lastConversationId?this.client.sendMessage(tt(e),{hidden:!0,conversationId:this.lastConversationId}).catch(t=>l.debug("Nudge kickoff message failed:",t)):e.kickoff?this.client.sendMessage(e.kickoff).catch(t=>l.debug("Nudge kickoff message failed:",t)):l.debug("Nudge accepted with no open conversation and no trigger.kickoff; skipping the chat pre-seed (a hidden message cannot open a conversation).")),e.action&&await this.runAction(e.action))}markConverted(e){this.tracker.track({clientNudgeId:e.id,triggerId:e.triggerId,source:e.source,type:"converted",occurredAt:Date.now()})}clearActive(e){this.activeNudge?.id===e.id&&(this.activeNudge=null),this.governor.releaseSlot()}async runAction(e){try{"functionName"in e?await this.client.executeClientFunction(e.functionName,e.arguments??{}):await this.client.executeClientFunction("setPageState",e.setPageState)}catch(t){l.warn("Nudge action failed:",t)}}};function et(e){if(e)return{label:e.label,functionName:e.function_name,arguments:e.arguments}}function tt(e){const t=e.goal?` Goal: ${e.goal}.`:"";return`The user accepted a proactive nudge that said: "${e.message}".${t} Recent friction signals are in the client context (friction_signals). Start helping with this now: briefly explain what you can do and take the first concrete step.`}var st=5e3,it="/api/sdk/v1/proactive/events",nt=class{constructor(e){if(this.queue=[],this.flushTimer=null,this.teardowns=[],this.destroyed=!1,this.post=e.post,this.agent=e.agent,this.flushIntervalMs=e.flushIntervalMs??st,typeof document<"u"){const t=()=>{document.visibilityState==="hidden"&&this.flush({keepalive:!0})};document.addEventListener("visibilitychange",t),this.teardowns.push(()=>document.removeEventListener("visibilitychange",t))}if(typeof window<"u"){const t=()=>this.flush({keepalive:!0});window.addEventListener("pagehide",t),this.teardowns.push(()=>window.removeEventListener("pagehide",t))}}track(e){this.destroyed||(this.queue.push(e),this.flushTimer===null&&(this.flushTimer=setTimeout(()=>this.flush(),this.flushIntervalMs)))}flush(e){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.queue.length===0)return;const t=this.queue;this.queue=[];const s={events:t.map(i=>({client_nudge_id:i.clientNudgeId,trigger_id:i.triggerId,source:i.source,type:i.type,...i.message!==void 0?{message:i.message}:{},...this.agent?{agent:this.agent}:{},occurred_at:new Date(i.occurredAt).toISOString()}))};this.post(it,s,e).catch(i=>{l.debug("Proactive event batch failed:",i)})}destroy(){if(!this.destroyed){this.flush({keepalive:!0}),this.destroyed=!0;for(const e of this.teardowns)e();this.teardowns=[]}}},X="friction_signals";function $(e,t){e.proactive&&(l.warn("createAgoProactive: a proactive controller is already attached; replacing it."),e.proactive.destroy());const s=new oe({...t.signals,getPageState:()=>{const o=e.getContextSnapshot();if(!o)return null;const c={};for(const[h,u]of Object.entries(o.entries))h.startsWith("page-state:")&&u.data&&Object.assign(c,u.data);return Object.keys(c).length>0?c:null}});s.start(),e.addDynamicContext(X,()=>{const{pageState:o,...c}=s.getSnapshot({pageState:!1});return{name:"Friction signals",description:"Behavioral friction observed on the current page: dwell/idle times, rage clicks, route bounces, repeated field errors (names and counters only).",data:c}});const i=new ze({frequencyCap:t.frequencyCap,storage:t.storage,storageKey:t.storageKey}),n=new nt({post:(o,c,h)=>e.getHttp().post(o,c,h),agent:e.getConfiguredAgent()}),r=new Ze({client:e,collector:s,governor:i,tracker:n,options:t});r.start();const a={optOut:()=>i.optOut(),optIn:()=>i.optIn(),isOptedOut:()=>i.isOptedOut(),setEngaged:o=>i.setEngaged(o),signalFieldError:o=>s.signalFieldError(o),getSignalsSnapshot:()=>s.getSnapshot(),getActiveNudge:()=>r.getActiveNudge(),shown:o=>r.shown(o),accept:o=>r.accept(o),dismiss:o=>r.dismiss(o),markConverted:o=>r.markConverted(o),destroy:()=>{r.stop(),n.destroy(),s.destroy(),e.removeDynamicContext(X),e.proactive===a&&(e.proactive=null)}};return e.proactive=a,a}var ue=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),l.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&l.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),l.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&l.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 i=s();i&&(e[t]=i)}catch(i){l.error(`DynamicContext provider "${t}" threw:`,i)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),l.log("ClientContext cleared")}},rt="page-state:";function ot(e){const t={};for(const[s,i]of Object.entries(e))s.startsWith(rt)&&i.data&&Object.assign(t,i.data);return t}function at(e){const t=e["current-page"]?.data;return t?.page?t.page:t?.url?t.url:e["browser-page"]?.data?.url}function ct(e,t){return e===t?!0:JSON.stringify(e)===JSON.stringify(t)}function lt(e,t){const s=[];for(const i of Object.keys(t))i in e&&(ct(e[i],t[i])||s.push({field:i,from:e[i],to:t[i]}));return s}function ut(e,t){const s=ot(t),i=at(t);return{changes:e&&e.page===i?lt(e.state,s):[],baseline:{page:i,state:s}}}function D(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(D).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${D(e[t])}`).join(",")}}`}var V="",he=class{constructor(e,t={}){this.callbacks=e,this.options=t,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.waitingClientEmitted=!1,this.firedClientFunctions=new Map}async processStream(e){if(!e.body)throw new d.AgoStreamError("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.","stream_no_body");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:i,value:n}=await t.read();if(i)break;const r=s.decode(n,{stream:!0});this.buffer+=r,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(i){if(this.options.signal?.aborted)return this.message.status="CANCELED",this.buildFinalMessage();const n=i instanceof Error?i:new d.AgoStreamError("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(n),n}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
5
+
6
+ `);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const s=t.split(`
7
+ `);for(const i of s)if(!i.startsWith(": ")&&i.startsWith("data: ")){const n=i.slice(6);try{const r=JSON.parse(n);this.handleChunk(r)}catch(r){l.warn("Failed to parse SSE data:",n,r)}}}}handleChunk(e){if(this.callbacks.onRawChunk?.(e),e.message_id&&!this.message.id&&(this.message.id=e.message_id),e.thread?.id&&(this.message.conversationId=e.thread.id,this.isFirstChunk&&this.message.id&&(this.isFirstChunk=!1,this.callbacks.onStart?.({conversationId:this.message.conversationId,messageId:this.message.id}))),e.title&&this.message.conversationId&&this.callbacks.onTitle?.({conversationId:this.message.conversationId,title:e.title}),e.content!==void 0&&(this.message.content=(this.message.content||"")+e.content,this.message.conversationId&&this.message.id&&this.callbacks.onChunk?.({content:e.content,conversationId:this.message.conversationId,messageId:this.message.id})),e.full_content!==void 0&&(this.message.content=e.full_content),e.status&&(this.message.status=e.status),e.agent&&(this.message.agent={id:e.agent.id,name:e.agent.name,displayName:e.agent.display_name}),e.knowledge_sources&&(this.sources=e.knowledge_sources.map(t=>{const s=t.knowledge_document;return{id:s.id,title:s.title,url:s.use_external_link?s.external_link_url:s.internal_link_url}})),e.type==="client_function"&&e.function_name){const t=`${e.function_name}::${D(e.arguments??{})}`,s=e.id||"",i=this.firedClientFunctions.get(t);let n=!1;i?s&&!i.has(s)&&(i.has(V)?(i.delete(V),i.add(s)):(i.add(s),n=!0)):(this.firedClientFunctions.set(t,new Set([s])),n=!0),n&&this.callbacks.onClientFunction?.({invocationId:s,functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""})}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(i=>i.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())),this.message.status==="WAITING_CLIENT"&&!this.waitingClientEmitted&&this.message.id&&(this.waitingClientEmitted=!0,this.callbacks.onWaitingClient?.({conversationId:this.message.conversationId||"",messageId:this.message.id,waitingToolCallIds:e.waiting_tool_call_ids??[]}))}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 e.status!=="WAITING_CLIENT"&&this.callbacks.onComplete?.(e),e}};function ht(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var dt=new Set(["image/jpeg","image/png","image/gif","image/webp","image/bmp","image/tiff"]);function de(e){if(!e)return;const t=typeof window<"u"&&window.location?window.location.href:"https://ago.local/";try{const s=new URL(e,t);if(s.protocol==="http:"||s.protocol==="https:"||s.protocol==="blob:")return e}catch{}}function ft(e){return e.isSafeImage===!0&&typeof e.contentType=="string"&&e.contentType.startsWith("image/")&&de(e.url)!==void 0}function gt(e){if(e==null||e<0)return"";if(e<1024)return`${e} B`;const t=e/1024;return t<1024?`${t.toFixed(1)} KB`:`${(t/1024).toFixed(1)} MB`}function pt(e){return{id:String(e.id??""),name:typeof e.name=="string"&&e.name?e.name:"file",contentType:typeof e.content_type=="string"?e.content_type:void 0,fileSize:typeof e.file_size=="number"?e.file_size:void 0,url:typeof e.file_url=="string"?e.file_url:void 0,isSafeImage:e.is_safe_image===!0}}function mt(e){return e.map((t,s)=>({id:`local-${s}-${t.name}`,name:t.name,contentType:t.type||void 0,fileSize:t.size,url:typeof URL<"u"&&URL.createObjectURL?URL.createObjectURL(t):void 0,isSafeImage:dt.has(t.type)}))}var fe=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(i=>{try{i(t)}catch(n){console.error(`Error in event handler for ${String(e)}:`,n)}})}once(e,t){const s=(i=>{this.off(e,s),t(i)});this.on(e,s)}waitFor(e,t){return new Promise((s,i)=>{let n;const r=(a=>{n&&clearTimeout(n),s(a)});this.once(e,r),t?.timeout&&(n=setTimeout(()=>{this.off(e,r),i(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},Y='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the public demo account https://playground.api.useago.com (agent generic-guide). See docs/general/configuration.md#error-codes (config_missing_base_url).',yt=/^[a-z][a-z0-9+.-]*:\/\//i,Q=!1;function N(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new d.AgoError(`${t}: ${Y}`,"config_missing_base_url");const s=e.baseUrl;if(typeof s!="string"||s.trim()==="")throw new d.AgoError(`${t}: ${Y}`,"config_missing_base_url");!s.startsWith("/")&&!yt.test(s)&&(Q||(Q=!0,console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)))}function vt(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function I(e){return e.split("/").filter(t=>t.startsWith(":")).map(t=>t.slice(1))}function wt(e,t){const s=[];return{path:e.split("/").map(i=>{if(!i.startsWith(":"))return i;const n=i.slice(1),r=t[n];return r==null||r===""?(s.push(n),i):encodeURIComponent(String(r))}).join("/"),missing:s}}function St(e,t){const s=t.find(n=>n.path===e);if(s)return s;const i=t.find(n=>{if(!n.path.includes(":"))return!1;const r="^"+n.path.split("/").map(a=>a.startsWith(":")?"[^/]+":vt(a)).join("/")+"/?$";return new RegExp(r).test(e)});return i||t.filter(n=>n.path!=="/"&&e.startsWith(n.path)).sort((n,r)=>r.path.length-n.path.length)[0]}var At="activity:recent",Ct="state:delta";function Z(e){return e==="setPageState"?"readPageData":`read${e.charAt(0).toUpperCase()}${e.slice(1)}Data`}var bt=class ge{constructor(t){this.lastSentPageState=null,this.warnedEmptyConversations=new Set,this.warnedPageDataPlaceholder=!1,this.pageDataCompanions=new Set,this.pendingResumes=new Map,this.pendingApprovals=new Map,this.resumeGate=null,this.activeTurn=null,this.pausedTurn=null,this.stoppedTurnIds=new Set,this.proactive=null,N(t,"AgoClient"),this.config=t,this.activityLedger=new ee(t.maxActivityEntries),this.httpClient=new Se(t),this.functionRegistry=new te({maxResultBytes:t.maxFunctionResultBytes}),this.contextRegistry=new ue,this.eventEmitter=new fe,this.registerActivityContext(),t.debug&&l.enable(),t.proactive&&$(this,t.proactive),l.log("AgoClient initialized")}async sendMessage(t,s){const i=this.functionRegistry.getSchemas(),n=this.buildSendContext(),r=this.config.agent||this.config.defaultAgentId,a=this.resolveClientFunctionsMode(s),o={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||r};i.length>0&&(o.client_functions=i,a==="pause"&&(o.client_functions_mode=a)),n&&(o.client_context=n),s?.hidden&&(o.hidden=!0);const c=this.beginTurn();let h;if(s?.files&&s.files.length>0){const u=new FormData;u.append("content",t),s.conversationId&&u.append("conversation_id",s.conversationId),(s.agentId||r)&&u.append("agent_id",s.agentId||r||""),i.length>0&&(u.append("client_functions",JSON.stringify(i)),a==="pause"&&u.append("client_functions_mode",a)),n&&u.append("client_context",JSON.stringify(n)),s.hidden&&u.append("hidden","true");for(const f of s.files)u.append("files",f);h=await this.sendRequest(c,()=>this.httpClient.postFormData("/api/sdk/v1/messages",u,{signal:c.controller.signal}))}else h=await this.sendRequest(c,()=>this.httpClient.postStream("/api/sdk/v1/messages",o,{signal:c.controller.signal}));return h?this.processSSEResponse(h,c):this.buildStoppedMessage(c)}async sendRequest(t,s){try{return await s()}catch(i){if(this.endTurn(t),T(i))return null;throw i}}async processSSEResponse(t,s){let i=!1;const n=new he({onRawChunk:r=>{s&&(r.message_id&&!s.messageId&&(s.messageId=r.message_id),r.thread?.id&&(s.conversationId=r.thread.id)),this.eventEmitter.emit("stream:message",r)},onStart:r=>{this.eventEmitter.emit("message:start",r)},onChunk:r=>{this.eventEmitter.emit("message:chunk",r)},onToolCall:r=>{this.eventEmitter.emit("toolCall:received",r),r.type==="form"&&this.eventEmitter.emit("toolCall:form",r)},onClientFunction:async r=>{if(i=!0,this.eventEmitter.emit("function:invoke",r),this.recordAgentAction(r),r.invocationId&&this.requiresApproval(r)){this.pendingApprovals.set(r.invocationId,r),this.eventEmitter.emit("function:awaiting-approval",r);return}await this.handleClientFunctionInvocation(r)},onTitle:r=>{this.eventEmitter.emit("conversation:title",r)},onAnswerComplete:r=>{this.eventEmitter.emit("message:answer-complete",r)},onWaitingClient:r=>{this.pausedTurn={messageId:r.messageId,conversationId:r.conversationId},this.eventEmitter.emit("message:waiting-client",r),this.markResumeSignal(r.messageId,r.conversationId,"waitingConfirmed")},onComplete:r=>{s?.stopRequested&&!r.id||this.eventEmitter.emit("message:complete",r)},onError:r=>{this.eventEmitter.emit("message:error",{error:r.message,code:r instanceof d.AgoError?r.code:void 0})}},{signal:s?.controller.signal});try{const r=await n.processStream(t);return s?.stopRequested&&(this.postStopForTurn(s,s.messageId??r.id),this.eventEmitter.emit("message:stopped",{conversationId:s.conversationId??r.conversationId??"",messageId:s.messageId??r.id??""})),r.status!=="WAITING_CLIENT"&&this.maybeFlagEmptyReply(r,i),r}finally{s&&this.endTurn(s)}}async stop(){const t=this.activeTurn;if(t){t.stopRequested=!0;const n=t.messageId;return t.controller.abort(),n?this.postStopForTurn(t,n):null}const s=this.pausedTurn;if(!s)return null;this.pausedTurn=null,this.pendingResumes.delete(s.messageId),this.stoppedTurnIds.add(s.messageId);let i=null;try{i=await this.stopMessage(s.messageId)}catch(n){l.warn("Failed to stop the paused turn:",n)}return this.eventEmitter.emit("message:stopped",{conversationId:s.conversationId,messageId:s.messageId}),i}async stopMessage(t){const s=await this.httpClient.post(`/api/sdk/v1/messages/${t}/stop`);return{status:s.status,messageStatus:s.message_status}}isGenerating(){return this.activeTurn!==null||this.pausedTurn!==null}beginTurn(){this.pausedTurn=null;const t={controller:new AbortController,messageId:null,conversationId:null,stopRequested:!1,stopPosted:!1};return this.activeTurn=t,t}endTurn(t){this.activeTurn===t&&(this.activeTurn=null)}async postStopForTurn(t,s){if(!s||t.stopPosted)return null;t.stopPosted=!0;try{return await this.stopMessage(s)}catch(i){return l.warn("Failed to stop the turn server-side:",i),null}}buildStoppedMessage(t){const s={id:t.messageId??"",conversationId:t.conversationId??"",content:"",role:"assistant",status:"CANCELED",createdAt:new Date};return s.id&&this.eventEmitter.emit("message:complete",s),this.eventEmitter.emit("message:stopped",{conversationId:s.conversationId,messageId:s.id}),s}resolveClientFunctionsMode(t){return t?.clientFunctionsMode??this.config.clientFunctionsMode??"pause"}registerResumeGate(t){return this.resumeGate=t,()=>{this.resumeGate===t&&(this.resumeGate=null)}}async continueMessage(t){const s=this.functionRegistry.getSchemas(),i=this.buildSendContext(),n={};s.length>0&&(n.client_functions=s),i&&(n.client_context=i);const r=this.beginTurn();r.messageId=t;const a=await this.sendRequest(r,()=>this.httpClient.postStream(`/api/sdk/v1/messages/${t}/continue`,n,{signal:r.controller.signal}));return a?this.processSSEResponse(a,r):this.buildStoppedMessage(r)}markResumeSignal(t,s,i){if(!t)return;const n=this.pendingResumes.get(t)??{conversationId:s,waitingConfirmed:!1,resultsReady:!1,started:!1};n[i]=!0,s&&(n.conversationId=s),this.pendingResumes.set(t,n),!(!n.waitingConfirmed||!n.resultsReady||n.started)&&(n.started=!0,this.runAutoResume(t,n.conversationId))}async runAutoResume(t,s){try{this.resumeGate&&await this.resumeGate({conversationId:s,messageId:t})}catch(i){l.warn("Resume gate threw; resuming anyway:",i)}if(this.pendingResumes.delete(t),!this.stoppedTurnIds.delete(t))try{await this.continueMessage(t)}catch(i){l.warn("Auto-resume of paused turn failed:",i)}}maybeFlagEmptyReply(t,s){t.status==="DONE"&&(t.content??"").trim()===""&&!s&&!(t.toolCalls&&t.toolCalls.length>0)&&!(t.followUpReplies&&t.followUpReplies.length>0)&&setTimeout(()=>{if(this.eventEmitter.emit("message:empty",{conversationId:t.conversationId??"",messageId:t.id??""}),this.config.warnOnEmptyReply===!1)return;const i=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(i))return;this.warnedEmptyConversations.add(i);const n=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(n?`the agent "${n}" may not exist for this tenant, `:"an unknown `agent` slug, ")+"or the agent replied with no text. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`."):console.warn("[AGO] The stream completed without any message data. Possible causes: "+(n?`the agent "${n}" may not exist for this tenant, or `:"")+"`baseUrl` does not point at an AGO endpoint that returns server-sent events. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`.")},0)}async handleClientFunctionInvocation(t){let s,i;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(n){i=n instanceof Error?n.message:"Unknown error",l.error("Client function execution failed:",n)}if(t.invocationId)try{const n=await this.submitToolCallForm(t.invocationId,{result:s,error:i,_type:"client_function_result"});n?.resume?.ready&&this.markResumeSignal(n.resume.message_id,t.conversationId,"resultsReady")}catch(n){l.error("Failed to submit function result:",n)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:i})}requiresApproval(t){const s=this.config.approvalPolicy;if(s)try{if(s(t))return!0}catch(i){l.warn("approvalPolicy threw; not gating this call:",i)}return this.functionRegistry.get(t.functionName)?.requiresApproval===!0}async approveFunction(t){const s=this.pendingApprovals.get(t);s&&(this.pendingApprovals.delete(t),await this.handleClientFunctionInvocation(s))}async rejectFunction(t){const s=this.pendingApprovals.get(t);if(!s)return;this.pendingApprovals.delete(t);const i={approved:!1,reason:"user_rejected"};try{const n=await this.submitToolCallForm(t,{result:i,_type:"client_function_result"});n?.resume?.ready&&this.markResumeSignal(n.resume.message_id,s.conversationId,"resultsReady")}catch(n){l.error("Failed to submit function rejection:",n)}this.eventEmitter.emit("function:result",{invocationId:t,result:i})}async getConversations(t){const s=new URLSearchParams;t?.page!==void 0&&s.set("page",String(t.page)),t?.pageSize!==void 0&&s.set("page_size",String(t.pageSize));const i=s.toString(),n=await this.httpClient.get(`/api/sdk/v1/conversations${i?`?${i}`:""}`),r=(Array.isArray(n.data)?n.data:[]).map(a=>({id:String(a.id),title:a.title??"",lastMessageDate:new Date(a.last_message_at??a.created_at??0)}));return{data:r,hasMore:n.has_more??!1,total:n.total??r.length}}async getConversation(t){const s=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),i={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_at??s.created_at??0),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),hidden:n.hidden,toolCalls:ge.mapPersistedToolCalls(n.tool_call_data),attachments:n.attachments&&n.attachments.length>0?n.attachments.map(pt):void 0,followUpReplies:n.follow_up_replies&&n.follow_up_replies.length>0?n.follow_up_replies:void 0}))};return this.eventEmitter.emit("conversation:loaded",i),i}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 resumePendingClientFunctions(t){const s=[...t.messages??[]].reverse().find(o=>o.role==="assistant"&&o.status==="WAITING_CLIENT");if(!s)return null;const i=(s.toolCalls??[]).filter(o=>o.type==="client_function"&&o.status==="waiting_input"&&o.functionName),n=new Set(this.functionRegistry.getSchemas().map(o=>o.name)),r=i.filter(o=>!n.has(o.functionName));if(r.length>0)return l.warn("Cannot resume paused turn: function(s) not registered on this page:",r.map(o=>o.functionName)),null;let a=i.length===0;for(const o of i){const c={invocationId:o.id,functionName:o.functionName,arguments:o.arguments??{},conversationId:t.id};if(this.requiresApproval(c)){this.pendingApprovals.set(o.id,c),this.markResumeSignal(s.id,t.id,"waitingConfirmed"),this.eventEmitter.emit("function:awaiting-approval",c),a=!1;continue}this.eventEmitter.emit("function:invoke",c);let h,u;try{h=await this.functionRegistry.execute(o.functionName,o.arguments??{})}catch(f){u=f instanceof Error?f.message:"Unknown error",l.error("Client function execution failed:",f)}this.eventEmitter.emit("function:result",{invocationId:o.id,result:h,error:u}),a=(await this.submitToolCallForm(o.id,{result:h,error:u,_type:"client_function_result"}))?.resume?.ready??a}return a?this.continueMessage(s.id):null}async submitToolCallForm(t,s){return this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:s})}async confirmToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/confirm/`)}async rejectToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/reject/`)}async getFormCollector(t){const s=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:s.name,description:s.description,schema:s.schema,submit:s.submit??void 0}}async submitFormCollector(t,s){return this.httpClient.post("/api/sdk/v1/forms/submit",{name:t,values:s})}async submitFeedback(t,s,i){const n=i?.comment?.trim(),r=i?.reasons?.length?[...new Set(i.reasons)]:[];await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:s,...r.length?{reasons:r}:{},...n?{comment:n}:{}})}async submitConversationFeedback(t,s,i){let n=i?.lastMessageId;if(!n){const r=[...(await this.getConversation(t)).messages??[]].reverse().find(a=>a.role==="assistant"&&!a.hidden&&!!a.content&&a.status!=="IN_PROGRESS"&&a.status!=="WAITING_CLIENT");if(!r)throw new d.AgoError(`Conversation ${t} has no finished answer to report feedback on. Wait for the turn to complete, or pass \`lastMessageId\`.`,"feedback_no_message");n=r.id}return await this.submitFeedback(n,s,i),n}registerFunction(t,s,i){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,i)}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()}async executeClientFunction(t,s){return this.functionRegistry.execute(t,s)}registerNavigationFunction(t,s){const i=s.map(o=>o.name),n=s.map(o=>{const c=I(o.path),h=c.length>0?` (requires ${c.map(u=>`"${u}"`).join(", ")})`:"";return`- "${o.name}"${h}: ${o.description}`}).join(`
8
+ `),r=new Map;for(const o of s)for(const c of I(o.path))r.set(c,[...r.get(c)??[],o.name]);const a={page:{type:"string",description:"The page to navigate to",enum:i}};for(const[o,c]of r){if(o==="page"){l.error('registerNavigationFunction: a ":page" placeholder collides with the "page" argument and is ignored. Rename the placeholder.');continue}a[o]={type:"string",description:`Value for ":${o}" in the page path. Required when page is ${c.map(h=>`"${h}"`).join(" or ")}.`}}this.registerFunction("navigateToPage",async o=>{const c=o.page,h=s.find(p=>p.name===c);if(!h)return{success:!1,error:`Unknown page: ${c}`};let u={};if(typeof o.params=="string")try{u=JSON.parse(o.params)}catch{}else o.params&&typeof o.params=="object"&&(u=o.params);const f={};for(const p of I(h.path))f[p]=o[p]??u[p];const{path:y,missing:A}=wt(h.path,f);if(A.length>0){const p=A.map(g=>`"${g}": "..."`).join(", ");return{success:!1,error:`Page "${c}" needs ${A.map(g=>`"${g}"`).join(", ")}. Retry with { "page": "${c}", ${p} }.`}}return t(y),{success:!0,navigatedTo:y}},{description:`Navigate the user to a page in the application. Available pages:
9
+ ${n}`,parameters:{type:"object",properties:a,required:["page"]}}),this.addDynamicContext("current-page",()=>{if(typeof window>"u"||!window.location)return null;const o=window.location.href,c=typeof document<"u"?document.title:void 0,h=St(window.location.pathname,s),u={url:o};return h&&(u.page=h.name),c&&(u.title=c),{name:"Current page",description:"The page the user is currently viewing.",data:u}})}unregisterNavigationFunction(){this.unregisterFunction("navigateToPage"),this.removeDynamicContext("current-page")}registerPageStateFunction(t,s){const i=s?.functionName??"setPageState",n=s?.data;this.registerFunction(Me(t,{name:i,requiresApproval:s?.requiresApproval,getResultBudget:()=>n?this.pageDataBudget(n):this.functionRegistry.getDefaultMaxResultBytes(),data:n?{description:n.description,maxResultBytes:n.maxResultBytes,read:async a=>G(i,await this.readPageData(i,n,s),this.pageDataBudget(n)-this.envelopeBytes(a))}:void 0}));const r=Z(i);n?(this.warnIfPlaceholderMode(i),this.registerFunction(r,async()=>({data:G(i,await this.readPageData(i,n,s),this.pageDataBudget(n)-this.envelopeBytes({}))}),{description:`Read what the current page is displaying, without changing anything: ${n.description}`,parameters:{type:"object",properties:{}},maxResultBytes:n.maxResultBytes}),this.pageDataCompanions.add(r)):this.pageDataCompanions.delete(r)&&this.unregisterFunction(r),this.addDynamicContext(`page-state:${i}`,()=>{const a=t.filter(c=>typeof c.get=="function");if(a.length===0)return null;const o={};for(const c of a)o[c.name]=c.get();return{name:"Page state",description:"Current, editable state of the page the user is viewing.",data:o}})}unregisterPageStateFunction(t){const s=t??"setPageState";this.unregisterFunction(s);const i=Z(s);this.pageDataCompanions.delete(i)&&this.unregisterFunction(i),this.removeDynamicContext(`page-state:${s}`)}pageDataBudget(t){return t.maxResultBytes??this.functionRegistry.getDefaultMaxResultBytes()}envelopeBytes(t){return m(JSON.stringify({...t,data:null}))-4}readPageData(t,s,i){return Te(()=>s,i?.settleTimeoutMs??1e4).catch(n=>(l.warn(`Reading page data for "${t}" failed:`,n),{error:"page_data_unavailable",message:n instanceof Error?n.message:String(n)}))}warnIfPlaceholderMode(t){this.warnedPageDataPlaceholder||this.config.clientFunctionsMode==="placeholder"&&(this.warnedPageDataPlaceholder=!0,l.warn(`"${t}" declares a data source, but clientFunctionsMode is "placeholder": the agent will not see that data during the turn it calls the function. Switch to "pause" (the default) for the data to come back as the result of its own call.`))}setContext(t,s){this.contextRegistry.set(t,s),this.notifyContextChanged()}removeContext(t){const s=this.contextRegistry.remove(t);return s&&this.notifyContextChanged(),s}addDynamicContext(t,s){this.contextRegistry.addDynamicProvider(t,s),this.notifyContextChanged()}removeDynamicContext(t){const s=this.contextRegistry.removeDynamicProvider(t);return s&&this.notifyContextChanged(),s}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}emitFormEvent(t,s){this.eventEmitter.emit(t,s)}emitProactiveEvent(t,s){this.eventEmitter.emit(t,s)}getHttp(){return this.httpClient}getConfiguredAgent(){return this.config.agent||this.config.defaultAgentId}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()}buildSendContext(){const t=this.contextRegistry.getSnapshot(),s=t?.entries??{},{changes:i,baseline:n}=ut(this.lastSentPageState,s);return this.lastSentPageState=n,i.length===0?t:{entries:{...s,[Ct]:{name:"State changes",description:"Fields in the page state that changed since your last message, as field: <old> -> <new>.",data:{changes:i}}}}}recordActivity(t){this.addActivity(t)}getRecentActivity(){return this.activityLedger.getRecent()}clearActivity(){this.activityLedger.clear()}addActivity(t){const s=this.activityLedger.add(t);this.eventEmitter.emit("activity:recorded",s)}recordAgentAction(t){const s=t.functionName,i=t.arguments;let n,r;if(s==="navigateToPage"){const a=i?.page;n="agent.navigate",r=a?`Agent navigated to "${String(a)}"`:"Agent navigated"}else s==="setPageState"?(n="agent.page_state",r="Agent changed the page state"):(n=`agent.${s}`,r=`Agent ran "${s}"`);this.addActivity({actor:"agent",name:n,summary:r,...i&&Object.keys(i).length>0?{data:{arguments:i}}:{}})}registerActivityContext(){this.contextRegistry.addDynamicProvider(At,()=>{const t=this.activityLedger.getRecent();return t.length===0?null:{name:"Recent activity",description:"Recent actions by the user and the agent in the app, oldest first. Use this to understand what just happened before this message.",data:{events:t}}})}on(t,s){this.eventEmitter.on(t,s)}off(t,s){this.eventEmitter.off(t,s)}once(t,s){this.eventEmitter.once(t,s)}waitFor(t,s){return this.eventEmitter.waitFor(t,s)}updateConfig(t){const s={};for(const[n,r]of Object.entries(t))r!==void 0&&(s[n]=r);const i={...this.config,...s};N(i,"AgoClient.updateConfig"),this.config=i,this.httpClient.updateConfig(s),s.debug!==void 0&&(s.debug?l.enable():l.disable()),s.maxFunctionResultBytes!==void 0&&this.functionRegistry.setDefaultMaxResultBytes(s.maxFunctionResultBytes)}destroy(){this.proactive?.destroy(),this.proactive=null,this.activeTurn?.controller.abort(),this.activeTurn=null,this.pausedTurn=null,this.stoppedTurnIds.clear(),this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),this.pendingResumes.clear(),this.pendingApprovals.clear(),this.resumeGate=null,l.log("AgoClient destroyed")}reviveAfterDestroy(){this.registerActivityContext(),this.config.proactive&&!this.proactive&&$(this,this.config.proactive)}},Et=["inaccurate","incomplete","information_not_found","technical_issue"];Object.defineProperty(exports,"ActivityLedger",{enumerable:!0,get:function(){return ee}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return bt}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return ue}});Object.defineProperty(exports,"DEFAULT_MAX_ACTIVITY_ENTRIES",{enumerable:!0,get:function(){return pe}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return fe}});Object.defineProperty(exports,"FEEDBACK_REASONS",{enumerable:!0,get:function(){return Et}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return te}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return he}});Object.defineProperty(exports,"SignalCollector",{enumerable:!0,get:function(){return oe}});Object.defineProperty(exports,"attachmentsFromFiles",{enumerable:!0,get:function(){return mt}});Object.defineProperty(exports,"canInlineImage",{enumerable:!0,get:function(){return ft}});Object.defineProperty(exports,"createAgoProactive",{enumerable:!0,get:function(){return $}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return ae}});Object.defineProperty(exports,"formatFileSize",{enumerable:!0,get:function(){return gt}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return ht}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return l}});Object.defineProperty(exports,"matchesRoutePattern",{enumerable:!0,get:function(){return ce}});Object.defineProperty(exports,"matchesWhen",{enumerable:!0,get:function(){return le}});Object.defineProperty(exports,"partialDeepMatch",{enumerable:!0,get:function(){return j}});Object.defineProperty(exports,"safeAttachmentUrl",{enumerable:!0,get:function(){return de}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return N}});
package/dist/vue.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=require("./AgoClient-7yXQ6R3O.cjs");let o=require("vue");var I=Symbol("ago-client"),L={install(t,e){const n=new w.AgoClient(e);t.provide(I,n)}};function d(t){if(t)return new w.AgoClient(t);const e=(0,o.inject)(I);if(!e)throw new Error("useAgo(): no AgoClient found. Either pass config or install AgoPlugin.");return e}function E(t={}){const e=t.client??d(),n=(0,o.ref)([]),s=(0,o.ref)(t.conversationId),a=(0,o.ref)(!1),i=(0,o.ref)(null),v=r=>{s.value||(s.value=r.conversationId)},f=r=>{const u=n.value.findIndex(l=>l.id===r.messageId);u>=0&&(n.value[u]={...n.value[u],content:n.value[u].content+r.content})},m=r=>{const u=n.value.findIndex(l=>l.id===r.id);u>=0?n.value[u]=r:n.value.push(r),a.value=!1},p=r=>{i.value=new Error(r.error),a.value=!1},g=()=>{let r=-1;for(let u=n.value.length-1;u>=0;u--){const l=n.value[u];if(l.role==="assistant"&&(l.status==="IN_PROGRESS"||l.status==="WAITING_CLIENT")){r=u;break}}r>=0&&(n.value[r].content?n.value[r]={...n.value[r],status:"CANCELED"}:n.value.splice(r,1)),a.value=!1};(0,o.onMounted)(()=>{e.on("message:start",v),e.on("message:chunk",f),e.on("message:complete",m),e.on("message:error",p),e.on("message:stopped",g)}),(0,o.onUnmounted)(()=>{e.off("message:start",v),e.off("message:chunk",f),e.off("message:complete",m),e.off("message:error",p),e.off("message:stopped",g)});async function C(r,u){a.value=!0,i.value=null;const l={id:`temp-${Date.now()}`,conversationId:s.value||"",content:r,role:"user",status:"DONE",createdAt:new Date},S={id:`temp-assistant-${Date.now()}`,conversationId:s.value||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date};n.value.push(l,S);try{const c=await e.sendMessage(r,{conversationId:s.value,files:u});c.conversationId&&!s.value&&(s.value=c.conversationId),n.value=n.value.filter(A=>!A.id.startsWith("temp-"));const h={...l,id:l.id.replace("temp-","user-"),conversationId:c.conversationId};return n.value.some(A=>A.id===c.id)?n.value.push(h):n.value.push(h,c),c}catch(c){return i.value=c instanceof Error?c:new Error("Failed to send"),a.value=!1,n.value=n.value.filter(h=>!h.id.startsWith("temp-")),null}}async function M(){await e.stop()}function y(){n.value=[],s.value=void 0,i.value=null}return{messages:n,isLoading:a,error:i,conversationId:s,sendMessage:C,stop:M,clearMessages:y}}function N(t={}){const e=t.client??d(),n=t.autoLoad??!0,s=(0,o.ref)([]),a=(0,o.ref)(null),i=(0,o.ref)(!1),v=(0,o.ref)(null);async function f(){i.value=!0,v.value=null;try{s.value=(await e.getConversations()).data}catch(g){v.value=g instanceof Error?g:new Error("Failed to load conversations")}finally{i.value=!1}}async function m(g){i.value=!0,v.value=null;try{a.value=await e.getConversation(g)}catch(C){v.value=C instanceof Error?C:new Error("Failed to load conversation")}finally{i.value=!1}}function p(){a.value=null}return(0,o.onMounted)(()=>{n&&f()}),{conversations:s,currentConversation:a,isLoading:i,error:v,selectConversation:m,startNewConversation:p,refreshConversations:f}}function P(t={}){const e=E({client:t.client,conversationId:t.conversationId}),n=N({client:t.client,autoLoad:t.autoLoad}),s=(0,o.computed)(()=>e.error.value||n.error.value);return{messages:e.messages,isLoading:e.isLoading,error:s,sendMessage:e.sendMessage,stop:e.stop,clearMessages:e.clearMessages,conversationId:e.conversationId,conversations:n.conversations,currentConversation:n.currentConversation,isConversationsLoading:n.isLoading,selectConversation:n.selectConversation,startNewConversation:n.startNewConversation,refreshConversations:n.refreshConversations}}function R(t,e){const n=d();(0,o.onMounted)(()=>{n.registerFunction(t,e.handler,{description:e.description,parameters:e.parameters,maxResultBytes:e.maxResultBytes})}),(0,o.onUnmounted)(()=>{n.unregisterFunction(t)})}function F(t,e){const n=d();(0,o.onMounted)(()=>{n.registerNavigationFunction(t,e)}),(0,o.onUnmounted)(()=>{n.unregisterNavigationFunction()})}function _(t,e){const n=d(),s=e?.functionName??"setPageState";(0,o.onMounted)(()=>{n.registerPageStateFunction(t,{...e,functionName:s})}),(0,o.onUnmounted)(()=>{n.unregisterPageStateFunction(s)})}function D(t,e){const n=d();(0,o.onMounted)(()=>{n.on(t,e)}),(0,o.onUnmounted)(()=>{n.off(t,e)})}function U(t){const e=(0,o.shallowRef)(t.get());return(0,o.onScopeDispose)(t.subscribe(n=>{e.value=n})),e}function b(){const t=d(),e=(0,o.shallowRef)(null),n=a=>{e.value=a,t.proactive?.shown(a)},s=({nudge:a})=>{e.value?.id===a.id&&(e.value=null)};return(0,o.onMounted)(()=>{t.on("nudge:ready",n),t.on("nudge:accepted",s),t.on("nudge:dismissed",s)}),(0,o.onUnmounted)(()=>{t.off("nudge:ready",n),t.off("nudge:accepted",s),t.off("nudge:dismissed",s)}),{nudge:e,accept:async()=>{const a=e.value;a&&(e.value=null,await t.proactive?.accept(a))},dismiss:()=>{const a=e.value;a&&(e.value=null,t.proactive?.dismiss(a))}}}exports.AGO_CLIENT_KEY=I;exports.AgoPlugin=L;exports.useAgo=d;exports.useAgoEvents=D;exports.useAgoFunction=R;exports.useAgoNavigation=F;exports.useAgoPageState=_;exports.useAgoStore=U;exports.useChat=P;exports.useConversation=N;exports.useMessages=E;exports.useProactiveNudge=b;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("./types-D3YQl1jx.cjs");let o=require("vue");var S=Symbol("ago-client"),I={install(t,n){const e=new y.AgoClient(n);t.provide(S,e)}};function g(t){if(t)return new y.AgoClient(t);const n=(0,o.inject)(S);if(!n)throw new Error("useAgo(): no AgoClient found. Either pass config or install AgoPlugin.");return n}function N(t={}){const n=t.client??g(),e=(0,o.ref)([]),a=(0,o.ref)(t.conversationId),r=(0,o.ref)(!1),l=(0,o.ref)(null),v=s=>{a.value||(a.value=s.conversationId)},m=s=>{const i=e.value.findIndex(d=>d.id===s.messageId);i>=0&&(e.value[i]={...e.value[i],content:e.value[i].content+s.content})},p=s=>{const i=e.value.findIndex(d=>d.id===s.id);i>=0?e.value[i]=s:e.value.push(s),r.value=!1},C=s=>{l.value=new Error(s.error),r.value=!1},u=()=>{let s=-1;for(let i=e.value.length-1;i>=0;i--){const d=e.value[i];if(d.role==="assistant"&&(d.status==="IN_PROGRESS"||d.status==="WAITING_CLIENT")){s=i;break}}s>=0&&(e.value[s].content?e.value[s]={...e.value[s],status:"CANCELED"}:e.value.splice(s,1)),r.value=!1};(0,o.onMounted)(()=>{n.on("message:start",v),n.on("message:chunk",m),n.on("message:complete",p),n.on("message:error",C),n.on("message:stopped",u)}),(0,o.onUnmounted)(()=>{n.off("message:start",v),n.off("message:chunk",m),n.off("message:complete",p),n.off("message:error",C),n.off("message:stopped",u)});async function c(s,i){r.value=!0,l.value=null;const d={id:`temp-${Date.now()}`,conversationId:a.value||"",content:s,role:"user",status:"DONE",createdAt:new Date},F={id:`temp-assistant-${Date.now()}`,conversationId:a.value||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date};e.value.push(d,F);try{const f=await n.sendMessage(s,{conversationId:a.value,files:i});f.conversationId&&!a.value&&(a.value=f.conversationId),e.value=e.value.filter(A=>!A.id.startsWith("temp-"));const w={...d,id:d.id.replace("temp-","user-"),conversationId:f.conversationId};return e.value.some(A=>A.id===f.id)?e.value.push(w):e.value.push(w,f),f}catch(f){return l.value=f instanceof Error?f:new Error("Failed to send"),r.value=!1,e.value=e.value.filter(w=>!w.id.startsWith("temp-")),null}}async function h(){await n.stop()}function E(){e.value=[],a.value=void 0,l.value=null}return{messages:e,isLoading:r,error:l,conversationId:a,sendMessage:c,stop:h,clearMessages:E}}function b(t={}){const n=t.client??g(),e=t.autoLoad??!0,a=(0,o.ref)([]),r=(0,o.ref)(null),l=(0,o.ref)(!1),v=(0,o.ref)(null);async function m(){l.value=!0,v.value=null;try{a.value=(await n.getConversations()).data}catch(u){v.value=u instanceof Error?u:new Error("Failed to load conversations")}finally{l.value=!1}}async function p(u){l.value=!0,v.value=null;try{r.value=await n.getConversation(u)}catch(c){v.value=c instanceof Error?c:new Error("Failed to load conversation")}finally{l.value=!1}}function C(){r.value=null}return(0,o.onMounted)(()=>{e&&m()}),{conversations:a,currentConversation:r,isLoading:l,error:v,selectConversation:p,startNewConversation:C,refreshConversations:m}}function M(t={}){const n=N({client:t.client,conversationId:t.conversationId}),e=b({client:t.client,autoLoad:t.autoLoad}),a=(0,o.computed)(()=>n.error.value||e.error.value);return{messages:n.messages,isLoading:n.isLoading,error:a,sendMessage:n.sendMessage,stop:n.stop,clearMessages:n.clearMessages,conversationId:n.conversationId,conversations:e.conversations,currentConversation:e.currentConversation,isConversationsLoading:e.isLoading,selectConversation:e.selectConversation,startNewConversation:e.startNewConversation,refreshConversations:e.refreshConversations}}function L(t={}){const n=t.client??g(),e=(0,o.ref)({}),a=(0,o.ref)(!1),r=(0,o.ref)(null),l=new Map;function v(u){const c=(l.get(u)??0)+1;return l.set(u,c),c}const m=(u,c)=>l.get(u)===c;async function p(u,c,h){const E=v(u);a.value=!0,r.value=null;try{await n.submitFeedback(u,c,h),m(u,E)&&(e.value={...e.value,[u]:c})}catch(s){const i=s instanceof Error?s:new Error("Failed to submit feedback");throw r.value=i,i}finally{a.value=!1}}async function C(u,c,h){const E=v(u);a.value=!0,r.value=null;try{const s=await n.submitConversationFeedback(u,c,h);return m(u,E)&&(e.value={...e.value,[s]:c}),s}catch(s){const i=s instanceof Error?s:new Error("Failed to submit feedback");throw r.value=i,i}finally{a.value=!1}}return{ratings:e,isSubmitting:a,error:r,submitFeedback:p,submitConversationFeedback:C}}function R(t,n){const e=g();(0,o.onMounted)(()=>{e.registerFunction(t,n.handler,{description:n.description,parameters:n.parameters,maxResultBytes:n.maxResultBytes})}),(0,o.onUnmounted)(()=>{e.unregisterFunction(t)})}function P(t,n){const e=g();(0,o.onMounted)(()=>{e.registerNavigationFunction(t,n)}),(0,o.onUnmounted)(()=>{e.unregisterNavigationFunction()})}function k(t,n){const e=g(),a=n?.functionName??"setPageState";(0,o.onMounted)(()=>{e.registerPageStateFunction(t,{...n,functionName:a})}),(0,o.onUnmounted)(()=>{e.unregisterPageStateFunction(a)})}function _(t,n){const e=g();(0,o.onMounted)(()=>{e.on(t,n)}),(0,o.onUnmounted)(()=>{e.off(t,n)})}function D(t){const n=(0,o.shallowRef)(t.get());return(0,o.onScopeDispose)(t.subscribe(e=>{n.value=e})),n}function q(){const t=g(),n=(0,o.shallowRef)(null),e=r=>{n.value=r,t.proactive?.shown(r)},a=({nudge:r})=>{n.value?.id===r.id&&(n.value=null)};return(0,o.onMounted)(()=>{t.on("nudge:ready",e),t.on("nudge:accepted",a),t.on("nudge:dismissed",a)}),(0,o.onUnmounted)(()=>{t.off("nudge:ready",e),t.off("nudge:accepted",a),t.off("nudge:dismissed",a)}),{nudge:n,accept:async()=>{const r=n.value;r&&(n.value=null,await t.proactive?.accept(r))},dismiss:()=>{const r=n.value;r&&(n.value=null,t.proactive?.dismiss(r))}}}exports.AGO_CLIENT_KEY=S;exports.AgoPlugin=I;exports.FEEDBACK_REASONS=y.FEEDBACK_REASONS;exports.useAgo=g;exports.useAgoEvents=_;exports.useAgoFunction=R;exports.useAgoNavigation=P;exports.useAgoPageState=k;exports.useAgoStore=D;exports.useChat=M;exports.useConversation=b;exports.useFeedback=L;exports.useMessages=N;exports.useProactiveNudge=q;
package/dist/vue.d.cts CHANGED
@@ -281,9 +281,40 @@ declare class AgoClient {
281
281
  */
282
282
  submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
283
283
  /**
284
- * Submit feedback for a message
284
+ * Report an answer: thumbs up/down, optionally with what went wrong.
285
+ *
286
+ * ```ts
287
+ * await client.submitFeedback(message.id, "negative", {
288
+ * reasons: ["inaccurate"],
289
+ * comment: "The price it quoted is from last year.",
290
+ * });
291
+ * ```
292
+ *
293
+ * A bare rating is a reaction (the thumbs counted in the dashboard). Adding a
294
+ * reason or a comment also files it in the feedback list, the analytics and
295
+ * the CSV export, so someone can act on it.
285
296
  */
286
- submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
297
+ submitFeedback(messageId: string, rating: FeedbackRating, details?: FeedbackDetails): Promise<void>;
298
+ /**
299
+ * Report a whole conversation ("this chat is not working").
300
+ *
301
+ * ```ts
302
+ * await client.submitConversationFeedback(conversationId, "negative", {
303
+ * reasons: ["information_not_found"],
304
+ * comment: "It never answered my question.",
305
+ * });
306
+ * ```
307
+ *
308
+ * Feedback is stored per message, so this attaches the report to the last
309
+ * answer of the conversation, which is the one the user is reacting to.
310
+ * Returns the message id it landed on.
311
+ *
312
+ * Pass `lastMessageId` when you already have it (the widget does) to skip the
313
+ * lookup round-trip.
314
+ */
315
+ submitConversationFeedback(conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
316
+ lastMessageId?: string;
317
+ }): Promise<string>;
287
318
  /**
288
319
  * Register a client-side function that AGO can call.
289
320
  * Accepts either a definition object or (name, handler, schema) args.
@@ -936,12 +967,27 @@ export declare interface AgoStateControl<T = unknown> {
936
967
  enum?: (string | number)[];
937
968
  };
938
969
  };
970
+ /** String-only: `""` means "clear" instead of being dropped as filler. */
971
+ clearable?: boolean;
939
972
  /** Current value → pushed as dynamic context so the agent knows what to change. */
940
973
  get?: () => T;
941
974
  /** Apply the state change on the page. May be async. */
942
- set: (value: T) => void | Promise<void>;
975
+ set: (value: T) => void | AgoStateSetResult | Promise<void | AgoStateSetResult>;
943
976
  }
944
977
 
978
+ /**
979
+ * Tagged outcome a page setter may return to reject or mark unchanged.
980
+ *
981
+ * Returning nothing (void) means APPLY. Returning an unrecognized JS value
982
+ * (e.g. a string from an assignment expression) is also treated as APPLY.
983
+ */
984
+ declare type AgoStateSetResult = {
985
+ result: "rejected";
986
+ reason: string;
987
+ } | {
988
+ result: "unchanged";
989
+ };
990
+
945
991
  /**
946
992
  * Single-object function definition — combines name, schema, and handler.
947
993
  *
@@ -1082,6 +1128,40 @@ export declare interface Conversation {
1082
1128
  */
1083
1129
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
1084
1130
 
1131
+ /** The four values of {@link FeedbackReason}, in dashboard order. */
1132
+ export declare const FEEDBACK_REASONS: readonly FeedbackReason[];
1133
+
1134
+ /**
1135
+ * Why the user is reporting a message (see `AgoClient.submitFeedback`).
1136
+ *
1137
+ * A rating on its own is a reaction (the thumbs count). Add a reason or a
1138
+ * comment and the report also lands in the feedback dashboard, the analytics
1139
+ * and the CSV export, where someone can act on it.
1140
+ */
1141
+ export declare interface FeedbackDetails {
1142
+ /** What went wrong. Several can apply at once. */
1143
+ reasons?: FeedbackReason[];
1144
+ /** The user's own words. Trimmed server-side; 5000 characters max. */
1145
+ comment?: string;
1146
+ }
1147
+
1148
+ /** Thumbs up / thumbs down on an answer. */
1149
+ export declare type FeedbackRating = "positive" | "negative";
1150
+
1151
+ /**
1152
+ * What went wrong with an answer. These are the four buckets the AGO feedback
1153
+ * dashboard filters and charts on.
1154
+ */
1155
+ export declare type FeedbackReason =
1156
+ /** The answer states something false. */
1157
+ "inaccurate"
1158
+ /** The answer is right but stops short. */
1159
+ | "incomplete"
1160
+ /** The agent could not find the information. */
1161
+ | "information_not_found"
1162
+ /** Something broke: the widget, a tool call, the stream. */
1163
+ | "technical_issue";
1164
+
1085
1165
  /**
1086
1166
  * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
1087
1167
  * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
@@ -2288,6 +2368,33 @@ declare interface UseConversationOptions {
2288
2368
  autoLoad?: boolean;
2289
2369
  }
2290
2370
 
2371
+ /**
2372
+ * Composable to report answers that did not work.
2373
+ *
2374
+ * ```ts
2375
+ * const { ratings, submitFeedback } = useFeedback();
2376
+ *
2377
+ * await submitFeedback(message.id, "negative", { reasons: ["inaccurate"] });
2378
+ * ```
2379
+ *
2380
+ * A bare rating is a reaction. Adding a reason or a comment files the report in
2381
+ * the AGO feedback dashboard, where someone can act on it. `ratings` holds what
2382
+ * was sent per message id, so a thumb can render as selected.
2383
+ */
2384
+ export declare function useFeedback(options?: UseFeedbackOptions): {
2385
+ ratings: Ref<Record<string, FeedbackRating>, Record<string, FeedbackRating>>;
2386
+ isSubmitting: Ref<boolean, boolean>;
2387
+ error: Ref<Error | null, Error | null>;
2388
+ submitFeedback: (messageId: string, rating: FeedbackRating, details?: FeedbackDetails) => Promise<void>;
2389
+ submitConversationFeedback: (conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
2390
+ lastMessageId?: string;
2391
+ }) => Promise<string>;
2392
+ };
2393
+
2394
+ export declare interface UseFeedbackOptions {
2395
+ client?: AgoClient;
2396
+ }
2397
+
2291
2398
  /**
2292
2399
  * Composable to manage messages in a conversation.
2293
2400
  *
package/dist/vue.d.ts CHANGED
@@ -281,9 +281,40 @@ declare class AgoClient {
281
281
  */
282
282
  submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
283
283
  /**
284
- * Submit feedback for a message
284
+ * Report an answer: thumbs up/down, optionally with what went wrong.
285
+ *
286
+ * ```ts
287
+ * await client.submitFeedback(message.id, "negative", {
288
+ * reasons: ["inaccurate"],
289
+ * comment: "The price it quoted is from last year.",
290
+ * });
291
+ * ```
292
+ *
293
+ * A bare rating is a reaction (the thumbs counted in the dashboard). Adding a
294
+ * reason or a comment also files it in the feedback list, the analytics and
295
+ * the CSV export, so someone can act on it.
285
296
  */
286
- submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
297
+ submitFeedback(messageId: string, rating: FeedbackRating, details?: FeedbackDetails): Promise<void>;
298
+ /**
299
+ * Report a whole conversation ("this chat is not working").
300
+ *
301
+ * ```ts
302
+ * await client.submitConversationFeedback(conversationId, "negative", {
303
+ * reasons: ["information_not_found"],
304
+ * comment: "It never answered my question.",
305
+ * });
306
+ * ```
307
+ *
308
+ * Feedback is stored per message, so this attaches the report to the last
309
+ * answer of the conversation, which is the one the user is reacting to.
310
+ * Returns the message id it landed on.
311
+ *
312
+ * Pass `lastMessageId` when you already have it (the widget does) to skip the
313
+ * lookup round-trip.
314
+ */
315
+ submitConversationFeedback(conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
316
+ lastMessageId?: string;
317
+ }): Promise<string>;
287
318
  /**
288
319
  * Register a client-side function that AGO can call.
289
320
  * Accepts either a definition object or (name, handler, schema) args.
@@ -936,12 +967,27 @@ export declare interface AgoStateControl<T = unknown> {
936
967
  enum?: (string | number)[];
937
968
  };
938
969
  };
970
+ /** String-only: `""` means "clear" instead of being dropped as filler. */
971
+ clearable?: boolean;
939
972
  /** Current value → pushed as dynamic context so the agent knows what to change. */
940
973
  get?: () => T;
941
974
  /** Apply the state change on the page. May be async. */
942
- set: (value: T) => void | Promise<void>;
975
+ set: (value: T) => void | AgoStateSetResult | Promise<void | AgoStateSetResult>;
943
976
  }
944
977
 
978
+ /**
979
+ * Tagged outcome a page setter may return to reject or mark unchanged.
980
+ *
981
+ * Returning nothing (void) means APPLY. Returning an unrecognized JS value
982
+ * (e.g. a string from an assignment expression) is also treated as APPLY.
983
+ */
984
+ declare type AgoStateSetResult = {
985
+ result: "rejected";
986
+ reason: string;
987
+ } | {
988
+ result: "unchanged";
989
+ };
990
+
945
991
  /**
946
992
  * Single-object function definition — combines name, schema, and handler.
947
993
  *
@@ -1082,6 +1128,40 @@ export declare interface Conversation {
1082
1128
  */
1083
1129
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
1084
1130
 
1131
+ /** The four values of {@link FeedbackReason}, in dashboard order. */
1132
+ export declare const FEEDBACK_REASONS: readonly FeedbackReason[];
1133
+
1134
+ /**
1135
+ * Why the user is reporting a message (see `AgoClient.submitFeedback`).
1136
+ *
1137
+ * A rating on its own is a reaction (the thumbs count). Add a reason or a
1138
+ * comment and the report also lands in the feedback dashboard, the analytics
1139
+ * and the CSV export, where someone can act on it.
1140
+ */
1141
+ export declare interface FeedbackDetails {
1142
+ /** What went wrong. Several can apply at once. */
1143
+ reasons?: FeedbackReason[];
1144
+ /** The user's own words. Trimmed server-side; 5000 characters max. */
1145
+ comment?: string;
1146
+ }
1147
+
1148
+ /** Thumbs up / thumbs down on an answer. */
1149
+ export declare type FeedbackRating = "positive" | "negative";
1150
+
1151
+ /**
1152
+ * What went wrong with an answer. These are the four buckets the AGO feedback
1153
+ * dashboard filters and charts on.
1154
+ */
1155
+ export declare type FeedbackReason =
1156
+ /** The answer states something false. */
1157
+ "inaccurate"
1158
+ /** The answer is right but stops short. */
1159
+ | "incomplete"
1160
+ /** The agent could not find the information. */
1161
+ | "information_not_found"
1162
+ /** Something broke: the widget, a tool call, the stream. */
1163
+ | "technical_issue";
1164
+
1085
1165
  /**
1086
1166
  * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
1087
1167
  * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
@@ -2288,6 +2368,33 @@ declare interface UseConversationOptions {
2288
2368
  autoLoad?: boolean;
2289
2369
  }
2290
2370
 
2371
+ /**
2372
+ * Composable to report answers that did not work.
2373
+ *
2374
+ * ```ts
2375
+ * const { ratings, submitFeedback } = useFeedback();
2376
+ *
2377
+ * await submitFeedback(message.id, "negative", { reasons: ["inaccurate"] });
2378
+ * ```
2379
+ *
2380
+ * A bare rating is a reaction. Adding a reason or a comment files the report in
2381
+ * the AGO feedback dashboard, where someone can act on it. `ratings` holds what
2382
+ * was sent per message id, so a thumb can render as selected.
2383
+ */
2384
+ export declare function useFeedback(options?: UseFeedbackOptions): {
2385
+ ratings: Ref<Record<string, FeedbackRating>, Record<string, FeedbackRating>>;
2386
+ isSubmitting: Ref<boolean, boolean>;
2387
+ error: Ref<Error | null, Error | null>;
2388
+ submitFeedback: (messageId: string, rating: FeedbackRating, details?: FeedbackDetails) => Promise<void>;
2389
+ submitConversationFeedback: (conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
2390
+ lastMessageId?: string;
2391
+ }) => Promise<string>;
2392
+ };
2393
+
2394
+ export declare interface UseFeedbackOptions {
2395
+ client?: AgoClient;
2396
+ }
2397
+
2291
2398
  /**
2292
2399
  * Composable to manage messages in a conversation.
2293
2400
  *