@useago/sdk 1.7.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +53 -6
  3. package/dist/angular.cjs +1 -1
  4. package/dist/angular.d.cts +89 -5
  5. package/dist/angular.d.ts +89 -5
  6. package/dist/angular.js +11 -7
  7. package/dist/{createConversationSession-Bgvx753t.js → createConversationSession-BaaXBQ5b.js} +3 -3
  8. package/dist/createConversationSession-CU0b-t1W.cjs +1 -0
  9. package/dist/{createFormCollector-CM3qjGcM.js → createFormCollector-Cf7kGhCB.js} +1 -1
  10. package/dist/createFormCollector-DfN1xZBy.cjs +1 -0
  11. package/dist/{createMockClient-BDLW6tVc.js → createMockClient-5YF-ZbVu.js} +22 -21
  12. package/dist/createMockClient-BZbOe-23.cjs +1 -0
  13. package/dist/devtools.cjs +61 -12
  14. package/dist/devtools.d.cts +90 -5
  15. package/dist/devtools.d.ts +90 -5
  16. package/dist/devtools.js +225 -73
  17. package/dist/errors-BLfjXnLB.js +32 -0
  18. package/dist/errors-o1IB5fEu.cjs +1 -0
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.cts +100 -3
  21. package/dist/index.d.ts +100 -3
  22. package/dist/index.js +77 -75
  23. package/dist/react.cjs +4 -4
  24. package/dist/react.d.cts +197 -3
  25. package/dist/react.d.ts +197 -3
  26. package/dist/react.js +1034 -752
  27. package/dist/testing.cjs +1 -1
  28. package/dist/testing.d.cts +80 -3
  29. package/dist/testing.d.ts +80 -3
  30. package/dist/testing.js +1 -1
  31. package/dist/{AgoClient-BJjLTOw4.js → types-CPga11Of.js} +489 -386
  32. package/dist/types-D3YQl1jx.cjs +9 -0
  33. package/dist/vue.cjs +1 -1
  34. package/dist/vue.d.cts +110 -3
  35. package/dist/vue.d.ts +110 -3
  36. package/dist/vue.js +202 -154
  37. package/dist/widget.cjs +4 -4
  38. package/dist/widget.d.cts +148 -3
  39. package/dist/widget.d.ts +148 -3
  40. package/dist/widget.js +871 -651
  41. package/llms-full.txt +144 -30
  42. package/package.json +1 -1
  43. package/dist/AgoClient-B_u_d-XS.cjs +0 -9
  44. package/dist/createConversationSession-BCdwAhLF.cjs +0 -1
  45. package/dist/createFormCollector-ssBP8u0p.cjs +0 -1
  46. package/dist/createMockClient-BSNuN3ys.cjs +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,96 @@ All notable changes to `@useago/sdk` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.0] - 2026-08-28
