@useago/sdk 1.5.3 → 1.5.5

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 (48) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +10 -0
  3. package/dist/AgoClient-BI5esqbd.js +1694 -0
  4. package/dist/AgoClient-CQh8YovA.cjs +8 -0
  5. package/dist/angular.cjs +1 -1
  6. package/dist/angular.d.cts +70 -3
  7. package/dist/angular.d.ts +70 -3
  8. package/dist/angular.js +3 -3
  9. package/dist/{createConversationSession-BCb0D6bt.cjs → createConversationSession-0zVkMdYj.cjs} +1 -1
  10. package/dist/{createConversationSession-C7cnnWKW.js → createConversationSession-BlYTpxwz.js} +1 -1
  11. package/dist/{createFormCollector-iCDwAwYJ.js → createFormCollector-Bgs94NyR.js} +1 -1
  12. package/dist/{createFormCollector-t_fGyuTD.cjs → createFormCollector-DiCe_8ik.cjs} +1 -1
  13. package/dist/devtools.d.cts +69 -2
  14. package/dist/devtools.d.ts +69 -2
  15. package/dist/functions-CPs7omgM.cjs +1 -0
  16. package/dist/helpers.cjs +1 -1
  17. package/dist/helpers.js +1 -1
  18. package/dist/index.cjs +1 -1
  19. package/dist/index.d.cts +90 -2
  20. package/dist/index.d.ts +90 -2
  21. package/dist/index.js +64 -62
  22. package/dist/react.cjs +3 -3
  23. package/dist/react.d.cts +83 -2
  24. package/dist/react.d.ts +83 -2
  25. package/dist/react.js +240 -219
  26. package/dist/testing.cjs +1 -1
  27. package/dist/testing.d.cts +69 -2
  28. package/dist/testing.d.ts +69 -2
  29. package/dist/testing.js +1 -1
  30. package/dist/vue.cjs +1 -1
  31. package/dist/vue.d.cts +69 -2
  32. package/dist/vue.d.ts +69 -2
  33. package/dist/vue.js +2 -2
  34. package/dist/widget.cjs +2 -2
  35. package/dist/widget.d.cts +69 -2
  36. package/dist/widget.d.ts +69 -2
  37. package/dist/widget.js +4 -4
  38. package/llms-full.txt +29 -0
  39. package/package.json +1 -1
  40. package/dist/AgoClient-BGkFSNZF.cjs +0 -8
  41. package/dist/AgoClient-CW-BLT1_.js +0 -1542
  42. package/dist/functions-IGSjjvF4.cjs +0 -1
  43. package/dist/rolldown-runtime-16Nf8qvH.cjs +0 -1
  44. /package/dist/{autoContinue-D3Mmaaca.js → autoContinue-CC8K9mBU.js} +0 -0
  45. /package/dist/{autoContinue-CcCTva-D.cjs → autoContinue-CP9pJR-V.cjs} +0 -0
  46. /package/dist/{createMockClient-Br0TWgLO.js → createMockClient-DcuNlufr.js} +0 -0
  47. /package/dist/{createMockClient-BwNLPjeT.cjs → createMockClient-Dw-cyISN.cjs} +0 -0
  48. /package/dist/{functions-CApuQZ2b.js → functions-tzyOZNp6.js} +0 -0
