@useago/sdk 1.7.2 → 1.12.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 (51) hide show
  1. package/CHANGELOG.md +175 -0
  2. package/README.md +96 -1
  3. package/dist/angular.cjs +1 -1
  4. package/dist/angular.d.cts +402 -5
  5. package/dist/angular.d.ts +402 -5
  6. package/dist/angular.js +11 -7
  7. package/dist/{createConversationSession-DP90nY71.js → createConversationSession-B1Qn-y0I.js} +3 -3
  8. package/dist/createConversationSession-B3v_xOU7.cjs +1 -0
  9. package/dist/createFormCollector-FvwDOqnV.cjs +1 -0
  10. package/dist/{createFormCollector-BivHRIAe.js → createFormCollector-m79zk_NA.js} +1 -1
  11. package/dist/createMockClient-BEOXI8yW.cjs +1 -0
  12. package/dist/{createMockClient-BDLW6tVc.js → createMockClient-Beao82tu.js} +31 -18
  13. package/dist/devtools.cjs +61 -12
  14. package/dist/devtools.d.cts +403 -5
  15. package/dist/devtools.d.ts +403 -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 +489 -7
  21. package/dist/index.d.ts +489 -7
  22. package/dist/index.js +124 -118
  23. package/dist/react.cjs +4 -4
  24. package/dist/react.d.cts +510 -3
  25. package/dist/react.d.ts +510 -3
  26. package/dist/react.js +1036 -752
  27. package/dist/sheetController-BThJRtOu.cjs +1 -0
  28. package/dist/sheetController-aEKXIvjk.js +343 -0
  29. package/dist/testing.cjs +1 -1
  30. package/dist/testing.d.cts +393 -3
  31. package/dist/testing.d.ts +393 -3
  32. package/dist/testing.js +1 -1
  33. package/dist/types-Ct1hlKwg.js +2408 -0
  34. package/dist/types-mcW8vB1U.cjs +10 -0
  35. package/dist/vue.cjs +1 -1
  36. package/dist/vue.d.cts +615 -3
  37. package/dist/vue.d.ts +615 -3
  38. package/dist/vue.js +202 -154
  39. package/dist/widget.cjs +6 -4
  40. package/dist/widget.d.cts +733 -5
  41. package/dist/widget.d.ts +733 -5
  42. package/dist/widget.js +3996 -786
  43. package/llms-full.txt +264 -31
  44. package/package.json +1 -1
  45. package/dist/AgoClient-7yXQ6R3O.cjs +0 -9
  46. package/dist/AgoClient-DTkBRGFE.js +0 -1965
  47. package/dist/createConversationSession-Bv6a15E0.cjs +0 -1
  48. package/dist/createFormCollector-CwfiYn0V.cjs +0 -1
  49. package/dist/createMockClient-BSNuN3ys.cjs +0 -1
  50. package/dist/sheetController-CBUVOroo.js +0 -205
  51. package/dist/sheetController-DY-sC13T.cjs +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,181 @@ 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.12.0] - 2026-09-07
