@useago/sdk 0.4.6 → 1.0.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 (41) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +10 -0
  4. package/README.md +19 -11
  5. package/dist/{AgoClient-rvTz2thR.js → AgoClient-BrYhSO5M.js} +32 -26
  6. package/dist/AgoClient-CPqPT5s6.cjs +6 -0
  7. package/dist/angular.cjs +1 -1
  8. package/dist/angular.d.cts +5 -0
  9. package/dist/angular.d.ts +5 -0
  10. package/dist/angular.js +1 -1
  11. package/dist/{createConversationSession-DGcM_Z3f.cjs → createConversationSession-CGRO0bs2.cjs} +1 -1
  12. package/dist/{createConversationSession-D-eq8VIo.js → createConversationSession-Dmqd80DX.js} +1 -1
  13. package/dist/{createFormCollector-DON4vdJV.js → createFormCollector-CPS2phYq.js} +51 -50
  14. package/dist/createFormCollector-DaWZsBsI.cjs +1 -0
  15. package/dist/devtools.cjs +3 -3
  16. package/dist/devtools.d.cts +7 -2
  17. package/dist/devtools.d.ts +7 -2
  18. package/dist/devtools.js +41 -35
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.cts +14 -0
  21. package/dist/index.d.ts +14 -0
  22. package/dist/index.js +38 -37
  23. package/dist/react.cjs +19 -19
  24. package/dist/react.d.cts +16 -0
  25. package/dist/react.d.ts +16 -0
  26. package/dist/react.js +1516 -1490
  27. package/dist/testing.cjs +1 -0
  28. package/dist/testing.d.cts +482 -0
  29. package/dist/testing.d.ts +482 -0
  30. package/dist/testing.js +4 -0
  31. package/dist/vue.cjs +1 -1
  32. package/dist/vue.d.cts +5 -0
  33. package/dist/vue.d.ts +5 -0
  34. package/dist/vue.js +1 -1
  35. package/dist/widget.cjs +4 -4
  36. package/dist/widget.d.cts +6 -1
  37. package/dist/widget.d.ts +6 -1
  38. package/dist/widget.js +300 -286
  39. package/package.json +30 -9
  40. package/dist/AgoClient-D4EL6nva.cjs +0 -6
  41. package/dist/createFormCollector-IO6bfPQx.cjs +0 -1
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Agent information
3
+ */
4
+ declare interface AgoAgent {
5
+ id: string;
6
+ name: string;
7
+ displayName?: string;
8
+ }
9
+
10
+ /**
11
+ * Main SDK client for AGO Chat integration
12
+ */
13
+ declare class AgoClient {
14
+ private httpClient;
15
+ private functionRegistry;
16
+ private contextRegistry;
17
+ private eventEmitter;
18
+ private config;
19
+ constructor(config: AgoConfig);
20
+ /**
21
+ * Send a message and receive a streaming response
22
+ */
23
+ sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
24
+ private processSSEResponse;
25
+ private handleClientFunctionInvocation;
26
+ /**
27
+ * Get list of conversations
28
+ */
29
+ getConversations(): Promise<Conversation[]>;
30
+ /**
31
+ * Get a specific conversation with messages
32
+ */
33
+ getConversation(conversationId: string): Promise<Conversation>;
34
+ /**
35
+ * Map the backend's snake_case `tool_call_data` entries onto the camelCase
36
+ * {@link ToolCallData} shape used everywhere else in the SDK. Mirrors
37
+ * `SSEHandler.parseToolCall` so persisted and streamed tool calls match.
38
+ */
39
+ private static mapPersistedToolCalls;
40
+ /**
41
+ * Get messages for a conversation
42
+ */
43
+ getMessages(conversationId: string): Promise<AgoMessage[]>;
44
+ /**
45
+ * Submit form data for a tool call
46
+ */
47
+ submitToolCallForm(toolCallId: string, formData: Record<string, unknown>): Promise<void>;
48
+ /**
49
+ * Confirm a tool call
50
+ */
51
+ confirmToolCall(toolCallId: string): Promise<void>;
52
+ /**
53
+ * Reject a tool call
54
+ */
55
+ rejectToolCall(toolCallId: string): Promise<void>;
56
+ /**
57
+ * Relay a completed form collector's values to a server-configured destination.
58
+ *
59
+ * Used by `createFormCollector` / `useFormCollector` in `{ via: "backend" }` mode:
60
+ * the browser never holds the destination URL or its secret — the backend resolves
61
+ * `destination` (a named, opted-in tool) and forwards the values from the server.
62
+ */
63
+ submitFormCollector(destination: string, values: Record<string, unknown>): Promise<unknown>;
64
+ /**
65
+ * Submit feedback for a message
66
+ */
67
+ submitFeedback(messageId: string, rating: "positive" | "negative"): Promise<void>;
68
+ /**
69
+ * Register a client-side function that AGO can call.
70
+ * Accepts either a definition object or (name, handler, schema) args.
71
+ *
72
+ * ```ts
73
+ * // Single-object (preferred)
74
+ * client.registerFunction({
75
+ * name: "lookupOrder",
76
+ * description: "Look up an order",
77
+ * parameters: { type: "object", properties: { id: { type: "string" } } },
78
+ * handler: async (args) => fetchOrder(args.id),
79
+ * });
80
+ *
81
+ * // Classic 3-arg form
82
+ * client.registerFunction("lookupOrder", handler, schema);
83
+ * ```
84
+ */
85
+ registerFunction(definition: ClientFunctionDefinition): void;
86
+ registerFunction(name: string, handler: ClientFunctionHandler, schema: Omit<ClientFunctionSchema, "name">): void;
87
+ /**
88
+ * Short alias for `registerFunction`. Also accepts an array of definitions.
89
+ *
90
+ * ```ts
91
+ * client.register(lookupOrder);
92
+ * client.register([lookupOrder, cancelOrder]);
93
+ * ```
94
+ */
95
+ register(definition: ClientFunctionDefinition | ClientFunctionDefinition[]): void;
96
+ /**
97
+ * Unregister a client-side function
98
+ */
99
+ unregisterFunction(name: string): boolean;
100
+ /**
101
+ * Get all registered function schemas
102
+ */
103
+ getRegisteredFunctions(): ClientFunctionSchema[];
104
+ /**
105
+ * Register a navigation function that lets AGO navigate users to different pages.
106
+ * @param navigate - A callback that performs the navigation (e.g. react-router's navigate)
107
+ * @param routes - Map of route names to paths, with descriptions for the LLM
108
+ */
109
+ registerNavigationFunction(navigate: (path: string) => void, routes: Array<{
110
+ name: string;
111
+ path: string;
112
+ description: string;
113
+ }>): void;
114
+ /**
115
+ * Register or update a piece of client-side context.
116
+ * This context is sent with every message so the AI understands the user's situation.
117
+ *
118
+ * ```ts
119
+ * client.setContext("order-page", {
120
+ * name: "Order detail",
121
+ * description: "User is viewing order #123",
122
+ * data: { orderId: "123", status: "shipped" },
123
+ * });
124
+ * ```
125
+ */
126
+ setContext(key: string, entry: ContextEntry): void;
127
+ /**
128
+ * Remove a previously registered context entry.
129
+ */
130
+ removeContext(key: string): boolean;
131
+ /**
132
+ * Register a dynamic context provider. The callback is invoked every time
133
+ * a message is sent, so the AI always gets the freshest data.
134
+ *
135
+ * Use this for context that lives outside React state — global stores,
136
+ * refs, or computed values.
137
+ *
138
+ * ```ts
139
+ * client.addDynamicContext("cart", () => ({
140
+ * name: "Checkout",
141
+ * data: { itemCount: cart.items.length, total: cart.total },
142
+ * }));
143
+ * ```
144
+ */
145
+ addDynamicContext(key: string, provider: DynamicContextProvider): void;
146
+ /**
147
+ * Remove a dynamic context provider.
148
+ */
149
+ removeDynamicContext(key: string): boolean;
150
+ /**
151
+ * Broadcast that the client-side context changed by emitting `context:changed`
152
+ * with the fresh snapshot. The context-mutating methods call this automatically;
153
+ * stateful helpers whose context lives in a store (e.g. `createFormCollector`)
154
+ * call it when their store updates so observers like the dev panel stay live.
155
+ */
156
+ notifyContextChanged(): void;
157
+ /**
158
+ * Enable automatic capture of the current browser page (URL + title).
159
+ * Injected as a dynamic context entry named `browser-page`.
160
+ */
161
+ enableAutoPageContext(): void;
162
+ /**
163
+ * Get the current context snapshot.
164
+ */
165
+ getContextSnapshot(): ContextSnapshot | null;
166
+ /**
167
+ * Subscribe to an event
168
+ */
169
+ on<K extends AgoEventName>(event: K, handler: AgoEventHandler<K>): void;
170
+ /**
171
+ * Unsubscribe from an event
172
+ */
173
+ off<K extends AgoEventName>(event: K, handler: AgoEventHandler<K>): void;
174
+ /**
175
+ * Subscribe to an event once — auto-unsubscribes after the first call.
176
+ */
177
+ once<K extends AgoEventName>(event: K, handler: AgoEventHandler<K>): void;
178
+ /**
179
+ * Returns a Promise that resolves the next time `event` fires.
180
+ *
181
+ * ```ts
182
+ * const msg = await client.waitFor("message:complete", { timeout: 10000 });
183
+ * ```
184
+ */
185
+ waitFor<K extends AgoEventName>(event: K, options?: {
186
+ timeout?: number;
187
+ }): Promise<AgoClientEvents[K]>;
188
+ /**
189
+ * Update client configuration
190
+ */
191
+ updateConfig(config: Partial<AgoConfig>): void;
192
+ /**
193
+ * Clean up resources
194
+ */
195
+ destroy(): void;
196
+ }
197
+
198
+ /**
199
+ * SDK Events
200
+ */
201
+ declare interface AgoClientEvents {
202
+ /**
203
+ * The client-side context changed: a context entry or dynamic provider was
204
+ * added/removed, or a stateful helper (e.g. `createFormCollector`) updated its
205
+ * store. Carries the fresh snapshot so observers — notably the dev panel — can
206
+ * repaint without waiting for the next message. Fires for the form collector's
207
+ * initial install too, so its missing fields show from the start of a conversation.
208
+ */
209
+ "context:changed": ContextSnapshot | null;
210
+ "message:start": {
211
+ conversationId: string;
212
+ messageId: string;
213
+ };
214
+ "message:chunk": {
215
+ content: string;
216
+ conversationId: string;
217
+ messageId: string;
218
+ };
219
+ /**
220
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
221
+ * replies may still be pending. Fires once, before `message:complete`.
222
+ */
223
+ "message:answer-complete": AgoMessage;
224
+ "message:complete": AgoMessage;
225
+ "message:error": {
226
+ error: string;
227
+ conversationId?: string;
228
+ messageId?: string;
229
+ };
230
+ /**
231
+ * A full conversation was loaded from the server (e.g. after a page reload).
232
+ * Carries the messages and their persisted tool calls so stateful helpers —
233
+ * notably `createFormCollector` — can replay them to restore their state.
234
+ */
235
+ "conversation:loaded": Conversation;
236
+ "toolCall:received": ToolCallData;
237
+ "toolCall:form": ToolCallData;
238
+ "function:invoke": ClientFunctionInvocation;
239
+ "function:result": {
240
+ invocationId: string;
241
+ result: unknown;
242
+ error?: string;
243
+ };
244
+ "connection:status": {
245
+ connected: boolean;
246
+ };
247
+ }
248
+
249
+ /**
250
+ * SDK Configuration
251
+ */
252
+ declare interface AgoConfig {
253
+ /** API base URL (e.g., https://YOUR-DOMAIN.useago.com) */
254
+ baseUrl: string;
255
+ /** Widget ID (X-Widget-Id header). Auto-generated if not provided. */
256
+ widgetId?: string;
257
+ /** Default agent (id or slug) for new conversations. Shorthand for `defaultAgentId`. */
258
+ agent?: string;
259
+ /** Default agent ID for new conversations. Prefer `agent`. */
260
+ defaultAgentId?: string;
261
+ /** Permission name to apply to all requests (sent as `X-Widget-Permission`). Mirrors the widget's `window.AGO.permission`. */
262
+ permission?: string;
263
+ /** User email for identification */
264
+ userEmail?: string;
265
+ /** JWT token for authenticated users */
266
+ userJwt?: string;
267
+ /** Enable debug logging */
268
+ debug?: boolean;
269
+ }
270
+
271
+ declare type AgoEventHandler<K extends AgoEventName> = (data: AgoClientEvents[K]) => void;
272
+
273
+ declare type AgoEventName = keyof AgoClientEvents;
274
+
275
+ /**
276
+ * Message from AGO
277
+ */
278
+ declare interface AgoMessage {
279
+ id: string;
280
+ conversationId: string;
281
+ content: string;
282
+ role: "user" | "assistant";
283
+ status: MessageStatus;
284
+ agent?: AgoAgent;
285
+ sources?: AgoSource[];
286
+ toolCalls?: ToolCallData[];
287
+ followUpReplies?: string[];
288
+ createdAt: Date;
289
+ }
290
+
291
+ /**
292
+ * Knowledge source citation
293
+ */
294
+ declare interface AgoSource {
295
+ id: string;
296
+ title: string;
297
+ url?: string;
298
+ }
299
+
300
+ /**
301
+ * Single-object function definition — combines name, schema, and handler.
302
+ *
303
+ * ```ts
304
+ * const fn = defineFunction({
305
+ * name: "lookupOrder",
306
+ * description: "Look up an order by ID",
307
+ * parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
308
+ * handler: async (args) => fetchOrder(args.id as string),
309
+ * });
310
+ * client.registerFunction(fn);
311
+ * ```
312
+ */
313
+ declare interface ClientFunctionDefinition {
314
+ name: string;
315
+ description: string;
316
+ parameters: ClientFunctionSchema["parameters"];
317
+ handler: ClientFunctionHandler;
318
+ }
319
+
320
+ /**
321
+ * Function handler type
322
+ */
323
+ declare type ClientFunctionHandler = (args: Record<string, unknown>) => Promise<unknown> | unknown;
324
+
325
+ declare interface ClientFunctionInvocation {
326
+ invocationId: string;
327
+ functionName: string;
328
+ arguments: Record<string, unknown>;
329
+ conversationId: string;
330
+ }
331
+
332
+ /**
333
+ * Schema for a client-side function that AGO can call
334
+ */
335
+ declare interface ClientFunctionSchema {
336
+ /** Function name (must be unique) */
337
+ name: string;
338
+ /** Description for the LLM to understand when to call this function */
339
+ description: string;
340
+ /** JSON Schema for function parameters */
341
+ parameters: {
342
+ type: "object";
343
+ properties: Record<string, {
344
+ type: string;
345
+ description?: string;
346
+ enum?: string[];
347
+ default?: unknown;
348
+ }>;
349
+ required?: string[];
350
+ };
351
+ }
352
+
353
+ /**
354
+ * A single piece of context the client wants the LLM to know about.
355
+ */
356
+ declare interface ContextEntry {
357
+ /** Human-readable label (e.g. "Order detail", "Current user") */
358
+ name?: string;
359
+ /** Short description of what this context represents */
360
+ description?: string;
361
+ /** Arbitrary structured data the AI should know about */
362
+ data?: Record<string, unknown>;
363
+ }
364
+
365
+ /**
366
+ * Serialised client context sent with each message.
367
+ */
368
+ declare interface ContextSnapshot {
369
+ /** All active context entries keyed by their registration key */
370
+ entries: Record<string, ContextEntry>;
371
+ }
372
+
373
+ /**
374
+ * Conversation/Thread
375
+ */
376
+ declare interface Conversation {
377
+ id: string;
378
+ title: string;
379
+ lastMessageDate: Date;
380
+ messages?: AgoMessage[];
381
+ }
382
+
383
+ /**
384
+ * Create a mock AgoClient for testing. Works with any framework.
385
+ *
386
+ * ```ts
387
+ * import { createMockClient } from "@useago/sdk/testing";
388
+ *
389
+ * const mock = createMockClient();
390
+ * mock.__emitEvent("message:complete", someMessage);
391
+ * expect(mock.__callsFor("sendMessage")).toHaveLength(1);
392
+ * ```
393
+ */
394
+ export declare function createMockClient(options?: MockAgoClientOptions): MockAgoClient;
395
+
396
+ /**
397
+ * A function that returns a fresh context entry on demand.
398
+ * Evaluated every time a message is sent — use it to pull data from stores,
399
+ * refs, or any source that isn't captured by React state.
400
+ */
401
+ declare type DynamicContextProvider = () => ContextEntry | null | undefined;
402
+
403
+ declare interface FormField {
404
+ type: "string" | "number" | "boolean" | "array";
405
+ title?: string;
406
+ description?: string;
407
+ enum?: string[];
408
+ default?: unknown;
409
+ }
410
+
411
+ /**
412
+ * Form schema for tool calls requiring user input
413
+ */
414
+ declare interface FormSchema {
415
+ type: "object";
416
+ properties: Record<string, FormField>;
417
+ required?: string[];
418
+ }
419
+
420
+ declare type MessageStatus = "IN_PROGRESS" | "DONE" | "ERROR" | "TODO" | "CANCELED";
421
+
422
+ export declare interface MockAgoClient extends AgoClient {
423
+ /**
424
+ * Simulate a server-pushed event.
425
+ * ```ts
426
+ * mock.__emitEvent("message:complete", { id: "1", content: "hi", ... });
427
+ * ```
428
+ */
429
+ __emitEvent<K extends AgoEventName>(event: K, data: AgoClientEvents[K]): void;
430
+ /**
431
+ * All recorded method calls: `[methodName, ...args][]`
432
+ */
433
+ __calls: Array<{
434
+ method: string;
435
+ args: unknown[];
436
+ }>;
437
+ /**
438
+ * Get calls for a specific method.
439
+ */
440
+ __callsFor(method: string): Array<{
441
+ method: string;
442
+ args: unknown[];
443
+ }>;
444
+ }
445
+
446
+ export declare interface MockAgoClientOptions {
447
+ overrides?: Partial<Record<string, MockFn>>;
448
+ }
449
+
450
+ declare type MockFn = (...args: any[]) => any;
451
+
452
+ /**
453
+ * Options for sending a message
454
+ */
455
+ declare interface SendMessageOptions {
456
+ /** Existing conversation ID */
457
+ conversationId?: string;
458
+ /** Override default agent */
459
+ agentId?: string;
460
+ /** File attachments */
461
+ files?: File[];
462
+ }
463
+
464
+ /**
465
+ * Tool call data from SSE stream
466
+ */
467
+ declare interface ToolCallData {
468
+ id: string;
469
+ type: ToolCallType;
470
+ status: string;
471
+ toolName: string;
472
+ toolDisplayName?: string;
473
+ message?: string;
474
+ formSchema?: FormSchema;
475
+ data?: Record<string, unknown>;
476
+ functionName?: string;
477
+ arguments?: Record<string, unknown>;
478
+ }
479
+
480
+ declare type ToolCallType = "form" | "confirmation_input" | "status_message" | "progress_indicator" | "client_function" | "reasoning" | "mcp_ui_resource";
481
+
482
+ export { }
@@ -0,0 +1,4 @@
1
+ import { t as e } from "./createMockClient-DwdxNwEn.js";
2
+ export {
3
+ e as createMockClient
4
+ };
package/dist/vue.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("./rolldown-runtime-CaekUdDJ.cjs"),p=require("./AgoClient-D4EL6nva.cjs");let t=require("vue");var I=Symbol("ago-client"),y={install(o,n){const e=new p.AgoClient(n);o.provide(I,e)}};function g(o){if(o)return new p.AgoClient(o);const n=(0,t.inject)(I);if(!n)throw new Error("useAgo(): no AgoClient found. Either pass config or install AgoPlugin.");return n}function E(o={}){const n=o.client??g(),e=(0,t.ref)([]),s=(0,t.ref)(o.conversationId),i=(0,t.ref)(!1),r=(0,t.ref)(null),c=a=>{s.value||(s.value=a.conversationId)},f=a=>{const u=e.value.findIndex(v=>v.id===a.messageId);u>=0&&(e.value[u]={...e.value[u],content:e.value[u].content+a.content})},m=a=>{const u=e.value.findIndex(v=>v.id===a.id);u>=0?e.value[u]=a:e.value.push(a),i.value=!1},C=a=>{r.value=new Error(a.error),i.value=!1};(0,t.onMounted)(()=>{n.on("message:start",c),n.on("message:chunk",f),n.on("message:complete",m),n.on("message:error",C)}),(0,t.onUnmounted)(()=>{n.off("message:start",c),n.off("message:chunk",f),n.off("message:complete",m),n.off("message:error",C)});async function d(a,u){i.value=!0,r.value=null;const v={id:`temp-${Date.now()}`,conversationId:s.value||"",content:a,role:"user",status:"DONE",createdAt:new Date},L={id:`temp-assistant-${Date.now()}`,conversationId:s.value||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date};e.value.push(v,L);try{const l=await n.sendMessage(a,{conversationId:s.value,files:u});l.conversationId&&!s.value&&(s.value=l.conversationId),e.value=e.value.filter(w=>!w.id.startsWith("temp-"));const A={...v,id:v.id.replace("temp-","user-"),conversationId:l.conversationId};return e.value.some(w=>w.id===l.id)?e.value.push(A):e.value.push(A,l),l}catch(l){return r.value=l instanceof Error?l:new Error("Failed to send"),i.value=!1,e.value=e.value.filter(A=>!A.id.startsWith("temp-")),null}}function h(){e.value=[],s.value=void 0,r.value=null}return{messages:e,isLoading:i,error:r,conversationId:s,sendMessage:d,clearMessages:h}}function M(o={}){const n=o.client??g(),e=o.autoLoad??!0,s=(0,t.ref)([]),i=(0,t.ref)(null),r=(0,t.ref)(!1),c=(0,t.ref)(null);async function f(){r.value=!0,c.value=null;try{s.value=await n.getConversations()}catch(d){c.value=d instanceof Error?d:new Error("Failed to load conversations")}finally{r.value=!1}}async function m(d){r.value=!0,c.value=null;try{i.value=await n.getConversation(d)}catch(h){c.value=h instanceof Error?h:new Error("Failed to load conversation")}finally{r.value=!1}}function C(){i.value=null}return(0,t.onMounted)(()=>{e&&f()}),{conversations:s,currentConversation:i,isLoading:r,error:c,selectConversation:m,startNewConversation:C,refreshConversations:f}}function N(o={}){const n=E({client:o.client,conversationId:o.conversationId}),e=M({client:o.client,autoLoad:o.autoLoad}),s=(0,t.computed)(()=>n.error.value||e.error.value);return{messages:n.messages,isLoading:n.isLoading,error:s,sendMessage:n.sendMessage,clearMessages:n.clearMessages,conversationId:n.conversationId,conversations:e.conversations,currentConversation:e.currentConversation,isConversationsLoading:e.isLoading,selectConversation:e.selectConversation,startNewConversation:e.startNewConversation,refreshConversations:e.refreshConversations}}function F(o,n){const e=g();(0,t.onMounted)(()=>{e.registerFunction(o,n.handler,{description:n.description,parameters:n.parameters})}),(0,t.onUnmounted)(()=>{e.unregisterFunction(o)})}function S(o,n){const e=g();(0,t.onMounted)(()=>{e.registerNavigationFunction(o,n)}),(0,t.onUnmounted)(()=>{e.unregisterFunction("navigateToPage")})}function _(o,n){const e=g();(0,t.onMounted)(()=>{e.on(o,n)}),(0,t.onUnmounted)(()=>{e.off(o,n)})}function D(o){const n=(0,t.shallowRef)(o.get());return(0,t.onScopeDispose)(o.subscribe(e=>{n.value=e})),n}exports.AGO_CLIENT_KEY=I;exports.AgoPlugin=y;exports.useAgo=g;exports.useAgoEvents=_;exports.useAgoFunction=F;exports.useAgoNavigation=S;exports.useAgoStore=D;exports.useChat=N;exports.useConversation=M;exports.useMessages=E;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("./rolldown-runtime-CaekUdDJ.cjs"),p=require("./AgoClient-CPqPT5s6.cjs");let t=require("vue");var I=Symbol("ago-client"),y={install(o,n){const e=new p.AgoClient(n);o.provide(I,e)}};function g(o){if(o)return new p.AgoClient(o);const n=(0,t.inject)(I);if(!n)throw new Error("useAgo(): no AgoClient found. Either pass config or install AgoPlugin.");return n}function E(o={}){const n=o.client??g(),e=(0,t.ref)([]),s=(0,t.ref)(o.conversationId),i=(0,t.ref)(!1),r=(0,t.ref)(null),c=a=>{s.value||(s.value=a.conversationId)},f=a=>{const u=e.value.findIndex(v=>v.id===a.messageId);u>=0&&(e.value[u]={...e.value[u],content:e.value[u].content+a.content})},m=a=>{const u=e.value.findIndex(v=>v.id===a.id);u>=0?e.value[u]=a:e.value.push(a),i.value=!1},C=a=>{r.value=new Error(a.error),i.value=!1};(0,t.onMounted)(()=>{n.on("message:start",c),n.on("message:chunk",f),n.on("message:complete",m),n.on("message:error",C)}),(0,t.onUnmounted)(()=>{n.off("message:start",c),n.off("message:chunk",f),n.off("message:complete",m),n.off("message:error",C)});async function d(a,u){i.value=!0,r.value=null;const v={id:`temp-${Date.now()}`,conversationId:s.value||"",content:a,role:"user",status:"DONE",createdAt:new Date},L={id:`temp-assistant-${Date.now()}`,conversationId:s.value||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date};e.value.push(v,L);try{const l=await n.sendMessage(a,{conversationId:s.value,files:u});l.conversationId&&!s.value&&(s.value=l.conversationId),e.value=e.value.filter(w=>!w.id.startsWith("temp-"));const A={...v,id:v.id.replace("temp-","user-"),conversationId:l.conversationId};return e.value.some(w=>w.id===l.id)?e.value.push(A):e.value.push(A,l),l}catch(l){return r.value=l instanceof Error?l:new Error("Failed to send"),i.value=!1,e.value=e.value.filter(A=>!A.id.startsWith("temp-")),null}}function h(){e.value=[],s.value=void 0,r.value=null}return{messages:e,isLoading:i,error:r,conversationId:s,sendMessage:d,clearMessages:h}}function M(o={}){const n=o.client??g(),e=o.autoLoad??!0,s=(0,t.ref)([]),i=(0,t.ref)(null),r=(0,t.ref)(!1),c=(0,t.ref)(null);async function f(){r.value=!0,c.value=null;try{s.value=await n.getConversations()}catch(d){c.value=d instanceof Error?d:new Error("Failed to load conversations")}finally{r.value=!1}}async function m(d){r.value=!0,c.value=null;try{i.value=await n.getConversation(d)}catch(h){c.value=h instanceof Error?h:new Error("Failed to load conversation")}finally{r.value=!1}}function C(){i.value=null}return(0,t.onMounted)(()=>{e&&f()}),{conversations:s,currentConversation:i,isLoading:r,error:c,selectConversation:m,startNewConversation:C,refreshConversations:f}}function N(o={}){const n=E({client:o.client,conversationId:o.conversationId}),e=M({client:o.client,autoLoad:o.autoLoad}),s=(0,t.computed)(()=>n.error.value||e.error.value);return{messages:n.messages,isLoading:n.isLoading,error:s,sendMessage:n.sendMessage,clearMessages:n.clearMessages,conversationId:n.conversationId,conversations:e.conversations,currentConversation:e.currentConversation,isConversationsLoading:e.isLoading,selectConversation:e.selectConversation,startNewConversation:e.startNewConversation,refreshConversations:e.refreshConversations}}function F(o,n){const e=g();(0,t.onMounted)(()=>{e.registerFunction(o,n.handler,{description:n.description,parameters:n.parameters})}),(0,t.onUnmounted)(()=>{e.unregisterFunction(o)})}function S(o,n){const e=g();(0,t.onMounted)(()=>{e.registerNavigationFunction(o,n)}),(0,t.onUnmounted)(()=>{e.unregisterFunction("navigateToPage")})}function _(o,n){const e=g();(0,t.onMounted)(()=>{e.on(o,n)}),(0,t.onUnmounted)(()=>{e.off(o,n)})}function D(o){const n=(0,t.shallowRef)(o.get());return(0,t.onScopeDispose)(o.subscribe(e=>{n.value=e})),n}exports.AGO_CLIENT_KEY=I;exports.AgoPlugin=y;exports.useAgo=g;exports.useAgoEvents=_;exports.useAgoFunction=F;exports.useAgoNavigation=S;exports.useAgoStore=D;exports.useChat=N;exports.useConversation=M;exports.useMessages=E;
package/dist/vue.d.cts CHANGED
@@ -224,6 +224,11 @@ declare interface AgoClientEvents {
224
224
  conversationId: string;
225
225
  messageId: string;
226
226
  };
