@useago/sdk 0.1.6 → 0.2.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 (79) hide show
  1. package/dist/AgoClient-CNT-8sh_.js +905 -0
  2. package/dist/AgoClient-CNT-8sh_.js.map +1 -0
  3. package/dist/AgoClient-D0l1GTRs.cjs +976 -0
  4. package/dist/AgoClient-D0l1GTRs.cjs.map +1 -0
  5. package/dist/angular/ago.service.d.ts +98 -0
  6. package/dist/angular/index.d.ts +4 -0
  7. package/dist/angular/provide.d.ts +27 -0
  8. package/dist/angular.cjs +143 -0
  9. package/dist/angular.cjs.map +1 -0
  10. package/dist/angular.d.ts +2 -0
  11. package/dist/angular.js +141 -0
  12. package/dist/angular.js.map +1 -0
  13. package/dist/auto/createAgo.d.ts +39 -0
  14. package/dist/auto/index.d.ts +1 -0
  15. package/dist/client/AgoClient.d.ts +56 -0
  16. package/dist/client/types.d.ts +9 -7
  17. package/dist/createMockClient-Ci_N2tH8.cjs +104 -0
  18. package/dist/createMockClient-Ci_N2tH8.cjs.map +1 -0
  19. package/dist/createMockClient-U0ae_AYy.js +99 -0
  20. package/dist/createMockClient-U0ae_AYy.js.map +1 -0
  21. package/dist/functions--c6lx3ic.cjs +480 -0
  22. package/dist/functions--c6lx3ic.cjs.map +1 -0
  23. package/dist/functions-C9F1dnmh.js +398 -0
  24. package/dist/functions-C9F1dnmh.js.map +1 -0
  25. package/dist/helpers/factory.d.ts +20 -0
  26. package/dist/helpers/functions.d.ts +62 -0
  27. package/dist/helpers/index.d.ts +1 -0
  28. package/dist/helpers.cjs +15 -0
  29. package/dist/helpers.d.ts +2 -0
  30. package/dist/helpers.js +2 -0
  31. package/dist/index.cjs +312 -17
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.ts +6 -0
  34. package/dist/index.js +277 -19
  35. package/dist/index.js.map +1 -1
  36. package/dist/react/components/ChatWidget.d.ts +2 -0
  37. package/dist/react/components/Markdown.d.ts +12 -0
  38. package/dist/react/components/Message.d.ts +2 -0
  39. package/dist/react/components/index.d.ts +2 -0
  40. package/dist/react/context/AgoContext.d.ts +30 -4
  41. package/dist/react/context/index.d.ts +1 -1
  42. package/dist/react/hooks/index.d.ts +1 -0
  43. package/dist/react/hooks/useAgoContext.d.ts +40 -0
  44. package/dist/react/hooks/useAgoFunction.d.ts +14 -2
  45. package/dist/react/index.d.ts +4 -1
  46. package/dist/react.cjs +22104 -10273
  47. package/dist/react.cjs.map +1 -1
  48. package/dist/react.d.ts +1 -0
  49. package/dist/react.js +22103 -10289
  50. package/dist/react.js.map +1 -1
  51. package/dist/rolldown-runtime-BqCkTl7Q.cjs +50 -0
  52. package/dist/rolldown-runtime-CNZpIYwj.js +33 -0
  53. package/dist/state/ClientContextRegistry.d.ts +64 -0
  54. package/dist/streaming/helpers.d.ts +67 -0
  55. package/dist/vue/composables/useAgo.d.ts +17 -0
  56. package/dist/vue/composables/useAgoEvents.d.ts +11 -0
  57. package/dist/vue/composables/useAgoFunction.d.ts +34 -0
  58. package/dist/vue/composables/useChat.d.ts +251 -0
  59. package/dist/vue/composables/useConversation.d.ts +178 -0
  60. package/dist/vue/composables/useMessages.d.ts +89 -0
  61. package/dist/vue/index.d.ts +10 -0
  62. package/dist/vue/plugin.d.ts +16 -0
  63. package/dist/vue/symbols.d.ts +3 -0
  64. package/dist/vue.cjs +311 -0
  65. package/dist/vue.cjs.map +1 -0
  66. package/dist/vue.d.ts +2 -0
  67. package/dist/vue.js +301 -0
  68. package/dist/vue.js.map +1 -0
  69. package/dist/widget/types.d.ts +1 -0
  70. package/dist/widget.cjs +0 -2
  71. package/dist/widget.d.ts +1 -0
  72. package/dist/widget.js +0 -2
  73. package/package.json +29 -7
  74. package/dist/createMockClient-BZKh_1em.cjs +0 -941
  75. package/dist/createMockClient-BZKh_1em.cjs.map +0 -1
  76. package/dist/createMockClient-uGlVyjbL.js +0 -942
  77. package/dist/createMockClient-uGlVyjbL.js.map +0 -1
  78. package/dist/widget.cjs.map +0 -1
  79. package/dist/widget.js.map +0 -1