9
+
10
+ ### Changed
11
+
12
+ - **`setPageState` result shape.** `applied` is now an array of field names
13
+ (was a value map). The result also includes `unchanged: string[]` (always
14
+ present) and `rejected?: Record<string, string>` (present when any field was
15
+ refused). `success` is `false` when `rejected` is non-empty, `true` otherwise.
16
+
17
+ ### Added
18
+
19
+ - **Per-field validation.** `setPageState` validates each field's type and enum
20
+ against the declared schema before calling `set()`. Unknown control names are
21
+ rejected with the list of available controls. A value equal to the current
22
+ `get()` is skipped without calling `set()`.
23
+ - **Placeholder dropping.** `null`, `undefined`, and `""` are silently dropped
24
+ instead of being applied. They appear in no result bucket.
25
+ - **`clearable` option on string controls.** When set, `""` means "clear the
26
+ field" and is applied instead of dropped. The SDK adds `""` to the enum (if
27
+ one exists) and appends a clearing hint to the description.
28
+ - **Tagged setter outcomes.** `set()` can return `{ result: "rejected", reason }`
29
+ to refuse a value, or `{ result: "unchanged" }` to signal the field already
30
+ holds the requested state. Returning nothing (void) means applied.
31
+ - **Result budget preservation.** When the result exceeds `maxResultBytes`, the
32
+ SDK preserves `success`, `applied`, `unchanged`, and `rejected` keys before
33
+ truncating `data`. Without a data source, oversized rejection reasons are
34
+ shortened in order rather than replaced wholesale.
35
+ - **React `useAgoPageState` re-registration.** The hook re-registers when a
36
+ control's model-visible signature changes (name, description, schema,
37
+ `clearable`), so an enum populated by an async fetch updates the advertised
38
+ schema and runtime validation.
39
+ - **Dev panel local function runner.** `initDevPanel({ enableFunctionRunner: true })`
40
+ adds a runner that executes registered functions locally via
41
+ `executeClientFunction`. The function list tracks route changes and the
42
+ diagnostic sections are collapsible.
43
+ - **Dev panel disposal.** `initDevPanel` now returns an idempotent disposer that
44
+ removes its panels and unsubscribes all event handlers. Return it from a React
45
+ effect to keep one connected panel under Strict Mode.
46
+
47
+ ## [1.8.0] - 2026-08-11
48
+
49
+ ### Added
50
+
51
+ - User feedback: a visitor can say that an answer, or a whole conversation, does
52
+ not work, and the report reaches the AGO feedback dashboard.
53
+ - `client.submitFeedback(messageId, rating, { reasons, comment })` now takes
54
+ what went wrong on top of the thumb. `reasons` is any of `"inaccurate"`,
55
+ `"incomplete"`, `"information_not_found"`, `"technical_issue"` (exported as
56
+ `FEEDBACK_REASONS`).
57
+ - `client.submitConversationFeedback(conversationId, rating, details?)` reports
58
+ a whole chat. Feedback is stored per message, so it attaches to the
59
+ conversation's last answer and returns that message id; pass
60
+ `details.lastMessageId` to skip the lookup.
61
+ - `feedback: true` on `mountChatWidget`, and `<ChatWidget feedback />`, render
62
+ a thumbs row under each finished answer with a "what went wrong?" panel on a
63
+ thumbs-down. Every string is overridable (`labels`), `askWhy: false` keeps
64
+ thumbs only, and `onSubmit` / `onError` report what went out.
65
+ - React: `useFeedback()` and `<MessageFeedback messageId={...} />`. Vue:
66
+ `useFeedback()`. Angular: `AgoService.submitFeedback` /
67
+ `submitConversationFeedback`.
68
+
69
+ ### Notes
70
+
71
+ - The details need a backend that accepts them.
72
+ `POST /api/sdk/v1/messages/{id}/feedback` used to take `rating` only and
73
+ silently dropped everything else, so reasons and comments never reached the
74
+ dashboard. It now also takes `reasons` and `comment` and writes the same
75
+ feedback record the in-app modal creates. The demo account
76
+ (`https://playground.api.useago.com`) already runs it; a self-hosted tenant on
77
+ an older build still accepts the rating and ignores the details.
78
+
79
+ ## [1.7.2] - 2026-08-10
80
+
81
+ ### Changed
82
+
83
+ - Every "try the SDK" instruction now points at the same public demo account
84
+ (`https://playground.api.useago.com`, agent `generic-guide`). The examples
85
+ under `examples/` still pointed at a second backend, so a reader following the
86
+ README and a reader cloning an example were testing against different
87
+ tenants. Docs, README, and examples now agree, and the wording is "demo
88
+ account" everywhere instead of a mix of "live demo", "demo backend", and
89
+ "demo endpoint".
90
+ - The `config_missing_base_url` error hint names the demo account and its agent
91
+ slug, so the message is copy-pasteable on its own.
92
+ - The copy-paste prompt for coding agents in the README now installs the SDK and
93
+ names the demo agent to wire up (`https://playground.api.useago.com`, agent
94
+ `generic-guide`). It only told the agent to read `llms-full.txt` and
95
+ integrate, so the install was implicit and the agent had to pick a `baseUrl`
96
+ and slug on its own. Pasting the prompt now ends on a chat that answers.
97
+
8
98
  ## [1.7.1] - 2026-08-10
9
99
 
10
100
  ### Fixed
package/README.md CHANGED
@@ -24,8 +24,11 @@ resolve customer needs, without rebuilding the full customer-facing agent platfo
24
24
  > this into your agent and let it do the integration:
25
25
  >
26
26
  > ```text
27
- > Read https://raw.githubusercontent.com/useago/ago-sdk/refs/heads/main/llms-full.txt
28
- > and integrate the AGO chat SDK into this app.
27
+ > Install the AGO chat SDK in this app: npm install @useago/sdk
28
+ > Then read https://raw.githubusercontent.com/useago/ago-sdk/refs/heads/main/llms-full.txt
29
+ > and wire up a working chat against the public demo agent:
30
+ > baseUrl https://playground.api.useago.com, agent generic-guide.
31
+ > It answers straight away, with no signup and no API key.
29
32
  > ```