9
+
10
+ ### Added
11
+
12
+ - **User metadata on messages.** Set `metadata` on the client config (or in
13
+ `window.AGO.metadata`) and the JSON-serializable object rides along with every
14
+ new message, both JSON and multipart uploads. `sendMessage(text, { metadata })`
15
+ replaces the defaults for that message, `null` omits the field, and
16
+ `updateConfig({ metadata })` changes it at runtime. In React, `useAgo`
17
+ re-applies the `metadata` prop without recreating the client. The API stores
18
+ it as widget metadata on the user, where field mappings can pull selected
19
+ values into tickets. It is untrusted browser-supplied context, not a
20
+ credential.
21
+ - **JavaScript errors as agent context.** Set `errorWatcher: true` (or options)
22
+ on the client config and the page's recent JS errors ride along with every
23
+ message as the `errors:recent` context entry: uncaught exceptions with file,
24
+ line and stack, unhandled promise rejections, `console.error` calls (the
25
+ method is wrapped, calls through, and is restored on `destroy()`), and
26
+ errors the app hands over with `client.reportError(error, context?)`.
27
+ Deduplicated with a `count`, capped at 10, pruned after 10 minutes, messages
28
+ and stacks truncated. Options `maxErrors`, `maxAgeMs`, `maxStackChars`,
29
+ `filter`. New client methods `enableErrorWatcher`, `disableErrorWatcher`,
30
+ `reportError`, `getRecentErrors`, `clearErrors`; new event `error:captured`;
31
+ new exports `ErrorWatcher`, `CapturedError`, `ErrorWatcherOptions`. Off by
32
+ default: error messages can carry PII.
33
+ - **`jsErrors` proactive matcher.** Captured errors count as friction on the
34
+ current route (`SignalsSnapshot.jsErrors`, reset on navigation), so a
35
+ trigger can nudge right after a crash with `when: { jsErrors: 1 }`. Needs
36
+ `errorWatcher` on; counts only, the messages stay in `client_context`.
37
+
38
+ ### Fixed
39
+
40
+ - Ticket attachments become available when the dashboard form configuration
41
+ finishes loading.
42
+ - Ticket forms now support multiple condition values, nested questions and
43
+ conditional choices across ticketing providers. Changing a branch clears
44
+ answers that no longer apply. Required questions are checked before sending,
45
+ including those not yet revealed.
46
+ - Ticket forms respect option groups and order, fields marked always visible,
47
+ format validation, priority by request type and dashboard success messages
48
+ when the API supplies these settings.
49
+
50
+ ## [1.11.0] - 2026-09-04
51
+
52
+ ### Added
53
+
54
+ - **`loadHomeConfig` on the bubble widget: the home screen from the AGO
55
+ dashboard.** `mountChatWidget(el, { placement: "bubble", loadHomeConfig: true })`
56
+ takes the home title, the markdown subtitle and the starter cards from
57
+ `GET /config` instead of the options, the way the hosted widget does. One
58
+ request on mount, off the critical path: the panel renders with whatever the
59
+ options set and re-renders when the config lands, and a failed request leaves
60
+ the options in place. Each part is replaced only when the dashboard has a
61
+ value for it, and the header keeps the `title` option. The dashboard's
62
+ *widget starter* (an opening message the agent sends by itself) fires when the
63
+ panel is first opened, on a fresh visit only, never over a resumed thread.
64
+ - **`agentId` on `ConversationStarter`.** A starter card can name the agent
65
+ that answers it. Dashboard starters carry their own.
66
+ - **`SdkPermissionConfig.homePage`.** `AgoClient.getConfig()` now maps the
67
+ `home_page` block (`title`, `subtitle`, `home_starters`, `widget_starter`)
68
+ when the backend sends one. A starter card shows its `description` and sends
69
+ its `initial_message`; one with neither is dropped. New types
70
+ `SdkHomePageConfig`, `SdkHomeStarter`, `SdkWidgetStarter`.
71
+
72
+
73
+ ## [1.10.0] - 2026-09-03
74
+
75
+ ### Added
76
+
77
+ - **`placement: "bubble"` on `mountChatWidget`.** The hosted embed widget
78
+ without the iframe: a 54px launcher bottom right, a teaser bubble one second
79
+ after mount, and a 550px panel with a home screen (title, markdown
80
+ `subtitle`, `conversationStarters` cards), a conversation screen, and a chat
81
+ history screen with relative times and a "New conversation" pill. Reopens
82
+ the visitor's most recent thread when its last message is under two hours
83
+ old (`autoResume`), goes full screen under 450px, closes on Escape, and
84
+ takes the embed snippet's `colors` (`button`, `header` with gradients,
85
+ `agentMessage`, `background`, `font`, `userMessage`) with the header text
86
+ derived for contrast. New options `prompt`, `icon`, `colors`, `hideFooter`,
87
+ `subtitle`, `conversationStarters`, `autoResume`, `labels`; new handle
88
+ members `screen`, `showScreen`, `openConversation`, `newConversation`. New
89
+ theme tokens `--ago-launcher-background`, `--ago-launcher-text-color`,
90
+ `--ago-send-button-background`, `--ago-user-bubble-background`,
91
+ `--ago-user-bubble-text-color`, `--ago-agent-bubble-text-color`,
92
+ `--ago-panel-width`.
93
+ - **The ticket form renders in the vanilla widget.** The `form` tool call the
94
+ agent's `ago_ticketing` tool opens now shows the tenant's contact form in the
95
+ conversation, on every placement: inline fields from `GET /config`, the
96
+ embedded (HubSpot) variant, the "not allowed" notice, a green success block,
97
+ and the composer replaced by a "complete the form" card, then "ticket
98
+ created" with a New conversation button. New `toolCallForm` option (labels,
99
+ success text, `userEmail`, callbacks).
100
+ - **`AgoClient.getConfig()`, `AgoClient.createTicket()`, and
101
+ `AgoClient.getUserIdentity()`.** `ToolCallData` carries the ticketing fields
102
+ (`displayMode`, `askToTalkToHuman`, `allowedToCreateTicket`, `ticket`,
103
+ `mode`, `ticketFormId`, `embedHtml`, `embedDescription`), streamed and
104
+ persisted alike. New exported types `TicketForm`, `TicketField`,
105
+ `SdkConfig`, `CreateTicketInput`, `CreateTicketResult`.
106
+
107
+ ### Changed
108
+
109
+ - Nothing for the existing `inline`, `left`, and `right` placements. The
110
+ `newConversation()` handle method is new on all of them.
111
+
112
+ ## [1.9.0] - 2026-08-28
113
+
114
+ ### Changed
115
+
116
+ - **`setPageState` result shape.** `applied` is now an array of field names
117
+ (was a value map). The result also includes `unchanged: string[]` (always
118
+ present) and `rejected?: Record<string, string>` (present when any field was
119
+ refused). `success` is `false` when `rejected` is non-empty, `true` otherwise.
120
+
121
+ ### Added
122
+
123
+ - **Per-field validation.** `setPageState` validates each field's type and enum
124
+ against the declared schema before calling `set()`. Unknown control names are
125
+ rejected with the list of available controls. A value equal to the current
126
+ `get()` is skipped without calling `set()`.
127
+ - **Placeholder dropping.** `null`, `undefined`, and `""` are silently dropped
128
+ instead of being applied. They appear in no result bucket.
129
+ - **`clearable` option on string controls.** When set, `""` means "clear the
130
+ field" and is applied instead of dropped. The SDK adds `""` to the enum (if
131
+ one exists) and appends a clearing hint to the description.
132
+ - **Tagged setter outcomes.** `set()` can return `{ result: "rejected", reason }`
133
+ to refuse a value, or `{ result: "unchanged" }` to signal the field already
134
+ holds the requested state. Returning nothing (void) means applied.
135
+ - **Result budget preservation.** When the result exceeds `maxResultBytes`, the
136
+ SDK preserves `success`, `applied`, `unchanged`, and `rejected` keys before
137
+ truncating `data`. Without a data source, oversized rejection reasons are
138
+ shortened in order rather than replaced wholesale.
139
+ - **React `useAgoPageState` re-registration.** The hook re-registers when a
140
+ control's model-visible signature changes (name, description, schema,
141
+ `clearable`), so an enum populated by an async fetch updates the advertised
142
+ schema and runtime validation.
143
+ - **Dev panel local function runner.** `initDevPanel({ enableFunctionRunner: true })`
144
+ adds a runner that executes registered functions locally via
145
+ `executeClientFunction`. The function list tracks route changes and the
146
+ diagnostic sections are collapsible.
147
+ - **Dev panel disposal.** `initDevPanel` now returns an idempotent disposer that
148
+ removes its panels and unsubscribes all event handlers. Return it from a React
149
+ effect to keep one connected panel under Strict Mode.
150
+
151
+ ## [1.8.0] - 2026-08-11
152
+
153
+ ### Added
154
+
155
+ - User feedback: a visitor can say that an answer, or a whole conversation, does
156
+ not work, and the report reaches the AGO feedback dashboard.
157
+ - `client.submitFeedback(messageId, rating, { reasons, comment })` now takes
158
+ what went wrong on top of the thumb. `reasons` is any of `"inaccurate"`,
159
+ `"incomplete"`, `"information_not_found"`, `"technical_issue"` (exported as
160
+ `FEEDBACK_REASONS`).
161
+ - `client.submitConversationFeedback(conversationId, rating, details?)` reports
162
+ a whole chat. Feedback is stored per message, so it attaches to the
163
+ conversation's last answer and returns that message id; pass
164
+ `details.lastMessageId` to skip the lookup.
165
+ - `feedback: true` on `mountChatWidget`, and `<ChatWidget feedback />`, render
166
+ a thumbs row under each finished answer with a "what went wrong?" panel on a
167
+ thumbs-down. Every string is overridable (`labels`), `askWhy: false` keeps
168
+ thumbs only, and `onSubmit` / `onError` report what went out.
169
+ - React: `useFeedback()` and `<MessageFeedback messageId={...} />`. Vue:
170
+ `useFeedback()`. Angular: `AgoService.submitFeedback` /
171
+ `submitConversationFeedback`.
172
+
173
+ ### Notes
174
+
175
+ - The details need a backend that accepts them.
176
+ `POST /api/sdk/v1/messages/{id}/feedback` used to take `rating` only and
177
+ silently dropped everything else, so reasons and comments never reached the
178
+ dashboard. It now also takes `reasons` and `comment` and writes the same
179
+ feedback record the in-app modal creates. The demo account
180
+ (`https://playground.api.useago.com`) already runs it; a self-hosted tenant on
181
+ an older build still accepts the rating and ignores the details.
182
+
8
183
  ## [1.7.2] - 2026-08-10