@@ -0,0 +1,8 @@
1
+ var X=10,T=1e3;function Y(e){if(typeof e!="object"||e===null)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function b(e,t){if(typeof e=="string"){if(e.length<=1e3)return e;const i=e.length-T;return e.slice(0,T)+`…[truncated ${i} chars]`}if(Array.isArray(e)){if(t.has(e))return"…[circular]";t.add(e);const i=e.slice(0,50).map(s=>b(s,t));return e.length>50&&i.push(`…[+${e.length-50} more]`),t.delete(e),i}if(Y(e)){if(t.has(e))return"…[circular]";t.add(e);const i={};for(const[s,n]of Object.entries(e))i[s]=b(n,t);return t.delete(e),i}return e}function J(e){return b(e,new WeakSet)}var D=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:J(e.data)}:{}};this.entries.push(t);const i=this.entries.length-this.maxEntries;return i>0&&this.entries.splice(0,i),t}getRecent(){return[...this.entries]}get size(){return this.entries.length}clear(){this.entries=[]}},d=class extends Error{constructor(e,t,i){super(e),this.code=t,this.statusCode=i,this.name="AgoError"}},p=class U extends d{constructor(t,i,s,n,o,a){super(t,i,s),this.type=n,this.param=o,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,i){const s=t.error;return new U(s.doc_url?`${s.message} See ${s.doc_url}`:s.message,s.code,i,s.type,s.param,s.doc_url)}},y=class extends d{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},A=class extends d{constructor(e,t="stream_error"){super(e,t),this.name="AgoStreamError"}},E=class extends d{constructor(e,t,i){super(e,"function_error"),this.functionName=t,this.originalError=i,this.name="AgoFunctionError"}},V=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)}},c=new V,F="ago_widget_id";function Q(){if(typeof localStorage<"u"){const t=localStorage.getItem(F);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(F,e)}catch{}return e}var Z=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||Q()},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,i){return this.request("POST",e,t,i)}async postStream(e,t){const i=`${this.baseUrl}${e}`;c.debug("POST (stream)",i,t);try{const s=await fetch(i,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return s.ok||await this.handleErrorResponse(s),s}catch(s){throw s instanceof p?s:new y(`Network error: ${s instanceof Error?s.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,s instanceof Error?s:void 0)}}async postFormData(e,t){const i=`${this.baseUrl}${e}`;c.debug("POST (formData)",i);const s={...this.headers};try{const n=await fetch(i,{method:"POST",headers:s,body:t});return n.ok||await this.handleErrorResponse(n),n}catch(n){throw n instanceof p?n:new y(`Network error: ${n instanceof Error?n.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,n instanceof Error?n:void 0)}}async request(e,t,i,s){const n=`${this.baseUrl}${t}`;c.debug(e,n,i);try{const o=await fetch(n,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:i?JSON.stringify(i):void 0,...s?.keepalive?{keepalive:!0}:{}});return o.ok||await this.handleErrorResponse(o),o.status===204?void 0:o.json()}catch(o){throw o instanceof p?o:new y(`Network error: ${o instanceof Error?o.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,o instanceof Error?o:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw p.fromResponse(t,e.status);let i="";throw e.status===401||e.status===403?i=" Check `userJwt` (and that it has not expired).":e.status===404&&(i=" Check that `baseUrl` points at your AGO API root."),new p(`HTTP ${e.status}: ${e.statusText}.${i}`,"http_error",e.status,"api_error")}},ee=5e4,te=2e4,ie=2e3,M=class{constructor(e){this.functions=new Map,this.defaultMaxResultBytes=e?.maxResultBytes??ee}setDefaultMaxResultBytes(e){this.defaultMaxResultBytes=e}register(e,t,i){if(typeof e=="object"){const{name:r,handler:l,description:u,parameters:h,maxResultBytes:g,requiresApproval:m}=e;return this.register(r,l,{description:u,parameters:h,maxResultBytes:g,requiresApproval:m})}const s=e;if(!t||!i)throw new d(`registerFunction("${s}"): 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(s)&&c.warn(`Function "${s}" is being overwritten`);const{maxResultBytes:n,requiresApproval:o,...a}=i;this.functions.set(s,{schema:{...a,name:s},handler:t,maxResultBytes:n,requiresApproval:o}),c.log(`Registered function: ${s}`)}unregister(e){const t=this.functions.delete(e);return t&&c.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 i=this.functions.get(e);if(!i)throw new E(`Function "${e}" is not registered`,e);c.log(`Executing function: ${e}`,t);try{const s=await i.handler(t);return c.log(`Function ${e} completed:`,s),this.guardResultSize(e,s,i.maxResultBytes)}catch(s){throw c.error(`Function ${e} failed:`,s),new E(`Function "${e}" execution failed: ${s instanceof Error?s.message:"Unknown error"}`,e,s instanceof Error?s:void 0)}}guardResultSize(e,t,i){let s;try{s=JSON.stringify(t)}catch{return t}if(s===void 0)return t;const n=new TextEncoder().encode(s).length,o=i??this.defaultMaxResultBytes;return n>o?(c.warn(`Function "${e}" result is ${n} bytes, over the ${o}-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:o,preview:s.slice(0,ie),hint:`The result of "${e}" exceeded the ${o}-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>te&&c.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(),c.log("Cleared all registered functions")}get size(){return this.functions.size}},se=250,ne=3,re=1e3,oe=24,ae=10,ce=50,le=["mousemove","mousedown","keydown","scroll","touchstart"],j=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??se,this.rageClickCount=e.rageClickCount??ne,this.rageClickWindowMs=e.rageClickWindowMs??re,this.rageClickRadiusPx=e.rageClickRadiusPx??oe,this.maxRecentRoutes=e.maxRecentRoutes??ae,this.maxSignals=e.maxSignals??ce}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=(s,n,o)=>{s.addEventListener(n,o,{passive:!0}),this.teardowns.push(()=>s.removeEventListener(n,o))},i=()=>this.recordActivity();for(const s of le)t(window,s,i);t(document,"visibilitychange",()=>{document.visibilityState==="visible"&&this.recordActivity()}),t(window,"popstate",()=>this.checkRoute()),t(window,"hashchange",()=>this.checkRoute()),t(window,"click",s=>this.onClick(s)),c.log("SignalCollector started")}destroy(){for(const e of this.teardowns)e();this.teardowns=[],this.listeners.clear(),this.recentClicks=[],this.started=!1,c.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 c.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(),i=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:i}});const s=this.recentRoutes,n=s.length;n>=4&&s[n-1]===s[n-3]&&s[n-2]===s[n-4]&&s[n-1]!==s[n-2]&&(this.routeBounces+=1,this.pushSignal({type:"route_bounce",route:e,at:t,count:this.routeBounces,meta:{between:`${s[n-2]}↔${s[n-1]}`}}))}onClick(e){this.recordActivity();const t=Date.now(),i=this.pageStateKey(),s={at:t,x:e.clientX,y:e.clientY,stateKey:i};this.recentClicks=this.recentClicks.filter(r=>t-r.at<=this.rageClickWindowMs);const n=this.recentClicks[0],o=!n||Math.abs(s.x-n.x)<=this.rageClickRadiusPx&&Math.abs(s.y-n.y)<=this.rageClickRadiusPx,a=!n||n.stateKey===i;if(!o||!a){this.recentClicks=[s];return}this.recentClicks.push(s),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(i){c.error("Signal listener threw:",i)}}};function L(e,t){const i=t?t.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let s=e;if(t&&i)try{const r=i.getItem(t.key);r!=null&&(s=JSON.parse(r))}catch{}const n=new Set,o=()=>n.forEach(r=>r(s));function a(){if(t&&i)try{i.setItem(t.key,JSON.stringify(s))}catch{}}return{get:()=>s,set:r=>{s=r,a(),o()},subscribe:r=>(n.add(r),()=>{n.delete(r)})}}var ue=6e4,he=1440*60*1e3,de="ago_proactive";function C(e){const t=new Date(e),i=String(t.getMonth()+1).padStart(2,"0"),s=String(t.getDate()).padStart(2,"0");return`${t.getFullYear()}-${i}-${s}`}var ge=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=L({optOut:!1,lastFiredAt:{},dismissedAt:{},day:{date:C(Date.now()),count:0}},{key:e.storageKey??de,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 i=this.store.get();if(i.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 s=i.lastFiredAt[e.id],n=e.cooldownMs??ue;if(s!==void 0&&t-s<n)return this.deny(e,"cooldown");const o=i.dismissedAt[e.id],a=e.resurfaceAfterMs??he;return o!==void 0&&t-o<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 i=this.store.get();this.store.set({...i,lastFiredAt:{...i.lastFiredAt,[e]:t}})}recordNudgeShown(e=Date.now()){this.sessionCount+=1;const t=this.store.get(),i=C(e),s=t.day.date===i?{date:i,count:t.day.count+1}:{date:i,count:1};this.store.set({...t,day:s})}recordDismissed(e,t=Date.now()){const i=this.store.get();this.store.set({...i,dismissedAt:{...i.dismissedAt,[e]:t}})}dayCount(e){const t=this.store.get();return t.day.date===C(e)?t.day.count:0}deny(e,t){return c.debug(`NudgeGovernor: trigger "${e.id}" blocked — ${t}`),!1}};function P(){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 fe(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function B(e,t){if(e==="*"||e===t)return!0;const i=e.split("/"),s=i.map((n,o)=>{const a=o===i.length-1;return n==="*"?a?"[^/]+(?:/[^/]+)*":"[^/]+":n.startsWith(":")?"[^/]+":fe(n)});return new RegExp("^"+s.join("/")+"/?$").test(t)}function x(e,t){return e===t?!0:e===null||t===null?!1:Array.isArray(e)?!Array.isArray(t)||t.length!==e.length?!1:e.every((i,s)=>_(i,t[s])):typeof e=="object"?typeof t!="object"||Array.isArray(t)?!1:Object.entries(e).every(([i,s])=>x(s,t[i])):!1}function _(e,t){if(e===t)return!0;if(e===null||t===null||typeof e!=typeof t)return!1;if(Array.isArray(e))return!Array.isArray(t)||e.length!==t.length?!1:e.every((i,s)=>_(i,t[s]));if(typeof e=="object"){const i=Object.keys(e),s=Object.keys(t);return i.length!==s.length?!1:i.every(n=>_(e[n],t[n]))}return!1}function G(e,t){if(e.route!==void 0&&!B(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[i,s]of Object.entries(e.fieldErrors))if((t.fieldErrors[i]??0)<s)return!1}return!(e.pageState!==void 0&&!x(e.pageState,t.pageState??{}))}var pe=1e3,me="/api/sdk/v1/config",ye="/api/sdk/v1/proactive/evaluate",ve=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??pe}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),i=()=>this.governor.setTurnInFlight(!1),s=n=>{n?.id&&(this.lastConversationId=n.id)};this.client.on("message:start",e),this.client.on("message:complete",t),this.client.on("message:error",i),this.client.on("conversation:loaded",s),this.teardowns.push(()=>{this.client.off("message:start",e),this.client.off("message:complete",t),this.client.off("message:error",i),this.client.off("conversation:loaded",s)}),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(me);this.governor.setKillSwitch(e?.proactive?.enabled===!0)}catch(e){c.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(G(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:P(),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=P(),i={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 s;try{s=await this.client.getHttp().post(ye,i)}catch(n){c.debug("Proactive evaluate failed (treated as no-intervene):",n),this.governor.releaseSlot();return}if(!s?.intervene||!s.message){this.governor.releaseSlot();return}this.setReady({id:t,triggerId:e.id,source:"agent",message:s.message,action:we(s.action),goal:e.goal,kickoff:e.kickoff,createdAt:new Date,serverNudgeId:s.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(Ce(e),{hidden:!0,conversationId:this.lastConversationId}).catch(t=>c.debug("Nudge kickoff message failed:",t)):e.kickoff?this.client.sendMessage(e.kickoff).catch(t=>c.debug("Nudge kickoff message failed:",t)):c.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){c.warn("Nudge action failed:",t)}}};function we(e){if(e)return{label:e.label,functionName:e.function_name,arguments:e.arguments}}function Ce(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 Se=5e3,be="/api/sdk/v1/proactive/events",Ae=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??Se,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 i={events:t.map(s=>({client_nudge_id:s.clientNudgeId,trigger_id:s.triggerId,source:s.source,type:s.type,...s.message!==void 0?{message:s.message}:{},...this.agent?{agent:this.agent}:{},occurred_at:new Date(s.occurredAt).toISOString()}))};this.post(be,i,e).catch(s=>{c.debug("Proactive event batch failed:",s)})}destroy(){if(!this.destroyed){this.flush({keepalive:!0}),this.destroyed=!0;for(const e of this.teardowns)e();this.teardowns=[]}}},O="friction_signals";function k(e,t){e.proactive&&(c.warn("createAgoProactive: a proactive controller is already attached; replacing it."),e.proactive.destroy());const i=new j({...t.signals,getPageState:()=>{const r=e.getContextSnapshot();if(!r)return null;const l={};for(const[u,h]of Object.entries(r.entries))u.startsWith("page-state:")&&h.data&&Object.assign(l,h.data);return Object.keys(l).length>0?l:null}});i.start(),e.addDynamicContext(O,()=>{const{pageState:r,...l}=i.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:l}});const s=new ge({frequencyCap:t.frequencyCap,storage:t.storage,storageKey:t.storageKey}),n=new Ae({post:(r,l,u)=>e.getHttp().post(r,l,u),agent:e.getConfiguredAgent()}),o=new ve({client:e,collector:i,governor:s,tracker:n,options:t});o.start();const a={optOut:()=>s.optOut(),optIn:()=>s.optIn(),isOptedOut:()=>s.isOptedOut(),setEngaged:r=>s.setEngaged(r),signalFieldError:r=>i.signalFieldError(r),getSignalsSnapshot:()=>i.getSnapshot(),getActiveNudge:()=>o.getActiveNudge(),shown:r=>o.shown(r),accept:r=>o.accept(r),dismiss:r=>o.dismiss(r),markConverted:r=>o.markConverted(r),destroy:()=>{o.stop(),n.destroy(),i.destroy(),e.removeDynamicContext(O),e.proactive===a&&(e.proactive=null)}};return e.proactive=a,a}var W=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),c.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&c.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),c.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&c.log(`DynamicContext provider removed: ${e}`),t}getSnapshot(){if(this.entries.size===0&&this.dynamicProviders.size===0)return null;const e={};for(const[t,i]of this.entries)e[t]=i;for(const[t,i]of this.dynamicProviders)try{const s=i();s&&(e[t]=s)}catch(s){c.error(`DynamicContext provider "${t}" threw:`,s)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),c.log("ClientContext cleared")}},Ee="page-state:";function _e(e){const t={};for(const[i,s]of Object.entries(e))i.startsWith(Ee)&&s.data&&Object.assign(t,s.data);return t}function ke(e){const t=e["current-page"]?.data;return t?.page?t.page:t?.url?t.url:e["browser-page"]?.data?.url}function Re(e,t){return e===t?!0:JSON.stringify(e)===JSON.stringify(t)}function Ie(e,t){const i=[];for(const s of Object.keys(t))s in e&&(Re(e[s],t[s])||i.push({field:s,from:e[s],to:t[s]}));return i}function xe(e,t){const i=_e(t),s=ke(t);return{changes:e&&e.page===s?Ie(e.state,i):[],baseline:{page:s,state:i}}}function R(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(R).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${R(e[t])}`).join(",")}}`}var K=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.waitingClientEmitted=!1,this.firedClientFunctions=new Set}async processStream(e){if(!e.body)throw new A("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(),i=new TextDecoder;try{for(;;){const{done:s,value:n}=await t.read();if(s)break;const o=i.decode(n,{stream:!0});this.buffer+=o,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(s){const n=s instanceof Error?s:new A("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(n),n}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
2
+
3
+ `);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const i=t.split(`
4
+ `);for(const s of i)if(!s.startsWith(": ")&&s.startsWith("data: ")){const n=s.slice(6);try{const o=JSON.parse(n);this.handleChunk(o)}catch(o){c.warn("Failed to parse SSE data:",n,o)}}}}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 i=t.knowledge_document;return{id:i.id,title:i.title,url:i.use_external_link?i.external_link_url:i.internal_link_url}})),e.type==="client_function"&&e.function_name){const t=`${e.function_name}::${R(e.arguments??{})}`;this.firedClientFunctions.has(t)||(this.firedClientFunctions.add(t),this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}))}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const i=this.toolCalls.findIndex(s=>s.id===t.id);i>=0?this.toolCalls[i]=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 Te(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var Fe=new Set(["image/jpeg","image/png","image/gif","image/webp","image/bmp","image/tiff"]);function q(e){if(!e)return;const t=typeof window<"u"&&window.location?window.location.href:"https://ago.local/";try{const i=new URL(e,t);if(i.protocol==="http:"||i.protocol==="https:"||i.protocol==="blob:")return e}catch{}}function Pe(e){return e.isSafeImage===!0&&typeof e.contentType=="string"&&e.contentType.startsWith("image/")&&q(e.url)!==void 0}function Oe(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 $e(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 Ne(e){return e.map((t,i)=>({id:`local-${i}-${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:Fe.has(t.type)}))}var H=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 i=this.handlers.get(e);i&&i.delete(t)}emit(e,t){const i=this.handlers.get(e);i&&i.forEach(s=>{try{s(t)}catch(n){console.error(`Error in event handler for ${String(e)}:`,n)}})}once(e,t){const i=(s=>{this.off(e,i),t(s)});this.on(e,i)}waitFor(e,t){return new Promise((i,s)=>{let n;const o=(a=>{n&&clearTimeout(n),i(a)});this.once(e,o),t?.timeout&&(n=setTimeout(()=>{this.off(e,o),s(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},$='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).',De=/^[a-z][a-z0-9+.-]*:\/\//i,N=!1;function I(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new d(`${t}: ${$}`,"config_missing_base_url");const i=e.baseUrl;if(typeof i!="string"||i.trim()==="")throw new d(`${t}: ${$}`,"config_missing_base_url");!i.startsWith("/")&&!De.test(i)&&(N||(N=!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 Ue(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function S(e){return e.split("/").filter(t=>t.startsWith(":")).map(t=>t.slice(1))}function Me(e,t){const i=[];return{path:e.split("/").map(s=>{if(!s.startsWith(":"))return s;const n=s.slice(1),o=t[n];return o==null||o===""?(i.push(n),s):encodeURIComponent(String(o))}).join("/"),missing:i}}function je(e,t){const i=t.find(n=>n.path===e);if(i)return i;const s=t.find(n=>{if(!n.path.includes(":"))return!1;const o="^"+n.path.split("/").map(a=>a.startsWith(":")?"[^/]+":Ue(a)).join("/")+"/?$";return new RegExp(o).test(e)});return s||t.filter(n=>n.path!=="/"&&e.startsWith(n.path)).sort((n,o)=>o.path.length-n.path.length)[0]}var Le="activity:recent",Be="state:delta",Ge=class z{constructor(t){this.lastSentPageState=null,this.warnedEmptyConversations=new Set,this.pendingResumes=new Map,this.pendingApprovals=new Map,this.resumeGate=null,this.proactive=null,I(t,"AgoClient"),this.config=t,this.activityLedger=new D(t.maxActivityEntries),this.httpClient=new Z(t),this.functionRegistry=new M({maxResultBytes:t.maxFunctionResultBytes}),this.contextRegistry=new W,this.eventEmitter=new H,this.registerActivityContext(),t.debug&&c.enable(),t.proactive&&k(this,t.proactive),c.log("AgoClient initialized")}async sendMessage(t,i){const s=this.functionRegistry.getSchemas(),n=this.buildSendContext(),o=this.config.agent||this.config.defaultAgentId,a=this.resolveClientFunctionsMode(i),r={content:t,conversation_id:i?.conversationId,agent_id:i?.agentId||o};s.length>0&&(r.client_functions=s,a==="pause"&&(r.client_functions_mode=a)),n&&(r.client_context=n),i?.hidden&&(r.hidden=!0);let l;if(i?.files&&i.files.length>0){const u=new FormData;u.append("content",t),i.conversationId&&u.append("conversation_id",i.conversationId),(i.agentId||o)&&u.append("agent_id",i.agentId||o||""),s.length>0&&(u.append("client_functions",JSON.stringify(s)),a==="pause"&&u.append("client_functions_mode",a)),n&&u.append("client_context",JSON.stringify(n)),i.hidden&&u.append("hidden","true");for(const h of i.files)u.append("files",h);l=await this.httpClient.postFormData("/api/sdk/v1/messages",u)}else l=await this.httpClient.postStream("/api/sdk/v1/messages",r);return this.processSSEResponse(l)}async processSSEResponse(t){let i=!1;const s=await new K({onRawChunk:n=>{this.eventEmitter.emit("stream:message",n)},onStart:n=>{this.eventEmitter.emit("message:start",n)},onChunk:n=>{this.eventEmitter.emit("message:chunk",n)},onToolCall:n=>{this.eventEmitter.emit("toolCall:received",n),n.type==="form"&&this.eventEmitter.emit("toolCall:form",n)},onClientFunction:async n=>{if(i=!0,this.eventEmitter.emit("function:invoke",n),this.recordAgentAction(n),n.invocationId&&this.requiresApproval(n)){this.pendingApprovals.set(n.invocationId,n),this.eventEmitter.emit("function:awaiting-approval",n);return}await this.handleClientFunctionInvocation(n)},onTitle:n=>{this.eventEmitter.emit("conversation:title",n)},onAnswerComplete:n=>{this.eventEmitter.emit("message:answer-complete",n)},onWaitingClient:n=>{this.eventEmitter.emit("message:waiting-client",n),this.markResumeSignal(n.messageId,n.conversationId,"waitingConfirmed")},onComplete:n=>{this.eventEmitter.emit("message:complete",n)},onError:n=>{this.eventEmitter.emit("message:error",{error:n.message,code:n instanceof d?n.code:void 0})}}).processStream(t);return s.status!=="WAITING_CLIENT"&&this.maybeFlagEmptyReply(s,i),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 i=this.functionRegistry.getSchemas(),s=this.buildSendContext(),n={};i.length>0&&(n.client_functions=i),s&&(n.client_context=s);const o=await this.httpClient.postStream(`/api/sdk/v1/messages/${t}/continue`,n);return this.processSSEResponse(o)}markResumeSignal(t,i,s){if(!t)return;const n=this.pendingResumes.get(t)??{conversationId:i,waitingConfirmed:!1,resultsReady:!1,started:!1};n[s]=!0,i&&(n.conversationId=i),this.pendingResumes.set(t,n),!(!n.waitingConfirmed||!n.resultsReady||n.started)&&(n.started=!0,this.runAutoResume(t,n.conversationId))}async runAutoResume(t,i){try{this.resumeGate&&await this.resumeGate({conversationId:i,messageId:t})}catch(s){c.warn("Resume gate threw; resuming anyway:",s)}this.pendingResumes.delete(t);try{await this.continueMessage(t)}catch(s){c.warn("Auto-resume of paused turn failed:",s)}}maybeFlagEmptyReply(t,i){t.status==="DONE"&&(t.content??"").trim()===""&&!i&&!(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 s=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(s))return;this.warnedEmptyConversations.add(s);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 i,s;try{i=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(n){s=n instanceof Error?n.message:"Unknown error",c.error("Client function execution failed:",n)}if(t.invocationId)try{const n=await this.submitToolCallForm(t.invocationId,{result:i,error:s,_type:"client_function_result"});n?.resume?.ready&&this.markResumeSignal(n.resume.message_id,t.conversationId,"resultsReady")}catch(n){c.error("Failed to submit function result:",n)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:i,error:s})}requiresApproval(t){const i=this.config.approvalPolicy;if(i)try{if(i(t))return!0}catch(s){c.warn("approvalPolicy threw; not gating this call:",s)}return this.functionRegistry.get(t.functionName)?.requiresApproval===!0}async approveFunction(t){const i=this.pendingApprovals.get(t);i&&(this.pendingApprovals.delete(t),await this.handleClientFunctionInvocation(i))}async rejectFunction(t){const i=this.pendingApprovals.get(t);if(!i)return;this.pendingApprovals.delete(t);const s={approved:!1,reason:"user_rejected"};try{const n=await this.submitToolCallForm(t,{result:s,_type:"client_function_result"});n?.resume?.ready&&this.markResumeSignal(n.resume.message_id,i.conversationId,"resultsReady")}catch(n){c.error("Failed to submit function rejection:",n)}this.eventEmitter.emit("function:result",{invocationId:t,result:s})}async getConversations(t){const i=new URLSearchParams;t?.page!==void 0&&i.set("page",String(t.page)),t?.pageSize!==void 0&&i.set("page_size",String(t.pageSize));const s=i.toString(),n=await this.httpClient.get(`/api/sdk/v1/conversations${s?`?${s}`:""}`),o=(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:o,hasMore:n.has_more??!1,total:n.total??o.length}}async getConversation(t){const i=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),s={id:i.id,title:i.title,lastMessageDate:new Date(i.last_message_at??i.created_at??0),messages:i.messages.map(n=>({id:n.id,conversationId:i.id,content:n.content,role:n.role,status:n.status,createdAt:new Date(n.created_at),hidden:n.hidden,toolCalls:z.mapPersistedToolCalls(n.tool_call_data),attachments:n.attachments&&n.attachments.length>0?n.attachments.map($e):void 0}))};return this.eventEmitter.emit("conversation:loaded",s),s}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(i=>({id:String(i.id??""),type:i.type??"status_message",status:String(i.status??"unknown"),toolName:i.tool_name??"",toolDisplayName:i.tool_display_name,message:i.message,formSchema:i.form_schema,data:i.data,functionName:i.function_name,arguments:i.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async resumePendingClientFunctions(t){const i=[...t.messages??[]].reverse().find(r=>r.role==="assistant"&&r.status==="WAITING_CLIENT");if(!i)return null;const s=(i.toolCalls??[]).filter(r=>r.type==="client_function"&&r.status==="waiting_input"&&r.functionName),n=new Set(this.functionRegistry.getSchemas().map(r=>r.name)),o=s.filter(r=>!n.has(r.functionName));if(o.length>0)return c.warn("Cannot resume paused turn: function(s) not registered on this page:",o.map(r=>r.functionName)),null;let a=s.length===0;for(const r of s){const l={invocationId:r.id,functionName:r.functionName,arguments:r.arguments??{},conversationId:t.id};if(this.requiresApproval(l)){this.pendingApprovals.set(r.id,l),this.markResumeSignal(i.id,t.id,"waitingConfirmed"),this.eventEmitter.emit("function:awaiting-approval",l),a=!1;continue}let u,h;try{u=await this.functionRegistry.execute(r.functionName,r.arguments??{})}catch(g){h=g instanceof Error?g.message:"Unknown error",c.error("Client function execution failed:",g)}a=(await this.submitToolCallForm(r.id,{result:u,error:h,_type:"client_function_result"}))?.resume?.ready??a}return a?this.continueMessage(i.id):null}async submitToolCallForm(t,i){return this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:i})}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 i=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:i.name,description:i.description,schema:i.schema,submit:i.submit??void 0}}async submitFormCollector(t,i){return this.httpClient.post("/api/sdk/v1/forms/submit",{name:t,values:i})}async submitFeedback(t,i){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:i})}registerFunction(t,i,s){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,i,s)}register(t){if(Array.isArray(t))for(const i of t)this.functionRegistry.register(i);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}async executeClientFunction(t,i){return this.functionRegistry.execute(t,i)}registerNavigationFunction(t,i){const s=i.map(r=>r.name),n=i.map(r=>{const l=S(r.path),u=l.length>0?` (requires ${l.map(h=>`"${h}"`).join(", ")})`:"";return`- "${r.name}"${u}: ${r.description}`}).join(`
5
+ `),o=new Map;for(const r of i)for(const l of S(r.path))o.set(l,[...o.get(l)??[],r.name]);const a={page:{type:"string",description:"The page to navigate to",enum:s}};for(const[r,l]of o){if(r==="page"){c.error('registerNavigationFunction: a ":page" placeholder collides with the "page" argument and is ignored. Rename the placeholder.');continue}a[r]={type:"string",description:`Value for ":${r}" in the page path. Required when page is ${l.map(u=>`"${u}"`).join(" or ")}.`}}this.registerFunction("navigateToPage",async r=>{const l=r.page,u=i.find(f=>f.name===l);if(!u)return{success:!1,error:`Unknown page: ${l}`};let h={};if(typeof r.params=="string")try{h=JSON.parse(r.params)}catch{}else r.params&&typeof r.params=="object"&&(h=r.params);const g={};for(const f of S(u.path))g[f]=r[f]??h[f];const{path:m,missing:v}=Me(u.path,g);if(v.length>0){const f=v.map(w=>`"${w}": "..."`).join(", ");return{success:!1,error:`Page "${l}" needs ${v.map(w=>`"${w}"`).join(", ")}. Retry with { "page": "${l}", ${f} }.`}}return t(m),{success:!0,navigatedTo:m}},{description:`Navigate the user to a page in the application. Available pages:
6
+ ${n}`,parameters:{type:"object",properties:a,required:["page"]}}),this.addDynamicContext("current-page",()=>{if(typeof window>"u"||!window.location)return null;const r=window.location.href,l=typeof document<"u"?document.title:void 0,u=je(window.location.pathname,i),h={url:r};return u&&(h.page=u.name),l&&(h.title=l),{name:"Current page",description:"The page the user is currently viewing.",data:h}})}unregisterNavigationFunction(){this.unregisterFunction("navigateToPage"),this.removeDynamicContext("current-page")}registerPageStateFunction(t,i){const s=i?.functionName??"setPageState",n=new Map(t.map(a=>[a.name,a])),o=t.map(a=>`- "${a.name}": ${a.description}`).join(`
7
+ `);this.registerFunction(s,async a=>{const r={};for(const[l,u]of Object.entries(a)){if(u===void 0)continue;const h=n.get(l);h&&(await h.set(u),r[l]=u)}return{success:!0,applied:r}},{description:`Change the state of the current page. Set ONLY the controls the user explicitly asked for; leave the others unset. Available controls:
8
+ ${o}`,parameters:{type:"object",properties:Object.fromEntries(t.map(a=>[a.name,{...a.schema,description:a.description}]))},requiresApproval:i?.requiresApproval}),this.addDynamicContext(`page-state:${s}`,()=>{const a=t.filter(l=>typeof l.get=="function");if(a.length===0)return null;const r={};for(const l of a)r[l.name]=l.get();return{name:"Page state",description:"Current, editable state of the page the user is viewing.",data:r}})}unregisterPageStateFunction(t){const i=t??"setPageState";this.unregisterFunction(i),this.removeDynamicContext(`page-state:${i}`)}setContext(t,i){this.contextRegistry.set(t,i),this.notifyContextChanged()}removeContext(t){const i=this.contextRegistry.remove(t);return i&&this.notifyContextChanged(),i}addDynamicContext(t,i){this.contextRegistry.addDynamicProvider(t,i),this.notifyContextChanged()}removeDynamicContext(t){const i=this.contextRegistry.removeDynamicProvider(t);return i&&this.notifyContextChanged(),i}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}emitFormEvent(t,i){this.eventEmitter.emit(t,i)}emitProactiveEvent(t,i){this.eventEmitter.emit(t,i)}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,i=typeof document<"u"?document.title:void 0;return!t&&!i?null:{name:"Browser page",description:"Current page the user is viewing",data:{url:t,title:i}}})}getContextSnapshot(){return this.contextRegistry.getSnapshot()}buildSendContext(){const t=this.contextRegistry.getSnapshot(),i=t?.entries??{},{changes:s,baseline:n}=xe(this.lastSentPageState,i);return this.lastSentPageState=n,s.length===0?t:{entries:{...i,[Be]:{name:"State changes",description:"Fields in the page state that changed since your last message, as field: <old> -> <new>.",data:{changes:s}}}}}recordActivity(t){this.addActivity(t)}getRecentActivity(){return this.activityLedger.getRecent()}clearActivity(){this.activityLedger.clear()}addActivity(t){const i=this.activityLedger.add(t);this.eventEmitter.emit("activity:recorded",i)}recordAgentAction(t){const i=t.functionName,s=t.arguments;let n,o;if(i==="navigateToPage"){const a=s?.page;n="agent.navigate",o=a?`Agent navigated to "${String(a)}"`:"Agent navigated"}else i==="setPageState"?(n="agent.page_state",o="Agent changed the page state"):(n=`agent.${i}`,o=`Agent ran "${i}"`);this.addActivity({actor:"agent",name:n,summary:o,...s&&Object.keys(s).length>0?{data:{arguments:s}}:{}})}registerActivityContext(){this.contextRegistry.addDynamicProvider(Le,()=>{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,i){this.eventEmitter.on(t,i)}off(t,i){this.eventEmitter.off(t,i)}once(t,i){this.eventEmitter.once(t,i)}waitFor(t,i){return this.eventEmitter.waitFor(t,i)}updateConfig(t){const i={};for(const[n,o]of Object.entries(t))o!==void 0&&(i[n]=o);const s={...this.config,...i};I(s,"AgoClient.updateConfig"),this.config=s,this.httpClient.updateConfig(i),i.debug!==void 0&&(i.debug?c.enable():c.disable()),i.maxFunctionResultBytes!==void 0&&this.functionRegistry.setDefaultMaxResultBytes(i.maxFunctionResultBytes)}destroy(){this.proactive?.destroy(),this.proactive=null,this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),this.pendingResumes.clear(),this.pendingApprovals.clear(),this.resumeGate=null,c.log("AgoClient destroyed")}reviveAfterDestroy(){this.registerActivityContext(),this.config.proactive&&!this.proactive&&k(this,this.config.proactive)}};Object.defineProperty(exports,"ActivityLedger",{enumerable:!0,get:function(){return D}});Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return p}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return Ge}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return d}});Object.defineProperty(exports,"AgoFunctionError",{enumerable:!0,get:function(){return E}});Object.defineProperty(exports,"AgoNetworkError",{enumerable:!0,get:function(){return y}});Object.defineProperty(exports,"AgoStreamError",{enumerable:!0,get:function(){return A}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return W}});Object.defineProperty(exports,"DEFAULT_MAX_ACTIVITY_ENTRIES",{enumerable:!0,get:function(){return X}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return H}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return M}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return K}});Object.defineProperty(exports,"SignalCollector",{enumerable:!0,get:function(){return j}});Object.defineProperty(exports,"attachmentsFromFiles",{enumerable:!0,get:function(){return Ne}});Object.defineProperty(exports,"canInlineImage",{enumerable:!0,get:function(){return Pe}});Object.defineProperty(exports,"createAgoProactive",{enumerable:!0,get:function(){return k}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return L}});Object.defineProperty(exports,"formatFileSize",{enumerable:!0,get:function(){return Oe}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return Te}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return c}});Object.defineProperty(exports,"matchesRoutePattern",{enumerable:!0,get:function(){return B}});Object.defineProperty(exports,"matchesWhen",{enumerable:!0,get:function(){return G}});Object.defineProperty(exports,"partialDeepMatch",{enumerable:!0,get:function(){return x}});Object.defineProperty(exports,"safeAttachmentUrl",{enumerable:!0,get:function(){return q}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return I}});
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-BGkFSNZF.cjs"),c=require("./autoContinue-CcCTva-D.cjs");var n=class{constructor(t){this.client=new o.AgoClient(t),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(t){const e=this.client;return{subscribe(i){const r=s=>{i.next?.(s)};return e.on(t,r),{unsubscribe:()=>e.off(t,r)}}}}sendMessage(t,e){return this.client.sendMessage(t,e)}getConversations(){return this.client.getConversations()}getConversation(t){return this.client.getConversation(t)}getMessages(t){return this.client.getMessages(t)}submitToolCallForm(t,e){return this.client.submitToolCallForm(t,e)}confirmToolCall(t){return this.client.confirmToolCall(t)}rejectToolCall(t){return this.client.rejectToolCall(t)}submitFeedback(t,e){return this.client.submitFeedback(t,e)}registerFunction(t,e,i){typeof t=="object"?this.client.registerFunction(t):this.client.registerFunction(t,e,i)}unregisterFunction(t){return this.client.unregisterFunction(t)}registerNavigationFunction(t,e){this.client.registerNavigationFunction(t,e)}unregisterNavigationFunction(){this.client.unregisterNavigationFunction()}enableAutoContinueAfterNavigation(t){return c.attachAutoContinueAfterNavigation(this.client,t)}registerPageStateFunction(t,e){this.client.registerPageStateFunction(t,e)}unregisterPageStateFunction(t){this.client.unregisterPageStateFunction(t)}on(t,e){this.client.on(t,e)}off(t,e){this.client.off(t,e)}updateConfig(t){this.client.updateConfig(t)}getClient(){return this.client}destroy(){this.client.destroy()}};function u(t){return{provide:n,useValue:new n(t)}}exports.AgoService=n;exports.provideAgo=u;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-CQh8YovA.cjs"),c=require("./autoContinue-CP9pJR-V.cjs");var n=class{constructor(t){this.client=new o.AgoClient(t),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(t){const e=this.client;return{subscribe(i){const r=s=>{i.next?.(s)};return e.on(t,r),{unsubscribe:()=>e.off(t,r)}}}}sendMessage(t,e){return this.client.sendMessage(t,e)}getConversations(){return this.client.getConversations().then(t=>t.data)}getConversation(t){return this.client.getConversation(t)}getMessages(t){return this.client.getMessages(t)}submitToolCallForm(t,e){return this.client.submitToolCallForm(t,e)}confirmToolCall(t){return this.client.confirmToolCall(t)}rejectToolCall(t){return this.client.rejectToolCall(t)}submitFeedback(t,e){return this.client.submitFeedback(t,e)}registerFunction(t,e,i){typeof t=="object"?this.client.registerFunction(t):this.client.registerFunction(t,e,i)}unregisterFunction(t){return this.client.unregisterFunction(t)}registerNavigationFunction(t,e){this.client.registerNavigationFunction(t,e)}unregisterNavigationFunction(){this.client.unregisterNavigationFunction()}enableAutoContinueAfterNavigation(t){return c.attachAutoContinueAfterNavigation(this.client,t)}registerPageStateFunction(t,e){this.client.registerPageStateFunction(t,e)}unregisterPageStateFunction(t){this.client.unregisterPageStateFunction(t)}on(t,e){this.client.on(t,e)}off(t,e){this.client.off(t,e)}updateConfig(t){this.client.updateConfig(t)}getClient(){return this.client}destroy(){this.client.destroy()}};function u(t){return{provide:n,useValue:new n(t)}}exports.AgoService=n;exports.provideAgo=u;
@@ -1,3 +1,19 @@
1
+ declare interface ActivityEntry {
2
+ ts: number;
3
+ actor: "user" | "agent";
4
+ name: string;
5
+ summary: string;
6
+ data?: Record<string, unknown>;
7
+ }
8
+
9
+ declare interface ActivityInput {
10
+ actor?: "user" | "agent";
11
+ name: string;
12
+ summary: string;
13
+ data?: Record<string, unknown>;
14
+ ts?: number;
15
+ }
16
+
1
17
  /**
2
18
  * Agent information
3
19
  */
@@ -53,6 +69,8 @@ declare class AgoClient {
53
69
  private functionRegistry;
54
70
  private contextRegistry;
55
71
  private eventEmitter;
72
+ private activityLedger;
73
+ private lastSentPageState;
56
74
  private config;
57
75
  /** Conversations already warned about an empty reply (one warning each). */
58
76
  private warnedEmptyConversations;
@@ -139,9 +157,14 @@ declare class AgoClient {
139
157
  */
140
158
  rejectFunction(invocationId: string): Promise<void>;
141
159
  /**
142
- * Get list of conversations
160
+ * Get a page of conversations, newest-first. `pageSize` is capped at 100 by
161
+ * the backend (default 50). Returns the `{ data, has_more, total }` envelope
162
+ * so callers can page; `total` counts across all pages.
143
163
  */
144
- getConversations(): Promise<Conversation[]>;
164
+ getConversations(options?: {
165
+ page?: number;
166
+ pageSize?: number;
167
+ }): Promise<PaginatedResult<Conversation>>;
145
168
  /**
146
169
  * Get a specific conversation with messages
147
170
  */
@@ -363,6 +386,19 @@ declare class AgoClient {
363
386
  * Get the current context snapshot.
364
387
  */
365
388
  getContextSnapshot(): ContextSnapshot | null;
389
+ private buildSendContext;
390
+ /**
391
+ * Record something the user just did so the agent is aware of it on the next
392
+ * message. `actor` defaults to `"user"`. Keep `summary` short and high-signal
393
+ * (no raw payloads, secrets, or PII).
394
+ */
395
+ recordActivity(entry: ActivityInput): void;
396
+ /** Recent user + agent actions, oldest first (a copy). */
397
+ getRecentActivity(): ActivityEntry[];
398
+ clearActivity(): void;
399
+ private addActivity;
400
+ private recordAgentAction;
401
+ private registerActivityContext;
366
402
  /**
367
403
  * Subscribe to an event
368
404
  */
@@ -474,6 +510,15 @@ export declare interface AgoClientEvents {
474
510
  * notably `createFormCollector` — can replay them to restore their state.
475
511
  */
476
512
  "conversation:loaded": Conversation;
513
+ /**
514
+ * The conversation's title was generated and streamed during a live turn
515
+ * (the backend emits it once, at the end of the first turn). Lets the UI
516
+ * update a header without a refetch.
517
+ */
518
+ "conversation:title": {
519
+ conversationId: string;
520
+ title: string;
521
+ };
477
522
  "toolCall:received": ToolCallData;
478
523
  "toolCall:form": ToolCallData;
479
524
  "function:invoke": ClientFunctionInvocation;
@@ -534,6 +579,8 @@ export declare interface AgoClientEvents {
534
579
  "nudge:accepted": {
535
580
  nudge: ProactiveNudgeInstance;
536
581
  };
582
+ /** A user- or agent-action was recorded into the activity ledger. */
583
+ "activity:recorded": ActivityEntry;
537
584
  }
538
585
 
539
586
  /**
@@ -595,6 +642,14 @@ export declare interface AgoConfig {
595
642
  * with `maxResultBytes` on its definition; `Infinity` disables the guard.
596
643
  */
597
644
  maxFunctionResultBytes?: number;
645
+ /**
646
+ * Max number of recent actions kept in the in-memory activity ledger that
647
+ * rides along as the `activity:recent` context entry. Older entries drop
648
+ * first. Default `10`. Larger values give the agent more history at the cost
649
+ * of tokens on every message. Each entry's `data` is also size-clamped (long
650
+ * strings truncated, large arrays capped) so one event can't bloat the context.
651
+ */
652
+ maxActivityEntries?: number;
598
653
  /**
599
654
  * Enable the proactive mode: declarative triggers evaluated client-side
600
655
  * against friction signals (dwell/idle time, rage clicks, route bounces…)
@@ -700,7 +755,7 @@ export declare class AgoService {
700
755
  private fromEvent;
701
756
  /** Send a message and get a streaming response */
702
757
  sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
703
- /** Get all conversations */
758
+ /** Get the most recent conversations (first page). */
704
759
  getConversations(): Promise<Conversation[]>;
705
760
  /** Get a specific conversation with messages */
706
761
  getConversation(id: string): Promise<Conversation>;
@@ -1108,6 +1163,16 @@ declare interface Observable<T> {
1108
1163
  };
1109
1164
  }
1110
1165
 
1166
+ /**
1167
+ * A page of list results, mirroring the API's `{ data, has_more, total }`
1168
+ * envelope. `total` is the count across all pages, not just this page.
1169
+ */
1170
+ declare interface PaginatedResult<T> {
1171
+ data: T[];
1172
+ hasMore: boolean;
1173
+ total: number;
1174
+ }
1175
+
1111
1176
  /**
1112
1177
  * Controller returned by {@link createAgoProactive} (also available as
1113
1178
  * `client.proactive`).
@@ -1384,6 +1449,8 @@ declare interface SSEChunkData {
1384
1449
  thread?: {
1385
1450
  id: string;
1386
1451
  };
1452
+ /** Generated conversation title, streamed once at the end of the first turn. */
1453
+ title?: string;
1387
1454
  agent?: {
1388
1455
  id: string;
1389
1456
  name: string;
package/dist/angular.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ declare interface ActivityEntry {
2
+ ts: number;
3
+ actor: "user" | "agent";
4
+ name: string;
5
+ summary: string;
6
+ data?: Record<string, unknown>;
7
+ }
8
+
9
+ declare interface ActivityInput {
10
+ actor?: "user" | "agent";
11
+ name: string;
12
+ summary: string;
13
+ data?: Record<string, unknown>;
14
+ ts?: number;
15
+ }
16
+
1
17
  /**
2
18
  * Agent information
3
19
  */
@@ -53,6 +69,8 @@ declare class AgoClient {
53
69
  private functionRegistry;
54
70
  private contextRegistry;
55
71
  private eventEmitter;
72
+ private activityLedger;
73
+ private lastSentPageState;
56
74
  private config;
57
75
  /** Conversations already warned about an empty reply (one warning each). */
58
76
  private warnedEmptyConversations;
@@ -139,9 +157,14 @@ declare class AgoClient {
139
157
  */
140
158
  rejectFunction(invocationId: string): Promise<void>;
141
159
  /**
142
- * Get list of conversations
160
+ * Get a page of conversations, newest-first. `pageSize` is capped at 100 by
161
+ * the backend (default 50). Returns the `{ data, has_more, total }` envelope
162
+ * so callers can page; `total` counts across all pages.
143
163
  */
144
- getConversations(): Promise<Conversation[]>;
164
+ getConversations(options?: {
165
+ page?: number;
166
+ pageSize?: number;
167
+ }): Promise<PaginatedResult<Conversation>>;
145
168
  /**
146
169
  * Get a specific conversation with messages
147
170
  */
@@ -363,6 +386,19 @@ declare class AgoClient {
363
386
  * Get the current context snapshot.
364
387
  */
365
388
  getContextSnapshot(): ContextSnapshot | null;
389
+ private buildSendContext;
390
+ /**
391
+ * Record something the user just did so the agent is aware of it on the next
392
+ * message. `actor` defaults to `"user"`. Keep `summary` short and high-signal
393
+ * (no raw payloads, secrets, or PII).
394
+ */
395
+ recordActivity(entry: ActivityInput): void;
396
+ /** Recent user + agent actions, oldest first (a copy). */
397
+ getRecentActivity(): ActivityEntry[];
398
+ clearActivity(): void;
399
+ private addActivity;
400
+ private recordAgentAction;
401
+ private registerActivityContext;
366
402
  /**
367
403
  * Subscribe to an event
368
404
  */
@@ -474,6 +510,15 @@ export declare interface AgoClientEvents {
474
510
  * notably `createFormCollector` — can replay them to restore their state.
475
511
  */
476
512
  "conversation:loaded": Conversation;
513
+ /**
514
+ * The conversation's title was generated and streamed during a live turn
515
+ * (the backend emits it once, at the end of the first turn). Lets the UI
516
+ * update a header without a refetch.
517
+ */
518
+ "conversation:title": {
519
+ conversationId: string;
520
+ title: string;
521
+ };
477
522
  "toolCall:received": ToolCallData;
478
523
  "toolCall:form": ToolCallData;
479
524
  "function:invoke": ClientFunctionInvocation;
@@ -534,6 +579,8 @@ export declare interface AgoClientEvents {
534
579
  "nudge:accepted": {
535
580
  nudge: ProactiveNudgeInstance;
536
581
  };
582
+ /** A user- or agent-action was recorded into the activity ledger. */
583
+ "activity:recorded": ActivityEntry;
537
584
  }
538
585
 
539
586
  /**
@@ -595,6 +642,14 @@ export declare interface AgoConfig {
595
642
  * with `maxResultBytes` on its definition; `Infinity` disables the guard.
596
643
  */
597
644
  maxFunctionResultBytes?: number;
645
+ /**
646
+ * Max number of recent actions kept in the in-memory activity ledger that
647
+ * rides along as the `activity:recent` context entry. Older entries drop
648
+ * first. Default `10`. Larger values give the agent more history at the cost
649
+ * of tokens on every message. Each entry's `data` is also size-clamped (long
650
+ * strings truncated, large arrays capped) so one event can't bloat the context.
651
+ */
652
+ maxActivityEntries?: number;
598
653
  /**
599
654
  * Enable the proactive mode: declarative triggers evaluated client-side
600
655
  * against friction signals (dwell/idle time, rage clicks, route bounces…)
@@ -700,7 +755,7 @@ export declare class AgoService {
700
755
  private fromEvent;
701
756
  /** Send a message and get a streaming response */
702
757
  sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
703
- /** Get all conversations */
758
+ /** Get the most recent conversations (first page). */
704
759
  getConversations(): Promise<Conversation[]>;
705
760
  /** Get a specific conversation with messages */
706
761
  getConversation(id: string): Promise<Conversation>;
@@ -1108,6 +1163,16 @@ declare interface Observable<T> {
1108
1163
  };
1109
1164
  }
1110
1165
 
1166
+ /**
1167
+ * A page of list results, mirroring the API's `{ data, has_more, total }`
1168
+ * envelope. `total` is the count across all pages, not just this page.
1169
+ */
1170
+ declare interface PaginatedResult<T> {
1171
+ data: T[];
1172
+ hasMore: boolean;
1173
+ total: number;
1174
+ }
1175
+
1111
1176
  /**
1112
1177
  * Controller returned by {@link createAgoProactive} (also available as
1113
1178
  * `client.proactive`).
@@ -1384,6 +1449,8 @@ declare interface SSEChunkData {
1384
1449
  thread?: {
1385
1450
  id: string;
1386
1451
  };
1452
+ /** Generated conversation title, streamed once at the end of the first turn. */
1453
+ title?: string;
1387
1454
  agent?: {
1388
1455
  id: string;
1389
1456
  name: string;
package/dist/angular.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as o } from "./AgoClient-CW-BLT1_.js";
2
- import { t as c } from "./autoContinue-D3Mmaaca.js";
1
+ import { t as o } from "./AgoClient-BI5esqbd.js";
2
+ import { t as c } from "./autoContinue-CC8K9mBU.js";
3
3
  var s = class {
4
4
  constructor(t) {
5
5
  this.client = new o(t), this.messages$ = this.fromEvent("message:complete"), this.chunks$ = this.fromEvent("message:chunk"), this.errors$ = this.fromEvent("message:error"), this.messageStart$ = this.fromEvent("message:start");
@@ -17,7 +17,7 @@ var s = class {
17
17
  return this.client.sendMessage(t, e);
18
18
  }
19
19
  getConversations() {
20
- return this.client.getConversations();
20
+ return this.client.getConversations().then((t) => t.data);
21
21
  }
22
22
  getConversation(t) {
23
23
  return this.client.getConversation(t);
@@ -1 +1 @@
1
- const d=require("./AgoClient-BGkFSNZF.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),s=o.get();s.value!==null&&c(s.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function c(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||c(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
1
+ const d=require("./AgoClient-CQh8YovA.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),s=o.get();s.value!==null&&c(s.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function c(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||c(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
@@ -1,4 +1,4 @@
1
- import { h as d } from "./AgoClient-CW-BLT1_.js";
1
+ import { h as d } from "./AgoClient-BI5esqbd.js";
2
2
  var f = "ago_widget_id", g = "ago_last_thread", y = 7200 * 1e3;
3
3
  function v() {
4
4
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
@@ -1,4 +1,4 @@
1
- import { h as R, v as w } from "./AgoClient-CW-BLT1_.js";
1
+ import { h as R, v as w } from "./AgoClient-BI5esqbd.js";
2
2
  var j = /^[a-zA-Z0-9_-]{1,40}$/, V = (s) => s == null || s === "";
3
3
  function S(s, e) {
4
4
  if ("anyOf" in s) return s.anyOf.some((c) => S(c, e));
@@ -1 +1 @@
1
- const C=require("./AgoClient-BGkFSNZF.cjs");var W=/^[a-zA-Z0-9_-]{1,40}$/,A=n=>n==null||n==="";function S(n,e){if("anyOf"in n)return n.anyOf.some(c=>S(c,e));if("allOf"in n)return n.allOf.every(c=>S(c,e));const l=e[n.property];if(A(l))return!1;if(Array.isArray(n.value))return n.value.some(c=>String(l)===String(c));if(!n.op)return String(l)===String(n.value);const i=Number(l),a=Number(n.value);if(Number.isNaN(i)||Number.isNaN(a))return!1;switch(n.op){case">=":return i>=a;case"<=":return i<=a;case">":return i>a;case"<":return i<a;default:return C.logger.warn(`Unknown requiredWhen op "${n.op}"; treating as not required.`),!1}}function h(n,e){const l=n.properties??{},i=new Set;for(const c of n.required??[]){const d=l[c]?.requiredWhen;(!d||S(d,e))&&i.add(c)}for(const[c,d]of Object.entries(l))d.requiredWhen&&S(d.requiredWhen,e)&&i.add(c);const a=[...i].filter(c=>A(e[c]));return{missing:a,complete:a.length===0}}function B(n){const e={};for(const[l,i]of Object.entries(n.properties??{}))e[l]={type:i.type,...i.description!=null&&{description:i.description},...i.enum&&{enum:i.enum},...i.default!==void 0&&{default:i.default}};return{type:"object",properties:e,required:[]}}function V(n){const{name:e,description:l,schema:i}=n;if(!W.test(e))throw new Error(`Invalid form collector name "${e}": must match ${W} (it becomes the update_/submit_ function names).`);const a=typeof n.submit=="string"?n.submit?{via:"client",url:n.submit}:!1:n.submit??!1;n.autoSubmit===!0&&!a&&C.logger.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);const c=(n.autoSubmit??!0)&&!!a,d=i.properties??{},$=t=>{const r={};for(const[o,s]of Object.entries(t)){const u=d[o];if(u)if(s==null)r[o]=s;else if(u.type==="number"||u.type==="integer"){const f=typeof s=="number"?s:Number(s);r[o]=Number.isNaN(f)?s:f}else u.type==="boolean"?r[o]=typeof s=="boolean"?s:s==="true"?!0:s==="false"?!1:!!s:r[o]=s}return r},N=n.initialValues??{},m=C.createStore({values:N,submitted:!1}),w=t=>{const r=m.get(),o={...r,values:{...r.values,...t}};return m.set(o),o};let b=null;const k=(t,r)=>{b?.emitFormEvent("form:error",{name:e,values:t,error:r})};let p=null;const I=async()=>{const{values:t}=m.get(),{complete:r,missing:o}=h(i,t);if(!r)return{ok:!1,missing:o};if(!a)return{ok:!1,error:"No submit target configured for this form collector."};const s=t;try{let u;if(a.via==="client")if("handler"in a)u=await a.handler(s);else{const f=await fetch(a.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(s)});if(!f.ok){const j=`Submit failed: HTTP ${f.status}`;return k(s,j),{ok:!1,error:j}}u=await f.json().catch(()=>{})}else{if(!b)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};u=await b.submitFormCollector(e,s)}return m.set({...m.get(),submitted:!0,submitResult:u}),b?.emitFormEvent("form:submitted",{name:e,values:s,result:u}),{ok:!0,result:u}}catch(u){const f=u instanceof Error?u.message:"Submit failed";return C.logger.error(`FormCollector "${e}" submit failed:`,u),k(s,f),{ok:!1,error:f}}},F=()=>p||(p=(async()=>{try{return await I()}finally{p=null}})(),p),q=async()=>{if(!c||!a)return null;const{values:t,submitted:r}=m.get();return r||!h(i,t).complete?null:F()},O={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${l} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,parameters:B(i),handler:async t=>{const r=w($(t)),{missing:o}=h(i,r.values),s=await q();return s?s.ok?{ok:!0,values:r.values,missing:o,submitted:!0}:{ok:!0,values:r.values,missing:o,submitted:!1,submitError:s.error}:{ok:!0,values:r.values,missing:o}}},y=[O];a&&!c&&y.push({name:`submit_${e}`,description:`Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,parameters:{type:"object",properties:{}},handler:()=>F()});const D="client__",_=a?`submit_${e}`:null,R=t=>{const r=t.functionName??t.toolName;if(r)return r.startsWith(D)?r.slice(8):r},x=t=>{let r={...N},o=!1;for(const s of t){const u=R(s);u===O.name?s.arguments&&(r={...r,...$(s.arguments)}):_&&u===_&&s.status?.toLowerCase()==="done"&&(o=!0)}m.set({values:r,submitted:o})},g=`form:${e}`,v=`${g}:definition`,P=()=>({name:`Form definition: ${e}`,description:`${l} Some fields are conditionally required; the requiredWhen field in the schema tells you when each becomes required. The form schema is the following: ${JSON.stringify(i)}.`,stable:!0}),T=()=>{const{values:t,submitted:r}=m.get(),{missing:o,complete:s}=h(i,t),u=a?c?" The form is submitted automatically as soon as every required field is filled, so there is no submit function to call.":` When nothing is missing and the user confirms, call submit_${e}.`:"",f=r?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${f} The form's schema and field requirements are in the "${v}" client context. Call update_${e} with any fields the user provides; ask only for what is still missing.${u}`,data:{values:t,missing:o,complete:s,submitted:r}}},E=t=>{x((t.messages??[]).flatMap(r=>r.toolCalls??[]))};return{name:e,store:m,functions:y,contextKey:g,contextProvider:T,definitionContextKey:v,definitionContextProvider:P,install:t=>{b=t;for(const o of y)t.register(o);t.addDynamicContext(v,P),t.addDynamicContext(g,T);const r=m.subscribe(()=>t.notifyContextChanged());return t.on("conversation:loaded",E),()=>{r();for(const o of y)t.unregisterFunction(o.name);t.removeDynamicContext(g),t.removeDynamicContext(v),t.off("conversation:loaded",E),b===t&&(b=null)}},hydrate:x,submit:F,getValues:()=>m.get().values,setValues:t=>{w($(t)),q()},reset:()=>{m.set({values:N,submitted:!1})},getStatus:()=>h(i,m.get().values)}}async function L(n,e){const l=await n.getFormCollector(e.name);return V({name:l.name,description:e.description??l.description,schema:e.schema??l.schema,submit:e.submit??l.submit,initialValues:e.initialValues,autoSubmit:e.autoSubmit??l.autoSubmit})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return V}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return L}});
1
+ const C=require("./AgoClient-CQh8YovA.cjs");var W=/^[a-zA-Z0-9_-]{1,40}$/,A=n=>n==null||n==="";function S(n,e){if("anyOf"in n)return n.anyOf.some(c=>S(c,e));if("allOf"in n)return n.allOf.every(c=>S(c,e));const l=e[n.property];if(A(l))return!1;if(Array.isArray(n.value))return n.value.some(c=>String(l)===String(c));if(!n.op)return String(l)===String(n.value);const i=Number(l),a=Number(n.value);if(Number.isNaN(i)||Number.isNaN(a))return!1;switch(n.op){case">=":return i>=a;case"<=":return i<=a;case">":return i>a;case"<":return i<a;default:return C.logger.warn(`Unknown requiredWhen op "${n.op}"; treating as not required.`),!1}}function h(n,e){const l=n.properties??{},i=new Set;for(const c of n.required??[]){const d=l[c]?.requiredWhen;(!d||S(d,e))&&i.add(c)}for(const[c,d]of Object.entries(l))d.requiredWhen&&S(d.requiredWhen,e)&&i.add(c);const a=[...i].filter(c=>A(e[c]));return{missing:a,complete:a.length===0}}function B(n){const e={};for(const[l,i]of Object.entries(n.properties??{}))e[l]={type:i.type,...i.description!=null&&{description:i.description},...i.enum&&{enum:i.enum},...i.default!==void 0&&{default:i.default}};return{type:"object",properties:e,required:[]}}function V(n){const{name:e,description:l,schema:i}=n;if(!W.test(e))throw new Error(`Invalid form collector name "${e}": must match ${W} (it becomes the update_/submit_ function names).`);const a=typeof n.submit=="string"?n.submit?{via:"client",url:n.submit}:!1:n.submit??!1;n.autoSubmit===!0&&!a&&C.logger.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);const c=(n.autoSubmit??!0)&&!!a,d=i.properties??{},$=t=>{const r={};for(const[o,s]of Object.entries(t)){const u=d[o];if(u)if(s==null)r[o]=s;else if(u.type==="number"||u.type==="integer"){const f=typeof s=="number"?s:Number(s);r[o]=Number.isNaN(f)?s:f}else u.type==="boolean"?r[o]=typeof s=="boolean"?s:s==="true"?!0:s==="false"?!1:!!s:r[o]=s}return r},N=n.initialValues??{},m=C.createStore({values:N,submitted:!1}),w=t=>{const r=m.get(),o={...r,values:{...r.values,...t}};return m.set(o),o};let b=null;const k=(t,r)=>{b?.emitFormEvent("form:error",{name:e,values:t,error:r})};let p=null;const I=async()=>{const{values:t}=m.get(),{complete:r,missing:o}=h(i,t);if(!r)return{ok:!1,missing:o};if(!a)return{ok:!1,error:"No submit target configured for this form collector."};const s=t;try{let u;if(a.via==="client")if("handler"in a)u=await a.handler(s);else{const f=await fetch(a.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(s)});if(!f.ok){const j=`Submit failed: HTTP ${f.status}`;return k(s,j),{ok:!1,error:j}}u=await f.json().catch(()=>{})}else{if(!b)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};u=await b.submitFormCollector(e,s)}return m.set({...m.get(),submitted:!0,submitResult:u}),b?.emitFormEvent("form:submitted",{name:e,values:s,result:u}),{ok:!0,result:u}}catch(u){const f=u instanceof Error?u.message:"Submit failed";return C.logger.error(`FormCollector "${e}" submit failed:`,u),k(s,f),{ok:!1,error:f}}},F=()=>p||(p=(async()=>{try{return await I()}finally{p=null}})(),p),q=async()=>{if(!c||!a)return null;const{values:t,submitted:r}=m.get();return r||!h(i,t).complete?null:F()},O={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${l} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,parameters:B(i),handler:async t=>{const r=w($(t)),{missing:o}=h(i,r.values),s=await q();return s?s.ok?{ok:!0,values:r.values,missing:o,submitted:!0}:{ok:!0,values:r.values,missing:o,submitted:!1,submitError:s.error}:{ok:!0,values:r.values,missing:o}}},y=[O];a&&!c&&y.push({name:`submit_${e}`,description:`Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,parameters:{type:"object",properties:{}},handler:()=>F()});const D="client__",_=a?`submit_${e}`:null,R=t=>{const r=t.functionName??t.toolName;if(r)return r.startsWith(D)?r.slice(8):r},x=t=>{let r={...N},o=!1;for(const s of t){const u=R(s);u===O.name?s.arguments&&(r={...r,...$(s.arguments)}):_&&u===_&&s.status?.toLowerCase()==="done"&&(o=!0)}m.set({values:r,submitted:o})},g=`form:${e}`,v=`${g}:definition`,P=()=>({name:`Form definition: ${e}`,description:`${l} Some fields are conditionally required; the requiredWhen field in the schema tells you when each becomes required. The form schema is the following: ${JSON.stringify(i)}.`,stable:!0}),T=()=>{const{values:t,submitted:r}=m.get(),{missing:o,complete:s}=h(i,t),u=a?c?" The form is submitted automatically as soon as every required field is filled, so there is no submit function to call.":` When nothing is missing and the user confirms, call submit_${e}.`:"",f=r?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${f} The form's schema and field requirements are in the "${v}" client context. Call update_${e} with any fields the user provides; ask only for what is still missing.${u}`,data:{values:t,missing:o,complete:s,submitted:r}}},E=t=>{x((t.messages??[]).flatMap(r=>r.toolCalls??[]))};return{name:e,store:m,functions:y,contextKey:g,contextProvider:T,definitionContextKey:v,definitionContextProvider:P,install:t=>{b=t;for(const o of y)t.register(o);t.addDynamicContext(v,P),t.addDynamicContext(g,T);const r=m.subscribe(()=>t.notifyContextChanged());return t.on("conversation:loaded",E),()=>{r();for(const o of y)t.unregisterFunction(o.name);t.removeDynamicContext(g),t.removeDynamicContext(v),t.off("conversation:loaded",E),b===t&&(b=null)}},hydrate:x,submit:F,getValues:()=>m.get().values,setValues:t=>{w($(t)),q()},reset:()=>{m.set({values:N,submitted:!1})},getStatus:()=>h(i,m.get().values)}}async function L(n,e){const l=await n.getFormCollector(e.name);return V({name:l.name,description:e.description??l.description,schema:e.schema??l.schema,submit:e.submit??l.submit,initialValues:e.initialValues,autoSubmit:e.autoSubmit??l.autoSubmit})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return V}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return L}});
@@ -1,3 +1,19 @@
1
+ declare interface ActivityEntry {
2
+ ts: number;
3
+ actor: "user" | "agent";
4
+ name: string;
5
+ summary: string;
6
+ data?: Record<string, unknown>;
7
+ }
8
+
9
+ declare interface ActivityInput {
10
+ actor?: "user" | "agent";
11
+ name: string;
12
+ summary: string;
13
+ data?: Record<string, unknown>;
14
+ ts?: number;
15
+ }
16
+
1
17
  /**
2
18
  * Agent information
3
19
  */
