@antipopp/agno-client 0.8.0 → 0.10.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.
package/dist/index.mjs CHANGED
@@ -1,85 +1,9 @@
1
+ // src/index.ts
2
+ import { RunEvent as RunEvent2 } from "@antipopp/agno-types";
3
+
1
4
  // src/client.ts
2
- import EventEmitter from "eventemitter3";
3
5
  import { RunEvent } from "@antipopp/agno-types";
4
-
5
- // src/stores/message-store.ts
6
- var MessageStore = class {
7
- constructor() {
8
- this.messages = [];
9
- }
10
- /**
11
- * Get all messages
12
- */
13
- getMessages() {
14
- return [...this.messages];
15
- }
16
- /**
17
- * Set messages (replaces all)
18
- */
19
- setMessages(messages) {
20
- this.messages = [...messages];
21
- }
22
- /**
23
- * Add a message
24
- */
25
- addMessage(message) {
26
- this.messages = [...this.messages, message];
27
- }
28
- /**
29
- * Update the last message
30
- */
31
- updateLastMessage(updater) {
32
- if (this.messages.length === 0)
33
- return void 0;
34
- const lastMessage = this.messages[this.messages.length - 1];
35
- const updatedMessage = updater(lastMessage);
36
- this.messages = [
37
- ...this.messages.slice(0, -1),
38
- updatedMessage
39
- ];
40
- return updatedMessage;
41
- }
42
- /**
43
- * Update a specific message by index
44
- */
45
- updateMessage(index, updater) {
46
- if (index < 0 || index >= this.messages.length)
47
- return void 0;
48
- const message = this.messages[index];
49
- const updatedMessage = updater(message);
50
- this.messages = [
51
- ...this.messages.slice(0, index),
52
- updatedMessage,
53
- ...this.messages.slice(index + 1)
54
- ];
55
- return updatedMessage;
56
- }
57
- /**
58
- * Remove last N messages
59
- */
60
- removeLastMessages(count) {
61
- this.messages = this.messages.slice(0, -count);
62
- }
63
- /**
64
- * Clear all messages
65
- */
66
- clear() {
67
- this.messages = [];
68
- }
69
- /**
70
- * Get the last message
71
- */
72
- getLastMessage() {
73
- return this.messages.length > 0 ? this.messages[this.messages.length - 1] : void 0;
74
- }
75
- /**
76
- * Check if last message has streaming error
77
- */
78
- hasLastMessageError() {
79
- const lastMessage = this.getLastMessage();
80
- return lastMessage?.streamingError === true;
81
- }
82
- };
6
+ import EventEmitter from "eventemitter3";
83
7
 
84
8
  // src/managers/config-manager.ts
