@useago/sdk 1.5.6 → 1.7.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 (42) hide show
  1. package/CHANGELOG.md +223 -0
  2. package/README.md +59 -0
  3. package/dist/AgoClient-BHegN73y.cjs +9 -0
  4. package/dist/{AgoClient-B_R_qi2s.js → AgoClient-PWPaekcg.js} +656 -387
  5. package/dist/angular.cjs +1 -1
  6. package/dist/angular.d.cts +230 -5
  7. package/dist/angular.d.ts +230 -5
  8. package/dist/angular.js +10 -1
  9. package/dist/{createConversationSession-Dqh7NXK4.cjs → createConversationSession-BbUUukV0.cjs} +1 -1
  10. package/dist/{createConversationSession-CdtI4vrf.js → createConversationSession-BkruoOVm.js} +1 -1
  11. package/dist/{createFormCollector-BjO3oB63.cjs → createFormCollector-C1ixsjV0.cjs} +1 -1
  12. package/dist/{createFormCollector-YwaZ78wU.js → createFormCollector-CvVFNkp6.js} +1 -1
  13. package/dist/{createMockClient-DcuNlufr.js → createMockClient-BDLW6tVc.js} +5 -2
  14. package/dist/createMockClient-BSNuN3ys.cjs +1 -0
  15. package/dist/devtools.d.cts +220 -5
  16. package/dist/devtools.d.ts +220 -5
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.d.cts +238 -6
  19. package/dist/index.d.ts +238 -6
  20. package/dist/index.js +111 -109
  21. package/dist/react.cjs +40 -3
  22. package/dist/react.d.cts +419 -7
  23. package/dist/react.d.ts +419 -7
  24. package/dist/react.js +1195 -743
  25. package/dist/sheetController-CBUVOroo.js +205 -0
  26. package/dist/sheetController-DY-sC13T.cjs +1 -0
  27. package/dist/testing.cjs +1 -1
  28. package/dist/testing.d.cts +220 -5
  29. package/dist/testing.d.ts +220 -5
  30. package/dist/testing.js +1 -1
  31. package/dist/vue.cjs +1 -1
  32. package/dist/vue.d.cts +235 -5
  33. package/dist/vue.d.ts +235 -5
  34. package/dist/vue.js +121 -100
  35. package/dist/widget.cjs +4 -4
  36. package/dist/widget.d.cts +328 -5
  37. package/dist/widget.d.ts +328 -5
  38. package/dist/widget.js +721 -629
  39. package/llms-full.txt +202 -14
  40. package/package.json +1 -1
  41. package/dist/AgoClient-DLB9icvv.cjs +0 -8
  42. package/dist/createMockClient-Dw-cyISN.cjs +0 -1