30
33
 
31
34
  In two minutes you'll have a working chat on your page and an agent that can
@@ -64,8 +67,10 @@ export default function App() {
64
67
  ```
65
68
 
66
69
  Start your dev server. A chat panel renders on the page; type a message and
67
- watch the reply stream in. That's a complete integration. (`generic-guide` is a
68
- public demo agent; swap `baseUrl` and `agent` for your own once you have a tenant.)
70
+ watch the reply stream in. That's a complete integration. (This is the public
71
+ demo account: `https://playground.api.useago.com` with agent `generic-guide`. It
72
+ needs no signup and no API key. Swap `baseUrl` and `agent` for your own once you
73
+ have a tenant.)
69
74
 
70
75
  `ChatWidget` is the high-level component to get started in minutes. Everything it
71
76
  does is also exposed through hooks and APIs (`useChat`, `useMessages`, the raw
@@ -143,7 +148,12 @@ function InvoiceList() {
143
148
  Each control becomes one optional property of a single `setPageState` function,
144
149
  so the agent changes only what the user asked for. The current value from each
145
150
  `get()` is sent with every message, so the agent knows the state before it
146
- changes it. Vue and Angular have the same helper.
151
+ changes it. The SDK validates type and enum before calling `set()`, skips values
152
+ that match the current `get()`, and drops placeholders (`null`, `undefined`,
153
+ `""`). The result reports each field in `applied`, `unchanged`, or `rejected`.
154
+ Vue and Angular have the same helper. See
155
+ [Page state shortcut](docs/general/functions-and-context.md#page-state-shortcut)
156
+ for `clearable`, tagged setter outcomes, and the full result envelope.
147
157
 
148
158
  Add a `data` source and the agent also gets back **what the page now shows**, as
149
159
  the result of its own call, so it can answer "did you find dupont?" in the same
@@ -257,6 +267,43 @@ with that partial message instead of rejecting. Vue and Angular have the same
257
267
  `stop`, and the vanilla `mountChatWidget` handle gained `stop()`. Details in
258
268
  [Stop the answer](docs/general/core.md#stop-the-answer).
259
269
 
270
+ ## Let the user say "this answer doesn't work"
271
+
272
+ Pass `feedback` and every finished answer gets a thumbs up / thumbs down. On a
273
+ thumbs-down, a panel asks what went wrong: four reason chips
274
+ (inaccurate, incomplete, information not found, technical issue) and a comment
275
+ box.
276
+
277
+ ```tsx
278
+ <ChatWidget feedback />
279
+ ```
280
+
281
+ ```ts
282
+ // vanilla widget
283
+ mountChatWidget("#chat", { config, feedback: true });
284
+ ```
285
+
286
+ The thumb is sent the moment it is clicked, so the signal survives a user who
287
+ ignores the panel. A bare rating is a reaction; a report with a reason or a
288
+ comment also lands in the AGO feedback dashboard, the analytics and the CSV
289
+ export, where someone can act on it.
290
+
291
+ Driving it yourself, from any framework:
292
+
293
+ ```ts
294
+ await ago.submitFeedback(messageId, "negative", {
295
+ reasons: ["inaccurate"],
296
+ comment: "The price it quoted is from last year.",
297
+ });
298
+
299
+ // the whole chat, not one answer (attached to its last answer)
300
+ await ago.submitConversationFeedback(conversationId, "negative");
301
+ ```
302
+
303
+ React and Vue have a `useFeedback()` hook/composable; React also exports the
304
+ `<MessageFeedback messageId={...} />` row for a custom message list. Details in
305
+ [Feedback](docs/general/widget.md#feedback).
306
+
260
307
  ## Show the source docs the agent retrieved
261
308
 
262
309
  Each assistant message carries the knowledge sources it used in `m.sources`
@@ -313,7 +360,7 @@ cd examples/simple-react
313
360
  npm install && npm run dev
314
361
  ```
315
362
 
316
- The examples ship pre-configured against the demo backend, so they answer
363
+ The examples ship pre-configured against the demo account, so they answer
317
364
  immediately. [`examples/`](examples/) has one per stack: React (with
318
365
  react-router navigation), Vue, Angular, plain TypeScript, and no-build HTML.
319
366
 
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-B_u_d-XS.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 s=r=>{i.next?.(r)};return e.on(t,s),{unsubscribe:()=>e.off(t,s)}}}}sendMessage(t,e){return this.client.sendMessage(t,e)}stop(){return this.client.stop()}stopMessage(t){return this.client.stopMessage(t)}isGenerating(){return this.client.isGenerating()}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
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./types-D3YQl1jx.cjs"),c=require("./autoContinue-CP9pJR-V.cjs");var n=class{constructor(t){this.client=new r.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 s=o=>{i.next?.(o)};return e.on(t,s),{unsubscribe:()=>e.off(t,s)}}}}sendMessage(t,e){return this.client.sendMessage(t,e)}stop(){return this.client.stop()}stopMessage(t){return this.client.stopMessage(t)}isGenerating(){return this.client.isGenerating()}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,i){return this.client.submitFeedback(t,e,i)}submitConversationFeedback(t,e,i){return this.client.submitConversationFeedback(t,e,i)}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.FEEDBACK_REASONS=r.FEEDBACK_REASONS;exports.provideAgo=u;
@@ -290,9 +290,40 @@ declare class AgoClient {
290
290
  */
291
291
  submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
292
292
  /**
293
- * Submit feedback for a message
293
+ * Report an answer: thumbs up/down, optionally with what went wrong.
294
+ *
295
+ * ```ts
296
+ * await client.submitFeedback(message.id, "negative", {
297
+ * reasons: ["inaccurate"],
298
+ * comment: "The price it quoted is from last year.",
299
+ * });
300
+ * ```
301
+ *
302
+ * A bare rating is a reaction (the thumbs counted in the dashboard). Adding a
303
+ * reason or a comment also files it in the feedback list, the analytics and
304
+ * the CSV export, so someone can act on it.
294
305
  */
295
- submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
306
+ submitFeedback(messageId: string, rating: FeedbackRating, details?: FeedbackDetails): Promise<void>;
307
+ /**
308
+ * Report a whole conversation ("this chat is not working").
309
+ *
310
+ * ```ts
311
+ * await client.submitConversationFeedback(conversationId, "negative", {
312
+ * reasons: ["information_not_found"],
313
+ * comment: "It never answered my question.",
314
+ * });
315
+ * ```
316
+ *
317
+ * Feedback is stored per message, so this attaches the report to the last
318
+ * answer of the conversation, which is the one the user is reacting to.
319
+ * Returns the message id it landed on.
320
+ *
321
+ * Pass `lastMessageId` when you already have it (the widget does) to skip the
322
+ * lookup round-trip.
323
+ */
324
+ submitConversationFeedback(conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
325
+ lastMessageId?: string;
326
+ }): Promise<string>;
296
327
  /**
297
328
  * Register a client-side function that AGO can call.
298
329
  * Accepts either a definition object or (name, handler, schema) args.
@@ -969,8 +1000,12 @@ export declare class AgoService {
969
1000
  confirmToolCall(toolCallId: string): Promise<void>;
970
1001
  /** Reject a tool call */
971
1002
  rejectToolCall(toolCallId: string): Promise<void>;
972
- /** Submit feedback for a message */
973
- submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
1003
+ /** Report an answer: thumbs up/down, optionally with what went wrong */
1004
+ submitFeedback(messageId: string, rating: FeedbackRating, details?: FeedbackDetails): Promise<void>;
1005
+ /** Report a whole conversation; lands on its last answer, whose id is returned */
1006
+ submitConversationFeedback(conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
1007
+ lastMessageId?: string;
1008
+ }): Promise<string>;
974
1009
  /** Register a client-side function */
975
1010
  registerFunction(definition: ClientFunctionDefinition): void;
976
1011
  registerFunction(name: string, handler: ClientFunctionHandler, schema: ClientFunctionRegisterOptions): void;
@@ -1054,12 +1089,27 @@ export declare interface AgoStateControl<T = unknown> {
1054
1089
  enum?: (string | number)[];
1055
1090
  };
1056
1091
  };
1092
+ /** String-only: `""` means "clear" instead of being dropped as filler. */
1093
+ clearable?: boolean;
1057
1094
  /** Current value → pushed as dynamic context so the agent knows what to change. */
1058
1095
  get?: () => T;
1059
1096
  /** Apply the state change on the page. May be async. */
1060
- set: (value: T) => void | Promise<void>;
1097
+ set: (value: T) => void | AgoStateSetResult | Promise<void | AgoStateSetResult>;
1061
1098
  }
1062
1099
 
1100
+ /**
1101
+ * Tagged outcome a page setter may return to reject or mark unchanged.
1102
+ *
1103
+ * Returning nothing (void) means APPLY. Returning an unrecognized JS value
1104
+ * (e.g. a string from an assignment expression) is also treated as APPLY.
1105
+ */
1106
+ declare type AgoStateSetResult = {
1107
+ result: "rejected";
1108
+ reason: string;
1109
+ } | {
1110
+ result: "unchanged";
1111
+ };
1112
+
1063
1113
  /**
1064
1114
  * Single-object function definition — combines name, schema, and handler.
1065
1115
  *
@@ -1200,6 +1250,40 @@ export declare interface Conversation {
1200
1250
  */
1201
1251
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
1202
1252
 
1253
+ /** The four values of {@link FeedbackReason}, in dashboard order. */
1254
+ export declare const FEEDBACK_REASONS: readonly FeedbackReason[];
1255
+
1256
+ /**
1257
+ * Why the user is reporting a message (see `AgoClient.submitFeedback`).
1258
+ *
1259
+ * A rating on its own is a reaction (the thumbs count). Add a reason or a
1260
+ * comment and the report also lands in the feedback dashboard, the analytics
1261
+ * and the CSV export, where someone can act on it.
1262
+ */
1263
+ export declare interface FeedbackDetails {
1264
+ /** What went wrong. Several can apply at once. */
1265
+ reasons?: FeedbackReason[];
1266
+ /** The user's own words. Trimmed server-side; 5000 characters max. */
1267
+ comment?: string;
1268
+ }
1269
+
1270
+ /** Thumbs up / thumbs down on an answer. */
1271
+ export declare type FeedbackRating = "positive" | "negative";
1272
+
1273
+ /**
1274
+ * What went wrong with an answer. These are the four buckets the AGO feedback
1275
+ * dashboard filters and charts on.
1276
+ */
1277
+ export declare type FeedbackReason =
1278
+ /** The answer states something false. */
1279
+ "inaccurate"
1280
+ /** The answer is right but stops short. */
1281
+ | "incomplete"
1282
+ /** The agent could not find the information. */
1283
+ | "information_not_found"
1284
+ /** Something broke: the widget, a tool call, the stream. */
1285
+ | "technical_issue";
1286
+
1203
1287
  /**
1204
1288
  * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
1205
1289
  * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
package/dist/angular.d.ts CHANGED
@@ -290,9 +290,40 @@ declare class AgoClient {
290
290
  */
291
291
  submitFormCollector(name: string, values: Record<string, unknown>): Promise<unknown>;
292
292
  /**
293
- * Submit feedback for a message
293
+ * Report an answer: thumbs up/down, optionally with what went wrong.
294
+ *
295
+ * ```ts
296
+ * await client.submitFeedback(message.id, "negative", {
297
+ * reasons: ["inaccurate"],
298
+ * comment: "The price it quoted is from last year.",
299
+ * });
300
+ * ```
301
+ *
302
+ * A bare rating is a reaction (the thumbs counted in the dashboard). Adding a
303
+ * reason or a comment also files it in the feedback list, the analytics and
304
+ * the CSV export, so someone can act on it.
294
305
  */
295
- submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
306
+ submitFeedback(messageId: string, rating: FeedbackRating, details?: FeedbackDetails): Promise<void>;
307
+ /**
308
+ * Report a whole conversation ("this chat is not working").
309
+ *
310
+ * ```ts
311
+ * await client.submitConversationFeedback(conversationId, "negative", {
312
+ * reasons: ["information_not_found"],
313
+ * comment: "It never answered my question.",
314
+ * });
315
+ * ```
316
+ *
317
+ * Feedback is stored per message, so this attaches the report to the last
318
+ * answer of the conversation, which is the one the user is reacting to.
319
+ * Returns the message id it landed on.
320
+ *
321
+ * Pass `lastMessageId` when you already have it (the widget does) to skip the
322
+ * lookup round-trip.
323
+ */
324
+ submitConversationFeedback(conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
325
+ lastMessageId?: string;
326
+ }): Promise<string>;
296
327
  /**
297
328
  * Register a client-side function that AGO can call.
298
329
  * Accepts either a definition object or (name, handler, schema) args.
@@ -969,8 +1000,12 @@ export declare class AgoService {
969
1000
  confirmToolCall(toolCallId: string): Promise<void>;
970
1001
  /** Reject a tool call */
971
1002
  rejectToolCall(toolCallId: string): Promise<void>;
972
- /** Submit feedback for a message */
973
- submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
1003
+ /** Report an answer: thumbs up/down, optionally with what went wrong */
1004
+ submitFeedback(messageId: string, rating: FeedbackRating, details?: FeedbackDetails): Promise<void>;
1005
+ /** Report a whole conversation; lands on its last answer, whose id is returned */
1006
+ submitConversationFeedback(conversationId: string, rating: FeedbackRating, details?: FeedbackDetails & {
1007
+ lastMessageId?: string;
1008
+ }): Promise<string>;
974
1009
  /** Register a client-side function */
975
1010
  registerFunction(definition: ClientFunctionDefinition): void;
976
1011
  registerFunction(name: string, handler: ClientFunctionHandler, schema: ClientFunctionRegisterOptions): void;
@@ -1054,12 +1089,27 @@ export declare interface AgoStateControl<T = unknown> {
1054
1089
  enum?: (string | number)[];
1055
1090
  };
1056
1091
  };
1092
+ /** String-only: `""` means "clear" instead of being dropped as filler. */
1093
+ clearable?: boolean;
1057
1094
  /** Current value → pushed as dynamic context so the agent knows what to change. */
1058
1095
  get?: () => T;
1059
1096
  /** Apply the state change on the page. May be async. */
1060
- set: (value: T) => void | Promise<void>;
1097
+ set: (value: T) => void | AgoStateSetResult | Promise<void | AgoStateSetResult>;
1061
1098
  }
1062
1099
 
1100
+ /**
1101
+ * Tagged outcome a page setter may return to reject or mark unchanged.
1102
+ *
1103
+ * Returning nothing (void) means APPLY. Returning an unrecognized JS value
1104
+ * (e.g. a string from an assignment expression) is also treated as APPLY.
1105
+ */
1106
+ declare type AgoStateSetResult = {
1107
+ result: "rejected";
1108
+ reason: string;
1109
+ } | {
1110
+ result: "unchanged";
1111
+ };
1112
+
1063
1113
  /**
1064
1114
  * Single-object function definition — combines name, schema, and handler.
1065
1115
  *
@@ -1200,6 +1250,40 @@ export declare interface Conversation {
1200
1250
  */
1201
1251
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
1202
1252
 
1253
+ /** The four values of {@link FeedbackReason}, in dashboard order. */
1254
+ export declare const FEEDBACK_REASONS: readonly FeedbackReason[];
1255
+
1256
+ /**
1257
+ * Why the user is reporting a message (see `AgoClient.submitFeedback`).
1258
+ *
1259
+ * A rating on its own is a reaction (the thumbs count). Add a reason or a
1260
+ * comment and the report also lands in the feedback dashboard, the analytics
1261
+ * and the CSV export, where someone can act on it.
1262
+ */
1263
+ export declare interface FeedbackDetails {
1264
+ /** What went wrong. Several can apply at once. */
1265
+ reasons?: FeedbackReason[];
1266
+ /** The user's own words. Trimmed server-side; 5000 characters max. */
1267
+ comment?: string;
1268
+ }
1269
+
1270
+ /** Thumbs up / thumbs down on an answer. */
1271
+ export declare type FeedbackRating = "positive" | "negative";
1272
+
1273
+ /**
1274
+ * What went wrong with an answer. These are the four buckets the AGO feedback
1275
+ * dashboard filters and charts on.
1276
+ */
1277
+ export declare type FeedbackReason =
1278
+ /** The answer states something false. */
1279
+ "inaccurate"
1280
+ /** The answer is right but stops short. */
1281
+ | "incomplete"
1282
+ /** The agent could not find the information. */
1283
+ | "information_not_found"
1284
+ /** Something broke: the widget, a tool call, the stream. */
1285
+ | "technical_issue";
1286
+
1203
1287
  /**
1204
1288
  * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
1205
1289
  * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
package/dist/angular.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as o } from "./AgoClient-BJjLTOw4.js";
2
- import { t as c } from "./autoContinue-CC8K9mBU.js";
1
+ import { n as o, t as u } from "./types-CPga11Of.js";
2
+ import { t as a } 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");
@@ -43,8 +43,11 @@ var s = class {
43
43
  rejectToolCall(t) {
44
44
  return this.client.rejectToolCall(t);
45
45
  }
46
- submitFeedback(t, e) {
47
- return this.client.submitFeedback(t, e);
46
+ submitFeedback(t, e, i) {
47
+ return this.client.submitFeedback(t, e, i);
48
+ }
49
+ submitConversationFeedback(t, e, i) {
50
+ return this.client.submitConversationFeedback(t, e, i);
48
51
  }
49
52
  registerFunction(t, e, i) {
50
53
  typeof t == "object" ? this.client.registerFunction(t) : this.client.registerFunction(t, e, i);
@@ -59,7 +62,7 @@ var s = class {
59
62
  this.client.unregisterNavigationFunction();
60
63
  }
61
64
  enableAutoContinueAfterNavigation(t) {
62
- return c(this.client, t);
65
+ return a(this.client, t);
63
66
  }
64
67
  registerPageStateFunction(t, e) {
65
68
  this.client.registerPageStateFunction(t, e);
@@ -83,7 +86,7 @@ var s = class {
83
86
  this.client.destroy();
84
87
  }
85
88
  };
86
- function l(t) {
89
+ function g(t) {
87
90
  return {
88
91
  provide: s,
89
92
  useValue: new s(t)
@@ -91,5 +94,6 @@ function l(t) {
91
94
  }
92
95
  export {
93
96
  s as AgoService,
94
- l as provideAgo
97
+ u as FEEDBACK_REASONS,
98
+ g as provideAgo
95
99
  };
@@ -1,4 +1,4 @@
1
- import { h as d } from "./AgoClient-BJjLTOw4.js";
1
+ import { g as d } from "./types-CPga11Of.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) => {
@@ -6,7 +6,7 @@ function v() {
6
6
  return (e === "x" ? r : r & 3 | 8).toString(16);
7
7
  });
8
8
  }
9
- function h(e = {}) {
9
+ function D(e = {}) {
10
10
  const r = e.key ?? f, c = e.threadKey ?? g, u = e.ttlMs ?? y, l = e.storage ?? (typeof localStorage < "u" ? localStorage : void 0);
11
11
  let n = e.widgetId ?? "";
12
12
  if (!n && l) try {
@@ -54,5 +54,5 @@ function h(e = {}) {
54
54
  };
55
55
  }
56
56
  export {
57
- h as t
57
+ D as t
58
58
  };
@@ -0,0 +1 @@
1
+ const d=require("./types-D3YQl1jx.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 R, v as w } from "./AgoClient-BJjLTOw4.js";
1
+ import { g as R, y as w } from "./types-CPga11Of.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));
@@ -0,0 +1 @@
1
+ const C=require("./types-D3YQl1jx.cjs");var W=/^[a-zA-Z0-9_-]{1,40}$/,V=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(V(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=>V(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 A(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 A({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 A}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return L}});
@@ -1,5 +1,5 @@
1
- function y(g = {}) {
2
- const { overrides: u = {} } = g, a = {
1
+ function y(u = {}) {
2
+ const { overrides: g = {} } = u, a = {
3
3
  id: "mock-msg-1",
4
4
  conversationId: "mock-conv-1",
5
5
  content: "Mock response",
@@ -10,7 +10,7 @@ function y(g = {}) {
10
10
  id: "mock-conv-1",
11
11
  title: "Mock Conversation",
12
12
  lastMessageDate: /* @__PURE__ */ new Date()
13
- }, o = /* @__PURE__ */ new Map(), c = [], m = {
13
+ }, n = /* @__PURE__ */ new Map(), c = [], m = {
14
14
  sendMessage: async () => a,
15
15
  continueMessage: async () => a,
16
16
  stop: async () => null,
@@ -29,6 +29,7 @@ function y(g = {}) {
29
29
  },
30
30
  submitFeedback: async () => {
31
31
  },
32
+ submitConversationFeedback: async () => a.id,
32
33
  registerFunction: () => {
33
34
  },
34
35
  unregisterFunction: () => !0,
@@ -55,44 +56,44 @@ function y(g = {}) {
55
56
  post: async () => ({})
56
57
  }),
57
58
  emitProactiveEvent: (e, t) => {
58
- const n = o.get(e);
59
- n && [...n].forEach((s) => s(t));
59
+ const o = n.get(e);
60
+ o && [...o].forEach((s) => s(t));
60
61
  },
61
62
  on: (e, t) => {
62
- o.has(e) || o.set(e, /* @__PURE__ */ new Set()), o.get(e).add(t);
63
+ n.has(e) || n.set(e, /* @__PURE__ */ new Set()), n.get(e).add(t);
63
64
  },
64
65
  off: (e, t) => {
65
- o.get(e)?.delete(t);
66
+ n.get(e)?.delete(t);
66
67
  },
67
68
  once: (e, t) => {
68
- const n = (...s) => {
69
- o.get(e)?.delete(n), t(...s);
69
+ const o = (...s) => {
70
+ n.get(e)?.delete(o), t(...s);
70
71
  };
71
- o.has(e) || o.set(e, /* @__PURE__ */ new Set()), o.get(e).add(n);
72
+ n.has(e) || n.set(e, /* @__PURE__ */ new Set()), n.get(e).add(o);
72
73
  },
73
- waitFor: (e, t) => new Promise((n, s) => {
74
+ waitFor: (e, t) => new Promise((o, s) => {
74
75
  let r;
75
76
  const d = (f) => {
76
- r && clearTimeout(r), o.get(e)?.delete(d), n(f);
77
+ r && clearTimeout(r), n.get(e)?.delete(d), o(f);
77
78
  };
78
- o.has(e) || o.set(e, /* @__PURE__ */ new Set()), o.get(e).add(d), t?.timeout && (r = setTimeout(() => {
79
- o.get(e)?.delete(d), s(/* @__PURE__ */ new Error(`waitFor("${e}") timed out after ${t.timeout}ms`));
79
+ n.has(e) || n.set(e, /* @__PURE__ */ new Set()), n.get(e).add(d), t?.timeout && (r = setTimeout(() => {
80
+ n.get(e)?.delete(d), s(/* @__PURE__ */ new Error(`waitFor("${e}") timed out after ${t.timeout}ms`));
80
81
  }, t.timeout));
81
82
  }),
82
83
  updateConfig: () => {
83
84
  },
84
85
  destroy: () => {
85
- o.clear();
86
+ n.clear();
86
87
  },
87
- ...u
88
+ ...g
88
89
  }, i = {};
89
- for (const [e, t] of Object.entries(m)) i[e] = (...n) => (c.push({
90
+ for (const [e, t] of Object.entries(m)) i[e] = (...o) => (c.push({
90
91
  method: e,
91
- args: n
92
- }), t(...n));
92
+ args: o
93
+ }), t(...o));
93
94
  return i.proactive = null, i.__calls = c, i.__callsFor = (e) => c.filter((t) => t.method === e), i.__emitEvent = (e, t) => {
94
- const n = o.get(e);
95
- n && [...n].forEach((s) => s(t));
95
+ const o = n.get(e);
96
+ o && [...o].forEach((s) => s(t));
96
97
  }, i;
97
98
  }
98
99
  export {
@@ -0,0 +1 @@
1
+ function y(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},n=new Map,c=[],m={sendMessage:async()=>a,continueMessage:async()=>a,stop:async()=>null,stopMessage:async()=>({status:"not_running"}),isGenerating:()=>!1,resumePendingClientFunctions:async()=>null,registerResumeGate:()=>()=>{},getConversations:async()=>[l],getConversation:async()=>l,getMessages:async()=>[a],submitToolCallForm:async()=>({status:"completed"}),confirmToolCall:async()=>{},rejectToolCall:async()=>{},submitFeedback:async()=>{},submitConversationFeedback:async()=>a.id,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 o=n.get(e);o&&[...o].forEach(s=>s(t))},on:(e,t)=>{n.has(e)||n.set(e,new Set),n.get(e).add(t)},off:(e,t)=>{n.get(e)?.delete(t)},once:(e,t)=>{const o=(...s)=>{n.get(e)?.delete(o),t(...s)};n.has(e)||n.set(e,new Set),n.get(e).add(o)},waitFor:(e,t)=>new Promise((o,s)=>{let r;const d=f=>{r&&clearTimeout(r),n.get(e)?.delete(d),o(f)};n.has(e)||n.set(e,new Set),n.get(e).add(d),t?.timeout&&(r=setTimeout(()=>{n.get(e)?.delete(d),s(new Error(`waitFor("${e}") timed out after ${t.timeout}ms`))},t.timeout))}),updateConfig:()=>{},destroy:()=>{n.clear()},...g},i={};for(const[e,t]of Object.entries(m))i[e]=(...o)=>(c.push({method:e,args:o}),t(...o));return i.proactive=null,i.__calls=c,i.__callsFor=e=>c.filter(t=>t.method===e),i.__emitEvent=(e,t)=>{const o=n.get(e);o&&[...o].forEach(s=>s(t))},i}Object.defineProperty(exports,"createMockClient",{enumerable:!0,get:function(){return y}});