@useago/sdk 1.4.3 → 1.5.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 (44) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/dist/{AgoClient-S8oeNnAE.js → AgoClient-q39FIjSC.js} +105 -81
  3. package/dist/AgoClient-wcPRaIMs.cjs +8 -0
  4. package/dist/angular.cjs +1 -1
  5. package/dist/angular.d.cts +75 -5
  6. package/dist/angular.d.ts +75 -5
  7. package/dist/angular.js +5 -1
  8. package/dist/autoContinue-CcCTva-D.cjs +1 -0
  9. package/dist/autoContinue-D3Mmaaca.js +63 -0
  10. package/dist/{createConversationSession-CmBq7uGi.cjs → createConversationSession-BBYfQLLS.cjs} +1 -1
  11. package/dist/{createConversationSession-DoUHdVNR.js → createConversationSession-DCSWShaW.js} +1 -1
  12. package/dist/{createFormCollector-Bz_0IJ0Q.cjs → createFormCollector-eimwwWEi.cjs} +1 -1
  13. package/dist/{createFormCollector-vy-QvFja.js → createFormCollector-sB6rMccD.js} +1 -1
  14. package/dist/devtools.d.cts +32 -4
  15. package/dist/devtools.d.ts +32 -4
  16. package/dist/helpers.cjs +1 -1
  17. package/dist/helpers.d.cts +6 -0
  18. package/dist/helpers.d.ts +6 -0
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.cts +101 -5
  21. package/dist/index.d.ts +101 -5
  22. package/dist/index.js +45 -43
  23. package/dist/react.cjs +3 -3
  24. package/dist/react.d.cts +40 -18
  25. package/dist/react.d.ts +40 -18
  26. package/dist/react.js +415 -471
  27. package/dist/testing.cjs +1 -1
  28. package/dist/testing.d.cts +32 -4
  29. package/dist/testing.d.ts +32 -4
  30. package/dist/testing.js +1 -1
  31. package/dist/vue.cjs +1 -1
  32. package/dist/vue.d.cts +38 -4
  33. package/dist/vue.d.ts +38 -4
  34. package/dist/vue.js +22 -21
  35. package/dist/widget.cjs +1 -1
  36. package/dist/widget.d.cts +32 -4
  37. package/dist/widget.d.ts +32 -4
  38. package/dist/widget.js +3 -3
  39. package/llms-full.txt +1932 -0
  40. package/package.json +5 -3
  41. package/dist/AgoClient-CMDVqNaH.cjs +0 -8
  42. /package/dist/{createMockClient-bAZ9KBHC.js → createMockClient-BUc9PSbo.js} +0 -0
  43. /package/dist/{createMockClient-BSr-UV8R.cjs → createMockClient-CjdCqixj.cjs} +0 -0
  44. /package/dist/{functions-Djnq-JAo.cjs → functions-IGSjjvF4.cjs} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,10 +5,18 @@ All notable changes to `@useago/sdk` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [1.5.0] - 2026-07-07
9
9
 
10
10
  ### Added
11
11
 
12
+ - `attachAutoContinueAfterNavigation(client, options?)`: the auto-continue
13
+ behavior ("go to page B and change X" in one user message) is now a
14
+ framework-agnostic core export, returning a detach function. The React hook
15
+ keeps its API and delegates to it.
16
+ - Angular: `AgoService.enableAutoContinueAfterNavigation(options?)` enables
17
+ auto-continue after navigation and returns the disable function (call it in
18
+ `ngOnDestroy`). `AgoAutoContinueOptions` is exported from
19
+ `@useago/sdk/angular`.
12
20
  - `AgoConfig.warnOnEmptyReply` (default `true`) and a `message:empty` event:
13
21
  a reply that completes `DONE` with no content, tool calls, or follow-ups
14
22
  (usually an unknown `agent` slug) now warns on the console once per
@@ -25,6 +33,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
25
33
 
26
34
  ### Changed
27
35
 
36
+ - `clientFunctionsMode` now defaults to `"pause"`: with client functions
37
+ registered, the turn stops on the client function call(s) and resumes the
38
+ SAME turn once the results are submitted, so the agent sees the real
39
+ results. Backends without pause/resume support ignore the flag and keep the
40
+ old placeholder behavior. Set `clientFunctionsMode: "placeholder"` (config
41
+ or per message) to opt back into the legacy mode.
28
42
  - `new AgoClient({})` (or missing/empty `baseUrl`) now throws an actionable
29
43
  `AgoError` (`config_missing_base_url`) instead of a raw `TypeError`.
30
44
  Same-origin `/path` baseUrls remain supported; a baseUrl with no protocol