package/llms-full.txt CHANGED
@@ -256,6 +256,24 @@ await ago.sendMessage("Summarise this", { files: [fileInput.files[0]], conversat
256
256
  await ago.sendMessage("Escalate this", { agentId: "human-handoff" });
257
257
  ```
258
258
 
259
+ Stop the answer being generated. `stop()` closes the stream AND calls the backend
260
+ to stop generating; closing the stream alone would leave the agent running:
261
+
262
+ ```ts
263
+ document.getElementById("stop").onclick = () => void ago.stop();
264
+ ```
265
+
266
+ The partial text is kept, the message is finalized as `CANCELED`, and the pending
267
+ `sendMessage` resolves with it (it does not reject). `message:complete` fires with
268
+ the partial message, then `message:stopped`. Finalize your UI on
269
+ `message:stopped`: it always fires, while `message:complete` is skipped when
270
+ there is nothing to complete (a stop that beat the backend naming the message, or
271
+ a turn stopped while paused on client functions). `stop()` resolves to `null` when
272
+ nothing was generating, `isGenerating()` reports whether there is anything to
273
+ stop, and `stopMessage(messageId)` stops a turn by id (e.g. one still running
274
+ after a page reload). A turn paused on client functions is stoppable too, and
275
+ stopping it cancels the automatic resume.
276
+
259
277
  ## 3. Conversations
260
278
 
261
279
  ```ts
@@ -357,9 +375,12 @@ const widget = mountChatWidget("#chat", {
357
375
  });
358
376
 
359
377
  widget.sendMessage("Hello");
378
+ widget.stop(); // interrupt the answer being generated (no-op when idle)
360
379
  widget.destroy(); // removes listeners, uninstalls forms, clears the DOM
361
380
  ```
362
381
 
382
+ While the agent answers, the send button becomes a Stop button that interrupts
383
+ the turn; pass `allowStop: false` to keep a disabled spinner instead.
363
384
  Set `placement: "left"` or `"right"` for a fixed full-height side panel with a
364
385
  launcher button. Set `persistConversation: true` to resume the visitor's last
365
386
  thread across reloads. Theme it with the `theme` option or `--ago-*` CSS variables
@@ -384,7 +405,8 @@ ago.destroy(); // clean up listeners, functions, conte
384
405
  ## Key events
385
406
 
386
407
  `message:start`, `message:chunk` (`{ content }` per token), `message:complete`
387
- (`AgoMessage`), `message:error`, `conversation:loaded`, `context:changed`,
408
+ (`AgoMessage`), `message:stopped` (`{ conversationId, messageId }`, after a
409
+ `stop()`), `message:error`, `conversation:loaded`, `context:changed`,
388
410
  `toolCall:received`, `function:invoke`, `function:result`, `connection:status`.
389
411
  Use `on` / `off` / `once`, or `await ago.waitFor("message:complete", { timeout })`.
390
412
 
@@ -496,10 +518,12 @@ function Support() {
496
518
  }
497
519
  ```
498
520
 
499
- Common props: `title`, `welcomeMessage`, `placeholder`, `allowFiles`, `height`,
500
- `logoUrl`, `showAgentName`, `forms`, `onMessageSent`, `onMessageReceived`,
521
+ Common props: `title`, `welcomeMessage`, `placeholder`, `allowFiles`, `allowStop`,
522
+ `height`, `logoUrl`, `showAgentName`, `forms`, `onMessageSent`, `onMessageReceived`,
501
523
  `onFollowUpClick`, `className`. When the agent returns follow-up suggestions the
502
524
  widget renders them as clickable buttons (clicking sends the reply by default).
525
+ While the agent answers, the send button becomes a **Stop** button that
526
+ interrupts the turn (`allowStop`, default `true`; pass `false` to disable it).
503
527
 
504
528
  `ChatWidget` is a high-level component. For a custom interface, use `useChat`.
505
529
 
@@ -512,14 +536,16 @@ All-in-one state for a custom chat interface (composes `useMessages` +
512
536
  import { useChat } from "@useago/sdk/react";
513
537
 
514
538
  function Chat() {
515
- const { messages, sendMessage, isLoading, error } = useChat();
539
+ const { messages, sendMessage, stop, isLoading, error } = useChat();
516
540
 
517
541
  return (
518
542
  <div>
519
543
  {messages.map((m) => (
520
544
  <p key={m.id}><b>{m.role}:</b> {m.content}</p>
521
545
  ))}
522
- <button onClick={() => sendMessage("Hello!")} disabled={isLoading}>Send</button>
546
+ {isLoading
547
+ ? <button onClick={() => void stop()}>Stop</button>
548
+ : <button onClick={() => sendMessage("Hello!")}>Send</button>}
523
549
  {error && <p role="alert">{error.message}</p>}
524
550
  </div>
525
551
  );
@@ -530,6 +556,12 @@ function Chat() {
530
556
  message is included). `sendMessage(content, files?)` resolves with the final
531
557
  message or `null` on error.
532
558
 
559
+ `stop()` interrupts the answer being generated: the stream closes and the backend
560
+ is told to stop generating, the partial text stays in `messages` with status
561
+ `CANCELED`, and `isLoading` goes back to `false`. It is a no-op when nothing is
562
+ generating. Building your own input? `<ChatInput onStop={...} disabled={isLoading} />`
563
+ renders the same Stop button.
564
+
533
565
  Show the knowledge sources the agent retrieved via `m.sources` (an `AgoSource[]`,
534
566
  each `{ id, title, url? }`):
535
567
 
@@ -634,6 +666,26 @@ useAgoPageState([
634
666
  ]);
635
667
  ```
636
668
 
669
+ Add a `data` source to hand the agent the resulting rows as the result of its own
670
+ call (same turn), instead of only as context on the next message:
671
+
672
+ ```tsx
673
+ const { data: invoices, isFetching } = useQuery({ queryKey: ["invoices", status], queryFn: fetchInvoices });
674
+
675
+ useAgoPageState(controls, {
676
+ data: {
677
+ description: "The invoices matching the current filters.",
678
+ get: () => invoices ?? [],
679
+ isLoading: () => isFetching, // isFetching, not isLoading: a background refetch must count
680
+ },
681
+ });
682
+ ```
683
+
684
+ `setPageState` then returns `{ success, applied, data }` and a read-only
685
+ `readPageData` function is registered too. The SDK waits for `isLoading` to go
686
+ false before reading, and truncates a long list by whole rows. Needs
687
+ `clientFunctionsMode: "pause"` (the default).
688
+
637
689
  ## 6. Give the agent context: `useAgoContext`
638
690
 
639
691
  Expose what the user is looking at, sent with every message.
@@ -680,8 +732,9 @@ useEffect(() => {
680
732
  ```
681
733
 
682
734
  Key events: `message:start`, `message:chunk` (`{ content }` per token),
683
- `message:complete` (`AgoMessage`), `message:error`, `toolCall:received`,
684
- `function:invoke`, `function:result`.
735
+ `message:complete` (`AgoMessage`), `message:stopped`
736
+ (`{ conversationId, messageId }`, after the turn was stopped), `message:error`,
737
+ `toolCall:received`, `function:invoke`, `function:result`.
685
738
 
686
739
  ## Exports cheat-sheet (`@useago/sdk/react`)
687
740
 
@@ -772,7 +825,7 @@ All-in-one reactive state (messages + conversations). Everything returned is a
772
825
  import { ref } from "vue";
773
826
  import { useChat } from "@useago/sdk/vue";
774
827
 
775
- const { messages, sendMessage, isLoading, error } = useChat();
828
+ const { messages, sendMessage, stop, isLoading, error } = useChat();
776
829
  const draft = ref("");
777
830
 
778
831
  async function onSend() {
@@ -789,12 +842,18 @@ async function onSend() {
789
842
  </div>
790
843
  <form @submit.prevent="onSend">
791
844
  <input v-model="draft" :disabled="isLoading" placeholder="Ask anything..." />
792
- <button :disabled="isLoading">Send</button>
845
+ <button v-if="isLoading" type="button" @click="stop()">Stop</button>
846
+ <button v-else>Send</button>
793
847
  </form>
794
848
  <p v-if="error" role="alert">{{ error.message }}</p>
795
849
  </template>
796
850
  ```
797
851
 
852
+ `stop()` interrupts the answer being generated: the stream closes and the backend
853
+ is told to stop generating, the partial text stays in `messages` with status
854
+ `CANCELED`, and `isLoading` goes back to `false`. It is a no-op when nothing is
855
+ generating.
856
+
798
857
  Each assistant message carries the knowledge sources it used in `m.sources` (an
799
858
  `AgoSource[]`, each `{ id, title, url? }`). Render them as links.
800
859
 
@@ -886,7 +945,8 @@ useAgoEvents("message:complete", (msg) => console.log("Got reply:", msg.content)
886
945
  ```
887
946
 
888
947
  Key events: `message:start`, `message:chunk` (`{ content }` per token),
889
- `message:complete` (`AgoMessage`), `message:error`.
948
+ `message:complete` (`AgoMessage`), `message:stopped`
949
+ (`{ conversationId, messageId }`, after the turn was stopped), `message:error`.
890
950
 
891
951
  ## 6. Client context
892
952
 
@@ -1079,6 +1139,9 @@ use `ago.on(event, handler)` / `ago.off(event, handler)`.
1079
1139
 
1080
1140
  ```ts
1081
1141
  ago.sendMessage(content, options?) // Promise<AgoMessage>
1142
+ ago.stop() // stop the turn being generated
1143
+ ago.stopMessage(messageId) // stop a turn by id
1144
+ ago.isGenerating() // boolean
1082
1145
  ago.getConversations() // Promise<Conversation[]>
1083
1146
  ago.getConversation(id)
1084
1147
  ago.getMessages(conversationId)
@@ -1100,6 +1163,17 @@ ago.getClient() // underlying AgoClient
1100
1163
  ago.destroy()
1101
1164
  ```
1102
1165
 
1166
+ `stop()` closes the stream and tells the backend to stop generating. The partial
1167
+ text is kept, the message is finalized as `CANCELED`, and the pending
1168
+ `sendMessage` resolves with it (it does not reject). It resolves to `null` when
1169
+ nothing was generating, so a Stop button can call it unconditionally:
1170
+
1171
+ ```ts
1172
+ async onStop() {
1173
+ await this.ago.stop();
1174
+ }
1175
+ ```
1176
+
1103
1177
  ## 5. Functions, navigation and context
1104
1178
 
1105
1179
  Register a client-side function the agent can call:
@@ -1384,10 +1458,97 @@ This does two things:
1384
1458
  current `get()` value, so the agent knows what to change. Controls without a
1385
1459
  `get()` are write-only and don't appear in context.
1386
1460
 
1387
- It's fire-and-forget: the handler applies each `set()` locally and returns
1388
- `{ success, applied }`. The new state reaches the agent through the context on
1389
- the next message. React/Vue offer `useAgoPageState(controls, opts?)` with
1390
- lifecycle cleanup; Angular exposes `agoService.registerPageStateFunction(...)`.
1461
+ By default it's fire-and-forget: the handler applies each `set()` locally and
1462
+ returns `{ success, applied }`. The new state reaches the agent through the
1463
+ context on the next message. React/Vue offer `useAgoPageState(controls, opts?)`
1464
+ with lifecycle cleanup; Angular exposes
1465
+ `agoService.registerPageStateFunction(...)`.
1466
+
1467
+ ### Return what the page displays
1468
+
1469
+ `{ success, applied }` only tells the agent its own arguments were accepted. Ask
1470
+ it to "find the user dupont" and it applies the filter but cannot say who it
1471
+ found: the rows only reach it on the next message, as context.
1472
+
1473
+ Add a `data` source and the rows come back as the result of the agent's own
1474
+ call, in the same turn:
1475
+
1476
+ ```ts
1477
+ const { data: users, isFetching } = useQuery({
1478
+ queryKey: ["users", filters],
1479
+ queryFn: fetchUsers,
1480
+ });
1481
+
1482
+ useAgoPageState(controls, {
1483
+ data: {
1484
+ description: "The users matching the current filters.",
1485
+ get: () => users ?? [],
1486
+ isLoading: () => isFetching,
1487
+ },
1488
+ });
1489
+ ```
1490
+
1491
+ `setPageState` now returns `{ success, applied, data }`, and a second function
1492
+ `readPageData` is registered: no parameters, changes nothing, returns `{ data }`.
1493
+ That one answers "what's on screen?" without touching the page. Both disappear
1494
+ when you unregister.
1495
+
1496
+ #### Telling the SDK when the work is done
1497
+
1498
+ A control change kicks off work, and the SDK has to wait for it. There are two
1499
+ ways to say when it finished. They are not equivalent.
1500
+
1501
+ **Return a promise from `get()`.** You own the await, so the SDK is exact: it
1502
+ resolves when your work resolves. No polling, no timing assumption. With
1503
+ TanStack Query, `ensureQueryData` hands you that promise and shares the single
1504
+ in-flight request with the UI, so the data is not fetched twice:
1505
+
1506
+ ```ts
1507
+ useAgoPageState(controls, {
1508
+ data: {
1509
+ description: "The users matching the current filters.",
1510
+ get: () => queryClient.ensureQueryData({
1511
+ queryKey: ["users", filters],
1512
+ queryFn: fetchUsers,
1513
+ }),
1514
+ },
1515
+ });
1516
+ ```
1517
+
1518
+ **Or declare `isLoading`**, for data you cannot get a promise for. The SDK polls
1519
+ it every 50 ms and treats two consecutive `false` readings as settled. That is a
1520
+ heuristic: the flag has to be up within ~100 ms of the change, or the SDK
1521
+ concludes the page settled and reads the previous rows. A query library that
1522
+ flips `isFetching` during render makes it in time; a **debounced** fetch does
1523
+ not, and the agent then answers with the previous search's results, silently.
1524
+
1525
+ If you do use it, pass `isFetching`, not `isLoading`: TanStack Query's
1526
+ `isLoading` is only true on the very first load, so a background refetch would
1527
+ look idle.
1528
+
1529
+ Both forms are bounded by `settleTimeoutMs` (10 s by default). On timeout the
1530
+ SDK returns what the page has rather than holding the turn open. If `get()`
1531
+ rejects, the agent is told the read failed instead of being handed an empty
1532
+ page.
1533
+
1534
+ Two things to keep in mind:
1535
+
1536
+ - **Size.** The snapshot lands in the model's context. Over
1537
+ `maxResultBytes` (the client's `maxFunctionResultBytes`, 50 000 by default)
1538
+ the SDK keeps the first whole items that fit and adds a `truncation` field
1539
+ (`{ truncated, returnedItems, totalItems, hint }`) next to them. The counts
1540
+ are nested rather than merged into your snapshot so they can never overwrite
1541
+ a field of your own called `totalItems`. `success` and `applied` always
1542
+ survive intact. Return the columns the agent needs, not your whole row
1543
+ objects.
1544
+ - **Pause mode only.** The result travels back inside the turn only when
1545
+ `clientFunctionsMode` is `"pause"` (the default). In `"placeholder"` mode the
1546
+ turn is already over by then, so the agent will not see the data during the
1547
+ call that produced it; the SDK warns once if you declare `data` anyway.
1548
+
1549
+ The snapshot deliberately stays out of the `page-state:` context entry, which
1550
+ keeps carrying control values only. Putting 200 rows in every message would cost
1551
+ a lot for nothing: the data travels only when the agent asks for it.
1391
1552
 
1392
1553
  The SDK also tells the agent **what changed**: on each message it diffs the page
1393
1554
  state against the previous message and adds a `state:delta` entry listing the
@@ -1699,6 +1860,7 @@ const final = await client.waitFor("message:complete", { timeout: 10_000 });
1699
1860
  | `message:chunk` | `{ content, conversationId, messageId }` |
1700
1861
  | `message:answer-complete` | `AgoMessage`: the main answer text is done, but follow-up replies may still be pending; fires once, before `message:complete` |
1701
1862
  | `message:complete` | `AgoMessage` |
1863
+ | `message:stopped` | `{ conversationId, messageId }`: the user stopped the turn (`client.stop()`). Fires once the stream has unwound, after the `message:complete` that carries the partial answer with status `CANCELED` (or on its own when there was nothing to complete). `messageId` is `""` when the stop landed before the backend had named the message. See [Stop the answer](core.md#stop-the-answer) |
1702
1864
  | `message:waiting-client` | `{ conversationId, messageId, waitingToolCallIds }`: the turn paused on client function call(s) (`clientFunctionsMode: "pause"`). `message:complete` does not fire for the paused stream — it fires when the resumed turn concludes. The SDK submits the results and resumes on its own; listen to this to keep a "working…" indicator up |
1703
1865
  | `message:empty` | `{ conversationId, messageId }`: the reply completed as `DONE` with no content, tool calls, or follow-ups (usually an unknown `agent` slug). Fires after `message:complete` AND after `sendMessage` resolves, so subscribing right after the `await` still catches it. Both ids are `""` when the stream carried no message data at all. See [Empty replies](configuration.md#empty-replies). |
1704
1866
  | `message:error` | `{ error, code?, conversationId?, messageId? }`: `code` is the stable [error code](configuration.md#error-codes) when the failure was an `AgoError` |
@@ -1779,6 +1941,32 @@ listeners automatically when the loop ends.
1779
1941
 
1780
1942
  ---
1781
1943
 
1944
+ ## Stopping a stream
1945
+
1946
+ `client.stop()` interrupts the turn being generated: it closes the stream and
1947
+ calls the backend to stop generating. Closing the stream alone would leave the
1948
+ agent running server-side.
1949
+
1950
+ ```ts
1951
+ document.getElementById("stop").onclick = () => void client.stop();
1952
+
1953
+ client.on("message:stopped", ({ messageId }) => {
1954
+ console.log("stopped", messageId);
1955
+ });
1956
+ ```
1957
+
1958
+ The text that already arrived stays: the message is finalized as `CANCELED` and
1959
+ the pending `sendMessage` resolves with it instead of rejecting.
1960
+ `message:complete` fires with the partial message, then `message:stopped`.
1961
+
1962
+ Finalize your UI on `message:stopped`. It is the one event that always fires,
1963
+ while `message:complete` is skipped when there is nothing to complete: a stop
1964
+ that landed before the backend had named the message, and a turn stopped while
1965
+ it was paused on client functions (no stream is open then). Full details in
1966
+ [Stop the answer](core.md#stop-the-answer).
1967
+
1968
+ ---
1969
+
1782
1970
  ## Tool calls
1783
1971
 
1784
1972
  When the agent needs structured input (a form), a confirmation, or shows a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useago/sdk",
3
- "version": "1.5.6",
3
+ "version": "1.7.0",
4
4
  "description": "Create In-APP AI agents that answers question and performs actions. Works with React, Vue, Angular and vanilla JS/TS.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,8 +0,0 @@
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,followUpReplies:n.follow_up_replies&&n.follow_up_replies.length>0?n.follow_up_replies: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}});
@@ -1 +0,0 @@
1
- function C(u={}){const{overrides:g={}}=u,a={id:"mock-msg-1",conversationId:"mock-conv-1",content:"Mock response",role:"assistant",status:"DONE",createdAt:new Date},l={id:"mock-conv-1",title:"Mock Conversation",lastMessageDate:new Date},o=new Map,r=[],m={sendMessage:async()=>a,continueMessage:async()=>a,resumePendingClientFunctions:async()=>null,registerResumeGate:()=>()=>{},getConversations:async()=>[l],getConversation:async()=>l,getMessages:async()=>[a],submitToolCallForm:async()=>({status:"completed"}),confirmToolCall:async()=>{},rejectToolCall:async()=>{},submitFeedback:async()=>{},registerFunction:()=>{},unregisterFunction:()=>!0,getRegisteredFunctions:()=>[],executeClientFunction:async()=>{},getContextSnapshot:()=>null,notifyContextChanged:()=>{},setContext:()=>{},removeContext:()=>!0,addDynamicContext:()=>{},removeDynamicContext:()=>!0,registerNavigationFunction:()=>{},unregisterNavigationFunction:()=>{},getConfiguredAgent:()=>{},getHttp:()=>({get:async()=>({}),post:async()=>({})}),emitProactiveEvent:(e,t)=>{const n=o.get(e);n&&[...n].forEach(s=>s(t))},on:(e,t)=>{o.has(e)||o.set(e,new Set),o.get(e).add(t)},off:(e,t)=>{o.get(e)?.delete(t)},once:(e,t)=>{const n=(...s)=>{o.get(e)?.delete(n),t(...s)};o.has(e)||o.set(e,new Set),o.get(e).add(n)},waitFor:(e,t)=>new Promise((n,s)=>{let c;const d=f=>{c&&clearTimeout(c),o.get(e)?.delete(d),n(f)};o.has(e)||o.set(e,new Set),o.get(e).add(d),t?.timeout&&(c=setTimeout(()=>{o.get(e)?.delete(d),s(new Error(`waitFor("${e}") timed out after ${t.timeout}ms`))},t.timeout))}),updateConfig:()=>{},destroy:()=>{o.clear()},...g},i={};for(const[e,t]of Object.entries(m))i[e]=(...n)=>(r.push({method:e,args:n}),t(...n));return i.proactive=null,i.__calls=r,i.__callsFor=e=>r.filter(t=>t.method===e),i.__emitEvent=(e,t)=>{const n=o.get(e);n&&[...n].forEach(s=>s(t))},i}Object.defineProperty(exports,"createMockClient",{enumerable:!0,get:function(){return C}});