227
+ /**
228
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
229
+ * replies may still be pending. Fires once, before `message:complete`.
230
+ */
231
+ "message:answer-complete": AgoMessage;
227
232
  "message:complete": AgoMessage;
228
233
  "message:error": {
229
234
  error: string;
package/dist/vue.d.ts CHANGED
@@ -224,6 +224,11 @@ declare interface AgoClientEvents {
224
224
  conversationId: string;
225
225
  messageId: string;
226
226
  };
227
+ /**
228
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
229
+ * replies may still be pending. Fires once, before `message:complete`.
230
+ */
231
+ "message:answer-complete": AgoMessage;
227
232
  "message:complete": AgoMessage;
228
233
  "message:error": {
229
234
  error: string;
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as A } from "./AgoClient-rvTz2thR.js";
1
+ import { t as A } from "./AgoClient-BrYhSO5M.js";
2
2
  import { computed as y, inject as F, onMounted as g, onScopeDispose as N, onUnmounted as I, ref as c, shallowRef as D } from "vue";
3
3
  var L = /* @__PURE__ */ Symbol("ago-client"), b = { install(t, n) {
4
4
  const e = new A(n);
package/dist/widget.cjs CHANGED
@@ -1,5 +1,5 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ke=require("./AgoClient-D4EL6nva.cjs"),$e=require("./createFormCollector-IO6bfPQx.cjs"),Ie=require("./createConversationSession-DGcM_Z3f.cjs");var Te={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function M(o){return o.replace(/[&<>"']/g,n=>Te[n])}function se(o){const n=o.trim();return/^(https?:|mailto:|tel:|#|\/|\.\/|\.\.\/)/i.test(n)||!/^[a-z][a-z0-9+.-]*:/i.test(n)?n:null}var pe='"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace',q="";function O(o){const n=[],r=u=>(n.push(u),`${q}${n.length-1}${q}`);let e=o;return e=e.replace(/`([^`]+)`/g,(u,a)=>r(`<code style="background:#f0f2f5;padding:2px 5px;border-radius:4px;font-size:13px;font-family:${pe}">${M(a)}</code>`)),e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(u,a,d)=>{const i=se(d);return i?r(`<img alt="${M(a)}" src="${M(i)}" style="max-width:100%;border-radius:8px;margin:4px 0" />`):u}),e=e.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(u,a,d)=>{const i=se(d);return i?r(`<a href="${M(i)}" target="_blank" rel="noopener noreferrer" style="color:#1b5fc4;text-decoration:underline">${O(a)}</a>`):u}),e=M(e),e=e.replace(/\*\*([^*]+?)\*\*/g,"<strong>$1</strong>").replace(/__([^_]+?)__/g,"<strong>$1</strong>").replace(/~~([^~]+?)~~/g,"<del>$1</del>").replace(/(^|[^*])\*(?!\s)([^*]+?)\*/g,"$1<em>$2</em>").replace(/(^|[^\w_])_(?!\s)([^_]+?)_/g,"$1<em>$2</em>"),e=e.replace(new RegExp(`${q}(\\d+)${q}`,"g"),(u,a)=>n[Number(a)]),e}function y(o,n,r){const e=document.createElement(o);return Object.assign(e.style,n),r!==void 0&&(e.innerHTML=r),e}var fe=/^ {0,3}([-*_])( *\1){2,} *$/,ue=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/,ge=/^ {0,3}(```+|~~~+)/,j=/^ {0,3}>\s?/,H=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/,Ae=["20px","18px","16px","15px","14px","13px"],Z=o=>o.match(/^\s*/)?.[0].length??0;function Le(o){return o.trim()===""||fe.test(o)||ue.test(o)||ge.test(o)||j.test(o)||H.test(o)}function me(o){const n=o[0].match(H),r=n[1].length,e=/\d/.test(n[2]),u=y(e?"ol":"ul",{margin:"0 0 8px 0",paddingLeft:"20px",listStyleType:e?"decimal":"disc",listStylePosition:"outside"});let a=0;for(;a<o.length;){const d=o[a].match(H),i=[];for(a++;a<o.length&&Z(o[a])>r;)i.push(o[a]),a++;const c=y("li",{display:"list-item",margin:"2px 0",lineHeight:"1.6"}),l=d[3].match(/^\[([ xX])\]\s+(.*)$/);l?(c.style.listStyleType="none",c.style.marginLeft="-20px",c.innerHTML=`<span style="margin-right:6px">${l[1].toLowerCase()==="x"?"☑":"☐"}</span>${O(l[2])}`):c.innerHTML=O(d[3]),i.filter(h=>H.test(h)).length>0&&c.appendChild(me(i.filter(h=>h.trim()!==""))),u.appendChild(c)}return u}function Oe(o){const n=i=>i.replace(/^\s*\|?/,"").replace(/\|?\s*$/,"").split("|").map(c=>c.trim()),r=y("div",{overflowX:"auto",margin:"0 0 8px 0"}),e=y("table",{borderCollapse:"collapse",width:"100%",fontSize:"13px"}),u=document.createElement("thead"),a=document.createElement("tr");for(const i of n(o[0]))a.appendChild(y("th",{border:"1px solid #dee3e8",padding:"6px 10px",textAlign:"left",backgroundColor:"#f5f7fa",fontWeight:"600"},O(i)));u.appendChild(a),e.appendChild(u);const d=document.createElement("tbody");for(const i of o.slice(2)){const c=document.createElement("tr");for(const l of n(i))c.appendChild(y("td",{border:"1px solid #dee3e8",padding:"6px 10px"},O(l)));d.appendChild(c)}return e.appendChild(d),r.appendChild(e),r}var Ne=o=>!!o&&/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o);function J(o){const n=document.createDocumentFragment(),r=o.replace(/\r\n?/g,`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Ie=require("./AgoClient-CPqPT5s6.cjs"),Te=require("./createFormCollector-DaWZsBsI.cjs"),Ne=require("./createConversationSession-CGRO0bs2.cjs");var Oe={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function H(o){return o.replace(/[&<>"']/g,n=>Oe[n])}function ce(o){const n=o.trim();return/^(https?:|mailto:|tel:|#|\/|\.\/|\.\.\/)/i.test(n)||!/^[a-z][a-z0-9+.-]*:/i.test(n)?n:null}var ge='"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace',q="";function L(o){const n=[],r=u=>(n.push(u),`${q}${n.length-1}${q}`);let e=o;return e=e.replace(/`([^`]+)`/g,(u,a)=>r(`<code style="background:#f0f2f5;padding:2px 5px;border-radius:4px;font-size:13px;font-family:${ge}">${H(a)}</code>`)),e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(u,a,p)=>{const i=ce(p);return i?r(`<img alt="${H(a)}" src="${H(i)}" style="max-width:100%;border-radius:8px;margin:4px 0" />`):u}),e=e.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(u,a,p)=>{const i=ce(p);return i?r(`<a href="${H(i)}" target="_blank" rel="noopener noreferrer" style="color:#1b5fc4;text-decoration:underline">${L(a)}</a>`):u}),e=H(e),e=e.replace(/\*\*([^*]+?)\*\*/g,"<strong>$1</strong>").replace(/__([^_]+?)__/g,"<strong>$1</strong>").replace(/~~([^~]+?)~~/g,"<del>$1</del>").replace(/(^|[^*])\*(?!\s)([^*]+?)\*/g,"$1<em>$2</em>").replace(/(^|[^\w_])_(?!\s)([^_]+?)_/g,"$1<em>$2</em>"),e=e.replace(new RegExp(`${q}(\\d+)${q}`,"g"),(u,a)=>n[Number(a)]),e}function w(o,n,r){const e=document.createElement(o);return Object.assign(e.style,n),r!==void 0&&(e.innerHTML=r),e}var he=/^ {0,3}([-*_])( *\1){2,} *$/,me=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/,xe=/^ {0,3}(```+|~~~+)/,X=/^ {0,3}>\s?/,B=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/,Ae=["20px","18px","16px","15px","14px","13px"],J=o=>o.match(/^\s*/)?.[0].length??0;function Le(o){return o.trim()===""||he.test(o)||me.test(o)||xe.test(o)||X.test(o)||B.test(o)}function be(o){const n=o[0].match(B),r=n[1].length,e=/\d/.test(n[2]),u=w(e?"ol":"ul",{margin:"0 0 8px 0",paddingLeft:"20px",listStyleType:e?"decimal":"disc",listStylePosition:"outside"});let a=0;for(;a<o.length;){const p=o[a].match(B),i=[];for(a++;a<o.length&&J(o[a])>r;)i.push(o[a]),a++;const f=w("li",{display:"list-item",margin:"2px 0",lineHeight:"1.6"}),d=p[3].match(/^\[([ xX])\]\s+(.*)$/);d?(f.style.listStyleType="none",f.style.marginLeft="-20px",f.innerHTML=`<span style="margin-right:6px">${d[1].toLowerCase()==="x"?"☑":"☐"}</span>${L(d[2])}`):f.innerHTML=L(p[3]),i.filter(b=>B.test(b)).length>0&&f.appendChild(be(i.filter(b=>b.trim()!==""))),u.appendChild(f)}return u}function De(o){const n=i=>i.replace(/^\s*\|?/,"").replace(/\|?\s*$/,"").split("|").map(f=>f.trim()),r=w("div",{overflowX:"auto",margin:"0 0 8px 0"}),e=w("table",{borderCollapse:"collapse",width:"100%",fontSize:"13px"}),u=document.createElement("thead"),a=document.createElement("tr");for(const i of n(o[0]))a.appendChild(w("th",{border:"1px solid #dee3e8",padding:"6px 10px",textAlign:"left",backgroundColor:"#f5f7fa",fontWeight:"600"},L(i)));u.appendChild(a),e.appendChild(u);const p=document.createElement("tbody");for(const i of o.slice(2)){const f=document.createElement("tr");for(const d of n(i))f.appendChild(w("td",{border:"1px solid #dee3e8",padding:"6px 10px"},L(d)));p.appendChild(f)}return e.appendChild(p),r.appendChild(e),r}var Me=o=>!!o&&/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(o);function ee(o){const n=document.createDocumentFragment(),r=o.replace(/\r\n?/g,`
2
2
  `).split(`
3
- `);let e=0;for(;e<r.length;){const a=r[e];if(a.trim()===""){e++;continue}const d=a.match(ge);if(d){const l=d[1][0],h=[];for(e++;e<r.length&&!new RegExp(`^ {0,3}${l==="`"?"`{3,}":"~{3,}"}\\s*$`).test(r[e]);)h.push(r[e]),e++;e++;const T=y("pre",{margin:"0 0 8px 0"});T.appendChild(y("code",{display:"block",background:"#f5f5f5",padding:"8px 12px",borderRadius:"6px",fontSize:"13px",overflowX:"auto",fontFamily:pe,whiteSpace:"pre"},M(h.join(`
4
- `)))),n.appendChild(T);continue}if(fe.test(a)){n.appendChild(y("hr",{border:"none",borderTop:"1px solid #dee3e8",margin:"12px 0"})),e++;continue}const i=a.match(ue);if(i){const l=i[1].length;n.appendChild(y(`h${l}`,{margin:"16px 0 8px 0",fontSize:Ae[l-1],fontWeight:"600",lineHeight:"1.3"},O(i[2]))),e++;continue}if(j.test(a)){const l=[];for(;e<r.length&&j.test(r[e]);)l.push(r[e].replace(j,"")),e++;const h=y("blockquote",{borderLeft:"4px solid #dee3e8",paddingLeft:"12px",margin:"0 0 8px 0",fontStyle:"italic",color:"#6b6d6f"});h.appendChild(J(l.join(`
5
- `))),n.appendChild(h);continue}if(a.includes("|")&&Ne(r[e+1])){const l=[a,r[e+1]];for(e+=2;e<r.length&&r[e].includes("|")&&r[e].trim();)l.push(r[e]),e++;n.appendChild(Oe(l));continue}if(H.test(a)){const l=[],h=Z(a);for(;e<r.length&&r[e].trim()!=="";)if(H.test(r[e])||Z(r[e])>h)l.push(r[e]),e++;else break;n.appendChild(me(l));continue}const c=[a];for(e++;e<r.length&&!Le(r[e]);)c.push(r[e]),e++;n.appendChild(y("p",{margin:"0 0 8px 0",lineHeight:"1.6"},c.map(l=>O(l)).join("<br>")))}const u=n.lastElementChild;return u&&(u.style.marginBottom="0"),n}var he='var(--ago-font, "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)',le={font:"--ago-font",radius:"--ago-radius",messageRadius:"--ago-message-radius",brand:"--ago-brand-color",brandText:"--ago-brand-text-color",headerBg:"--ago-header-background",headerText:"--ago-header-text-color",panelBg:"--ago-panel-background",messagesBg:"--ago-messages-background",text:"--ago-text-color",mutedText:"--ago-muted-text-color",border:"--ago-border-color",accent:"--ago-accent-color"},xe="var(--ago-brand-color, #03182f)",be="var(--ago-brand-text-color, #fff)",De="var(--ago-header-background, var(--ago-brand-color, #03182f))",Me="var(--ago-header-text-color, #e8f0fe)",z="var(--ago-panel-background, #fff)",He="var(--ago-messages-background, #fbfbfb)",G="var(--ago-text-color, #30373e)",Be="var(--ago-muted-text-color, #6b6d6f)",k="var(--ago-border-color, #dee3e8)",Y="var(--ago-accent-color, #1b5fc4)",ze="var(--ago-radius, 16px)",de="var(--ago-message-radius, 16px)";function Ue(o,n){if(n)for(const r of Object.keys(le)){const e=n[r];e!=null&&o.style.setProperty(le[r],e)}}function E(o,n){Object.assign(o.style,n)}function C(o={}){const n=document.createElement("div");return E(n,o),n}var ce="ago-chat-widget-keyframes";function Fe(){if(typeof document>"u"||document.getElementById(ce))return;const o=document.createElement("style");o.id=ce,o.textContent="@keyframes ago-pulse { 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } 40% { opacity: 1; transform: scale(1); } }",document.head.appendChild(o)}function We(o){const n=typeof o=="string"?document.querySelector(o):o;if(!n)throw new Error(`mountChatWidget: target "${String(o)}" not found.`);return n}function Pe(o,n){const{title:r="Chat",welcomeMessage:e="Hello! How can I help you today?",placeholder:u="Type a message...",allowFiles:a=!1,height:d=500,logoUrl:i,showAgentName:c=!1,theme:l,loadThreads:h=!1,forms:T,onFollowUpClick:m,onMessageSent:_,onMessageReceived:U}=n;if(!n.client&&!n.config?.baseUrl)throw new Error("mountChatWidget requires either `client` or `config` (with a baseUrl).");const x=n.client??new ke.AgoClient(n.config),A=We(o),F=n.persistConversation,N=F?Ie.createConversationSession(F===!0?{}:F):void 0;let w=n.conversationId??N?.getLastActiveThread()??void 0,p=[],L=!1,B=null;const W=[],D=C({display:"flex",flexDirection:"column",height:typeof d=="number"?`${d}px`:d,border:`1px solid ${k}`,borderRadius:ze,overflow:"hidden",backgroundColor:z,fontFamily:he,textAlign:"left",boxShadow:"rgba(15, 15, 15, 0.08) 0px 2px 16px 0px"});D.className="ago-chat-widget",Ue(D,l);const P=C({padding:"14px 16px",borderBottom:`1px solid ${k}`,backgroundColor:De,color:Me,display:"flex",alignItems:"center",gap:"10px"});if(P.className="ago-chat-widget__header",i){const t=document.createElement("img");t.src=i,t.alt="Logo",E(t,{height:"24px",width:"auto"}),P.appendChild(t)}const X=document.createElement("h3");X.textContent=r,E(X,{margin:"0",fontSize:"15px",fontWeight:"600"}),P.appendChild(X);const $=C({flex:"1",overflow:"auto",padding:"16px",backgroundColor:He});$.className="ago-chat-widget__messages";const{inputRow:Ce,setDisabled:ve,focus:ye}=qe({placeholder:u,allowFiles:a,onSend:(t,s)=>{K(t,s)}});Fe(),D.append(P,$,Ce),A.appendChild(D);const ee=m!==!1,te=m===!1?void 0:m??(t=>{K(t)});function Ee(t){const s=t.role==="user",b=C({display:"flex",flexDirection:"column",alignItems:s?"flex-end":"flex-start",marginBottom:"16px"});if(b.className=`ago-message ago-message--${t.role}`,!s&&c&&t.agent){const f=C({fontSize:"13px",fontWeight:"500",color:G,marginBottom:"6px",padding:"0 4px"});f.className="ago-message__agent",f.textContent=t.agent.displayName||t.agent.name,b.appendChild(f)}if(!s&&t.sources&&t.sources.length>0){const f=C({display:"grid",gridTemplateColumns:"1fr 1fr",gap:"6px",marginBottom:"10px",width:"100%",maxWidth:"85%"});f.className="ago-message__sources",t.sources.forEach((v,g)=>{const R=v.url?document.createElement("a"):document.createElement("div");v.url&&R instanceof HTMLAnchorElement&&(R.href=v.url,R.target="_blank",R.rel="noopener noreferrer"),E(R,{display:"flex",alignItems:"center",gap:"8px",padding:"8px 10px",border:`1px solid ${k}`,borderRadius:"8px",backgroundColor:z,textDecoration:"none",color:G,fontSize:"12px",overflow:"hidden"});const ie=C({flexShrink:"0",width:"18px",height:"18px",borderRadius:"3px",border:`1px solid ${Y}`,color:Y,fontSize:"11px",fontWeight:"500",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"#f0f4ff"});ie.textContent=String(g+1);const Q=C({overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});Q.textContent=v.title,Q.title=v.title,R.append(ie,Q),f.appendChild(R)}),b.appendChild(f)}const S=C({maxWidth:s?"75%":"100%",padding:s?"10px 14px":"2px 8px",borderRadius:s?de:"0",backgroundColor:s?xe:"transparent",color:s?be:G,wordBreak:"break-word",fontSize:"14px",lineHeight:"1.6"});if(S.className="ago-message__content",t.content?S.appendChild(J(t.content)):t.status==="IN_PROGRESS"&&S.appendChild(Re()),b.appendChild(S),t.followUpReplies&&t.followUpReplies.length>0){const f=C({display:"flex",flexWrap:"wrap",gap:"8px",marginTop:"10px"});f.className="ago-message__followups";for(const v of t.followUpReplies){const g=document.createElement("button");g.type="button",g.className="ago-message__followup-btn",g.textContent=v,g.disabled=!ee,E(g,{padding:"6px 14px",fontSize:"13px",borderRadius:de,border:`1px solid ${k}`,backgroundColor:z,color:G,cursor:ee?"pointer":"default",transition:"border-color 0.15s"}),te&&g.addEventListener("click",()=>te(v)),g.addEventListener("mouseenter",()=>{g.style.borderColor=Y}),g.addEventListener("mouseleave",()=>{g.style.borderColor=k}),f.appendChild(g)}b.appendChild(f)}return b}function I(){if($.replaceChildren(),p.length===0){const t=C({textAlign:"center",color:Be,padding:"24px 16px",fontSize:"14px",lineHeight:"1.5"});t.textContent=e,$.appendChild(t)}else for(const t of p)$.appendChild(Ee(t));if(B){const t=C({padding:"10px 14px",backgroundColor:"#fef2f2",color:"#dc2626",borderRadius:"12px",marginTop:"8px",fontSize:"13px",border:"1px solid #fecaca"});t.textContent=B,$.appendChild(t)}$.scrollTop=$.scrollHeight,ve(L)}function we(){for(let t=p.length-1;t>=0;t--){const s=p[t];if(s.role==="assistant"&&s.status==="IN_PROGRESS")return s}}const ne=t=>{w||(w=t.conversationId)},oe=t=>{const s=we();s&&(s.content+=t.content,I())},re=t=>{const s=p.findIndex(b=>b.id===t.id||b.role==="assistant"&&b.status==="IN_PROGRESS");s>=0?p[s]=t:p.push(t),L=!1,I(),t.status==="DONE"&&U?.({id:t.id,content:t.content})},ae=t=>{B=t.error,L=!1,p=p.filter(s=>!s.id.startsWith("temp-")),I()};x.on("message:start",ne),x.on("message:chunk",oe),x.on("message:complete",re),x.on("message:error",ae);const Se=(T??[]).map(t=>$e.createFormCollector(t).install(x));async function K(t,s){const b=t.trim();if(!b&&!s?.length||L)return;_?.(b),L=!0,B=null;const S=Date.now();p.push({id:`temp-user-${S}`,conversationId:w||"",content:b,role:"user",status:"DONE",createdAt:new Date}),p.push({id:`temp-assistant-${S}`,conversationId:w||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date}),I();try{const f=await x.sendMessage(b,{conversationId:w,files:s});f.conversationId&&(w||(w=f.conversationId),N?.setActiveThread(f.conversationId,f.createdAt));const v=p.find(g=>g.id===`temp-user-${S}`);if(v&&(v.id=`user-${S}`,v.conversationId=f.conversationId),!p.some(g=>g.id===f.id)){const g=p.findIndex(R=>R.id===`temp-assistant-${S}`);g>=0?p[g]=f:p.push(f)}p=p.filter(g=>!g.id.startsWith("temp-")),L=!1,I(),h&&V()}catch(f){B=f instanceof Error?f.message:"Failed to send message",L=!1,p=p.filter(v=>!v.id.startsWith("temp-")),I()}}async function V(){try{const t=await x.getConversations();W.splice(0,W.length,...t)}catch{}return W}async function _e(t){try{const s=(await x.getConversation(t))?.messages??[];s.length>0&&p.length===0&&(p=s,I())}catch{p.length===0&&(N?.clear(),w=void 0)}}return I(),ye(),w&&_e(w),h&&V(),{client:x,element:D,sendMessage:K,session:N,threads:W,refreshThreads:V,destroy(){x.off("message:start",ne),x.off("message:chunk",oe),x.off("message:complete",re),x.off("message:error",ae),Se.forEach(t=>t()),D.remove(),n.client||x.destroy()}};function Re(){const t=C({display:"flex",gap:"4px",padding:"4px 0"});for(let s=0;s<3;s++){const b=C({width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"#b5bfc8",animation:"ago-pulse 1.2s ease-in-out infinite",animationDelay:`${s*.2}s`});t.appendChild(b)}return t}}function qe(o){let n=[];const r=document.createElement("form");E(r,{display:"flex",flexDirection:"column",gap:"8px",padding:"12px",borderTop:`1px solid ${k}`,backgroundColor:z}),r.className="ago-chat-input";const e=C({display:"flex",flexWrap:"wrap",gap:"6px"}),u=C({display:"flex",gap:"8px",alignItems:"flex-end"}),a=document.createElement("textarea");a.placeholder=o.placeholder,a.rows=1,E(a,{flex:"1",resize:"none",padding:"10px 12px",border:`1px solid ${k}`,borderRadius:"12px",fontSize:"14px",fontFamily:he,lineHeight:"1.4",maxHeight:"120px",outline:"none"});const d=document.createElement("button");d.type="submit",d.textContent="Send",E(d,{padding:"10px 16px",border:"none",borderRadius:"12px",backgroundColor:xe,color:be,fontSize:"14px",fontWeight:"500",cursor:"pointer"});let i=null,c=null;o.allowFiles&&(i=document.createElement("input"),i.type="file",i.multiple=!0,E(i,{display:"none"}),c=document.createElement("button"),c.type="button",c.textContent="📎",E(c,{padding:"10px 12px",border:`1px solid ${k}`,borderRadius:"12px",backgroundColor:z,cursor:"pointer",fontSize:"14px"}),c.addEventListener("click",()=>i?.click()),i.addEventListener("change",()=>{n=[...n,...Array.from(i?.files??[])],l()}));function l(){e.replaceChildren(),n.forEach((m,_)=>{const U=C({display:"flex",alignItems:"center",gap:"4px",padding:"4px 8px",backgroundColor:"#f0f4ff",border:`1px solid ${k}`,borderRadius:"8px",fontSize:"12px"}),x=document.createElement("span");x.textContent=m.name;const A=document.createElement("button");A.type="button",A.textContent="×",E(A,{border:"none",background:"transparent",cursor:"pointer",fontSize:"14px",lineHeight:"1"}),A.addEventListener("click",()=>{n=n.filter((F,N)=>N!==_),l()}),U.append(x,A),e.appendChild(U)})}const h=()=>{const m=a.value,_=n;return a.value="",n=[],l(),{content:m,files:_}},T=()=>{const{content:m,files:_}=h();(m.trim()||_.length>0)&&o.onSend(m.trim(),_.length>0?_:void 0)};return r.addEventListener("submit",m=>{m.preventDefault(),T()}),a.addEventListener("keydown",m=>{m.key==="Enter"&&!m.shiftKey&&(m.preventDefault(),T())}),c&&u.appendChild(c),u.append(a,d),i&&r.appendChild(i),r.append(e,u),{inputRow:r,getValueAndClear:h,setDisabled:m=>{a.disabled=m,d.disabled=m,d.style.opacity=m?"0.6":"1",d.style.cursor=m?"not-allowed":"pointer"},focus:()=>a.focus()}}exports.mountChatWidget=Pe;exports.renderMarkdown=J;
3
+ `);let e=0;for(;e<r.length;){const a=r[e];if(a.trim()===""){e++;continue}const p=a.match(xe);if(p){const d=p[1][0],b=[];for(e++;e<r.length&&!new RegExp(`^ {0,3}${d==="`"?"`{3,}":"~{3,}"}\\s*$`).test(r[e]);)b.push(r[e]),e++;e++;const N=w("pre",{margin:"0 0 8px 0"});N.appendChild(w("code",{display:"block",background:"#f5f5f5",padding:"8px 12px",borderRadius:"6px",fontSize:"13px",overflowX:"auto",fontFamily:ge,whiteSpace:"pre"},H(b.join(`
4
+ `)))),n.appendChild(N);continue}if(he.test(a)){n.appendChild(w("hr",{border:"none",borderTop:"1px solid #dee3e8",margin:"12px 0"})),e++;continue}const i=a.match(me);if(i){const d=i[1].length;n.appendChild(w(`h${d}`,{margin:"16px 0 8px 0",fontSize:Ae[d-1],fontWeight:"600",lineHeight:"1.3"},L(i[2]))),e++;continue}if(X.test(a)){const d=[];for(;e<r.length&&X.test(r[e]);)d.push(r[e].replace(X,"")),e++;const b=w("blockquote",{borderLeft:"4px solid #dee3e8",paddingLeft:"12px",margin:"0 0 8px 0",fontStyle:"italic",color:"#6b6d6f"});b.appendChild(ee(d.join(`
5
+ `))),n.appendChild(b);continue}if(a.includes("|")&&Me(r[e+1])){const d=[a,r[e+1]];for(e+=2;e<r.length&&r[e].includes("|")&&r[e].trim();)d.push(r[e]),e++;n.appendChild(De(d));continue}if(B.test(a)){const d=[],b=J(a);for(;e<r.length&&r[e].trim()!=="";)if(B.test(r[e])||J(r[e])>b)d.push(r[e]),e++;else break;n.appendChild(be(d));continue}const f=[a];for(e++;e<r.length&&!Le(r[e]);)f.push(r[e]),e++;n.appendChild(w("p",{margin:"0 0 8px 0",lineHeight:"1.6"},f.map(d=>L(d)).join("<br>")))}const u=n.lastElementChild;return u&&(u.style.marginBottom="0"),n}var Ce='var(--ago-font, "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif)',pe={font:"--ago-font",radius:"--ago-radius",messageRadius:"--ago-message-radius",brand:"--ago-brand-color",brandText:"--ago-brand-text-color",headerBg:"--ago-header-background",headerText:"--ago-header-text-color",panelBg:"--ago-panel-background",messagesBg:"--ago-messages-background",text:"--ago-text-color",mutedText:"--ago-muted-text-color",border:"--ago-border-color",accent:"--ago-accent-color"},ve="var(--ago-brand-color, #03182f)",ye="var(--ago-brand-text-color, #fff)",He="var(--ago-header-background, var(--ago-brand-color, #03182f))",Be="var(--ago-header-text-color, #e8f0fe)",z="var(--ago-panel-background, #fff)",Ue="var(--ago-messages-background, #fbfbfb)",j="var(--ago-text-color, #30373e)",ze="var(--ago-muted-text-color, #6b6d6f)",$="var(--ago-border-color, #dee3e8)",Z="var(--ago-accent-color, #1b5fc4)",Fe="var(--ago-radius, 16px)",fe="var(--ago-message-radius, 16px)";function We(o,n){if(n)for(const r of Object.keys(pe)){const e=n[r];e!=null&&o.style.setProperty(pe[r],e)}}function S(o,n){Object.assign(o.style,n)}function x(o={}){const n=document.createElement("div");return S(n,o),n}var ue="ago-chat-widget-keyframes";function Pe(){if(typeof document>"u"||document.getElementById(ue))return;const o=document.createElement("style");o.id=ue,o.textContent="@keyframes ago-pulse { 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } 40% { opacity: 1; transform: scale(1); } }",document.head.appendChild(o)}function Ge(o){const n=typeof o=="string"?document.querySelector(o):o;if(!n)throw new Error(`mountChatWidget: target "${String(o)}" not found.`);return n}function qe(o,n){const{title:r="Chat",welcomeMessage:e="Hello! How can I help you today?",placeholder:u="Type a message...",allowFiles:a=!1,height:p=500,logoUrl:i,showAgentName:f=!1,theme:d,loadThreads:b=!1,forms:N,onFollowUpClick:g,onMessageSent:_,onMessageReceived:F}=n;if(!n.client&&!n.config?.baseUrl)throw new Error("mountChatWidget requires either `client` or `config` (with a baseUrl).");const m=n.client??new Ie.AgoClient(n.config),O=Ge(o),W=n.persistConversation,D=W?Ne.createConversationSession(W===!0?{}:W):void 0;let R=n.conversationId??D?.getLastActiveThread()??void 0,l=[],I=!1,U=null;const P=[],M=x({display:"flex",flexDirection:"column",height:typeof p=="number"?`${p}px`:p,border:`1px solid ${$}`,borderRadius:Fe,overflow:"hidden",backgroundColor:z,fontFamily:Ce,textAlign:"left",boxShadow:"rgba(15, 15, 15, 0.08) 0px 2px 16px 0px"});M.className="ago-chat-widget",We(M,d);const G=x({padding:"14px 16px",borderBottom:`1px solid ${$}`,backgroundColor:He,color:Be,display:"flex",alignItems:"center",gap:"10px"});if(G.className="ago-chat-widget__header",i){const t=document.createElement("img");t.src=i,t.alt="Logo",S(t,{height:"24px",width:"auto"}),G.appendChild(t)}const K=document.createElement("h3");K.textContent=r,S(K,{margin:"0",fontSize:"15px",fontWeight:"600"}),G.appendChild(K);const T=x({flex:"1",overflow:"auto",padding:"16px",backgroundColor:Ue});T.className="ago-chat-widget__messages";const{inputRow:Ee,setDisabled:we,focus:Se}=je({placeholder:u,allowFiles:a,onSend:(t,s)=>{V(t,s)}});Pe(),M.append(G,T,Ee),O.appendChild(M);const te=g!==!1,ne=g===!1?void 0:g??(t=>{V(t)});function Re(t,s){const c=t.role==="user",E=x({display:"flex",flexDirection:"column",alignItems:c?"flex-end":"flex-start",marginBottom:"16px"});if(E.className=`ago-message ago-message--${t.role}`,!c&&f&&t.agent){const h=x({fontSize:"13px",fontWeight:"500",color:j,marginBottom:"6px",padding:"0 4px"});h.className="ago-message__agent",h.textContent=t.agent.displayName||t.agent.name,E.appendChild(h)}if(!c&&t.sources&&t.sources.length>0){const h=x({display:"grid",gridTemplateColumns:"1fr 1fr",gap:"6px",marginBottom:"10px",width:"100%",maxWidth:"85%"});h.className="ago-message__sources",t.sources.forEach((C,y)=>{const A=C.url?document.createElement("a"):document.createElement("div");C.url&&A instanceof HTMLAnchorElement&&(A.href=C.url,A.target="_blank",A.rel="noopener noreferrer"),S(A,{display:"flex",alignItems:"center",gap:"8px",padding:"8px 10px",border:`1px solid ${$}`,borderRadius:"8px",backgroundColor:z,textDecoration:"none",color:j,fontSize:"12px",overflow:"hidden"});const de=x({flexShrink:"0",width:"18px",height:"18px",borderRadius:"3px",border:`1px solid ${Z}`,color:Z,fontSize:"11px",fontWeight:"500",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"#f0f4ff"});de.textContent=String(y+1);const Y=x({overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});Y.textContent=C.title,Y.title=C.title,A.append(de,Y),h.appendChild(A)}),E.appendChild(h)}const v=x({maxWidth:c?"75%":"100%",padding:c?"10px 14px":"2px 8px",borderRadius:c?fe:"0",backgroundColor:c?ve:"transparent",color:c?ye:j,wordBreak:"break-word",fontSize:"14px",lineHeight:"1.6"});if(v.className="ago-message__content",t.content?v.appendChild(ee(t.content)):t.status==="IN_PROGRESS"&&v.appendChild(le()),E.appendChild(v),s&&I&&t.role==="assistant"&&t.status==="DONE"&&!(t.followUpReplies&&t.followUpReplies.length>0)){const h=x({marginTop:"10px",paddingLeft:"8px"});h.className="ago-message__followups-loading",h.appendChild(le()),E.appendChild(h)}if(s&&t.followUpReplies&&t.followUpReplies.length>0){const h=x({display:"flex",flexWrap:"wrap",gap:"8px",marginTop:"10px"});h.className="ago-message__followups";for(const C of t.followUpReplies){const y=document.createElement("button");y.type="button",y.className="ago-message__followup-btn",y.textContent=C,y.disabled=!te,S(y,{padding:"6px 14px",fontSize:"13px",borderRadius:fe,border:`1px solid ${$}`,backgroundColor:z,color:j,cursor:te?"pointer":"default",transition:"border-color 0.15s"}),ne&&y.addEventListener("click",()=>ne(C)),y.addEventListener("mouseenter",()=>{y.style.borderColor=Z}),y.addEventListener("mouseleave",()=>{y.style.borderColor=$}),h.appendChild(y)}E.appendChild(h)}return E}function k(){if(T.replaceChildren(),l.length===0){const s=x({textAlign:"center",color:ze,padding:"24px 16px",fontSize:"14px",lineHeight:"1.5"});s.textContent=e,T.appendChild(s)}else l.forEach((s,c)=>{T.appendChild(Re(s,c===l.length-1))});if(U){const s=x({padding:"10px 14px",backgroundColor:"#fef2f2",color:"#dc2626",borderRadius:"12px",marginTop:"8px",fontSize:"13px",border:"1px solid #fecaca"});s.textContent=U,T.appendChild(s)}T.scrollTop=T.scrollHeight;const t=l[l.length-1];we(I&&t?.role==="assistant"&&t.status==="IN_PROGRESS")}function _e(){for(let t=l.length-1;t>=0;t--){const s=l[t];if(s.role==="assistant"&&s.status==="IN_PROGRESS")return s}}const oe=t=>{R||(R=t.conversationId)},re=t=>{const s=_e();s&&(s.content+=t.content,k())},ae=t=>{const s=l.findIndex(c=>c.id===t.id||c.role==="assistant"&&c.status==="IN_PROGRESS");s>=0?l[s]=t:l.push(t),k()},se=t=>{const s=l.findIndex(c=>c.id===t.id||c.role==="assistant"&&c.status==="IN_PROGRESS");s>=0?l[s]=t:l.push(t),I=!1,k(),t.status==="DONE"&&F?.({id:t.id,content:t.content})},ie=t=>{U=t.error,I=!1,l=l.filter(s=>!s.id.startsWith("temp-")),k()};m.on("message:start",oe),m.on("message:chunk",re),m.on("message:answer-complete",ae),m.on("message:complete",se),m.on("message:error",ie);const ke=(N??[]).map(t=>Te.createFormCollector(t).install(m));async function V(t,s){const c=t.trim();if(!c&&!s?.length||I)return;_?.(c),I=!0,U=null;const E=Date.now();l.push({id:`temp-user-${E}`,conversationId:R||"",content:c,role:"user",status:"DONE",createdAt:new Date}),l.push({id:`temp-assistant-${E}`,conversationId:R||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date}),k();try{const v=await m.sendMessage(c,{conversationId:R,files:s});v.conversationId&&(R||(R=v.conversationId),D?.setActiveThread(v.conversationId,v.createdAt));const h=l.find(C=>C.id===`temp-user-${E}`);if(h&&(h.id=`user-${E}`,h.conversationId=v.conversationId),!l.some(C=>C.id===v.id)){const C=l.findIndex(y=>y.id===`temp-assistant-${E}`);C>=0?l[C]=v:l.push(v)}l=l.filter(C=>!C.id.startsWith("temp-")),I=!1,k(),b&&Q()}catch(v){U=v instanceof Error?v.message:"Failed to send message",I=!1,l=l.filter(h=>!h.id.startsWith("temp-")),k()}}async function Q(){try{const t=await m.getConversations();P.splice(0,P.length,...t)}catch{}return P}async function $e(t){try{const s=(await m.getConversation(t))?.messages??[];s.length>0&&l.length===0&&(l=s,k())}catch{l.length===0&&(D?.clear(),R=void 0)}}return k(),Se(),R&&$e(R),b&&Q(),{client:m,element:M,sendMessage:V,session:D,threads:P,refreshThreads:Q,destroy(){m.off("message:start",oe),m.off("message:chunk",re),m.off("message:answer-complete",ae),m.off("message:complete",se),m.off("message:error",ie),ke.forEach(t=>t()),M.remove(),n.client||m.destroy()}};function le(){const t=x({display:"flex",gap:"4px",padding:"4px 0"});for(let s=0;s<3;s++){const c=x({width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"#b5bfc8",animation:"ago-pulse 1.2s ease-in-out infinite",animationDelay:`${s*.2}s`});t.appendChild(c)}return t}}function je(o){let n=[];const r=document.createElement("form");S(r,{display:"flex",flexDirection:"column",gap:"8px",padding:"12px",borderTop:`1px solid ${$}`,backgroundColor:z}),r.className="ago-chat-input";const e=x({display:"flex",flexWrap:"wrap",gap:"6px"}),u=x({display:"flex",gap:"8px",alignItems:"flex-end"}),a=document.createElement("textarea");a.placeholder=o.placeholder,a.rows=1,S(a,{flex:"1",resize:"none",padding:"10px 12px",border:`1px solid ${$}`,borderRadius:"12px",fontSize:"14px",fontFamily:Ce,lineHeight:"1.4",maxHeight:"120px",outline:"none"});const p=document.createElement("button");p.type="submit",p.textContent="Send",S(p,{padding:"10px 16px",border:"none",borderRadius:"12px",backgroundColor:ve,color:ye,fontSize:"14px",fontWeight:"500",cursor:"pointer"});let i=null,f=null;o.allowFiles&&(i=document.createElement("input"),i.type="file",i.multiple=!0,S(i,{display:"none"}),f=document.createElement("button"),f.type="button",f.textContent="📎",S(f,{padding:"10px 12px",border:`1px solid ${$}`,borderRadius:"12px",backgroundColor:z,cursor:"pointer",fontSize:"14px"}),f.addEventListener("click",()=>i?.click()),i.addEventListener("change",()=>{n=[...n,...Array.from(i?.files??[])],d()}));function d(){e.replaceChildren(),n.forEach((g,_)=>{const F=x({display:"flex",alignItems:"center",gap:"4px",padding:"4px 8px",backgroundColor:"#f0f4ff",border:`1px solid ${$}`,borderRadius:"8px",fontSize:"12px"}),m=document.createElement("span");m.textContent=g.name;const O=document.createElement("button");O.type="button",O.textContent="×",S(O,{border:"none",background:"transparent",cursor:"pointer",fontSize:"14px",lineHeight:"1"}),O.addEventListener("click",()=>{n=n.filter((W,D)=>D!==_),d()}),F.append(m,O),e.appendChild(F)})}const b=()=>{const g=a.value,_=n;return a.value="",n=[],d(),{content:g,files:_}},N=()=>{const{content:g,files:_}=b();(g.trim()||_.length>0)&&o.onSend(g.trim(),_.length>0?_:void 0)};return r.addEventListener("submit",g=>{g.preventDefault(),N()}),a.addEventListener("keydown",g=>{g.key==="Enter"&&!g.shiftKey&&(g.preventDefault(),N())}),f&&u.appendChild(f),u.append(a,p),i&&r.appendChild(i),r.append(e,u),{inputRow:r,getValueAndClear:b,setDisabled:g=>{a.disabled=g,p.disabled=g,p.style.opacity=g?"0.6":"1",p.style.cursor=g?"not-allowed":"pointer"},focus:()=>a.focus()}}exports.mountChatWidget=qe;exports.renderMarkdown=ee;
package/dist/widget.d.cts CHANGED
@@ -216,6 +216,11 @@ declare interface AgoClientEvents {
216
216
  conversationId: string;
217
217
  messageId: string;
218
218
  };
219
+ /**
220
+ * The main answer text is done (backend emitted `status: "DONE"`), but follow-up
221
+ * replies may still be pending. Fires once, before `message:complete`.
222
+ */
223
+ "message:answer-complete": AgoMessage;
219
224
  "message:complete": AgoMessage;
220
225
  "message:error": {
221
226
  error: string;
@@ -763,7 +768,7 @@ declare type ToolCallType = "form" | "confirmation_input" | "status_message" | "
763
768
 
764
769
  /**
765
770
  * Theme overrides for {@link mountChatWidget}. *
766
- * @see The `--ago-*` token reference in `docs/widget.md`.
771
+ * @see The `--ago-*` token reference in `docs/general/widget.md`.
767
772
  */
768
773
  export declare interface WidgetTheme {
769
774
  /** Font family for the whole panel. Pass `"inherit"` to adopt the page font. (`--ago-font`) */