85
9
  var ConfigManager = class {
@@ -212,6 +136,18 @@ var ConfigManager = class {
212
136
  setHeaders(headers) {
213
137
  this.updateField("headers", headers);
214
138
  }
139
+ /**
140
+ * Get global query parameters
141
+ */
142
+ getParams() {
143
+ return this.config.params;
144
+ }
145
+ /**
146
+ * Set global query parameters
147
+ */
148
+ setParams(params) {
149
+ this.updateField("params", params);
150
+ }
215
151
  /**
216
152
  * Get current entity ID (agent or team based on mode)
217
153
  */
@@ -225,14 +161,14 @@ var ConfigManager = class {
225
161
  const mode = this.getMode();
226
162
  const endpoint = this.getEndpoint();
227
163
  const entityId = this.getCurrentEntityId();
228
- if (!entityId)
164
+ if (!entityId) {
229
165
  return null;
166
+ }
230
167
  const encodedEntityId = encodeURIComponent(entityId);
231
168
  if (mode === "team") {
232
169
  return `${endpoint}/teams/${encodedEntityId}/runs`;
233
- } else {
234
- return `${endpoint}/agents/${encodedEntityId}/runs`;
235
170
  }
171
+ return `${endpoint}/agents/${encodedEntityId}/runs`;
236
172
  }
237
173
  /**
238
174
  * Build request headers by merging global headers, per-request headers, and auth token.
@@ -255,10 +191,30 @@ var ConfigManager = class {
255
191
  }
256
192
  const authToken = this.getAuthToken();
257
193
  if (authToken) {
258
- headers["Authorization"] = `Bearer ${authToken}`;
194
+ headers.Authorization = `Bearer ${authToken}`;
259
195
  }
260
196
  return headers;
261
197
  }
198
+ /**
199
+ * Build query string by merging global params and per-request params.
200
+ * Merge order (lowest to highest precedence):
201
+ * 1. Global params from config
202
+ * 2. Per-request params (overrides global)
203
+ *
204
+ * @param perRequestParams - Optional query parameters for this specific request
205
+ * @returns URLSearchParams object ready to append to URLs
206
+ */
207
+ buildQueryString(perRequestParams) {
208
+ const params = {};
209
+ const globalParams = this.getParams();
210
+ if (globalParams) {
211
+ Object.assign(params, globalParams);
212
+ }
213
+ if (perRequestParams) {
214
+ Object.assign(params, perRequestParams);
215
+ }
216
+ return new URLSearchParams(params);
217
+ }
262
218
  };
263
219
 
264
220
  // src/managers/session-manager.ts
@@ -266,11 +222,16 @@ var SessionManager = class {
266
222
  /**
267
223
  * Fetch all sessions for an entity
268
224
  */
269
- async fetchSessions(endpoint, entityType, entityId, dbId, headers) {
225
+ async fetchSessions(endpoint, entityType, entityId, dbId, headers, params) {
270
226
  const url = new URL(`${endpoint}/sessions`);
271
227
  url.searchParams.set("type", entityType);
272
228
  url.searchParams.set("component_id", entityId);
273
229
  url.searchParams.set("db_id", dbId);
230
+ if (params) {
231
+ params.forEach((value, key) => {
232
+ url.searchParams.set(key, value);
233
+ });
234
+ }
274
235
  const response = await fetch(url.toString(), { headers });
275
236
  if (!response.ok) {
276
237
  if (response.status === 404) {
@@ -285,7 +246,7 @@ var SessionManager = class {
285
246
  * Fetch a specific session's runs
286
247
  * Returns an array of RunSchema directly (not wrapped in { data, meta })
287
248
  */
288
- async fetchSession(endpoint, entityType, sessionId, dbId, headers, userId) {
249
+ async fetchSession(endpoint, entityType, sessionId, dbId, headers, userId, params) {
289
250
  const url = new URL(`${endpoint}/sessions/${sessionId}/runs`);
290
251
  url.searchParams.set("type", entityType);
291
252
  if (dbId) {
@@ -294,6 +255,11 @@ var SessionManager = class {
294
255
  if (userId) {
295
256
  url.searchParams.set("user_id", userId);
296
257
  }
258
+ if (params) {
259
+ params.forEach((value, key) => {
260
+ url.searchParams.set(key, value);
261
+ });
262
+ }
297
263
  const response = await fetch(url.toString(), { headers });
298
264
  if (!response.ok) {
299
265
  throw new Error(`Failed to fetch session: ${response.statusText}`);
@@ -303,11 +269,16 @@ var SessionManager = class {
303
269
  /**
304
270
  * Delete a session
305
271
  */
306
- async deleteSession(endpoint, sessionId, dbId, headers) {
272
+ async deleteSession(endpoint, sessionId, dbId, headers, params) {
307
273
  const url = new URL(`${endpoint}/sessions/${sessionId}`);
308
274
  if (dbId) {
309
275
  url.searchParams.set("db_id", dbId);
310
276
  }
277
+ if (params) {
278
+ params.forEach((value, key) => {
279
+ url.searchParams.set(key, value);
280
+ });
281
+ }
311
282
  const response = await fetch(url.toString(), {
312
283
  method: "DELETE",
313
284
  headers
@@ -366,7 +337,9 @@ var SessionManager = class {
366
337
  tool_name: reasoningMsg.tool_name ?? "",
367
338
  tool_args: reasoningMsg.tool_args ?? {},
368
339
  tool_call_error: reasoningMsg.tool_call_error ?? false,
369
- metrics: reasoningMsg.metrics ?? { time: 0 },
340
+ metrics: reasoningMsg.metrics ?? {
341
+ time: 0
342
+ },
370
343
  created_at: reasoningMsg.created_at ?? timestamp
371
344
  });
372
345
  }
@@ -400,6 +373,164 @@ var SessionManager = class {
400
373
  }
401
374
  };
402
375
 
376
+ // src/parsers/stream-parser.ts
377
+ function isLegacyFormat(data) {
378
+ return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
379
+ }
380
+ function convertNewFormatToLegacy(newFormatData) {
381
+ const { event, data } = newFormatData;
382
+ let parsedData;
383
+ if (typeof data === "string") {
384
+ try {
385
+ parsedData = JSON.parse(data);
386
+ } catch {
387
+ parsedData = {};
388
+ }
389
+ } else {
390
+ parsedData = data;
391
+ }
392
+ return {
393
+ event,
394
+ ...parsedData
395
+ };
396
+ }
397
+ function processChunk(chunk, onChunk) {
398
+ onChunk(chunk);
399
+ }
400
+ function parseBuffer(buffer, onChunk) {
401
+ let currentIndex = 0;
402
+ let jsonStartIndex = buffer.indexOf("{", currentIndex);
403
+ while (jsonStartIndex !== -1 && jsonStartIndex < buffer.length) {
404
+ let braceCount = 0;
405
+ let inString = false;
406
+ let escapeNext = false;
407
+ let jsonEndIndex = -1;
408
+ let i = jsonStartIndex;
409
+ for (; i < buffer.length; i++) {
410
+ const char = buffer[i];
411
+ if (inString) {
412
+ if (escapeNext) {
413
+ escapeNext = false;
414
+ } else if (char === "\\") {
415
+ escapeNext = true;
416
+ } else if (char === '"') {
417
+ inString = false;
418
+ }
419
+ } else if (char === '"') {
420
+ inString = true;
421
+ } else if (char === "{") {
422
+ braceCount++;
423
+ } else if (char === "}") {
424
+ braceCount--;
425
+ if (braceCount === 0) {
426
+ jsonEndIndex = i;
427
+ break;
428
+ }
429
+ }
430
+ }
431
+ if (jsonEndIndex !== -1) {
432
+ const jsonString = buffer.slice(jsonStartIndex, jsonEndIndex + 1);
433
+ try {
434
+ const parsed = JSON.parse(jsonString);
435
+ if (isLegacyFormat(parsed)) {
436
+ processChunk(parsed, onChunk);
437
+ } else {
438
+ const legacyChunk = convertNewFormatToLegacy(parsed);
439
+ processChunk(legacyChunk, onChunk);
440
+ }
441
+ } catch (error) {
442
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
443
+ console.error("Failed to parse JSON chunk:", {
444
+ error,
445
+ chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
446
+ position: jsonStartIndex
447
+ });
448
+ }
449
+ if (jsonString.length > 1e4) {
450
+ throw new Error(
451
+ `Failed to parse large JSON chunk at position ${jsonStartIndex}`
452
+ );
453
+ }
454
+ jsonStartIndex = buffer.indexOf("{", jsonStartIndex + 1);
455
+ continue;
456
+ }
457
+ currentIndex = jsonEndIndex + 1;
458
+ buffer = buffer.slice(currentIndex).trim();
459
+ currentIndex = 0;
460
+ jsonStartIndex = buffer.indexOf("{", currentIndex);
461
+ } else {
462
+ break;
463
+ }
464
+ }
465
+ return buffer;
466
+ }
467
+ async function streamResponse(options) {
468
+ const {
469
+ apiUrl,
470
+ headers = {},
471
+ params,
472
+ requestBody,
473
+ onChunk,
474
+ onError,
475
+ onComplete,
476
+ signal
477
+ } = options;
478
+ let buffer = "";
479
+ const finalUrl = params?.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
480
+ try {
481
+ const response = await fetch(finalUrl, {
482
+ method: "POST",
483
+ headers: {
484
+ ...!(requestBody instanceof FormData) && {
485
+ "Content-Type": "application/json"
486
+ },
487
+ ...headers
488
+ },
489
+ body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
490
+ signal
491
+ });
492
+ if (!response.ok) {
493
+ let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
494
+ const contentType = response.headers.get("content-type");
495
+ if (contentType?.includes("application/json")) {
496
+ try {
497
+ const errorData = await response.json();
498
+ errorMessage = errorData.detail || errorData.message || errorMessage;
499
+ } catch {
500
+ }
501
+ }
502
+ throw new Error(errorMessage);
503
+ }
504
+ if (!response.body) {
505
+ throw new Error("No response body");
506
+ }
507
+ const reader = response.body.getReader();
508
+ const decoder = new TextDecoder();
509
+ const processStream = async () => {
510
+ while (true) {
511
+ const { done, value } = await reader.read();
512
+ if (done) {
513
+ buffer = parseBuffer(buffer, onChunk);
514
+ onComplete();
515
+ return;
516
+ }
517
+ buffer += decoder.decode(value, { stream: true });
518
+ buffer = parseBuffer(buffer, onChunk);
519
+ }
520
+ };
521
+ await processStream();
522
+ } catch (error) {
523
+ if (error instanceof Error && error.name === "AbortError") {
524
+ return;
525
+ }
526
+ if (typeof error === "object" && error !== null && "detail" in error) {
527
+ onError(new Error(String(error.detail)));
528
+ } else {
529
+ onError(new Error(String(error)));
530
+ }
531
+ }
532
+ }
533
+
403
534
  // src/processors/event-processor.ts
404
535
  import { RunEvent as RunEventEnum } from "@antipopp/agno-types";
405
536
 
@@ -428,9 +559,8 @@ function processToolCall(toolCall, prevToolCalls = []) {
428
559
  ...toolCall
429
560
  };
430
561
  return updatedToolCalls;
431
- } else {
432
- return [...prevToolCalls, toolCall];
433
562
  }
563
+ return [...prevToolCalls, toolCall];
434
564
  }
435
565
  function processChunkToolCalls(chunk, existingToolCalls = []) {
436
566
  let updatedToolCalls = [...existingToolCalls];
@@ -518,7 +648,7 @@ var EventProcessor = class {
518
648
  }
519
649
  break;
520
650
  case RunEventEnum.ReasoningStep:
521
- case RunEventEnum.TeamReasoningStep:
651
+ case RunEventEnum.TeamReasoningStep: {
522
652
  const existingSteps = lastMessage.extra_data?.reasoning_steps ?? [];
523
653
  const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
524
654
  updatedMessage.extra_data = {
@@ -526,6 +656,7 @@ var EventProcessor = class {
526
656
  reasoning_steps: [...existingSteps, ...incomingSteps]
527
657
  };
528
658
  break;
659
+ }
529
660
  case RunEventEnum.ReasoningCompleted:
530
661
  case RunEventEnum.TeamReasoningCompleted:
531
662
  if (chunk.extra_data?.reasoning_steps) {
@@ -536,7 +667,7 @@ var EventProcessor = class {
536
667
  }
537
668
  break;
538
669
  case RunEventEnum.RunCompleted:
539
- case RunEventEnum.TeamRunCompleted:
670
+ case RunEventEnum.TeamRunCompleted: {
540
671
  let updatedContent;
541
672
  if (typeof chunk.content === "string") {
542
673
  updatedContent = chunk.content;
@@ -561,6 +692,7 @@ var EventProcessor = class {
561
692
  references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
562
693
  };
563
694
  break;
695
+ }
564
696
  case RunEventEnum.UpdatingMemory:
565
697
  case RunEventEnum.TeamMemoryUpdateStarted:
566
698
  case RunEventEnum.TeamMemoryUpdateCompleted:
@@ -583,164 +715,95 @@ var EventProcessor = class {
583
715
  }
584
716
  };
585
717
 
586
- // src/parsers/stream-parser.ts
587
- function isLegacyFormat(data) {
588
- return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
589
- }
590
- function convertNewFormatToLegacy(newFormatData) {
591
- const { event, data } = newFormatData;
592
- let parsedData;
593
- if (typeof data === "string") {
594
- try {
595
- parsedData = JSON.parse(data);
596
- } catch {
597
- parsedData = {};
598
- }
599
- } else {
600
- parsedData = data;
718
+ // src/stores/message-store.ts
719
+ var MessageStore = class {
720
+ constructor() {
721
+ this.messages = [];
601
722
  }
602
- return {
603
- event,
604
- ...parsedData
605
- };
606
- }
607
- function processChunk(chunk, onChunk) {
608
- onChunk(chunk);
609
- }
610
- function parseBuffer(buffer, onChunk) {
611
- let currentIndex = 0;
612
- let jsonStartIndex = buffer.indexOf("{", currentIndex);
613
- while (jsonStartIndex !== -1 && jsonStartIndex < buffer.length) {
614
- let braceCount = 0;
615
- let inString = false;
616
- let escapeNext = false;
617
- let jsonEndIndex = -1;
618
- let i = jsonStartIndex;
619
- for (; i < buffer.length; i++) {
620
- const char = buffer[i];
621
- if (inString) {
622
- if (escapeNext) {
623
- escapeNext = false;
624
- } else if (char === "\\") {
625
- escapeNext = true;
626
- } else if (char === '"') {
627
- inString = false;
628
- }
629
- } else {
630
- if (char === '"') {
631
- inString = true;
632
- } else if (char === "{") {
633
- braceCount++;
634
- } else if (char === "}") {
635
- braceCount--;
636
- if (braceCount === 0) {
637
- jsonEndIndex = i;
638
- break;
639
- }
640
- }
641
- }
642
- }
643
- if (jsonEndIndex !== -1) {
644
- const jsonString = buffer.slice(jsonStartIndex, jsonEndIndex + 1);
645
- try {
646
- const parsed = JSON.parse(jsonString);
647
- if (isLegacyFormat(parsed)) {
648
- processChunk(parsed, onChunk);
649
- } else {
650
- const legacyChunk = convertNewFormatToLegacy(parsed);
651
- processChunk(legacyChunk, onChunk);
652
- }
653
- } catch (error) {
654
- if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
655
- console.error("Failed to parse JSON chunk:", {
656
- error,
657
- chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
658
- position: jsonStartIndex
659
- });
660
- }
661
- if (jsonString.length > 1e4) {
662
- throw new Error(`Failed to parse large JSON chunk at position ${jsonStartIndex}`);
663
- }
664
- jsonStartIndex = buffer.indexOf("{", jsonStartIndex + 1);
665
- continue;
666
- }
667
- currentIndex = jsonEndIndex + 1;
668
- buffer = buffer.slice(currentIndex).trim();
669
- currentIndex = 0;
670
- jsonStartIndex = buffer.indexOf("{", currentIndex);
671
- } else {
672
- break;
673
- }
723
+ /**
724
+ * Get all messages
725
+ */
726
+ getMessages() {
727
+ return [...this.messages];
674
728
  }
675
- return buffer;
676
- }
677
- async function streamResponse(options) {
678
- const {
679
- apiUrl,
680
- headers = {},
681
- requestBody,
682
- onChunk,
683
- onError,
684
- onComplete,
685
- signal
686
- } = options;
687
- let buffer = "";
688
- try {
689
- const response = await fetch(apiUrl, {
690
- method: "POST",
691
- headers: {
692
- ...!(requestBody instanceof FormData) && {
693
- "Content-Type": "application/json"
694
- },
695
- ...headers
696
- },
697
- body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
698
- signal
699
- });
700
- if (!response.ok) {
701
- let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
702
- const contentType = response.headers.get("content-type");
703
- if (contentType?.includes("application/json")) {
704
- try {
705
- const errorData = await response.json();
706
- errorMessage = errorData.detail || errorData.message || errorMessage;
707
- } catch {
708
- }
709
- }
710
- throw new Error(errorMessage);
711
- }
712
- if (!response.body) {
713
- throw new Error("No response body");
729
+ /**
730
+ * Set messages (replaces all)
731
+ */
732
+ setMessages(messages) {
733
+ this.messages = [...messages];
734
+ }
735
+ /**
736
+ * Add a message
737
+ */
738
+ addMessage(message) {
739
+ this.messages = [...this.messages, message];
740
+ }
741
+ /**
742
+ * Update the last message
743
+ */
744
+ updateLastMessage(updater) {
745
+ if (this.messages.length === 0) {
746
+ return void 0;
714
747
  }
715
- const reader = response.body.getReader();
716
- const decoder = new TextDecoder();
717
- const processStream = async () => {
718
- while (true) {
719
- const { done, value } = await reader.read();
720
- if (done) {
721
- buffer = parseBuffer(buffer, onChunk);
722
- onComplete();
723
- return;
724
- }
725
- buffer += decoder.decode(value, { stream: true });
726
- buffer = parseBuffer(buffer, onChunk);
727
- }
728
- };
729
- await processStream();
730
- } catch (error) {
731
- if (error instanceof Error && error.name === "AbortError") {
732
- return;
748
+ const lastMessage = this.messages.at(-1);
749
+ if (!lastMessage) {
750
+ return void 0;
733
751
  }
734
- if (typeof error === "object" && error !== null && "detail" in error) {
735
- onError(new Error(String(error.detail)));
736
- } else {
737
- onError(new Error(String(error)));
752
+ const updatedMessage = updater(lastMessage);
753
+ this.messages = [...this.messages.slice(0, -1), updatedMessage];
754
+ return updatedMessage;
755
+ }
756
+ /**
757
+ * Update a specific message by index
758
+ */
759
+ updateMessage(index, updater) {
760
+ if (index < 0 || index >= this.messages.length) {
761
+ return void 0;
738
762
  }
763
+ const message = this.messages[index];
764
+ const updatedMessage = updater(message);
765
+ this.messages = [
766
+ ...this.messages.slice(0, index),
767
+ updatedMessage,
768
+ ...this.messages.slice(index + 1)
769
+ ];
770
+ return updatedMessage;
739
771
  }
740
- }
772
+ /**
773
+ * Remove last N messages
774
+ */
775
+ removeLastMessages(count) {
776
+ this.messages = this.messages.slice(0, -count);
777
+ }
778
+ /**
779
+ * Clear all messages
780
+ */
781
+ clear() {
782
+ this.messages = [];
783
+ }
784
+ /**
785
+ * Get the last message
786
+ */
787
+ getLastMessage() {
788
+ return this.messages.length > 0 ? this.messages.at(-1) : void 0;
789
+ }
790
+ /**
791
+ * Check if last message has streaming error
792
+ */
793
+ hasLastMessageError() {
794
+ const lastMessage = this.getLastMessage();
795
+ return lastMessage?.streamingError === true;
796
+ }
797
+ };
741
798
 
742
799
  // src/utils/logger.ts
743
- var SENSITIVE_KEYS = ["authToken", "Authorization", "token", "password", "apiKey"];
800
+ var SENSITIVE_KEYS = [
801
+ "authToken",
802
+ "Authorization",
803
+ "token",
804
+ "password",
805
+ "apiKey"
806
+ ];
744
807
  function sanitizeObject(obj) {
745
808
  if (obj === null || obj === void 0) {
746
809
  return obj;
@@ -828,6 +891,7 @@ var AgnoClient = class extends EventEmitter {
828
891
  this.state = {
829
892
  isStreaming: false,
830
893
  isRefreshing: false,
894
+ isCancelling: false,
831
895
  isEndpointActive: false,
832
896
  agents: [],
833
897
  teams: [],
@@ -872,6 +936,49 @@ var AgnoClient = class extends EventEmitter {
872
936
  this.emit("message:update", this.messageStore.getMessages());
873
937
  this.emit("state:change", this.getState());
874
938
  }
939
+ /**
940
+ * Cancel an active or paused run
941
+ */
942
+ async cancelRun() {
943
+ if (!(this.state.isStreaming || this.state.isPaused)) {
944
+ throw new Error("No active or paused run to cancel");
945
+ }
946
+ const runUrl = this.configManager.getRunUrl();
947
+ if (!runUrl) {
948
+ throw new Error("No agent or team selected");
949
+ }
950
+ const runId = this.state.pausedRunId || this.currentRunId;
951
+ if (!runId) {
952
+ throw new Error("No run ID available to cancel");
953
+ }
954
+ const cancelUrl = `${runUrl}/${runId}/cancel`;
955
+ const headers = this.configManager.buildRequestHeaders();
956
+ this.state.isCancelling = true;
957
+ this.emit("state:change", this.getState());
958
+ try {
959
+ const response = await fetch(cancelUrl, {
960
+ method: "POST",
961
+ headers
962
+ });
963
+ if (!response.ok) {
964
+ throw new Error("Failed to cancel run");
965
+ }
966
+ this.state.isStreaming = false;
967
+ this.state.isPaused = false;
968
+ this.state.isCancelling = false;
969
+ this.state.pausedRunId = void 0;
970
+ this.state.toolsAwaitingExecution = void 0;
971
+ this.currentRunId = void 0;
972
+ this.emit("run:cancelled", { runId });
973
+ this.emit("state:change", this.getState());
974
+ } catch (error) {
975
+ this.state.isCancelling = false;
976
+ this.emit("state:change", this.getState());
977
+ throw new Error(
978
+ `Error cancelling run: ${error instanceof Error ? error.message : String(error)}`
979
+ );
980
+ }
981
+ }
875
982
  /**
876
983
  * Send a message to the agent/team (streaming)
877
984
  */
@@ -922,17 +1029,21 @@ var AgnoClient = class extends EventEmitter {
922
1029
  formData.append("user_id", userId);
923
1030
  }
924
1031
  const headers = this.configManager.buildRequestHeaders(options?.headers);
1032
+ const params = this.configManager.buildQueryString(options?.params);
925
1033
  await streamResponse({
926
1034
  apiUrl: runUrl,
927
1035
  headers,
1036
+ params,
928
1037
  requestBody: formData,
929
1038
  onChunk: (chunk) => {
930
- this.handleChunk(chunk, newSessionId, formData.get("message"));
931
- if (chunk.event === RunEvent.RunStarted || chunk.event === RunEvent.TeamRunStarted || chunk.event === RunEvent.ReasoningStarted || chunk.event === RunEvent.TeamReasoningStarted) {
932
- if (chunk.session_id) {
933
- newSessionId = chunk.session_id;
934
- this.configManager.setSessionId(chunk.session_id);
935
- }
1039
+ this.handleChunk(
1040
+ chunk,
1041
+ newSessionId,
1042
+ formData.get("message")
1043
+ );
1044
+ if ((chunk.event === RunEvent.RunStarted || chunk.event === RunEvent.TeamRunStarted || chunk.event === RunEvent.ReasoningStarted || chunk.event === RunEvent.TeamReasoningStarted) && chunk.session_id) {
1045
+ newSessionId = chunk.session_id;
1046
+ this.configManager.setSessionId(chunk.session_id);
936
1047
  }
937
1048
  },
938
1049
  onError: (error) => {
@@ -940,6 +1051,7 @@ var AgnoClient = class extends EventEmitter {
940
1051
  },
941
1052
  onComplete: async () => {
942
1053
  this.state.isStreaming = false;
1054
+ this.currentRunId = void 0;
943
1055
  this.emit("stream:end");
944
1056
  this.emit("message:complete", this.messageStore.getMessages());
945
1057
  this.emit("state:change", this.getState());
@@ -961,20 +1073,21 @@ var AgnoClient = class extends EventEmitter {
961
1073
  */
962
1074
  handleChunk(chunk, currentSessionId, messageContent) {
963
1075
  const event = chunk.event;
964
- if (event === RunEvent.RunStarted || event === RunEvent.TeamRunStarted || event === RunEvent.ReasoningStarted || event === RunEvent.TeamReasoningStarted) {
965
- if (chunk.session_id && (!currentSessionId || currentSessionId !== chunk.session_id)) {
966
- const sessionData = {
967
- session_id: chunk.session_id,
968
- session_name: messageContent,
969
- created_at: toSafeISOString(chunk.created_at)
970
- };
971
- const sessionExists = this.state.sessions.some(
972
- (s) => s.session_id === chunk.session_id
973
- );
974
- if (!sessionExists) {
975
- this.state.sessions = [sessionData, ...this.state.sessions];
976
- this.emit("session:created", sessionData);
977
- }
1076
+ if ((event === RunEvent.RunStarted || event === RunEvent.TeamRunStarted) && chunk.run_id) {
1077
+ this.currentRunId = chunk.run_id;
1078
+ }
1079
+ if ((event === RunEvent.RunStarted || event === RunEvent.TeamRunStarted || event === RunEvent.ReasoningStarted || event === RunEvent.TeamReasoningStarted) && chunk.session_id && (!currentSessionId || currentSessionId !== chunk.session_id)) {
1080
+ const sessionData = {
1081
+ session_id: chunk.session_id,
1082
+ session_name: messageContent,
1083
+ created_at: toSafeISOString(chunk.created_at)
1084
+ };
1085
+ const sessionExists = this.state.sessions.some(
1086
+ (s) => s.session_id === chunk.session_id
1087
+ );
1088
+ if (!sessionExists) {
1089
+ this.state.sessions = [sessionData, ...this.state.sessions];
1090
+ this.emit("session:created", sessionData);
978
1091
  }
979
1092
  }
980
1093
  if (event === RunEvent.RunPaused) {
@@ -1054,7 +1167,10 @@ var AgnoClient = class extends EventEmitter {
1054
1167
  if (message.tool_calls) {
1055
1168
  for (const toolCall of message.tool_calls) {
1056
1169
  if (toolCall.ui_component) {
1057
- existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
1170
+ existingUIComponents.set(
1171
+ toolCall.tool_call_id,
1172
+ toolCall.ui_component
1173
+ );
1058
1174
  }
1059
1175
  }
1060
1176
  }
@@ -1064,13 +1180,15 @@ var AgnoClient = class extends EventEmitter {
1064
1180
  const dbId = this.configManager.getDbId() || "";
1065
1181
  const userId = this.configManager.getUserId();
1066
1182
  const headers = this.configManager.buildRequestHeaders();
1183
+ const params = this.configManager.buildQueryString();
1067
1184
  const response = await this.sessionManager.fetchSession(
1068
1185
  config.endpoint,
1069
1186
  entityType,
1070
1187
  sessionId,
1071
1188
  dbId,
1072
1189
  headers,
1073
- userId
1190
+ userId,
1191
+ params
1074
1192
  );
1075
1193
  const messages = this.sessionManager.convertSessionToMessages(response);
1076
1194
  if (existingUIComponents.size > 0) {
@@ -1078,7 +1196,9 @@ var AgnoClient = class extends EventEmitter {
1078
1196
  if (message.tool_calls) {
1079
1197
  for (let i = 0; i < message.tool_calls.length; i++) {
1080
1198
  const toolCall = message.tool_calls[i];
1081
- const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
1199
+ const uiComponent = existingUIComponents.get(
1200
+ toolCall.tool_call_id
1201
+ );
1082
1202
  if (uiComponent) {
1083
1203
  message.tool_calls[i].ui_component = uiComponent;
1084
1204
  }
@@ -1087,12 +1207,18 @@ var AgnoClient = class extends EventEmitter {
1087
1207
  }
1088
1208
  }
1089
1209
  this.messageStore.setMessages(messages);
1090
- Logger.debug("[AgnoClient] Session refreshed:", `${messages.length} messages`);
1210
+ Logger.debug(
1211
+ "[AgnoClient] Session refreshed:",
1212
+ `${messages.length} messages`
1213
+ );
1091
1214
  this.emit("message:refreshed", messages);
1092
1215
  this.emit("message:update", messages);
1093
1216
  } catch (error) {
1094
1217
  Logger.error("[AgnoClient] Failed to refresh session:", error);
1095
- this.emit("message:error", `Session refresh failed: ${error instanceof Error ? error.message : String(error)}`);
1218
+ this.emit(
1219
+ "message:error",
1220
+ `Session refresh failed: ${error instanceof Error ? error.message : String(error)}`
1221
+ );
1096
1222
  } finally {
1097
1223
  this.state.isRefreshing = false;
1098
1224
  this.emit("state:change", this.getState());
@@ -1101,24 +1227,33 @@ var AgnoClient = class extends EventEmitter {
1101
1227
  /**
1102
1228
  * Load a session
1103
1229
  */
1104
- async loadSession(sessionId) {
1230
+ async loadSession(sessionId, options) {
1105
1231
  Logger.debug("[AgnoClient] loadSession called with sessionId:", sessionId);
1106
1232
  const config = this.configManager.getConfig();
1107
1233
  const entityType = this.configManager.getMode();
1108
1234
  const dbId = this.configManager.getDbId() || "";
1109
1235
  const userId = this.configManager.getUserId();
1110
- Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId, userId });
1236
+ Logger.debug("[AgnoClient] Loading session with:", {
1237
+ entityType,
1238
+ dbId,
1239
+ userId
1240
+ });
1111
1241
  const headers = this.configManager.buildRequestHeaders();
1242
+ const params = this.configManager.buildQueryString(options?.params);
1112
1243
  const response = await this.sessionManager.fetchSession(
1113
1244
  config.endpoint,
1114
1245
  entityType,
1115
1246
  sessionId,
1116
1247
  dbId,
1117
1248
  headers,
1118
- userId
1249
+ userId,
1250
+ params
1119
1251
  );
1120
1252
  const messages = this.sessionManager.convertSessionToMessages(response);
1121
- Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
1253
+ Logger.debug(
1254
+ "[AgnoClient] Setting messages to store:",
1255
+ `${messages.length} messages`
1256
+ );
1122
1257
  this.messageStore.setMessages(messages);
1123
1258
  this.configManager.setSessionId(sessionId);
1124
1259
  Logger.debug("[AgnoClient] Emitting events...");
@@ -1131,7 +1266,7 @@ var AgnoClient = class extends EventEmitter {
1131
1266
  /**
1132
1267
  * Fetch all sessions
1133
1268
  */
1134
- async fetchSessions() {
1269
+ async fetchSessions(options) {
1135
1270
  const config = this.configManager.getConfig();
1136
1271
  const entityType = this.configManager.getMode();
1137
1272
  const entityId = this.configManager.getCurrentEntityId();
@@ -1140,12 +1275,14 @@ var AgnoClient = class extends EventEmitter {
1140
1275
  throw new Error("Entity ID must be configured");
1141
1276
  }
1142
1277
  const headers = this.configManager.buildRequestHeaders();
1278
+ const params = this.configManager.buildQueryString(options?.params);
1143
1279
  const sessions = await this.sessionManager.fetchSessions(
1144
1280
  config.endpoint,
1145
1281
  entityType,
1146
1282
  entityId,
1147
1283
  dbId,
1148
- headers
1284
+ headers,
1285
+ params
1149
1286
  );
1150
1287
  this.state.sessions = sessions;
1151
1288
  this.emit("state:change", this.getState());
@@ -1154,15 +1291,17 @@ var AgnoClient = class extends EventEmitter {
1154
1291
  /**
1155
1292
  * Delete a session
1156
1293
  */
1157
- async deleteSession(sessionId) {
1294
+ async deleteSession(sessionId, options) {
1158
1295
  const config = this.configManager.getConfig();
1159
1296
  const dbId = this.configManager.getDbId() || "";
1160
1297
  const headers = this.configManager.buildRequestHeaders();
1298
+ const params = this.configManager.buildQueryString(options?.params);
1161
1299
  await this.sessionManager.deleteSession(
1162
1300
  config.endpoint,
1163
1301
  sessionId,
1164
1302
  dbId,
1165
- headers
1303
+ headers,
1304
+ params
1166
1305
  );
1167
1306
  this.state.sessions = this.state.sessions.filter(
1168
1307
  (s) => s.session_id !== sessionId
@@ -1183,7 +1322,9 @@ var AgnoClient = class extends EventEmitter {
1183
1322
  }
1184
1323
  const existingToolCalls = lastMessage.tool_calls || [];
1185
1324
  const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
1186
- const newToolCalls = toolCalls.filter((t) => !existingIds.has(t.tool_call_id));
1325
+ const newToolCalls = toolCalls.filter(
1326
+ (t) => !existingIds.has(t.tool_call_id)
1327
+ );
1187
1328
  if (newToolCalls.length > 0) {
1188
1329
  this.messageStore.updateLastMessage((msg) => ({
1189
1330
  ...msg,
@@ -1230,8 +1371,9 @@ var AgnoClient = class extends EventEmitter {
1230
1371
  * Batches all updates to emit only one message:update event
1231
1372
  */
1232
1373
  applyPendingUISpecs() {
1233
- if (this.pendingUISpecs.size === 0)
1374
+ if (this.pendingUISpecs.size === 0) {
1234
1375
  return;
1376
+ }
1235
1377
  const messages = this.messageStore.getMessages();
1236
1378
  const updatedMessages = [];
1237
1379
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -1276,7 +1418,7 @@ var AgnoClient = class extends EventEmitter {
1276
1418
  * Teams do not support the continue endpoint.
1277
1419
  *
1278
1420
  * @param tools - Array of tool calls with execution results
1279
- * @param options - Optional request headers
1421
+ * @param options - Optional request headers and query parameters
1280
1422
  * @throws Error if no paused run exists
1281
1423
  * @throws Error if called with team mode (teams don't support HITL)
1282
1424
  */
@@ -1286,7 +1428,7 @@ var AgnoClient = class extends EventEmitter {
1286
1428
  "HITL (Human-in-the-Loop) frontend tool execution is not supported for teams. Only agents support the continue endpoint."
1287
1429
  );
1288
1430
  }
1289
- if (!this.state.isPaused || !this.state.pausedRunId) {
1431
+ if (!(this.state.isPaused && this.state.pausedRunId)) {
1290
1432
  throw new Error("No paused run to continue");
1291
1433
  }
1292
1434
  const runUrl = this.configManager.getRunUrl();
@@ -1314,10 +1456,12 @@ var AgnoClient = class extends EventEmitter {
1314
1456
  formData.append("user_id", userId);
1315
1457
  }
1316
1458
  const headers = this.configManager.buildRequestHeaders(options?.headers);
1459
+ const params = this.configManager.buildQueryString(options?.params);
1317
1460
  try {
1318
1461
  await streamResponse({
1319
1462
  apiUrl: continueUrl,
1320
1463
  headers,
1464
+ params,
1321
1465
  requestBody: formData,
1322
1466
  onChunk: (chunk) => {
1323
1467
  this.handleChunk(chunk, currentSessionId, "");
@@ -1348,10 +1492,17 @@ var AgnoClient = class extends EventEmitter {
1348
1492
  /**
1349
1493
  * Check endpoint status
1350
1494
  */
1351
- async checkStatus() {
1495
+ async checkStatus(options) {
1352
1496
  try {
1353
1497
  const headers = this.configManager.buildRequestHeaders();
1354
- const response = await fetch(`${this.configManager.getEndpoint()}/health`, { headers });
1498
+ const params = this.configManager.buildQueryString(options?.params);
1499
+ const url = new URL(`${this.configManager.getEndpoint()}/health`);
1500
+ if (params.toString()) {
1501
+ params.forEach((value, key) => {
1502
+ url.searchParams.set(key, value);
1503
+ });
1504
+ }
1505
+ const response = await fetch(url.toString(), { headers });
1355
1506
  const isActive = response.ok;
1356
1507
  this.state.isEndpointActive = isActive;
1357
1508
  this.emit("state:change", this.getState());
@@ -1365,9 +1516,16 @@ var AgnoClient = class extends EventEmitter {
1365
1516
  /**
1366
1517
  * Fetch agents from endpoint
1367
1518
  */
1368
- async fetchAgents() {
1519
+ async fetchAgents(options) {
1369
1520
  const headers = this.configManager.buildRequestHeaders();
1370
- const response = await fetch(`${this.configManager.getEndpoint()}/agents`, { headers });
1521
+ const params = this.configManager.buildQueryString(options?.params);
1522
+ const url = new URL(`${this.configManager.getEndpoint()}/agents`);
1523
+ if (params.toString()) {
1524
+ params.forEach((value, key) => {
1525
+ url.searchParams.set(key, value);
1526
+ });
1527
+ }
1528
+ const response = await fetch(url.toString(), { headers });
1371
1529
  if (!response.ok) {
1372
1530
  throw new Error("Failed to fetch agents");
1373
1531
  }
@@ -1379,9 +1537,16 @@ var AgnoClient = class extends EventEmitter {
1379
1537
  /**
1380
1538
  * Fetch teams from endpoint
1381
1539
  */
1382
- async fetchTeams() {
1540
+ async fetchTeams(options) {
1383
1541
  const headers = this.configManager.buildRequestHeaders();
1384
- const response = await fetch(`${this.configManager.getEndpoint()}/teams`, { headers });
1542
+ const params = this.configManager.buildQueryString(options?.params);
1543
+ const url = new URL(`${this.configManager.getEndpoint()}/teams`);
1544
+ if (params.toString()) {
1545
+ params.forEach((value, key) => {
1546
+ url.searchParams.set(key, value);
1547
+ });
1548
+ }
1549
+ const response = await fetch(url.toString(), { headers });
1385
1550
  if (!response.ok) {
1386
1551
  throw new Error("Failed to fetch teams");
1387
1552
  }
@@ -1394,19 +1559,19 @@ var AgnoClient = class extends EventEmitter {
1394
1559
  * Initialize client (check status and fetch agents/teams)
1395
1560
  * Automatically selects the first available agent or team if none is configured
1396
1561
  */
1397
- async initialize() {
1398
- const isActive = await this.checkStatus();
1562
+ async initialize(options) {
1563
+ const isActive = await this.checkStatus(options);
1399
1564
  if (!isActive) {
1400
1565
  return { agents: [], teams: [] };
1401
1566
  }
1402
1567
  const [agents, teams] = await Promise.all([
1403
- this.fetchAgents(),
1404
- this.fetchTeams()
1568
+ this.fetchAgents(options),
1569
+ this.fetchTeams(options)
1405
1570
  ]);
1406
1571
  const currentConfig = this.configManager.getConfig();
1407
1572
  const hasAgentConfigured = currentConfig.agentId;
1408
1573
  const hasTeamConfigured = currentConfig.teamId;
1409
- if (!hasAgentConfigured && !hasTeamConfigured) {
1574
+ if (!(hasAgentConfigured || hasTeamConfigured)) {
1410
1575
  if (agents.length > 0) {
1411
1576
  const firstAgent = agents[0];
1412
1577
  this.configManager.updateConfig({
@@ -1427,10 +1592,28 @@ var AgnoClient = class extends EventEmitter {
1427
1592
  }
1428
1593
  return { agents, teams };
1429
1594
  }
1595
+ /**
1596
+ * Dispose of the client and clean up all resources.
1597
+ * Call this method when the client is no longer needed to prevent memory leaks.
1598
+ * After calling dispose(), the client instance should not be reused.
1599
+ */
1600
+ dispose() {
1601
+ this.removeAllListeners();
1602
+ this.messageStore.clear();
1603
+ this.pendingUISpecs.clear();
1604
+ this.eventProcessor.reset();
1605
+ this.state.isStreaming = false;
1606
+ this.state.isRefreshing = false;
1607
+ this.state.isEndpointActive = false;
1608
+ this.state.agents = [];
1609
+ this.state.teams = [];
1610
+ this.state.sessions = [];
1611
+ this.state.isPaused = false;
1612
+ this.state.pausedRunId = void 0;
1613
+ this.state.toolsAwaitingExecution = void 0;
1614
+ this.state.errorMessage = void 0;
1615
+ }
1430
1616
  };
1431
-
1432
- // src/index.ts
1433
- import { RunEvent as RunEvent2 } from "@antipopp/agno-types";
1434
1617
  export {
1435
1618
  AgnoClient,
1436
1619
  Logger,