@@ -0,0 +1,905 @@
1
+ //#region src/client/errors.ts
2
+ /**
3
+ * Base error class for AGO SDK
4
+ */
5
+ var AgoError = class extends Error {
6
+ constructor(message, code, statusCode) {
7
+ super(message);
8
+ this.code = code;
9
+ this.statusCode = statusCode;
10
+ this.name = "AgoError";
11
+ }
12
+ };
13
+ /**
14
+ * Error from API response
15
+ */
16
+ var AgoApiError = class AgoApiError extends AgoError {
17
+ constructor(message, code, statusCode, type, param, docUrl) {
18
+ super(message, code, statusCode);
19
+ this.type = type;
20
+ this.param = param;
21
+ this.docUrl = docUrl;
22
+ this.name = "AgoApiError";
23
+ }
24
+ static fromResponse(data, statusCode) {
25
+ const error = data.error;
26
+ return new AgoApiError(error.message, error.code, statusCode, error.type, error.param, error.doc_url);
27
+ }
28
+ };
29
+ /**
30
+ * Network/connection error
31
+ */
32
+ var AgoNetworkError = class extends AgoError {
33
+ constructor(message, originalError) {
34
+ super(message, "network_error");
35
+ this.originalError = originalError;
36
+ this.name = "AgoNetworkError";
37
+ }
38
+ };
39
+ /**
40
+ * SSE stream error
41
+ */
42
+ var AgoStreamError = class extends AgoError {
43
+ constructor(message) {
44
+ super(message, "stream_error");
45
+ this.name = "AgoStreamError";
46
+ }
47
+ };
48
+ /**
49
+ * Function execution error
50
+ */
51
+ var AgoFunctionError = class extends AgoError {
52
+ constructor(message, functionName, originalError) {
53
+ super(message, "function_error");
54
+ this.functionName = functionName;
55
+ this.originalError = originalError;
56
+ this.name = "AgoFunctionError";
57
+ }
58
+ };
59
+ //#endregion
60
+ //#region src/utils/logger.ts
61
+ /**
62
+ * Debug logger for SDK
63
+ */
64
+ var Logger = class {
65
+ constructor(enabled = false) {
66
+ this.enabled = enabled;
67
+ }
68
+ enable() {
69
+ this.enabled = true;
70
+ }
71
+ disable() {
72
+ this.enabled = false;
73
+ }
74
+ log(...args) {
75
+ if (this.enabled) console.log("[AGO SDK]", ...args);
76
+ }
77
+ warn(...args) {
78
+ if (this.enabled) console.warn("[AGO SDK]", ...args);
79
+ }
80
+ error(...args) {
81
+ console.error("[AGO SDK]", ...args);
82
+ }
83
+ debug(...args) {
84
+ if (this.enabled) console.debug("[AGO SDK]", ...args);
85
+ }
86
+ };
87
+ var logger = new Logger();
88
+ //#endregion
89
+ //#region src/api/HttpClient.ts
90
+ var WIDGET_ID_KEY = "ago_widget_id";
91
+ function generateWidgetId() {
92
+ if (typeof localStorage !== "undefined") {
93
+ const stored = localStorage.getItem(WIDGET_ID_KEY);
94
+ if (stored) return stored;
95
+ }
96
+ const id = crypto.randomUUID();
97
+ if (typeof localStorage !== "undefined") try {
98
+ localStorage.setItem(WIDGET_ID_KEY, id);
99
+ } catch {}
100
+ return id;
101
+ }
102
+ /**
103
+ * HTTP client with authentication headers
104
+ */
105
+ var HttpClient = class {
106
+ constructor(config) {
107
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
108
+ this.headers = { "X-Widget-Id": config.widgetId || generateWidgetId() };
109
+ if (config.userEmail) this.headers["X-User-Email"] = config.userEmail;
110
+ if (config.userJwt) this.headers["Authorization"] = `Bearer ${config.userJwt}`;
111
+ if (config.permission) this.headers["X-Widget-Permission"] = config.permission;
112
+ }
113
+ /**
114
+ * Update configuration (e.g., JWT token)
115
+ */
116
+ updateConfig(config) {
117
+ if (config.baseUrl) this.baseUrl = config.baseUrl.replace(/\/$/, "");
118
+ if (config.widgetId) this.headers["X-Widget-Id"] = config.widgetId;
119
+ if (config.userEmail) this.headers["X-User-Email"] = config.userEmail;
120
+ if (config.userJwt) this.headers["Authorization"] = `Bearer ${config.userJwt}`;
121
+ if (config.permission !== void 0) if (config.permission) this.headers["X-Widget-Permission"] = config.permission;
122
+ else delete this.headers["X-Widget-Permission"];
123
+ }
124
+ /**
125
+ * Make a GET request
126
+ */
127
+ async get(path) {
128
+ return this.request("GET", path);
129
+ }
130
+ /**
131
+ * Make a POST request with JSON body
132
+ */
133
+ async post(path, body) {
134
+ return this.request("POST", path, body);
135
+ }
136
+ /**
137
+ * Make a POST request and return the raw Response (for streaming)
138
+ */
139
+ async postStream(path, body) {
140
+ const url = `${this.baseUrl}${path}`;
141
+ logger.debug("POST (stream)", url, body);
142
+ try {
143
+ const response = await fetch(url, {
144
+ method: "POST",
145
+ headers: {
146
+ ...this.headers,
147
+ "Content-Type": "application/json"
148
+ },
149
+ body: body ? JSON.stringify(body) : void 0
150
+ });
151
+ if (!response.ok) await this.handleErrorResponse(response);
152
+ return response;
153
+ } catch (error) {
154
+ if (error instanceof AgoApiError) throw error;
155
+ throw new AgoNetworkError(`Network error: ${error instanceof Error ? error.message : "Unknown error"}`, error instanceof Error ? error : void 0);
156
+ }
157
+ }
158
+ /**
159
+ * Make a POST request with FormData (for file uploads)
160
+ */
161
+ async postFormData(path, formData) {
162
+ const url = `${this.baseUrl}${path}`;
163
+ logger.debug("POST (formData)", url);
164
+ const headers = { ...this.headers };
165
+ try {
166
+ const response = await fetch(url, {
167
+ method: "POST",
168
+ headers,
169
+ body: formData
170
+ });
171
+ if (!response.ok) await this.handleErrorResponse(response);
172
+ return response;
173
+ } catch (error) {
174
+ if (error instanceof AgoApiError) throw error;
175
+ throw new AgoNetworkError(`Network error: ${error instanceof Error ? error.message : "Unknown error"}`, error instanceof Error ? error : void 0);
176
+ }
177
+ }
178
+ async request(method, path, body) {
179
+ const url = `${this.baseUrl}${path}`;
180
+ logger.debug(method, url, body);
181
+ try {
182
+ const response = await fetch(url, {
183
+ method,
184
+ headers: {
185
+ ...this.headers,
186
+ "Content-Type": "application/json"
187
+ },
188
+ body: body ? JSON.stringify(body) : void 0
189
+ });
190
+ if (!response.ok) await this.handleErrorResponse(response);
191
+ if (response.status === 204) return;
192
+ return response.json();
193
+ } catch (error) {
194
+ if (error instanceof AgoApiError) throw error;
195
+ throw new AgoNetworkError(`Network error: ${error instanceof Error ? error.message : "Unknown error"}`, error instanceof Error ? error : void 0);
196
+ }
197
+ }
198
+ async handleErrorResponse(response) {
199
+ let errorData;
200
+ try {
201
+ errorData = await response.json();
202
+ } catch {}
203
+ if (errorData?.error) throw AgoApiError.fromResponse(errorData, response.status);
204
+ throw new AgoApiError(`HTTP ${response.status}: ${response.statusText}`, "http_error", response.status, "api_error");
205
+ }
206
+ };
207
+ //#endregion
208
+ //#region src/functions/FunctionRegistry.ts
209
+ /**
210
+ * Registry for client-side functions that AGO can call
211
+ */
212
+ var FunctionRegistry = class {
213
+ constructor() {
214
+ this.functions = /* @__PURE__ */ new Map();
215
+ }
216
+ register(nameOrDef, handler, schema) {
217
+ if (typeof nameOrDef === "object") {
218
+ const { name, handler: h, description, parameters } = nameOrDef;
219
+ return this.register(name, h, {
220
+ description,
221
+ parameters
222
+ });
223
+ }
224
+ const name = nameOrDef;
225
+ if (!handler || !schema) throw new Error("handler and schema are required");
226
+ if (this.functions.has(name)) logger.warn(`Function "${name}" is being overwritten`);
227
+ this.functions.set(name, {
228
+ schema: {
229
+ ...schema,
230
+ name
231
+ },
232
+ handler
233
+ });
234
+ logger.log(`Registered function: ${name}`);
235
+ }
236
+ /**
237
+ * Unregister a function
238
+ */
239
+ unregister(name) {
240
+ const deleted = this.functions.delete(name);
241
+ if (deleted) logger.log(`Unregistered function: ${name}`);
242
+ return deleted;
243
+ }
244
+ /**
245
+ * Get a registered function
246
+ */
247
+ get(name) {
248
+ return this.functions.get(name);
249
+ }
250
+ /**
251
+ * Check if a function is registered
252
+ */
253
+ has(name) {
254
+ return this.functions.has(name);
255
+ }
256
+ /**
257
+ * Get all registered function schemas (for sending to backend)
258
+ */
259
+ getSchemas() {
260
+ return Array.from(this.functions.values()).map((f) => f.schema);
261
+ }
262
+ /**
263
+ * Execute a registered function
264
+ */
265
+ async execute(name, args) {
266
+ const registration = this.functions.get(name);
267
+ if (!registration) throw new AgoFunctionError(`Function "${name}" is not registered`, name);
268
+ logger.log(`Executing function: ${name}`, args);
269
+ try {
270
+ const result = await registration.handler(args);
271
+ logger.log(`Function ${name} completed:`, result);
272
+ return result;
273
+ } catch (error) {
274
+ logger.error(`Function ${name} failed:`, error);
275
+ throw new AgoFunctionError(`Function "${name}" execution failed: ${error instanceof Error ? error.message : "Unknown error"}`, name, error instanceof Error ? error : void 0);
276
+ }
277
+ }
278
+ /**
279
+ * Clear all registered functions
280
+ */
281
+ clear() {
282
+ this.functions.clear();
283
+ logger.log("Cleared all registered functions");
284
+ }
285
+ /**
286
+ * Get the number of registered functions
287
+ */
288
+ get size() {
289
+ return this.functions.size;
290
+ }
291
+ };
292
+ //#endregion
293
+ //#region src/state/ClientContextRegistry.ts
294
+ /**
295
+ * Registry that collects client-side context from across the component tree.
296
+ *
297
+ * Components register/unregister context slices via unique keys.
298
+ * When a message is sent the registry produces a single snapshot.
299
+ */
300
+ var ClientContextRegistry = class {
301
+ constructor() {
302
+ this.entries = /* @__PURE__ */ new Map();
303
+ this.dynamicProviders = /* @__PURE__ */ new Map();
304
+ }
305
+ /**
306
+ * Register or update a static context entry.
307
+ */
308
+ set(key, entry) {
309
+ this.entries.set(key, entry);
310
+ logger.log(`ClientContext set: ${key}`);
311
+ }
312
+ /**
313
+ * Remove a static context entry (typically on component unmount).
314
+ */
315
+ remove(key) {
316
+ const deleted = this.entries.delete(key);
317
+ if (deleted) logger.log(`ClientContext removed: ${key}`);
318
+ return deleted;
319
+ }
320
+ /**
321
+ * Register a dynamic context provider. The function is called every time
322
+ * a message is sent, so it always returns the freshest data.
323
+ *
324
+ * Use this for context that lives outside React state — global stores,
325
+ * refs, or computed values that shouldn't trigger re-renders.
326
+ */
327
+ addDynamicProvider(key, provider) {
328
+ this.dynamicProviders.set(key, provider);
329
+ logger.log(`DynamicContext provider added: ${key}`);
330
+ }
331
+ /**
332
+ * Remove a dynamic context provider.
333
+ */
334
+ removeDynamicProvider(key) {
335
+ const deleted = this.dynamicProviders.delete(key);
336
+ if (deleted) logger.log(`DynamicContext provider removed: ${key}`);
337
+ return deleted;
338
+ }
339
+ /**
340
+ * Build a snapshot of the current client context.
341
+ * Evaluates every registered dynamic provider. Returns `null` when there is
342
+ * nothing to report.
343
+ */
344
+ getSnapshot() {
345
+ if (this.entries.size === 0 && this.dynamicProviders.size === 0) return null;
346
+ const entries = {};
347
+ for (const [key, entry] of this.entries) entries[key] = entry;
348
+ for (const [key, provider] of this.dynamicProviders) try {
349
+ const entry = provider();
350
+ if (entry) entries[key] = entry;
351
+ } catch (err) {
352
+ logger.error(`DynamicContext provider "${key}" threw:`, err);
353
+ }
354
+ if (Object.keys(entries).length === 0) return null;
355
+ return { entries };
356
+ }
357
+ /**
358
+ * Remove all entries and dynamic providers.
359
+ */
360
+ clear() {
361
+ this.entries.clear();
362
+ this.dynamicProviders.clear();
363
+ logger.log("ClientContext cleared");
364
+ }
365
+ };
366
+ //#endregion
367
+ //#region src/streaming/SSEHandler.ts
368
+ /**
369
+ * Handles SSE streaming responses from AGO backend
370
+ */
371
+ var SSEHandler = class {
372
+ constructor(callbacks) {
373
+ this.callbacks = callbacks;
374
+ this.buffer = "";
375
+ this.message = {};
376
+ this.toolCalls = [];
377
+ this.sources = [];
378
+ this.followUpReplies = [];
379
+ this.isFirstChunk = true;
380
+ }
381
+ /**
382
+ * Process a streaming response
383
+ */
384
+ async processStream(response) {
385
+ if (!response.body) throw new AgoStreamError("Response has no body");
386
+ const reader = response.body.getReader();
387
+ const decoder = new TextDecoder();
388
+ try {
389
+ while (true) {
390
+ const { done, value } = await reader.read();
391
+ if (done) break;
392
+ const text = decoder.decode(value, { stream: true });
393
+ this.buffer += text;
394
+ this.processBuffer();
395
+ }
396
+ if (this.buffer.trim()) this.processBuffer();
397
+ return this.buildFinalMessage();
398
+ } catch (error) {
399
+ const streamError = error instanceof Error ? error : new AgoStreamError("Stream processing failed");
400
+ this.callbacks.onError?.(streamError);
401
+ throw streamError;
402
+ } finally {
403
+ reader.releaseLock();
404
+ }
405
+ }
406
+ processBuffer() {
407
+ const parts = this.buffer.split("\n\n");
408
+ this.buffer = parts.pop() || "";
409
+ for (const part of parts) {
410
+ if (!part.trim()) continue;
411
+ const lines = part.split("\n");
412
+ for (const line of lines) {
413
+ if (line.startsWith(": ")) continue;
414
+ if (line.startsWith("data: ")) {
415
+ const jsonStr = line.slice(6);
416
+ try {
417
+ const data = JSON.parse(jsonStr);
418
+ this.handleChunk(data);
419
+ } catch (error) {
420
+ logger.warn("Failed to parse SSE data:", jsonStr, error);
421
+ }
422
+ }
423
+ }
424
+ }
425
+ }
426
+ handleChunk(data) {
427
+ if (data.message_id && !this.message.id) this.message.id = data.message_id;
428
+ if (data.thread?.id) {
429
+ this.message.conversationId = data.thread.id;
430
+ if (this.isFirstChunk && this.message.id) {
431
+ this.isFirstChunk = false;
432
+ this.callbacks.onStart?.({
433
+ conversationId: this.message.conversationId,
434
+ messageId: this.message.id
435
+ });
436
+ }
437
+ }
438
+ if (data.content !== void 0) {
439
+ this.message.content = (this.message.content || "") + data.content;
440
+ if (this.message.conversationId && this.message.id) this.callbacks.onChunk?.({
441
+ content: data.content,
442
+ conversationId: this.message.conversationId,
443
+ messageId: this.message.id
444
+ });
445
+ }
446
+ if (data.full_content !== void 0) this.message.content = data.full_content;
447
+ if (data.status) this.message.status = data.status;
448
+ if (data.agent) this.message.agent = {
449
+ id: data.agent.id,
450
+ name: data.agent.name,
451
+ displayName: data.agent.display_name
452
+ };
453
+ if (data.knowledge_sources) this.sources = data.knowledge_sources.map((s) => {
454
+ const doc = s.knowledge_document;
455
+ return {
456
+ id: doc.id,
457
+ title: doc.title,
458
+ url: doc.use_external_link ? doc.external_link_url : doc.internal_link_url
459
+ };
460
+ });
461
+ if (data.type === "client_function" && data.function_name) this.callbacks.onClientFunction?.({
462
+ invocationId: data.id || "",
463
+ functionName: data.function_name,
464
+ arguments: data.arguments || {},
465
+ conversationId: this.message.conversationId || ""
466
+ });
467
+ if (data.tool_call_data && data.type && data.type !== "client_function") {
468
+ const toolCall = this.parseToolCall(data);
469
+ this.callbacks.onToolCall?.(toolCall);
470
+ const existingIndex = this.toolCalls.findIndex((t) => t.id === toolCall.id);
471
+ if (existingIndex >= 0) this.toolCalls[existingIndex] = toolCall;
472
+ else this.toolCalls.push(toolCall);
473
+ }
474
+ if (data.follow_up_replies) this.followUpReplies = data.follow_up_replies;
475
+ }
476
+ parseToolCall(data) {
477
+ return {
478
+ id: data.id || "",
479
+ type: data.type || "status_message",
480
+ status: data.status || "unknown",
481
+ toolName: data.tool_name || "",
482
+ toolDisplayName: data.tool_display_name,
483
+ message: data.message,
484
+ formSchema: data.form_schema,
485
+ data: data.data,
486
+ functionName: data.function_name,
487
+ arguments: data.arguments
488
+ };
489
+ }
490
+ buildFinalMessage() {
491
+ const message = {
492
+ id: this.message.id || "",
493
+ conversationId: this.message.conversationId || "",
494
+ content: this.message.content || "",
495
+ role: "assistant",
496
+ status: this.message.status || "DONE",
497
+ agent: this.message.agent,
498
+ sources: this.sources.length > 0 ? this.sources : void 0,
499
+ toolCalls: this.toolCalls.length > 0 ? this.toolCalls : void 0,
500
+ followUpReplies: this.followUpReplies.length > 0 ? this.followUpReplies : void 0,
501
+ createdAt: /* @__PURE__ */ new Date()
502
+ };
503
+ this.callbacks.onComplete?.(message);
504
+ return message;
505
+ }
506
+ };
507
+ /**
508
+ * Check if an error is a network error that should trigger polling fallback
509
+ */
510
+ function isStreamNetworkError(error) {
511
+ const message = error.message.toLowerCase();
512
+ return message.includes("load failed") || message.includes("failed to fetch") || message.includes("network") || message.includes("abort");
513
+ }
514
+ //#endregion
515
+ //#region src/utils/eventEmitter.ts
516
+ /**
517
+ * Simple typed event emitter
518
+ */
519
+ var EventEmitter = class {
520
+ constructor() {
521
+ this.handlers = /* @__PURE__ */ new Map();
522
+ }
523
+ on(event, handler) {
524
+ if (!this.handlers.has(event)) this.handlers.set(event, /* @__PURE__ */ new Set());
525
+ this.handlers.get(event).add(handler);
526
+ }
527
+ off(event, handler) {
528
+ const eventHandlers = this.handlers.get(event);
529
+ if (eventHandlers) eventHandlers.delete(handler);
530
+ }
531
+ emit(event, data) {
532
+ const eventHandlers = this.handlers.get(event);
533
+ if (eventHandlers) eventHandlers.forEach((handler) => {
534
+ try {
535
+ handler(data);
536
+ } catch (error) {
537
+ console.error(`Error in event handler for ${String(event)}:`, error);
538
+ }
539
+ });
540
+ }
541
+ /**
542
+ * Subscribe to an event and auto-unsubscribe after the first call.
543
+ */
544
+ once(event, handler) {
545
+ const wrapper = ((data) => {
546
+ this.off(event, wrapper);
547
+ handler(data);
548
+ });
549
+ this.on(event, wrapper);
550
+ }
551
+ /**
552
+ * Returns a Promise that resolves the next time `event` fires.
553
+ * Rejects if `timeout` (ms) is reached first.
554
+ */
555
+ waitFor(event, options) {
556
+ return new Promise((resolve, reject) => {
557
+ let timer;
558
+ const handler = ((data) => {
559
+ if (timer) clearTimeout(timer);
560
+ resolve(data);
561
+ });
562
+ this.once(event, handler);
563
+ if (options?.timeout) timer = setTimeout(() => {
564
+ this.off(event, handler);
565
+ reject(/* @__PURE__ */ new Error(`waitFor("${String(event)}") timed out after ${options.timeout}ms`));
566
+ }, options.timeout);
567
+ });
568
+ }
569
+ removeAllListeners(event) {
570
+ if (event) this.handlers.delete(event);
571
+ else this.handlers.clear();
572
+ }
573
+ };
574
+ //#endregion
575
+ //#region src/client/AgoClient.ts
576
+ /**
577
+ * Main SDK client for AGO Chat integration
578
+ */
579
+ var AgoClient = class {
580
+ constructor(config) {
581
+ this.config = config;
582
+ this.httpClient = new HttpClient(config);
583
+ this.functionRegistry = new FunctionRegistry();
584
+ this.contextRegistry = new ClientContextRegistry();
585
+ this.eventEmitter = new EventEmitter();
586
+ if (config.debug) logger.enable();
587
+ logger.log("AgoClient initialized");
588
+ }
589
+ /**
590
+ * Send a message and receive a streaming response
591
+ */
592
+ async sendMessage(content, options) {
593
+ const clientFunctions = this.functionRegistry.getSchemas();
594
+ const clientContext = this.contextRegistry.getSnapshot();
595
+ const configAgent = this.config.agent || this.config.defaultAgentId;
596
+ const body = {
597
+ content,
598
+ conversation_id: options?.conversationId,
599
+ agent_id: options?.agentId || configAgent
600
+ };
601
+ if (clientFunctions.length > 0) body.client_functions = clientFunctions;
602
+ if (clientContext) body.client_context = clientContext;
603
+ let response;
604
+ if (options?.files && options.files.length > 0) {
605
+ const formData = new FormData();
606
+ formData.append("content", content);
607
+ if (options.conversationId) formData.append("conversation_id", options.conversationId);
608
+ if (options.agentId || configAgent) formData.append("agent_id", options.agentId || configAgent || "");
609
+ if (clientFunctions.length > 0) formData.append("client_functions", JSON.stringify(clientFunctions));
610
+ if (clientContext) formData.append("client_context", JSON.stringify(clientContext));
611
+ for (const file of options.files) formData.append("files", file);
612
+ response = await this.httpClient.postFormData("/api/sdk/v1/messages", formData);
613
+ } else response = await this.httpClient.postStream("/api/sdk/v1/messages", body);
614
+ return this.processSSEResponse(response);
615
+ }
616
+ async processSSEResponse(response) {
617
+ return new SSEHandler({
618
+ onStart: (data) => {
619
+ this.eventEmitter.emit("message:start", data);
620
+ },
621
+ onChunk: (data) => {
622
+ this.eventEmitter.emit("message:chunk", data);
623
+ },
624
+ onToolCall: (toolCall) => {
625
+ this.eventEmitter.emit("toolCall:received", toolCall);
626
+ if (toolCall.type === "form") this.eventEmitter.emit("toolCall:form", toolCall);
627
+ },
628
+ onClientFunction: async (data) => {
629
+ this.eventEmitter.emit("function:invoke", data);
630
+ await this.handleClientFunctionInvocation(data);
631
+ },
632
+ onComplete: (message) => {
633
+ this.eventEmitter.emit("message:complete", message);
634
+ },
635
+ onError: (error) => {
636
+ this.eventEmitter.emit("message:error", { error: error.message });
637
+ }
638
+ }).processStream(response);
639
+ }
640
+ async handleClientFunctionInvocation(data) {
641
+ let result;
642
+ let error;
643
+ try {
644
+ result = await this.functionRegistry.execute(data.functionName, data.arguments);
645
+ } catch (err) {
646
+ error = err instanceof Error ? err.message : "Unknown error";
647
+ logger.error("Client function execution failed:", err);
648
+ }
649
+ if (data.invocationId) try {
650
+ await this.submitToolCallForm(data.invocationId, {
651
+ result,
652
+ error,
653
+ _type: "client_function_result"
654
+ });
655
+ } catch (submitError) {
656
+ logger.error("Failed to submit function result:", submitError);
657
+ }
658
+ this.eventEmitter.emit("function:result", {
659
+ invocationId: data.invocationId,
660
+ result,
661
+ error
662
+ });
663
+ }
664
+ /**
665
+ * Get list of conversations
666
+ */
667
+ async getConversations() {
668
+ return (await this.httpClient.get("/api/sdk/v1/conversations")).items.map((item) => ({
669
+ id: item.id,
670
+ title: item.title,
671
+ lastMessageDate: new Date(item.last_message_date)
672
+ }));
673
+ }
674
+ /**
675
+ * Get a specific conversation with messages
676
+ */
677
+ async getConversation(conversationId) {
678
+ const response = await this.httpClient.get(`/api/sdk/v1/conversations/${conversationId}`);
679
+ return {
680
+ id: response.id,
681
+ title: response.title,
682
+ lastMessageDate: new Date(response.last_message_date),
683
+ messages: response.messages.map((m) => ({
684
+ id: m.id,
685
+ conversationId: response.id,
686
+ content: m.content,
687
+ role: m.role,
688
+ status: m.status,
689
+ createdAt: new Date(m.created_at)
690
+ }))
691
+ };
692
+ }
693
+ /**
694
+ * Get messages for a conversation
695
+ */
696
+ async getMessages(conversationId) {
697
+ return (await this.getConversation(conversationId)).messages || [];
698
+ }
699
+ /**
700
+ * Submit form data for a tool call
701
+ */
702
+ async submitToolCallForm(toolCallId, formData) {
703
+ await this.httpClient.post(`/api/tool-calls/${toolCallId}/submit/`, { formData });
704
+ }
705
+ /**
706
+ * Confirm a tool call
707
+ */
708
+ async confirmToolCall(toolCallId) {
709
+ await this.httpClient.post(`/api/tool-calls/${toolCallId}/confirm/`);
710
+ }
711
+ /**
712
+ * Reject a tool call
713
+ */
714
+ async rejectToolCall(toolCallId) {
715
+ await this.httpClient.post(`/api/tool-calls/${toolCallId}/reject/`);
716
+ }
717
+ /**
718
+ * Submit feedback for a message
719
+ */
720
+ async submitFeedback(messageId, rating) {
721
+ await this.httpClient.post(`/api/sdk/v1/messages/${messageId}/feedback`, { rating });
722
+ }
723
+ registerFunction(nameOrDef, handler, schema) {
724
+ if (typeof nameOrDef === "object") this.functionRegistry.register(nameOrDef);
725
+ else this.functionRegistry.register(nameOrDef, handler, schema);
726
+ }
727
+ /**
728
+ * Short alias for `registerFunction`. Also accepts an array of definitions.
729
+ *
730
+ * ```ts
731
+ * client.register(lookupOrder);
732
+ * client.register([lookupOrder, cancelOrder]);
733
+ * ```
734
+ */
735
+ register(definition) {
736
+ if (Array.isArray(definition)) for (const def of definition) this.functionRegistry.register(def);
737
+ else this.functionRegistry.register(definition);
738
+ }
739
+ /**
740
+ * Unregister a client-side function
741
+ */
742
+ unregisterFunction(name) {
743
+ return this.functionRegistry.unregister(name);
744
+ }
745
+ /**
746
+ * Get all registered function schemas
747
+ */
748
+ getRegisteredFunctions() {
749
+ return this.functionRegistry.getSchemas();
750
+ }
751
+ /**
752
+ * Register a navigation function that lets AGO navigate users to different pages.
753
+ * @param navigate - A callback that performs the navigation (e.g. react-router's navigate)
754
+ * @param routes - Map of route names to paths, with descriptions for the LLM
755
+ */
756
+ registerNavigationFunction(navigate, routes) {
757
+ const routeNames = routes.map((r) => r.name);
758
+ const routeDescriptions = routes.map((r) => `- "${r.name}": ${r.description}`).join("\n");
759
+ this.registerFunction("navigateToPage", async (args) => {
760
+ const pageName = args.page;
761
+ const route = routes.find((r) => r.name === pageName);
762
+ if (!route) return {
763
+ success: false,
764
+ error: `Unknown page: ${pageName}`
765
+ };
766
+ navigate(route.path);
767
+ return {
768
+ success: true,
769
+ navigatedTo: route.path
770
+ };
771
+ }, {
772
+ description: `Navigate the user to a page in the application. Available pages:\n${routeDescriptions}`,
773
+ parameters: {
774
+ type: "object",
775
+ properties: { page: {
776
+ type: "string",
777
+ description: "The page to navigate to",
778
+ enum: routeNames
779
+ } },
780
+ required: ["page"]
781
+ }
782
+ });
783
+ }
784
+ /**
785
+ * Register or update a piece of client-side context.
786
+ * This context is sent with every message so the AI understands the user's situation.
787
+ *
788
+ * ```ts
789
+ * client.setContext("order-page", {
790
+ * name: "Order detail",
791
+ * description: "User is viewing order #123",
792
+ * data: { orderId: "123", status: "shipped" },
793
+ * });
794
+ * ```
795
+ */
796
+ setContext(key, entry) {
797
+ this.contextRegistry.set(key, entry);
798
+ }
799
+ /**
800
+ * Remove a previously registered context entry.
801
+ */
802
+ removeContext(key) {
803
+ return this.contextRegistry.remove(key);
804
+ }
805
+ /**
806
+ * Register a dynamic context provider. The callback is invoked every time
807
+ * a message is sent, so the AI always gets the freshest data.
808
+ *
809
+ * Use this for context that lives outside React state — global stores,
810
+ * refs, or computed values.
811
+ *
812
+ * ```ts
813
+ * client.addDynamicContext("cart", () => ({
814
+ * name: "Checkout",
815
+ * data: { itemCount: cart.items.length, total: cart.total },
816
+ * }));
817
+ * ```
818
+ */
819
+ addDynamicContext(key, provider) {
820
+ this.contextRegistry.addDynamicProvider(key, provider);
821
+ }
822
+ /**
823
+ * Remove a dynamic context provider.
824
+ */
825
+ removeDynamicContext(key) {
826
+ return this.contextRegistry.removeDynamicProvider(key);
827
+ }
828
+ /**
829
+ * Enable automatic capture of the current browser page (URL + title).
830
+ * Injected as a dynamic context entry named `browser-page`.
831
+ */
832
+ enableAutoPageContext() {
833
+ this.contextRegistry.addDynamicProvider("browser-page", () => {
834
+ const url = typeof window !== "undefined" ? window.location.href : void 0;
835
+ const title = typeof document !== "undefined" ? document.title : void 0;
836
+ if (!url && !title) return null;
837
+ return {
838
+ name: "Browser page",
839
+ description: "Current page the user is viewing",
840
+ data: {
841
+ url,
842
+ title
843
+ }
844
+ };
845
+ });
846
+ }
847
+ /**
848
+ * Get the current context snapshot.
849
+ */
850
+ getContextSnapshot() {
851
+ return this.contextRegistry.getSnapshot();
852
+ }
853
+ /**
854
+ * Subscribe to an event
855
+ */
856
+ on(event, handler) {
857
+ this.eventEmitter.on(event, handler);
858
+ }
859
+ /**
860
+ * Unsubscribe from an event
861
+ */
862
+ off(event, handler) {
863
+ this.eventEmitter.off(event, handler);
864
+ }
865
+ /**
866
+ * Subscribe to an event once — auto-unsubscribes after the first call.
867
+ */
868
+ once(event, handler) {
869
+ this.eventEmitter.once(event, handler);
870
+ }
871
+ /**
872
+ * Returns a Promise that resolves the next time `event` fires.
873
+ *
874
+ * ```ts
875
+ * const msg = await client.waitFor("message:complete", { timeout: 10000 });
876
+ * ```
877
+ */
878
+ waitFor(event, options) {
879
+ return this.eventEmitter.waitFor(event, options);
880
+ }
881
+ /**
882
+ * Update client configuration
883
+ */
884
+ updateConfig(config) {
885
+ this.config = {
886
+ ...this.config,
887
+ ...config
888
+ };
889
+ this.httpClient.updateConfig(config);
890
+ if (config.debug !== void 0) config.debug ? logger.enable() : logger.disable();
891
+ }
892
+ /**
893
+ * Clean up resources
894
+ */
895
+ destroy() {
896
+ this.eventEmitter.removeAllListeners();
897
+ this.functionRegistry.clear();
898
+ this.contextRegistry.clear();
899
+ logger.log("AgoClient destroyed");
900
+ }
901
+ };
902
+ //#endregion
903
+ export { ClientContextRegistry as a, AgoApiError as c, AgoNetworkError as d, AgoStreamError as f, isStreamNetworkError as i, AgoError as l, EventEmitter as n, FunctionRegistry as o, SSEHandler as r, logger as s, AgoClient as t, AgoFunctionError as u };
904
+
905
+ //# sourceMappingURL=AgoClient-CNT-8sh_.js.map