9
184
 
10
185
  ### Changed
package/README.md CHANGED
@@ -148,7 +148,12 @@ function InvoiceList() {
148
148
  Each control becomes one optional property of a single `setPageState` function,
149
149
  so the agent changes only what the user asked for. The current value from each
150
150
  `get()` is sent with every message, so the agent knows the state before it
151
- 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.
152
157
 
153
158
  Add a `data` source and the agent also gets back **what the page now shows**, as
154
159
  the result of its own call, so it can answer "did you find dupont?" in the same
@@ -262,6 +267,96 @@ with that partial message instead of rejecting. Vue and Angular have the same
262
267
  `stop`, and the vanilla `mountChatWidget` handle gained `stop()`. Details in
263
268
  [Stop the answer](docs/general/core.md#stop-the-answer).
264
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
+
307
+ ## Let the agent see what broke
308
+
309
+ "The button does nothing" is easier to answer with the exception in hand. Turn
310
+ on the error watcher and the page's recent JavaScript errors (uncaught
311
+ exceptions with file, line and stack, unhandled rejections, `console.error`
312
+ calls) ride along with every message, deduplicated and capped.
313
+
314
+ ```ts
315
+ const ago = new AgoClient({
316
+ baseUrl: "https://playground.api.useago.com",
317
+ agent: "generic-guide",
318
+ errorWatcher: true, // off by default: error messages can carry PII
319
+ });
320
+
321
+ // Errors you already catch (error boundaries, framework handlers):
322
+ ago.reportError(error, { component: "OrderTable" });
323
+ ```
324
+
325
+ Same option on `<AgoProvider>`, the Vue plugin, `provideAgo` and
326
+ `mountChatWidget({ config })`. Redact with a `filter`, tune the caps, or use
327
+ `when: { jsErrors: 1 }` in a proactive trigger to nudge right after a crash.
328
+ Details in [JavaScript errors](docs/general/functions-and-context.md#javascript-errors).
329
+
330
+ ## Drop the chat bubble on any page
331
+
332
+ The hosted embed widget, without the iframe: a launcher in the corner, a teaser
333
+ bubble, and a panel with a home screen, the conversation, and the chat history.
334
+ It reopens the visitor's last thread for two hours and goes full screen on a
335
+ phone.
336
+
337
+ ```ts
338
+ import { mountChatWidget } from "@useago/sdk/widget";
339
+
340
+ mountChatWidget(document.body, {
341
+ config: { baseUrl: "https://playground.api.useago.com", agent: "generic-guide" },
342
+ placement: "bubble",
343
+ title: "Ask AGO",
344
+ conversationStarters: [{ label: "What can the SDK do?" }],
345
+ colors: { button: "#007bff", header: "#03182f" },
346
+ });
347
+ ```
348
+
349
+ Add `loadHomeConfig: true` and the home title, subtitle and starter cards come
350
+ from your AGO dashboard instead of the options above.
351
+
352
+ When the visitor asks for a human, the agent's ticket form renders inside the
353
+ conversation on every placement, with the fields from your AGO dashboard.
354
+ Conditional questions and choices work across ticketing providers; changing an
355
+ answer clears responses that no longer apply. The API must include the form
356
+ metadata described in the ticket form guide.
357
+ Details in [Floating bubble](docs/general/widget.md#floating-bubble-placement-bubble)
358
+ and [Ticket form](docs/general/widget.md#ticket-form-the-form-tool-call).
359
+
265
360
  ## Show the source docs the agent retrieved
266
361
 
267
362
  Each assistant message carries the knowledge sources it used in `m.sources`
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-7yXQ6R3O.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-mcW8vB1U.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;