@@ -2,13 +2,13 @@ var d = class extends Error {
2
2
  constructor(e, t, s) {
3
3
  super(e), this.code = t, this.statusCode = s, this.name = "AgoError";
4
4
  }
5
- }, f = class I extends d {
5
+ }, f = class k extends d {
6
6
  constructor(t, s, i, n, o, a) {
7
7
  super(t, s, i), this.type = n, this.param = o, this.docUrl = a, this.name = "AgoApiError";
8
8
  }
9
9
  static fromResponse(t, s) {
10
10
  const i = t.error;
11
- return new I(i.doc_url ? `${i.message} See ${i.doc_url}` : i.message, i.code, s, i.type, i.param, i.doc_url);
11
+ return new k(i.doc_url ? `${i.message} See ${i.doc_url}` : i.message, i.code, s, i.type, i.param, i.doc_url);
12
12
  }
13
13
  }, y = class extends d {
14
14
  constructor(e, t) {
@@ -22,7 +22,7 @@ var d = class extends Error {
22
22
  constructor(e, t, s) {
23
23
  super(e, "function_error"), this.functionName = t, this.originalError = s, this.name = "AgoFunctionError";
24
24
  }
25
- }, A = class {
25
+ }, I = class {
26
26
  constructor(e = !1) {
27
27
  this.enabled = e;
28
28
  }
@@ -44,15 +44,15 @@ var d = class extends Error {
44
44
  debug(...e) {
45
45
  this.enabled && console.debug("[AGO SDK]", ...e);
46
46
  }
47
- }, l = new A(), S = "ago_widget_id";
47
+ }, l = new I(), R = "ago_widget_id";
48
48
  function F() {
49
49
  if (typeof localStorage < "u") {
50
- const t = localStorage.getItem(S);
50
+ const t = localStorage.getItem(R);
51
51
  if (t) return t;
52
52
  }
53
53
  const e = typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
54
54
  if (typeof localStorage < "u") try {
55
- localStorage.setItem(S, e);
55
+ localStorage.setItem(R, e);
56
56
  } catch {
57
57
  }
58
58
  return e;
@@ -129,26 +129,33 @@ var U = class {
129
129
  let s = "";
130
130
  throw e.status === 401 || e.status === 403 ? s = " Check `userJwt` (and that it has not expired)." : e.status === 404 && (s = " Check that `baseUrl` points at your AGO API root."), new f(`HTTP ${e.status}: ${e.statusText}.${s}`, "http_error", e.status, "api_error");
131
131
  }
132
- }, N = class {
133
- constructor() {
134
- this.functions = /* @__PURE__ */ new Map();
132
+ }, T = 5e4, N = 2e4, D = 2e3, P = class {
133
+ constructor(e) {
134
+ this.functions = /* @__PURE__ */ new Map(), this.defaultMaxResultBytes = e?.maxResultBytes ?? T;
135
+ }
136
+ setDefaultMaxResultBytes(e) {
137
+ this.defaultMaxResultBytes = e;
135
138
  }
136
139
  register(e, t, s) {
137
140
  if (typeof e == "object") {
138
- const { name: n, handler: o, description: a, parameters: r } = e;
139
- return this.register(n, o, {
140
- description: a,
141
- parameters: r
141
+ const { name: a, handler: r, description: c, parameters: u, maxResultBytes: h } = e;
142
+ return this.register(a, r, {
143
+ description: c,
144
+ parameters: u,
145
+ maxResultBytes: h
142
146
  });
143
147
  }
144
148
  const i = e;
145
149
  if (!t || !s) throw new d(`registerFunction("${i}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`, "function_invalid_registration");
146
- this.functions.has(i) && l.warn(`Function "${i}" is being overwritten`), this.functions.set(i, {
150
+ this.functions.has(i) && l.warn(`Function "${i}" is being overwritten`);
151
+ const { maxResultBytes: n, ...o } = s;
152
+ this.functions.set(i, {
147
153
  schema: {
148
- ...s,
154
+ ...o,
149
155
  name: i
150
156
  },
151
- handler: t
157
+ handler: t,
158
+ maxResultBytes: n
152
159
  }), l.log(`Registered function: ${i}`);
153
160
  }
154
161
  unregister(e) {
@@ -170,18 +177,35 @@ var U = class {
170
177
  l.log(`Executing function: ${e}`, t);
171
178
  try {
172
179
  const i = await s.handler(t);
173
- return l.log(`Function ${e} completed:`, i), i;
180
+ return l.log(`Function ${e} completed:`, i), this.guardResultSize(e, i, s.maxResultBytes);
174
181
  } catch (i) {
175
182
  throw l.error(`Function ${e} failed:`, i), new E(`Function "${e}" execution failed: ${i instanceof Error ? i.message : "Unknown error"}`, e, i instanceof Error ? i : void 0);
176
183
  }
177
184
  }
185
+ guardResultSize(e, t, s) {
186
+ let i;
187
+ try {
188
+ i = JSON.stringify(t);
189
+ } catch {
190
+ return t;
191
+ }
192
+ if (i === void 0) return t;
193
+ const n = new TextEncoder().encode(i).length, o = s ?? this.defaultMaxResultBytes;
194
+ return n > o ? (l.warn(`Function "${e}" result is ${n} bytes, over the ${o}-byte limit; a truncated preview was sent to the agent instead. Return fewer fields, paginate, or raise maxResultBytes for this function.`), {
195
+ truncated: !0,
196
+ originalBytes: n,
197
+ maxBytes: o,
198
+ preview: i.slice(0, D),
199
+ hint: `The result of "${e}" exceeded the ${o}-byte limit and was truncated. Request less data (use limit or filter parameters if available), or tell the user the result is too large to process.`
200
+ }) : (n > N && l.warn(`Function "${e}" returned a large result (${Math.round(n / 1024)} KB). Large results consume LLM context: return fewer fields, paginate, or push the data to the UI and return a summary.`), t);
201
+ }
178
202
  clear() {
179
203
  this.functions.clear(), l.log("Cleared all registered functions");
180
204
  }
181
205
  get size() {
182
206
  return this.functions.size;
183
207
  }
184
- }, T = class {
208
+ }, M = class {
185
209
  constructor() {
186
210
  this.entries = /* @__PURE__ */ new Map(), this.dynamicProviders = /* @__PURE__ */ new Map();
187
211
  }
@@ -218,7 +242,7 @@ var U = class {
218
242
  function v(e) {
219
243
  return e === null || typeof e != "object" ? JSON.stringify(e) ?? "null" : Array.isArray(e) ? `[${e.map(v).join(",")}]` : `{${Object.keys(e).sort().map((t) => `${JSON.stringify(t)}:${v(e[t])}`).join(",")}}`;
220
244
  }
221
- var D = class {
245
+ var O = class {
222
246
  constructor(e) {
223
247
  this.callbacks = e, this.buffer = "", this.message = {}, this.toolCalls = [], this.sources = [], this.followUpReplies = [], this.isFirstChunk = !0, this.answerCompleteEmitted = !1, this.waitingClientEmitted = !1, this.firedClientFunctions = /* @__PURE__ */ new Set();
224
248
  }
@@ -334,11 +358,11 @@ var D = class {
334
358
  return e.status !== "WAITING_CLIENT" && this.callbacks.onComplete?.(e), e;
335
359
  }
336
360
  };
337
- function J(e) {
361
+ function H(e) {
338
362
  const t = e.message.toLowerCase();
339
363
  return t.includes("load failed") || t.includes("failed to fetch") || t.includes("network") || t.includes("abort");
340
364
  }
341
- var P = /* @__PURE__ */ new Set([
365
+ var j = /* @__PURE__ */ new Set([
342
366
  "image/jpeg",
343
367
  "image/png",
344
368
  "image/gif",
@@ -346,7 +370,7 @@ var P = /* @__PURE__ */ new Set([
346
370
  "image/bmp",
347
371
  "image/tiff"
348
372
  ]);
349
- function O(e) {
373
+ function B(e) {
350
374
  if (!e) return;
351
375
  const t = typeof window < "u" && window.location ? window.location.href : "https://ago.local/";
352
376
  try {
@@ -355,16 +379,16 @@ function O(e) {
355
379
  } catch {
356
380
  }
357
381
  }
358
- function B(e) {
359
- return e.isSafeImage === !0 && typeof e.contentType == "string" && e.contentType.startsWith("image/") && O(e.url) !== void 0;
382
+ function K(e) {
383
+ return e.isSafeImage === !0 && typeof e.contentType == "string" && e.contentType.startsWith("image/") && B(e.url) !== void 0;
360
384
  }
361
- function q(e) {
385
+ function X(e) {
362
386
  if (e == null || e < 0) return "";
363
387
  if (e < 1024) return `${e} B`;
364
388
  const t = e / 1024;
365
389
  return t < 1024 ? `${t.toFixed(1)} KB` : `${(t / 1024).toFixed(1)} MB`;
366
390
  }
367
- function j(e) {
391
+ function L(e) {
368
392
  return {
369
393
  id: String(e.id ?? ""),
370
394
  name: typeof e.name == "string" && e.name ? e.name : "file",
@@ -374,17 +398,17 @@ function j(e) {
374
398
  isSafeImage: e.is_safe_image === !0
375
399
  };
376
400
  }
377
- function H(e) {
401
+ function Y(e) {
378
402
  return e.map((t, s) => ({
379
403
  id: `local-${s}-${t.name}`,
380
404
  name: t.name,
381
405
  contentType: t.type || void 0,
382
406
  fileSize: t.size,
383
407
  url: typeof URL < "u" && URL.createObjectURL ? URL.createObjectURL(t) : void 0,
384
- isSafeImage: P.has(t.type)
408
+ isSafeImage: j.has(t.type)
385
409
  }));
386
410
  }
387
- var M = class {
411
+ var G = class {
388
412
  constructor() {
389
413
  this.handlers = /* @__PURE__ */ new Map();
390
414
  }
@@ -425,20 +449,20 @@ var M = class {
425
449
  removeAllListeners(e) {
426
450
  e ? this.handlers.delete(e) : this.handlers.clear();
427
451
  }
428
- }, R = '`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).', G = /^[a-z][a-z0-9+.-]*:\/\//i, $ = !1;
429
- function k(e, t = "AgoClient") {
430
- if (typeof e != "object" || e === null) throw new d(`${t}: ${R}`, "config_missing_base_url");
452
+ }, S = '`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).', W = /^[a-z][a-z0-9+.-]*:\/\//i, $ = !1;
453
+ function x(e, t = "AgoClient") {
454
+ if (typeof e != "object" || e === null) throw new d(`${t}: ${S}`, "config_missing_base_url");
431
455
  const s = e.baseUrl;
432
- if (typeof s != "string" || s.trim() === "") throw new d(`${t}: ${R}`, "config_missing_base_url");
433
- !s.startsWith("/") && !G.test(s) && ($ || ($ = !0, console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)));
456
+ if (typeof s != "string" || s.trim() === "") throw new d(`${t}: ${S}`, "config_missing_base_url");
457
+ !s.startsWith("/") && !W.test(s) && ($ || ($ = !0, console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)));
434
458
  }
435
- function L(e) {
459
+ function z(e) {
436
460
  return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
437
461
  }
438
462
  function w(e) {
439
463
  return e.split("/").filter((t) => t.startsWith(":")).map((t) => t.slice(1));
440
464
  }
441
- function W(e, t) {
465
+ function J(e, t) {
442
466
  const s = [];
443
467
  return {
444
468
  path: e.split("/").map((i) => {
@@ -449,19 +473,19 @@ function W(e, t) {
449
473
  missing: s
450
474
  };
451
475
  }
452
- function z(e, t) {
476
+ function q(e, t) {
453
477
  const s = t.find((n) => n.path === e);
454
478
  if (s) return s;
455
479
  const i = t.find((n) => {
456
480
  if (!n.path.includes(":")) return !1;
457
- const o = "^" + n.path.split("/").map((a) => a.startsWith(":") ? "[^/]+" : L(a)).join("/") + "/?$";
481
+ const o = "^" + n.path.split("/").map((a) => a.startsWith(":") ? "[^/]+" : z(a)).join("/") + "/?$";
458
482
  return new RegExp(o).test(e);
459
483
  });
460
484
  return i || t.filter((n) => n.path !== "/" && e.startsWith(n.path)).sort((n, o) => o.path.length - n.path.length)[0];
461
485
  }
462
- var K = class x {
486
+ var V = class A {
463
487
  constructor(t) {
464
- this.warnedEmptyConversations = /* @__PURE__ */ new Set(), this.pendingResumes = /* @__PURE__ */ new Map(), this.resumeGate = null, k(t, "AgoClient"), this.config = t, this.httpClient = new U(t), this.functionRegistry = new N(), this.contextRegistry = new T(), this.eventEmitter = new M(), t.debug && l.enable(), l.log("AgoClient initialized");
488
+ this.warnedEmptyConversations = /* @__PURE__ */ new Set(), this.pendingResumes = /* @__PURE__ */ new Map(), this.resumeGate = null, x(t, "AgoClient"), this.config = t, this.httpClient = new U(t), this.functionRegistry = new P({ maxResultBytes: t.maxFunctionResultBytes }), this.contextRegistry = new M(), this.eventEmitter = new G(), t.debug && l.enable(), l.log("AgoClient initialized");
465
489
  }
466
490
  async sendMessage(t, s) {
467
491
  const i = this.functionRegistry.getSchemas(), n = this.contextRegistry.getSnapshot(), o = this.config.agent || this.config.defaultAgentId, a = this.resolveClientFunctionsMode(s), r = {
@@ -472,16 +496,16 @@ var K = class x {
472
496
  i.length > 0 && (r.client_functions = i, a === "pause" && (r.client_functions_mode = a)), n && (r.client_context = n), s?.hidden && (r.hidden = !0);
473
497
  let c;
474
498
  if (s?.files && s.files.length > 0) {
475
- const h = new FormData();
476
- h.append("content", t), s.conversationId && h.append("conversation_id", s.conversationId), (s.agentId || o) && h.append("agent_id", s.agentId || o || ""), i.length > 0 && (h.append("client_functions", JSON.stringify(i)), a === "pause" && h.append("client_functions_mode", a)), n && h.append("client_context", JSON.stringify(n)), s.hidden && h.append("hidden", "true");
477
- for (const u of s.files) h.append("files", u);
478
- c = await this.httpClient.postFormData("/api/sdk/v1/messages", h);
499
+ const u = new FormData();
500
+ u.append("content", t), s.conversationId && u.append("conversation_id", s.conversationId), (s.agentId || o) && u.append("agent_id", s.agentId || o || ""), i.length > 0 && (u.append("client_functions", JSON.stringify(i)), a === "pause" && u.append("client_functions_mode", a)), n && u.append("client_context", JSON.stringify(n)), s.hidden && u.append("hidden", "true");
501
+ for (const h of s.files) u.append("files", h);
502
+ c = await this.httpClient.postFormData("/api/sdk/v1/messages", u);
479
503
  } else c = await this.httpClient.postStream("/api/sdk/v1/messages", r);
480
504
  return this.processSSEResponse(c);
481
505
  }
482
506
  async processSSEResponse(t) {
483
507
  let s = !1;
484
- const i = await new D({
508
+ const i = await new O({
485
509
  onRawChunk: (n) => {
486
510
  this.eventEmitter.emit("stream:message", n);
487
511
  },
@@ -516,7 +540,7 @@ var K = class x {
516
540
  return i.status !== "WAITING_CLIENT" && this.maybeFlagEmptyReply(i, s), i;
517
541
  }
518
542
  resolveClientFunctionsMode(t) {
519
- return t?.clientFunctionsMode ?? this.config.clientFunctionsMode ?? "placeholder";
543
+ return t?.clientFunctionsMode ?? this.config.clientFunctionsMode ?? "pause";
520
544
  }
521
545
  registerResumeGate(t) {
522
546
  return this.resumeGate = t, () => {
@@ -611,8 +635,8 @@ var K = class x {
611
635
  status: n.status,
612
636
  createdAt: new Date(n.created_at),
613
637
  hidden: n.hidden,
614
- toolCalls: x.mapPersistedToolCalls(n.tool_call_data),
615
- attachments: n.attachments && n.attachments.length > 0 ? n.attachments.map(j) : void 0
638
+ toolCalls: A.mapPersistedToolCalls(n.tool_call_data),
639
+ attachments: n.attachments && n.attachments.length > 0 ? n.attachments.map(L) : void 0
616
640
  }))
617
641
  };
618
642
  return this.eventEmitter.emit("conversation:loaded", i), i;
@@ -643,15 +667,15 @@ var K = class x {
643
667
  return l.warn("Cannot resume paused turn: function(s) not registered on this page:", o.map((r) => r.functionName)), null;
644
668
  let a = i.length === 0;
645
669
  for (const r of i) {
646
- let c, h;
670
+ let c, u;
647
671
  try {
648
672
  c = await this.functionRegistry.execute(r.functionName, r.arguments ?? {});
649
- } catch (u) {
650
- h = u instanceof Error ? u.message : "Unknown error", l.error("Client function execution failed:", u);
673
+ } catch (h) {
674
+ u = h instanceof Error ? h.message : "Unknown error", l.error("Client function execution failed:", h);
651
675
  }
652
676
  a = (await this.submitToolCallForm(r.id, {
653
677
  result: c,
654
- error: h,
678
+ error: u,
655
679
  _type: "client_function_result"
656
680
  }))?.resume?.ready ?? a;
657
681
  }
@@ -699,8 +723,8 @@ var K = class x {
699
723
  }
700
724
  registerNavigationFunction(t, s) {
701
725
  const i = s.map((r) => r.name), n = s.map((r) => {
702
- const c = w(r.path), h = c.length > 0 ? ` (requires ${c.map((u) => `"${u}"`).join(", ")})` : "";
703
- return `- "${r.name}"${h}: ${r.description}`;
726
+ const c = w(r.path), u = c.length > 0 ? ` (requires ${c.map((h) => `"${h}"`).join(", ")})` : "";
727
+ return `- "${r.name}"${u}: ${r.description}`;
704
728
  }).join(`
705
729
  `), o = /* @__PURE__ */ new Map();
706
730
  for (const r of s) for (const c of w(r.path)) o.set(c, [...o.get(c) ?? [], r.name]);
@@ -716,24 +740,24 @@ var K = class x {
716
740
  }
717
741
  a[r] = {
718
742
  type: "string",
719
- description: `Value for ":${r}" in the page path. Required when page is ${c.map((h) => `"${h}"`).join(" or ")}.`
743
+ description: `Value for ":${r}" in the page path. Required when page is ${c.map((u) => `"${u}"`).join(" or ")}.`
720
744
  };
721
745
  }
722
746
  this.registerFunction("navigateToPage", async (r) => {
723
- const c = r.page, h = s.find((m) => m.name === c);
724
- if (!h) return {
747
+ const c = r.page, u = s.find((m) => m.name === c);
748
+ if (!u) return {
725
749
  success: !1,
726
750
  error: `Unknown page: ${c}`
727
751
  };
728
- let u = {};
752
+ let h = {};
729
753
  if (typeof r.params == "string") try {
730
- u = JSON.parse(r.params);
754
+ h = JSON.parse(r.params);
731
755
  } catch {
732
756
  }
733
- else r.params && typeof r.params == "object" && (u = r.params);
757
+ else r.params && typeof r.params == "object" && (h = r.params);
734
758
  const C = {};
735
- for (const m of w(h.path)) C[m] = r[m] ?? u[m];
736
- const { path: b, missing: g } = W(h.path, C);
759
+ for (const m of w(u.path)) C[m] = r[m] ?? h[m];
760
+ const { path: b, missing: g } = J(u.path, C);
737
761
  if (g.length > 0) {
738
762
  const m = g.map((p) => `"${p}": "..."`).join(", ");
739
763
  return {
@@ -755,11 +779,11 @@ ${n}`,
755
779
  }
756
780
  }), this.addDynamicContext("current-page", () => {
757
781
  if (typeof window > "u" || !window.location) return null;
758
- const r = window.location.href, c = typeof document < "u" ? document.title : void 0, h = z(window.location.pathname, s), u = { url: r };
759
- return h && (u.page = h.name), c && (u.title = c), {
782
+ const r = window.location.href, c = typeof document < "u" ? document.title : void 0, u = q(window.location.pathname, s), h = { url: r };
783
+ return u && (h.page = u.name), c && (h.title = c), {
760
784
  name: "Current page",
761
785
  description: "The page the user is currently viewing.",
762
- data: u
786
+ data: h
763
787
  };
764
788
  });
765
789
  }
@@ -771,10 +795,10 @@ ${n}`,
771
795
  `);
772
796
  this.registerFunction(i, async (a) => {
773
797
  const r = {};
774
- for (const [c, h] of Object.entries(a)) {
775
- if (h === void 0) continue;
776
- const u = n.get(c);
777
- u && (await u.set(h), r[c] = h);
798
+ for (const [c, u] of Object.entries(a)) {
799
+ if (u === void 0) continue;
800
+ const h = n.get(c);
801
+ h && (await h.set(u), r[c] = u);
778
802
  }
779
803
  return {
780
804
  success: !0,
@@ -861,7 +885,7 @@ ${o}`,
861
885
  ...this.config,
862
886
  ...s
863
887
  };
864
- k(i, "AgoClient.updateConfig"), this.config = i, this.httpClient.updateConfig(s), s.debug !== void 0 && (s.debug ? l.enable() : l.disable());
888
+ x(i, "AgoClient.updateConfig"), this.config = i, this.httpClient.updateConfig(s), s.debug !== void 0 && (s.debug ? l.enable() : l.disable()), s.maxFunctionResultBytes !== void 0 && this.functionRegistry.setDefaultMaxResultBytes(s.maxFunctionResultBytes);
865
889
  }
866
890
  destroy() {
867
891
  this.eventEmitter.removeAllListeners(), this.functionRegistry.clear(), this.contextRegistry.clear(), this.pendingResumes.clear(), this.resumeGate = null, l.log("AgoClient destroyed");
@@ -869,20 +893,20 @@ ${o}`,
869
893
  };
870
894
  export {
871
895
  _,
872
- B as a,
873
- D as c,
874
- N as d,
896
+ K as a,
897
+ O as c,
898
+ P as d,
875
899
  l as f,
876
900
  y as g,
877
901
  E as h,
878
- H as i,
879
- J as l,
902
+ Y as i,
903
+ H as l,
880
904
  d as m,
881
- k as n,
882
- q as o,
905
+ x as n,
906
+ X as o,
883
907
  f as p,
884
- M as r,
885
- O as s,
886
- K as t,
887
- T as u
908
+ G as r,
909
+ B as s,
910
+ V as t,
911
+ M as u
888
912
  };
@@ -0,0 +1,8 @@
1
+ var d=class extends Error{constructor(e,t,n){super(e),this.code=t,this.statusCode=n,this.name="AgoError"}},f=class A extends d{constructor(t,n,i,s,o,a){super(t,n,i),this.type=s,this.param=o,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,n){const i=t.error;return new A(i.doc_url?`${i.message} See ${i.doc_url}`:i.message,i.code,n,i.type,i.param,i.doc_url)}},g=class extends d{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},v=class extends d{constructor(e,t="stream_error"){super(e,t),this.name="AgoStreamError"}},b=class extends d{constructor(e,t,n){super(e,"function_error"),this.functionName=t,this.originalError=n,this.name="AgoFunctionError"}},P=class{constructor(e=!1){this.enabled=e}enable(){this.enabled=!0}disable(){this.enabled=!1}log(...e){this.enabled&&console.log("[AGO SDK]",...e)}warn(...e){this.enabled&&console.warn("[AGO SDK]",...e)}error(...e){console.error("[AGO SDK]",...e)}debug(...e){this.enabled&&console.debug("[AGO SDK]",...e)}},l=new P,S="ago_widget_id";function O(){if(typeof localStorage<"u"){const t=localStorage.getItem(S);if(t)return t}const e=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`;if(typeof localStorage<"u")try{localStorage.setItem(S,e)}catch{}return e}var j=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||O()},e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission&&(this.headers["X-Widget-Permission"]=e.permission)}updateConfig(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),e.widgetId&&(this.headers["X-User-Anon-Id"]=e.widgetId),e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission!==void 0&&(e.permission?this.headers["X-Widget-Permission"]=e.permission:delete this.headers["X-Widget-Permission"])}async get(e){return this.request("GET",e)}async post(e,t){return this.request("POST",e,t)}async postStream(e,t){const n=`${this.baseUrl}${e}`;l.debug("POST (stream)",n,t);try{const i=await fetch(n,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return i.ok||await this.handleErrorResponse(i),i}catch(i){throw i instanceof f?i:new g(`Network error: ${i instanceof Error?i.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,i instanceof Error?i:void 0)}}async postFormData(e,t){const n=`${this.baseUrl}${e}`;l.debug("POST (formData)",n);const i={...this.headers};try{const s=await fetch(n,{method:"POST",headers:i,body:t});return s.ok||await this.handleErrorResponse(s),s}catch(s){throw s instanceof f?s:new g(`Network error: ${s instanceof Error?s.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,s instanceof Error?s:void 0)}}async request(e,t,n){const i=`${this.baseUrl}${t}`;l.debug(e,i,n);try{const s=await fetch(i,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:n?JSON.stringify(n):void 0});return s.ok||await this.handleErrorResponse(s),s.status===204?void 0:s.json()}catch(s){throw s instanceof f?s:new g(`Network error: ${s instanceof Error?s.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,s instanceof Error?s:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw f.fromResponse(t,e.status);let n="";throw e.status===401||e.status===403?n=" Check `userJwt` (and that it has not expired).":e.status===404&&(n=" Check that `baseUrl` points at your AGO API root."),new f(`HTTP ${e.status}: ${e.statusText}.${n}`,"http_error",e.status,"api_error")}},D=5e4,M=2e4,B=2e3,k=class{constructor(e){this.functions=new Map,this.defaultMaxResultBytes=e?.maxResultBytes??D}setDefaultMaxResultBytes(e){this.defaultMaxResultBytes=e}register(e,t,n){if(typeof e=="object"){const{name:a,handler:r,description:c,parameters:u,maxResultBytes:h}=e;return this.register(a,r,{description:c,parameters:u,maxResultBytes:h})}const i=e;if(!t||!n)throw new d(`registerFunction("${i}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`,"function_invalid_registration");this.functions.has(i)&&l.warn(`Function "${i}" is being overwritten`);const{maxResultBytes:s,...o}=n;this.functions.set(i,{schema:{...o,name:i},handler:t,maxResultBytes:s}),l.log(`Registered function: ${i}`)}unregister(e){const t=this.functions.delete(e);return t&&l.log(`Unregistered function: ${e}`),t}get(e){return this.functions.get(e)}has(e){return this.functions.has(e)}getSchemas(){return Array.from(this.functions.values()).map(e=>e.schema)}async execute(e,t){const n=this.functions.get(e);if(!n)throw new b(`Function "${e}" is not registered`,e);l.log(`Executing function: ${e}`,t);try{const i=await n.handler(t);return l.log(`Function ${e} completed:`,i),this.guardResultSize(e,i,n.maxResultBytes)}catch(i){throw l.error(`Function ${e} failed:`,i),new b(`Function "${e}" execution failed: ${i instanceof Error?i.message:"Unknown error"}`,e,i instanceof Error?i:void 0)}}guardResultSize(e,t,n){let i;try{i=JSON.stringify(t)}catch{return t}if(i===void 0)return t;const s=new TextEncoder().encode(i).length,o=n??this.defaultMaxResultBytes;return s>o?(l.warn(`Function "${e}" result is ${s} bytes, over the ${o}-byte limit; a truncated preview was sent to the agent instead. Return fewer fields, paginate, or raise maxResultBytes for this function.`),{truncated:!0,originalBytes:s,maxBytes:o,preview:i.slice(0,B),hint:`The result of "${e}" exceeded the ${o}-byte limit and was truncated. Request less data (use limit or filter parameters if available), or tell the user the result is too large to process.`}):(s>M&&l.warn(`Function "${e}" returned a large result (${Math.round(s/1024)} KB). Large results consume LLM context: return fewer fields, paginate, or push the data to the UI and return a summary.`),t)}clear(){this.functions.clear(),l.log("Cleared all registered functions")}get size(){return this.functions.size}},F=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),l.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&l.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),l.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&l.log(`DynamicContext provider removed: ${e}`),t}getSnapshot(){if(this.entries.size===0&&this.dynamicProviders.size===0)return null;const e={};for(const[t,n]of this.entries)e[t]=n;for(const[t,n]of this.dynamicProviders)try{const i=n();i&&(e[t]=i)}catch(i){l.error(`DynamicContext provider "${t}" threw:`,i)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),l.log("ClientContext cleared")}};function C(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(C).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${C(e[t])}`).join(",")}}`}var I=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.waitingClientEmitted=!1,this.firedClientFunctions=new Set}async processStream(e){if(!e.body)throw new v("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.","stream_no_body");const t=e.body.getReader(),n=new TextDecoder;try{for(;;){const{done:i,value:s}=await t.read();if(i)break;const o=n.decode(s,{stream:!0});this.buffer+=o,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(i){const s=i instanceof Error?i:new v("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(s),s}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
2
+
3
+ `);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const n=t.split(`
4
+ `);for(const i of n)if(!i.startsWith(": ")&&i.startsWith("data: ")){const s=i.slice(6);try{const o=JSON.parse(s);this.handleChunk(o)}catch(o){l.warn("Failed to parse SSE data:",s,o)}}}}handleChunk(e){if(this.callbacks.onRawChunk?.(e),e.message_id&&!this.message.id&&(this.message.id=e.message_id),e.thread?.id&&(this.message.conversationId=e.thread.id,this.isFirstChunk&&this.message.id&&(this.isFirstChunk=!1,this.callbacks.onStart?.({conversationId:this.message.conversationId,messageId:this.message.id}))),e.content!==void 0&&(this.message.content=(this.message.content||"")+e.content,this.message.conversationId&&this.message.id&&this.callbacks.onChunk?.({content:e.content,conversationId:this.message.conversationId,messageId:this.message.id})),e.full_content!==void 0&&(this.message.content=e.full_content),e.status&&(this.message.status=e.status),e.agent&&(this.message.agent={id:e.agent.id,name:e.agent.name,displayName:e.agent.display_name}),e.knowledge_sources&&(this.sources=e.knowledge_sources.map(t=>{const n=t.knowledge_document;return{id:n.id,title:n.title,url:n.use_external_link?n.external_link_url:n.internal_link_url}})),e.type==="client_function"&&e.function_name){const t=`${e.function_name}::${C(e.arguments??{})}`;this.firedClientFunctions.has(t)||(this.firedClientFunctions.add(t),this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}))}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const n=this.toolCalls.findIndex(i=>i.id===t.id);n>=0?this.toolCalls[n]=t:this.toolCalls.push(t)}e.follow_up_replies&&(this.followUpReplies=e.follow_up_replies),this.message.status==="DONE"&&!this.answerCompleteEmitted&&this.message.id&&(this.answerCompleteEmitted=!0,this.callbacks.onAnswerComplete?.(this.buildMessage())),this.message.status==="WAITING_CLIENT"&&!this.waitingClientEmitted&&this.message.id&&(this.waitingClientEmitted=!0,this.callbacks.onWaitingClient?.({conversationId:this.message.conversationId||"",messageId:this.message.id,waitingToolCallIds:e.waiting_tool_call_ids??[]}))}parseToolCall(e){return{id:e.id||"",type:e.type||"status_message",status:e.status||"unknown",toolName:e.tool_name||"",toolDisplayName:e.tool_display_name,message:e.message,formSchema:e.form_schema,data:e.data,functionName:e.function_name,arguments:e.arguments}}buildMessage(){return{id:this.message.id||"",conversationId:this.message.conversationId||"",content:this.message.content||"",role:"assistant",status:this.message.status||"DONE",agent:this.message.agent,sources:this.sources.length>0?this.sources:void 0,toolCalls:this.toolCalls.length>0?this.toolCalls:void 0,followUpReplies:this.followUpReplies.length>0?this.followUpReplies:void 0,createdAt:new Date}}buildFinalMessage(){const e=this.buildMessage();return e.status!=="WAITING_CLIENT"&&this.callbacks.onComplete?.(e),e}};function L(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var G=new Set(["image/jpeg","image/png","image/gif","image/webp","image/bmp","image/tiff"]);function U(e){if(!e)return;const t=typeof window<"u"&&window.location?window.location.href:"https://ago.local/";try{const n=new URL(e,t);if(n.protocol==="http:"||n.protocol==="https:"||n.protocol==="blob:")return e}catch{}}function W(e){return e.isSafeImage===!0&&typeof e.contentType=="string"&&e.contentType.startsWith("image/")&&U(e.url)!==void 0}function z(e){if(e==null||e<0)return"";if(e<1024)return`${e} B`;const t=e/1024;return t<1024?`${t.toFixed(1)} KB`:`${(t/1024).toFixed(1)} MB`}function J(e){return{id:String(e.id??""),name:typeof e.name=="string"&&e.name?e.name:"file",contentType:typeof e.content_type=="string"?e.content_type:void 0,fileSize:typeof e.file_size=="number"?e.file_size:void 0,url:typeof e.file_url=="string"?e.file_url:void 0,isSafeImage:e.is_safe_image===!0}}function q(e){return e.map((t,n)=>({id:`local-${n}-${t.name}`,name:t.name,contentType:t.type||void 0,fileSize:t.size,url:typeof URL<"u"&&URL.createObjectURL?URL.createObjectURL(t):void 0,isSafeImage:G.has(t.type)}))}var N=class{constructor(){this.handlers=new Map}on(e,t){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(t)}off(e,t){const n=this.handlers.get(e);n&&n.delete(t)}emit(e,t){const n=this.handlers.get(e);n&&n.forEach(i=>{try{i(t)}catch(s){console.error(`Error in event handler for ${String(e)}:`,s)}})}once(e,t){const n=(i=>{this.off(e,n),t(i)});this.on(e,n)}waitFor(e,t){return new Promise((n,i)=>{let s;const o=(a=>{s&&clearTimeout(s),n(a)});this.once(e,o),t?.timeout&&(s=setTimeout(()=>{this.off(e,o),i(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},$='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).',H=/^[a-z][a-z0-9+.-]*:\/\//i,x=!1;function E(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new d(`${t}: ${$}`,"config_missing_base_url");const n=e.baseUrl;if(typeof n!="string"||n.trim()==="")throw new d(`${t}: ${$}`,"config_missing_base_url");!n.startsWith("/")&&!H.test(n)&&(x||(x=!0,console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)))}function K(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function w(e){return e.split("/").filter(t=>t.startsWith(":")).map(t=>t.slice(1))}function X(e,t){const n=[];return{path:e.split("/").map(i=>{if(!i.startsWith(":"))return i;const s=i.slice(1),o=t[s];return o==null||o===""?(n.push(s),i):encodeURIComponent(String(o))}).join("/"),missing:n}}function Y(e,t){const n=t.find(s=>s.path===e);if(n)return n;const i=t.find(s=>{if(!s.path.includes(":"))return!1;const o="^"+s.path.split("/").map(a=>a.startsWith(":")?"[^/]+":K(a)).join("/")+"/?$";return new RegExp(o).test(e)});return i||t.filter(s=>s.path!=="/"&&e.startsWith(s.path)).sort((s,o)=>o.path.length-s.path.length)[0]}var V=class T{constructor(t){this.warnedEmptyConversations=new Set,this.pendingResumes=new Map,this.resumeGate=null,E(t,"AgoClient"),this.config=t,this.httpClient=new j(t),this.functionRegistry=new k({maxResultBytes:t.maxFunctionResultBytes}),this.contextRegistry=new F,this.eventEmitter=new N,t.debug&&l.enable(),l.log("AgoClient initialized")}async sendMessage(t,n){const i=this.functionRegistry.getSchemas(),s=this.contextRegistry.getSnapshot(),o=this.config.agent||this.config.defaultAgentId,a=this.resolveClientFunctionsMode(n),r={content:t,conversation_id:n?.conversationId,agent_id:n?.agentId||o};i.length>0&&(r.client_functions=i,a==="pause"&&(r.client_functions_mode=a)),s&&(r.client_context=s),n?.hidden&&(r.hidden=!0);let c;if(n?.files&&n.files.length>0){const u=new FormData;u.append("content",t),n.conversationId&&u.append("conversation_id",n.conversationId),(n.agentId||o)&&u.append("agent_id",n.agentId||o||""),i.length>0&&(u.append("client_functions",JSON.stringify(i)),a==="pause"&&u.append("client_functions_mode",a)),s&&u.append("client_context",JSON.stringify(s)),n.hidden&&u.append("hidden","true");for(const h of n.files)u.append("files",h);c=await this.httpClient.postFormData("/api/sdk/v1/messages",u)}else c=await this.httpClient.postStream("/api/sdk/v1/messages",r);return this.processSSEResponse(c)}async processSSEResponse(t){let n=!1;const i=await new I({onRawChunk:s=>{this.eventEmitter.emit("stream:message",s)},onStart:s=>{this.eventEmitter.emit("message:start",s)},onChunk:s=>{this.eventEmitter.emit("message:chunk",s)},onToolCall:s=>{this.eventEmitter.emit("toolCall:received",s),s.type==="form"&&this.eventEmitter.emit("toolCall:form",s)},onClientFunction:async s=>{n=!0,this.eventEmitter.emit("function:invoke",s),await this.handleClientFunctionInvocation(s)},onAnswerComplete:s=>{this.eventEmitter.emit("message:answer-complete",s)},onWaitingClient:s=>{this.eventEmitter.emit("message:waiting-client",s),this.markResumeSignal(s.messageId,s.conversationId,"waitingConfirmed")},onComplete:s=>{this.eventEmitter.emit("message:complete",s)},onError:s=>{this.eventEmitter.emit("message:error",{error:s.message,code:s instanceof d?s.code:void 0})}}).processStream(t);return i.status!=="WAITING_CLIENT"&&this.maybeFlagEmptyReply(i,n),i}resolveClientFunctionsMode(t){return t?.clientFunctionsMode??this.config.clientFunctionsMode??"pause"}registerResumeGate(t){return this.resumeGate=t,()=>{this.resumeGate===t&&(this.resumeGate=null)}}async continueMessage(t){const n=this.functionRegistry.getSchemas(),i=this.contextRegistry.getSnapshot(),s={};n.length>0&&(s.client_functions=n),i&&(s.client_context=i);const o=await this.httpClient.postStream(`/api/sdk/v1/messages/${t}/continue`,s);return this.processSSEResponse(o)}markResumeSignal(t,n,i){if(!t)return;const s=this.pendingResumes.get(t)??{conversationId:n,waitingConfirmed:!1,resultsReady:!1,started:!1};s[i]=!0,n&&(s.conversationId=n),this.pendingResumes.set(t,s),!(!s.waitingConfirmed||!s.resultsReady||s.started)&&(s.started=!0,this.runAutoResume(t,s.conversationId))}async runAutoResume(t,n){try{this.resumeGate&&await this.resumeGate({conversationId:n,messageId:t})}catch(i){l.warn("Resume gate threw; resuming anyway:",i)}this.pendingResumes.delete(t);try{await this.continueMessage(t)}catch(i){l.warn("Auto-resume of paused turn failed:",i)}}maybeFlagEmptyReply(t,n){t.status==="DONE"&&(t.content??"").trim()===""&&!n&&!(t.toolCalls&&t.toolCalls.length>0)&&!(t.followUpReplies&&t.followUpReplies.length>0)&&setTimeout(()=>{if(this.eventEmitter.emit("message:empty",{conversationId:t.conversationId??"",messageId:t.id??""}),this.config.warnOnEmptyReply===!1)return;const i=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(i))return;this.warnedEmptyConversations.add(i);const s=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(s?`the agent "${s}" may not exist for this tenant, `:"an unknown `agent` slug, ")+"or the agent replied with no text. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`."):console.warn("[AGO] The stream completed without any message data. Possible causes: "+(s?`the agent "${s}" may not exist for this tenant, or `:"")+"`baseUrl` does not point at an AGO endpoint that returns server-sent events. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`.")},0)}async handleClientFunctionInvocation(t){let n,i;try{n=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(s){i=s instanceof Error?s.message:"Unknown error",l.error("Client function execution failed:",s)}if(t.invocationId)try{const s=await this.submitToolCallForm(t.invocationId,{result:n,error:i,_type:"client_function_result"});s?.resume?.ready&&this.markResumeSignal(s.resume.message_id,t.conversationId,"resultsReady")}catch(s){l.error("Failed to submit function result:",s)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:n,error:i})}async getConversations(){return(await this.httpClient.get("/api/sdk/v1/conversations")).items.map(t=>({id:t.id,title:t.title,lastMessageDate:new Date(t.last_message_date)}))}async getConversation(t){const n=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),i={id:n.id,title:n.title,lastMessageDate:new Date(n.last_message_date),messages:n.messages.map(s=>({id:s.id,conversationId:n.id,content:s.content,role:s.role,status:s.status,createdAt:new Date(s.created_at),hidden:s.hidden,toolCalls:T.mapPersistedToolCalls(s.tool_call_data),attachments:s.attachments&&s.attachments.length>0?s.attachments.map(J):void 0}))};return this.eventEmitter.emit("conversation:loaded",i),i}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(n=>({id:String(n.id??""),type:n.type??"status_message",status:String(n.status??"unknown"),toolName:n.tool_name??"",toolDisplayName:n.tool_display_name,message:n.message,formSchema:n.form_schema,data:n.data,functionName:n.function_name,arguments:n.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async resumePendingClientFunctions(t){const n=[...t.messages??[]].reverse().find(r=>r.role==="assistant"&&r.status==="WAITING_CLIENT");if(!n)return null;const i=(n.toolCalls??[]).filter(r=>r.type==="client_function"&&r.status==="waiting_input"&&r.functionName),s=new Set(this.functionRegistry.getSchemas().map(r=>r.name)),o=i.filter(r=>!s.has(r.functionName));if(o.length>0)return l.warn("Cannot resume paused turn: function(s) not registered on this page:",o.map(r=>r.functionName)),null;let a=i.length===0;for(const r of i){let c,u;try{c=await this.functionRegistry.execute(r.functionName,r.arguments??{})}catch(h){u=h instanceof Error?h.message:"Unknown error",l.error("Client function execution failed:",h)}a=(await this.submitToolCallForm(r.id,{result:c,error:u,_type:"client_function_result"}))?.resume?.ready??a}return a?this.continueMessage(n.id):null}async submitToolCallForm(t,n){return this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:n})}async confirmToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/confirm/`)}async rejectToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/reject/`)}async getFormCollector(t){const n=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:n.name,description:n.description,schema:n.schema,submit:n.submit??void 0}}async submitFormCollector(t,n){return this.httpClient.post("/api/sdk/v1/forms/submit",{name:t,values:n})}async submitFeedback(t,n){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:n})}registerFunction(t,n,i){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,n,i)}register(t){if(Array.isArray(t))for(const n of t)this.functionRegistry.register(n);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}registerNavigationFunction(t,n){const i=n.map(r=>r.name),s=n.map(r=>{const c=w(r.path),u=c.length>0?` (requires ${c.map(h=>`"${h}"`).join(", ")})`:"";return`- "${r.name}"${u}: ${r.description}`}).join(`
5
+ `),o=new Map;for(const r of n)for(const c of w(r.path))o.set(c,[...o.get(c)??[],r.name]);const a={page:{type:"string",description:"The page to navigate to",enum:i}};for(const[r,c]of o){if(r==="page"){l.error('registerNavigationFunction: a ":page" placeholder collides with the "page" argument and is ignored. Rename the placeholder.');continue}a[r]={type:"string",description:`Value for ":${r}" in the page path. Required when page is ${c.map(u=>`"${u}"`).join(" or ")}.`}}this.registerFunction("navigateToPage",async r=>{const c=r.page,u=n.find(m=>m.name===c);if(!u)return{success:!1,error:`Unknown page: ${c}`};let h={};if(typeof r.params=="string")try{h=JSON.parse(r.params)}catch{}else r.params&&typeof r.params=="object"&&(h=r.params);const _={};for(const m of w(u.path))_[m]=r[m]??h[m];const{path:R,missing:p}=X(u.path,_);if(p.length>0){const m=p.map(y=>`"${y}": "..."`).join(", ");return{success:!1,error:`Page "${c}" needs ${p.map(y=>`"${y}"`).join(", ")}. Retry with { "page": "${c}", ${m} }.`}}return t(R),{success:!0,navigatedTo:R}},{description:`Navigate the user to a page in the application. Available pages:
6
+ ${s}`,parameters:{type:"object",properties:a,required:["page"]}}),this.addDynamicContext("current-page",()=>{if(typeof window>"u"||!window.location)return null;const r=window.location.href,c=typeof document<"u"?document.title:void 0,u=Y(window.location.pathname,n),h={url:r};return u&&(h.page=u.name),c&&(h.title=c),{name:"Current page",description:"The page the user is currently viewing.",data:h}})}unregisterNavigationFunction(){this.unregisterFunction("navigateToPage"),this.removeDynamicContext("current-page")}registerPageStateFunction(t,n){const i=n?.functionName??"setPageState",s=new Map(t.map(a=>[a.name,a])),o=t.map(a=>`- "${a.name}": ${a.description}`).join(`
7
+ `);this.registerFunction(i,async a=>{const r={};for(const[c,u]of Object.entries(a)){if(u===void 0)continue;const h=s.get(c);h&&(await h.set(u),r[c]=u)}return{success:!0,applied:r}},{description:`Change the state of the current page. Set ONLY the controls the user explicitly asked for; leave the others unset. Available controls:
8
+ ${o}`,parameters:{type:"object",properties:Object.fromEntries(t.map(a=>[a.name,{...a.schema,description:a.description}]))}}),this.addDynamicContext(`page-state:${i}`,()=>{const a=t.filter(c=>typeof c.get=="function");if(a.length===0)return null;const r={};for(const c of a)r[c.name]=c.get();return{name:"Page state",description:"Current, editable state of the page the user is viewing.",data:r}})}unregisterPageStateFunction(t){const n=t??"setPageState";this.unregisterFunction(n),this.removeDynamicContext(`page-state:${n}`)}setContext(t,n){this.contextRegistry.set(t,n),this.notifyContextChanged()}removeContext(t){const n=this.contextRegistry.remove(t);return n&&this.notifyContextChanged(),n}addDynamicContext(t,n){this.contextRegistry.addDynamicProvider(t,n),this.notifyContextChanged()}removeDynamicContext(t){const n=this.contextRegistry.removeDynamicProvider(t);return n&&this.notifyContextChanged(),n}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}emitFormEvent(t,n){this.eventEmitter.emit(t,n)}enableAutoPageContext(){this.addDynamicContext("browser-page",()=>{const t=typeof window<"u"?window.location.href:void 0,n=typeof document<"u"?document.title:void 0;return!t&&!n?null:{name:"Browser page",description:"Current page the user is viewing",data:{url:t,title:n}}})}getContextSnapshot(){return this.contextRegistry.getSnapshot()}on(t,n){this.eventEmitter.on(t,n)}off(t,n){this.eventEmitter.off(t,n)}once(t,n){this.eventEmitter.once(t,n)}waitFor(t,n){return this.eventEmitter.waitFor(t,n)}updateConfig(t){const n={};for(const[s,o]of Object.entries(t))o!==void 0&&(n[s]=o);const i={...this.config,...n};E(i,"AgoClient.updateConfig"),this.config=i,this.httpClient.updateConfig(n),n.debug!==void 0&&(n.debug?l.enable():l.disable()),n.maxFunctionResultBytes!==void 0&&this.functionRegistry.setDefaultMaxResultBytes(n.maxFunctionResultBytes)}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),this.pendingResumes.clear(),this.resumeGate=null,l.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return f}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return V}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return d}});Object.defineProperty(exports,"AgoFunctionError",{enumerable:!0,get:function(){return b}});Object.defineProperty(exports,"AgoNetworkError",{enumerable:!0,get:function(){return g}});Object.defineProperty(exports,"AgoStreamError",{enumerable:!0,get:function(){return v}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return F}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return N}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return k}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return I}});Object.defineProperty(exports,"attachmentsFromFiles",{enumerable:!0,get:function(){return q}});Object.defineProperty(exports,"canInlineImage",{enumerable:!0,get:function(){return W}});Object.defineProperty(exports,"formatFileSize",{enumerable:!0,get:function(){return z}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return L}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return l}});Object.defineProperty(exports,"safeAttachmentUrl",{enumerable:!0,get:function(){return U}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return E}});
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-CMDVqNaH.cjs");var n=class{constructor(e){this.client=new o.AgoClient(e),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(e){const t=this.client;return{subscribe(i){const s=r=>{i.next?.(r)};return t.on(e,s),{unsubscribe:()=>t.off(e,s)}}}}sendMessage(e,t){return this.client.sendMessage(e,t)}getConversations(){return this.client.getConversations()}getConversation(e){return this.client.getConversation(e)}getMessages(e){return this.client.getMessages(e)}submitToolCallForm(e,t){return this.client.submitToolCallForm(e,t)}confirmToolCall(e){return this.client.confirmToolCall(e)}rejectToolCall(e){return this.client.rejectToolCall(e)}submitFeedback(e,t){return this.client.submitFeedback(e,t)}registerFunction(e,t,i){typeof e=="object"?this.client.registerFunction(e):this.client.registerFunction(e,t,i)}unregisterFunction(e){return this.client.unregisterFunction(e)}registerNavigationFunction(e,t){this.client.registerNavigationFunction(e,t)}unregisterNavigationFunction(){this.client.unregisterNavigationFunction()}registerPageStateFunction(e,t){this.client.registerPageStateFunction(e,t)}unregisterPageStateFunction(e){this.client.unregisterPageStateFunction(e)}on(e,t){this.client.on(e,t)}off(e,t){this.client.off(e,t)}updateConfig(e){this.client.updateConfig(e)}getClient(){return this.client}destroy(){this.client.destroy()}};function c(e){return{provide:n,useValue:new n(e)}}exports.AgoService=n;exports.provideAgo=c;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-wcPRaIMs.cjs"),c=require("./autoContinue-CcCTva-D.cjs");var n=class{constructor(t){this.client=new o.AgoClient(t),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(t){const e=this.client;return{subscribe(i){const r=s=>{i.next?.(s)};return e.on(t,r),{unsubscribe:()=>e.off(t,r)}}}}sendMessage(t,e){return this.client.sendMessage(t,e)}getConversations(){return this.client.getConversations()}getConversation(t){return this.client.getConversation(t)}getMessages(t){return this.client.getMessages(t)}submitToolCallForm(t,e){return this.client.submitToolCallForm(t,e)}confirmToolCall(t){return this.client.confirmToolCall(t)}rejectToolCall(t){return this.client.rejectToolCall(t)}submitFeedback(t,e){return this.client.submitFeedback(t,e)}registerFunction(t,e,i){typeof t=="object"?this.client.registerFunction(t):this.client.registerFunction(t,e,i)}unregisterFunction(t){return this.client.unregisterFunction(t)}registerNavigationFunction(t,e){this.client.registerNavigationFunction(t,e)}unregisterNavigationFunction(){this.client.unregisterNavigationFunction()}enableAutoContinueAfterNavigation(t){return c.attachAutoContinueAfterNavigation(this.client,t)}registerPageStateFunction(t,e){this.client.registerPageStateFunction(t,e)}unregisterPageStateFunction(t){this.client.unregisterPageStateFunction(t)}on(t,e){this.client.on(t,e)}off(t,e){this.client.off(t,e)}updateConfig(t){this.client.updateConfig(t)}getClient(){return this.client}destroy(){this.client.destroy()}};function u(t){return{provide:n,useValue:new n(t)}}exports.AgoService=n;exports.provideAgo=u;