@@ -36,6 +52,8 @@ declare class AgoClient {
36
52
  private functionRegistry;
37
53
  private contextRegistry;
38
54
  private eventEmitter;
55
+ private activityLedger;
56
+ private lastSentPageState;
39
57
  private config;
40
58
  /** Conversations already warned about an empty reply (one warning each). */
41
59
  private warnedEmptyConversations;
@@ -122,9 +140,14 @@ declare class AgoClient {
122
140
  */
123
141
  rejectFunction(invocationId: string): Promise<void>;
124
142
  /**
125
- * Get list of conversations
143
+ * Get a page of conversations, newest-first. `pageSize` is capped at 100 by
144
+ * the backend (default 50). Returns the `{ data, has_more, total }` envelope
145
+ * so callers can page; `total` counts across all pages.
126
146
  */
127
- getConversations(): Promise<Conversation[]>;
147
+ getConversations(options?: {
148
+ page?: number;
149
+ pageSize?: number;
150
+ }): Promise<PaginatedResult<Conversation>>;
128
151
  /**
129
152
  * Get a specific conversation with messages
130
153
  */
@@ -346,6 +369,19 @@ declare class AgoClient {
346
369
  * Get the current context snapshot.
347
370
  */
348
371
  getContextSnapshot(): ContextSnapshot | null;
372
+ private buildSendContext;
373
+ /**
374
+ * Record something the user just did so the agent is aware of it on the next
375
+ * message. `actor` defaults to `"user"`. Keep `summary` short and high-signal
376
+ * (no raw payloads, secrets, or PII).
377
+ */
378
+ recordActivity(entry: ActivityInput): void;
379
+ /** Recent user + agent actions, oldest first (a copy). */
380
+ getRecentActivity(): ActivityEntry[];
381
+ clearActivity(): void;
382
+ private addActivity;
383
+ private recordAgentAction;
384
+ private registerActivityContext;
349
385
  /**
350
386
  * Subscribe to an event
351
387
  */
@@ -457,6 +493,15 @@ declare interface AgoClientEvents {
457
493
  * notably `createFormCollector` — can replay them to restore their state.
458
494
  */
459
495
  "conversation:loaded": Conversation;
496
+ /**
497
+ * The conversation's title was generated and streamed during a live turn
498
+ * (the backend emits it once, at the end of the first turn). Lets the UI
499
+ * update a header without a refetch.
500
+ */
501
+ "conversation:title": {
502
+ conversationId: string;
503
+ title: string;
504
+ };
460
505
  "toolCall:received": ToolCallData;
461
506
  "toolCall:form": ToolCallData;
462
507
  "function:invoke": ClientFunctionInvocation;
@@ -517,6 +562,8 @@ declare interface AgoClientEvents {
517
562
  "nudge:accepted": {
518
563
  nudge: ProactiveNudgeInstance;
519
564
  };
565
+ /** A user- or agent-action was recorded into the activity ledger. */
566
+ "activity:recorded": ActivityEntry;
520
567
  }
521
568
 
522
569
  /**
@@ -578,6 +625,14 @@ declare interface AgoConfig {
578
625
  * with `maxResultBytes` on its definition; `Infinity` disables the guard.
579
626
  */
580
627
  maxFunctionResultBytes?: number;
628
+ /**
629
+ * Max number of recent actions kept in the in-memory activity ledger that
630
+ * rides along as the `activity:recent` context entry. Older entries drop
631
+ * first. Default `10`. Larger values give the agent more history at the cost
632
+ * of tokens on every message. Each entry's `data` is also size-clamped (long
633
+ * strings truncated, large arrays capped) so one event can't bloat the context.
634
+ */
635
+ maxActivityEntries?: number;
581
636
  /**
582
637
  * Enable the proactive mode: declarative triggers evaluated client-side
583
638
  * against friction signals (dwell/idle time, rage clicks, route bounces…)
@@ -987,6 +1042,16 @@ declare type NudgeAction = {
987
1042
  setPageState: Record<string, unknown>;
988
1043
  };
989
1044
 
1045
+ /**
1046
+ * A page of list results, mirroring the API's `{ data, has_more, total }`
1047
+ * envelope. `total` is the count across all pages, not just this page.
1048
+ */
1049
+ declare interface PaginatedResult<T> {
1050
+ data: T[];
1051
+ hasMore: boolean;
1052
+ total: number;
1053
+ }
1054
+
990
1055
  /**
991
1056
  * Controller returned by {@link createAgoProactive} (also available as
992
1057
  * `client.proactive`).
@@ -1239,6 +1304,8 @@ declare interface SSEChunkData {
1239
1304
  thread?: {
1240
1305
  id: string;
1241
1306
  };
1307
+ /** Generated conversation title, streamed once at the end of the first turn. */
1308
+ title?: string;
1242
1309
  agent?: {
1243
1310
  id: string;
1244
1311
  name: string;