@antipopp/agno-client 0.9.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 {
@@ -237,14 +161,14 @@ var ConfigManager = class {
237
161
  const mode = this.getMode();
238
162
  const endpoint = this.getEndpoint();
239
163
  const entityId = this.getCurrentEntityId();
240
- if (!entityId)
164
+ if (!entityId) {
241
165
  return null;
166
+ }
242
167
  const encodedEntityId = encodeURIComponent(entityId);
243
168
  if (mode === "team") {
244
169
  return `${endpoint}/teams/${encodedEntityId}/runs`;
245
- } else {
246
- return `${endpoint}/agents/${encodedEntityId}/runs`;
247
170
  }
171
+ return `${endpoint}/agents/${encodedEntityId}/runs`;
248
172
  }
249
173
  /**
250
174
  * Build request headers by merging global headers, per-request headers, and auth token.
@@ -267,7 +191,7 @@ var ConfigManager = class {
267
191
  }
268
192
  const authToken = this.getAuthToken();
269
193
  if (authToken) {
270
- headers["Authorization"] = `Bearer ${authToken}`;
194
+ headers.Authorization = `Bearer ${authToken}`;
271
195
  }
272
196
  return headers;
273
197
  }
@@ -413,7 +337,9 @@ var SessionManager = class {
413
337
  tool_name: reasoningMsg.tool_name ?? "",
414
338
  tool_args: reasoningMsg.tool_args ?? {},
415
339
  tool_call_error: reasoningMsg.tool_call_error ?? false,
416
- metrics: reasoningMsg.metrics ?? { time: 0 },
340
+ metrics: reasoningMsg.metrics ?? {
341
+ time: 0
342
+ },
417
343
  created_at: reasoningMsg.created_at ?? timestamp
418
344
  });
419
345
  }
@@ -447,6 +373,164 @@ var SessionManager = class {
447
373
  }
448
374
  };
449
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
+
450
534
  // src/processors/event-processor.ts
451
535
  import { RunEvent as RunEventEnum } from "@antipopp/agno-types";
452
536
 
@@ -475,9 +559,8 @@ function processToolCall(toolCall, prevToolCalls = []) {
475
559
  ...toolCall
476
560
  };
477
561
  return updatedToolCalls;
478
- } else {
479
- return [...prevToolCalls, toolCall];
480
562
  }
563
+ return [...prevToolCalls, toolCall];
481
564
  }
482
565
  function processChunkToolCalls(chunk, existingToolCalls = []) {
483
566
  let updatedToolCalls = [...existingToolCalls];
@@ -565,7 +648,7 @@ var EventProcessor = class {
565
648
  }
566
649
  break;
567
650
  case RunEventEnum.ReasoningStep:
568
- case RunEventEnum.TeamReasoningStep:
651
+ case RunEventEnum.TeamReasoningStep: {
569
652
  const existingSteps = lastMessage.extra_data?.reasoning_steps ?? [];
570
653
  const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
571
654
  updatedMessage.extra_data = {
@@ -573,6 +656,7 @@ var EventProcessor = class {
573
656
  reasoning_steps: [...existingSteps, ...incomingSteps]
574
657
  };
575
658
  break;
659
+ }
576
660
  case RunEventEnum.ReasoningCompleted:
577
661
  case RunEventEnum.TeamReasoningCompleted:
578
662
  if (chunk.extra_data?.reasoning_steps) {
@@ -583,7 +667,7 @@ var EventProcessor = class {
583
667
  }
584
668
  break;
585
669
  case RunEventEnum.RunCompleted:
586
- case RunEventEnum.TeamRunCompleted:
670
+ case RunEventEnum.TeamRunCompleted: {
587
671
  let updatedContent;
588
672
  if (typeof chunk.content === "string") {
589
673
  updatedContent = chunk.content;
@@ -608,6 +692,7 @@ var EventProcessor = class {
608
692
  references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
609
693
  };
610
694
  break;
695
+ }
611
696
  case RunEventEnum.UpdatingMemory:
612
697
  case RunEventEnum.TeamMemoryUpdateStarted:
613
698
  case RunEventEnum.TeamMemoryUpdateCompleted:
@@ -630,166 +715,95 @@ var EventProcessor = class {
630
715
  }
631
716
  };
632
717
 
633
- // src/parsers/stream-parser.ts
634
- function isLegacyFormat(data) {
635
- return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
636
- }
637
- function convertNewFormatToLegacy(newFormatData) {
638
- const { event, data } = newFormatData;
639
- let parsedData;
640
- if (typeof data === "string") {
641
- try {
642
- parsedData = JSON.parse(data);
643
- } catch {
644
- parsedData = {};
645
- }
646
- } else {
647
- parsedData = data;
718
+ // src/stores/message-store.ts
719
+ var MessageStore = class {
720
+ constructor() {
721
+ this.messages = [];
648
722
  }
649
- return {
650
- event,
651
- ...parsedData
652
- };
653
- }
654
- function processChunk(chunk, onChunk) {
655
- onChunk(chunk);
656
- }
657
- function parseBuffer(buffer, onChunk) {
658
- let currentIndex = 0;
659
- let jsonStartIndex = buffer.indexOf("{", currentIndex);
660
- while (jsonStartIndex !== -1 && jsonStartIndex < buffer.length) {
661
- let braceCount = 0;
662
- let inString = false;
663
- let escapeNext = false;
664
- let jsonEndIndex = -1;
665
- let i = jsonStartIndex;
666
- for (; i < buffer.length; i++) {
667
- const char = buffer[i];
668
- if (inString) {
669
- if (escapeNext) {
670
- escapeNext = false;
671
- } else if (char === "\\") {
672
- escapeNext = true;
673
- } else if (char === '"') {
674
- inString = false;
675
- }
676
- } else {
677
- if (char === '"') {
678
- inString = true;
679
- } else if (char === "{") {
680
- braceCount++;
681
- } else if (char === "}") {
682
- braceCount--;
683
- if (braceCount === 0) {
684
- jsonEndIndex = i;
685
- break;
686
- }
687
- }
688
- }
689
- }
690
- if (jsonEndIndex !== -1) {
691
- const jsonString = buffer.slice(jsonStartIndex, jsonEndIndex + 1);
692
- try {
693
- const parsed = JSON.parse(jsonString);
694
- if (isLegacyFormat(parsed)) {
695
- processChunk(parsed, onChunk);
696
- } else {
697
- const legacyChunk = convertNewFormatToLegacy(parsed);
698
- processChunk(legacyChunk, onChunk);
699
- }
700
- } catch (error) {
701
- if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
702
- console.error("Failed to parse JSON chunk:", {
703
- error,
704
- chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
705
- position: jsonStartIndex
706
- });
707
- }
708
- if (jsonString.length > 1e4) {
709
- throw new Error(`Failed to parse large JSON chunk at position ${jsonStartIndex}`);
710
- }
711
- jsonStartIndex = buffer.indexOf("{", jsonStartIndex + 1);
712
- continue;
713
- }
714
- currentIndex = jsonEndIndex + 1;
715
- buffer = buffer.slice(currentIndex).trim();
716
- currentIndex = 0;
717
- jsonStartIndex = buffer.indexOf("{", currentIndex);
718
- } else {
719
- break;
720
- }
723
+ /**
724
+ * Get all messages
725
+ */
726
+ getMessages() {
727
+ return [...this.messages];
721
728
  }
722
- return buffer;
723
- }
724
- async function streamResponse(options) {
725
- const {
726
- apiUrl,
727
- headers = {},
728
- params,
729
- requestBody,
730
- onChunk,
731
- onError,
732
- onComplete,
733
- signal
734
- } = options;
735
- let buffer = "";
736
- const finalUrl = params && params.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
737
- try {
738
- const response = await fetch(finalUrl, {
739
- method: "POST",
740
- headers: {
741
- ...!(requestBody instanceof FormData) && {
742
- "Content-Type": "application/json"
743
- },
744
- ...headers
745
- },
746
- body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
747
- signal
748
- });
749
- if (!response.ok) {
750
- let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
751
- const contentType = response.headers.get("content-type");
752
- if (contentType?.includes("application/json")) {
753
- try {
754
- const errorData = await response.json();
755
- errorMessage = errorData.detail || errorData.message || errorMessage;
756
- } catch {
757
- }
758
- }
759
- throw new Error(errorMessage);
760
- }
761
- if (!response.body) {
762
- 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;
763
747
  }
764
- const reader = response.body.getReader();
765
- const decoder = new TextDecoder();
766
- const processStream = async () => {
767
- while (true) {
768
- const { done, value } = await reader.read();
769
- if (done) {
770
- buffer = parseBuffer(buffer, onChunk);
771
- onComplete();
772
- return;
773
- }
774
- buffer += decoder.decode(value, { stream: true });
775
- buffer = parseBuffer(buffer, onChunk);
776
- }
777
- };
778
- await processStream();
779
- } catch (error) {
780
- if (error instanceof Error && error.name === "AbortError") {
781
- return;
748
+ const lastMessage = this.messages.at(-1);
749
+ if (!lastMessage) {
750
+ return void 0;
782
751
  }
783
- if (typeof error === "object" && error !== null && "detail" in error) {
784
- onError(new Error(String(error.detail)));
785
- } else {
786
- 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;
787
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;
788
771
  }
789
- }
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
+ };
790
798
 
791
799
  // src/utils/logger.ts
792
- var SENSITIVE_KEYS = ["authToken", "Authorization", "token", "password", "apiKey"];
800
+ var SENSITIVE_KEYS = [
801
+ "authToken",
802
+ "Authorization",
803
+ "token",
804
+ "password",
805
+ "apiKey"
806
+ ];
793
807
  function sanitizeObject(obj) {
794
808
  if (obj === null || obj === void 0) {
795
809
  return obj;
@@ -877,6 +891,7 @@ var AgnoClient = class extends EventEmitter {
877
891
  this.state = {
878
892
  isStreaming: false,
879
893
  isRefreshing: false,
894
+ isCancelling: false,
880
895
  isEndpointActive: false,
881
896
  agents: [],
882
897
  teams: [],
@@ -921,6 +936,49 @@ var AgnoClient = class extends EventEmitter {
921
936
  this.emit("message:update", this.messageStore.getMessages());
922
937
  this.emit("state:change", this.getState());
923
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
+ }
924
982
  /**
925
983
  * Send a message to the agent/team (streaming)
926
984
  */
@@ -978,12 +1036,14 @@ var AgnoClient = class extends EventEmitter {
978
1036
  params,
979
1037
  requestBody: formData,
980
1038
  onChunk: (chunk) => {
981
- this.handleChunk(chunk, newSessionId, formData.get("message"));
982
- if (chunk.event === RunEvent.RunStarted || chunk.event === RunEvent.TeamRunStarted || chunk.event === RunEvent.ReasoningStarted || chunk.event === RunEvent.TeamReasoningStarted) {
983
- if (chunk.session_id) {
984
- newSessionId = chunk.session_id;
985
- this.configManager.setSessionId(chunk.session_id);
986
- }
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);
987
1047
  }
988
1048
  },
989
1049
  onError: (error) => {
@@ -991,6 +1051,7 @@ var AgnoClient = class extends EventEmitter {
991
1051
  },
992
1052
  onComplete: async () => {
993
1053
  this.state.isStreaming = false;
1054
+ this.currentRunId = void 0;
994
1055
  this.emit("stream:end");
995
1056
  this.emit("message:complete", this.messageStore.getMessages());
996
1057
  this.emit("state:change", this.getState());
@@ -1012,20 +1073,21 @@ var AgnoClient = class extends EventEmitter {
1012
1073
  */
1013
1074
  handleChunk(chunk, currentSessionId, messageContent) {
1014
1075
  const event = chunk.event;
1015
- if (event === RunEvent.RunStarted || event === RunEvent.TeamRunStarted || event === RunEvent.ReasoningStarted || event === RunEvent.TeamReasoningStarted) {
1016
- if (chunk.session_id && (!currentSessionId || currentSessionId !== chunk.session_id)) {
1017
- const sessionData = {
1018
- session_id: chunk.session_id,
1019
- session_name: messageContent,
1020
- created_at: toSafeISOString(chunk.created_at)
1021
- };
1022
- const sessionExists = this.state.sessions.some(
1023
- (s) => s.session_id === chunk.session_id
1024
- );
1025
- if (!sessionExists) {
1026
- this.state.sessions = [sessionData, ...this.state.sessions];
1027
- this.emit("session:created", sessionData);
1028
- }
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);
1029
1091
  }
1030
1092
  }
1031
1093
  if (event === RunEvent.RunPaused) {
@@ -1105,7 +1167,10 @@ var AgnoClient = class extends EventEmitter {
1105
1167
  if (message.tool_calls) {
1106
1168
  for (const toolCall of message.tool_calls) {
1107
1169
  if (toolCall.ui_component) {
1108
- existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
1170
+ existingUIComponents.set(
1171
+ toolCall.tool_call_id,
1172
+ toolCall.ui_component
1173
+ );
1109
1174
  }
1110
1175
  }
1111
1176
  }
@@ -1131,7 +1196,9 @@ var AgnoClient = class extends EventEmitter {
1131
1196
  if (message.tool_calls) {
1132
1197
  for (let i = 0; i < message.tool_calls.length; i++) {
1133
1198
  const toolCall = message.tool_calls[i];
1134
- const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
1199
+ const uiComponent = existingUIComponents.get(
1200
+ toolCall.tool_call_id
1201
+ );
1135
1202
  if (uiComponent) {
1136
1203
  message.tool_calls[i].ui_component = uiComponent;
1137
1204
  }
@@ -1140,12 +1207,18 @@ var AgnoClient = class extends EventEmitter {
1140
1207
  }
1141
1208
  }
1142
1209
  this.messageStore.setMessages(messages);
1143
- Logger.debug("[AgnoClient] Session refreshed:", `${messages.length} messages`);
1210
+ Logger.debug(
1211
+ "[AgnoClient] Session refreshed:",
1212
+ `${messages.length} messages`
1213
+ );
1144
1214
  this.emit("message:refreshed", messages);
1145
1215
  this.emit("message:update", messages);
1146
1216
  } catch (error) {
1147
1217
  Logger.error("[AgnoClient] Failed to refresh session:", error);
1148
- 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
+ );
1149
1222
  } finally {
1150
1223
  this.state.isRefreshing = false;
1151
1224
  this.emit("state:change", this.getState());
@@ -1160,7 +1233,11 @@ var AgnoClient = class extends EventEmitter {
1160
1233
  const entityType = this.configManager.getMode();
1161
1234
  const dbId = this.configManager.getDbId() || "";
1162
1235
  const userId = this.configManager.getUserId();
1163
- Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId, userId });
1236
+ Logger.debug("[AgnoClient] Loading session with:", {
1237
+ entityType,
1238
+ dbId,
1239
+ userId
1240
+ });
1164
1241
  const headers = this.configManager.buildRequestHeaders();
1165
1242
  const params = this.configManager.buildQueryString(options?.params);
1166
1243
  const response = await this.sessionManager.fetchSession(
@@ -1173,7 +1250,10 @@ var AgnoClient = class extends EventEmitter {
1173
1250
  params
1174
1251
  );
1175
1252
  const messages = this.sessionManager.convertSessionToMessages(response);
1176
- Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
1253
+ Logger.debug(
1254
+ "[AgnoClient] Setting messages to store:",
1255
+ `${messages.length} messages`
1256
+ );
1177
1257
  this.messageStore.setMessages(messages);
1178
1258
  this.configManager.setSessionId(sessionId);
1179
1259
  Logger.debug("[AgnoClient] Emitting events...");
@@ -1242,7 +1322,9 @@ var AgnoClient = class extends EventEmitter {
1242
1322
  }
1243
1323
  const existingToolCalls = lastMessage.tool_calls || [];
1244
1324
  const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
1245
- 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
+ );
1246
1328
  if (newToolCalls.length > 0) {
1247
1329
  this.messageStore.updateLastMessage((msg) => ({
1248
1330
  ...msg,
@@ -1289,8 +1371,9 @@ var AgnoClient = class extends EventEmitter {
1289
1371
  * Batches all updates to emit only one message:update event
1290
1372
  */
1291
1373
  applyPendingUISpecs() {
1292
- if (this.pendingUISpecs.size === 0)
1374
+ if (this.pendingUISpecs.size === 0) {
1293
1375
  return;
1376
+ }
1294
1377
  const messages = this.messageStore.getMessages();
1295
1378
  const updatedMessages = [];
1296
1379
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -1345,7 +1428,7 @@ var AgnoClient = class extends EventEmitter {
1345
1428
  "HITL (Human-in-the-Loop) frontend tool execution is not supported for teams. Only agents support the continue endpoint."
1346
1429
  );
1347
1430
  }
1348
- if (!this.state.isPaused || !this.state.pausedRunId) {
1431
+ if (!(this.state.isPaused && this.state.pausedRunId)) {
1349
1432
  throw new Error("No paused run to continue");
1350
1433
  }
1351
1434
  const runUrl = this.configManager.getRunUrl();
@@ -1488,7 +1571,7 @@ var AgnoClient = class extends EventEmitter {
1488
1571
  const currentConfig = this.configManager.getConfig();
1489
1572
  const hasAgentConfigured = currentConfig.agentId;
1490
1573
  const hasTeamConfigured = currentConfig.teamId;
1491
- if (!hasAgentConfigured && !hasTeamConfigured) {
1574
+ if (!(hasAgentConfigured || hasTeamConfigured)) {
1492
1575
  if (agents.length > 0) {
1493
1576
  const firstAgent = agents[0];
1494
1577
  this.configManager.updateConfig({
@@ -1509,10 +1592,28 @@ var AgnoClient = class extends EventEmitter {
1509
1592
  }
1510
1593
  return { agents, teams };
1511
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
+ }
1512
1616
  };
1513
-
1514
- // src/index.ts
1515
- import { RunEvent as RunEvent2 } from "@antipopp/agno-types";
1516
1617
  export {
1517
1618
  AgnoClient,
1518
1619
  Logger,