@antipopp/agno-client 0.1.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.js ADDED
@@ -0,0 +1,1266 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ AgnoClient: () => AgnoClient,
34
+ Logger: () => Logger,
35
+ RunEvent: () => import_agno_types3.RunEvent
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+
39
+ // src/client.ts
40
+ var import_eventemitter3 = __toESM(require("eventemitter3"));
41
+ var import_agno_types2 = require("@antipopp/agno-types");
42
+
43
+ // src/stores/message-store.ts
44
+ var MessageStore = class {
45
+ constructor() {
46
+ this.messages = [];
47
+ }
48
+ /**
49
+ * Get all messages
50
+ */
51
+ getMessages() {
52
+ return [...this.messages];
53
+ }
54
+ /**
55
+ * Set messages (replaces all)
56
+ */
57
+ setMessages(messages) {
58
+ this.messages = [...messages];
59
+ }
60
+ /**
61
+ * Add a message
62
+ */
63
+ addMessage(message) {
64
+ this.messages = [...this.messages, message];
65
+ }
66
+ /**
67
+ * Update the last message
68
+ */
69
+ updateLastMessage(updater) {
70
+ if (this.messages.length === 0)
71
+ return void 0;
72
+ const lastMessage = this.messages[this.messages.length - 1];
73
+ const updatedMessage = updater(lastMessage);
74
+ this.messages = [
75
+ ...this.messages.slice(0, -1),
76
+ updatedMessage
77
+ ];
78
+ return updatedMessage;
79
+ }
80
+ /**
81
+ * Remove last N messages
82
+ */
83
+ removeLastMessages(count) {
84
+ this.messages = this.messages.slice(0, -count);
85
+ }
86
+ /**
87
+ * Clear all messages
88
+ */
89
+ clear() {
90
+ this.messages = [];
91
+ }
92
+ /**
93
+ * Get the last message
94
+ */
95
+ getLastMessage() {
96
+ return this.messages.length > 0 ? this.messages[this.messages.length - 1] : void 0;
97
+ }
98
+ /**
99
+ * Check if last message has streaming error
100
+ */
101
+ hasLastMessageError() {
102
+ const lastMessage = this.getLastMessage();
103
+ return lastMessage?.streamingError === true;
104
+ }
105
+ };
106
+
107
+ // src/managers/config-manager.ts
108
+ var ConfigManager = class {
109
+ constructor(initialConfig) {
110
+ this.config = { ...initialConfig };
111
+ }
112
+ /**
113
+ * Get current configuration
114
+ */
115
+ getConfig() {
116
+ return { ...this.config };
117
+ }
118
+ /**
119
+ * Update configuration
120
+ */
121
+ updateConfig(updates) {
122
+ this.config = { ...this.config, ...updates };
123
+ }
124
+ /**
125
+ * Helper to update a single field immutably
126
+ */
127
+ updateField(key, value) {
128
+ this.config = { ...this.config, [key]: value };
129
+ }
130
+ /**
131
+ * Get endpoint URL
132
+ */
133
+ getEndpoint() {
134
+ return this.config.endpoint;
135
+ }
136
+ /**
137
+ * Set endpoint URL
138
+ */
139
+ setEndpoint(endpoint) {
140
+ this.updateField("endpoint", endpoint);
141
+ }
142
+ /**
143
+ * Get auth token
144
+ */
145
+ getAuthToken() {
146
+ return this.config.authToken;
147
+ }
148
+ /**
149
+ * Set auth token
150
+ */
151
+ setAuthToken(token) {
152
+ this.updateField("authToken", token);
153
+ }
154
+ /**
155
+ * Get mode (agent or team)
156
+ */
157
+ getMode() {
158
+ return this.config.mode || "agent";
159
+ }
160
+ /**
161
+ * Set mode
162
+ */
163
+ setMode(mode) {
164
+ this.updateField("mode", mode);
165
+ }
166
+ /**
167
+ * Get agent ID
168
+ */
169
+ getAgentId() {
170
+ return this.config.agentId;
171
+ }
172
+ /**
173
+ * Set agent ID
174
+ */
175
+ setAgentId(agentId) {
176
+ this.updateField("agentId", agentId);
177
+ }
178
+ /**
179
+ * Get team ID
180
+ */
181
+ getTeamId() {
182
+ return this.config.teamId;
183
+ }
184
+ /**
185
+ * Set team ID
186
+ */
187
+ setTeamId(teamId) {
188
+ this.updateField("teamId", teamId);
189
+ }
190
+ /**
191
+ * Get database ID
192
+ */
193
+ getDbId() {
194
+ return this.config.dbId;
195
+ }
196
+ /**
197
+ * Set database ID
198
+ */
199
+ setDbId(dbId) {
200
+ this.updateField("dbId", dbId);
201
+ }
202
+ /**
203
+ * Get session ID
204
+ */
205
+ getSessionId() {
206
+ return this.config.sessionId;
207
+ }
208
+ /**
209
+ * Set session ID
210
+ */
211
+ setSessionId(sessionId) {
212
+ this.updateField("sessionId", sessionId);
213
+ }
214
+ /**
215
+ * Get current entity ID (agent or team based on mode)
216
+ */
217
+ getCurrentEntityId() {
218
+ return this.getMode() === "agent" ? this.getAgentId() : this.getTeamId();
219
+ }
220
+ /**
221
+ * Construct the run URL based on current config
222
+ */
223
+ getRunUrl() {
224
+ const mode = this.getMode();
225
+ const endpoint = this.getEndpoint();
226
+ const entityId = this.getCurrentEntityId();
227
+ if (!entityId)
228
+ return null;
229
+ const encodedEntityId = encodeURIComponent(entityId);
230
+ if (mode === "team") {
231
+ return `${endpoint}/teams/${encodedEntityId}/runs`;
232
+ } else {
233
+ return `${endpoint}/agents/${encodedEntityId}/runs`;
234
+ }
235
+ }
236
+ };
237
+
238
+ // src/managers/session-manager.ts
239
+ var SessionManager = class {
240
+ /**
241
+ * Fetch all sessions for an entity
242
+ */
243
+ async fetchSessions(endpoint, entityType, entityId, dbId, authToken) {
244
+ const url = new URL(`${endpoint}/sessions`);
245
+ url.searchParams.set("type", entityType);
246
+ url.searchParams.set("component_id", entityId);
247
+ url.searchParams.set("db_id", dbId);
248
+ const headers = {};
249
+ if (authToken) {
250
+ headers["Authorization"] = `Bearer ${authToken}`;
251
+ }
252
+ const response = await fetch(url.toString(), { headers });
253
+ if (!response.ok) {
254
+ if (response.status === 404) {
255
+ return [];
256
+ }
257
+ throw new Error(`Failed to fetch sessions: ${response.statusText}`);
258
+ }
259
+ const data = await response.json();
260
+ return data.data ?? [];
261
+ }
262
+ /**
263
+ * Fetch a specific session's runs
264
+ * Returns an array of RunSchema directly (not wrapped in { data, meta })
265
+ */
266
+ async fetchSession(endpoint, entityType, sessionId, dbId, authToken) {
267
+ const url = new URL(`${endpoint}/sessions/${sessionId}/runs`);
268
+ url.searchParams.set("type", entityType);
269
+ if (dbId) {
270
+ url.searchParams.set("db_id", dbId);
271
+ }
272
+ const headers = {};
273
+ if (authToken) {
274
+ headers["Authorization"] = `Bearer ${authToken}`;
275
+ }
276
+ const response = await fetch(url.toString(), { headers });
277
+ if (!response.ok) {
278
+ throw new Error(`Failed to fetch session: ${response.statusText}`);
279
+ }
280
+ return await response.json();
281
+ }
282
+ /**
283
+ * Delete a session
284
+ */
285
+ async deleteSession(endpoint, sessionId, dbId, authToken) {
286
+ const url = new URL(`${endpoint}/sessions/${sessionId}`);
287
+ if (dbId) {
288
+ url.searchParams.set("db_id", dbId);
289
+ }
290
+ const headers = {};
291
+ if (authToken) {
292
+ headers["Authorization"] = `Bearer ${authToken}`;
293
+ }
294
+ const response = await fetch(url.toString(), {
295
+ method: "DELETE",
296
+ headers
297
+ });
298
+ if (!response.ok) {
299
+ throw new Error(`Failed to delete session: ${response.statusText}`);
300
+ }
301
+ }
302
+ /**
303
+ * Delete a team session
304
+ * Note: The API route has a typo with double slashes (/v1//teams), keeping it as-is for compatibility
305
+ */
306
+ async deleteTeamSession(endpoint, teamId, sessionId, authToken) {
307
+ const url = `${endpoint}/v1//teams/${teamId}/sessions/${sessionId}`;
308
+ const headers = {};
309
+ if (authToken) {
310
+ headers["Authorization"] = `Bearer ${authToken}`;
311
+ }
312
+ const response = await fetch(url, {
313
+ method: "DELETE",
314
+ headers
315
+ });
316
+ if (!response.ok) {
317
+ throw new Error(`Failed to delete team session: ${response.statusText}`);
318
+ }
319
+ }
320
+ /**
321
+ * Convert session runs array to chat messages
322
+ */
323
+ convertSessionToMessages(runs) {
324
+ console.log("[SessionManager] convertSessionToMessages received:", runs.length, "runs");
325
+ const messages = this.convertRunsToMessages(runs);
326
+ console.log("[SessionManager] Converted to messages:", messages.length, "messages");
327
+ return messages;
328
+ }
329
+ /**
330
+ * Convert RunSchema[] to ChatMessage[]
331
+ * Each run represents a user input + agent response pair
332
+ */
333
+ convertRunsToMessages(runs) {
334
+ const messages = [];
335
+ for (const run of runs) {
336
+ const timestamp = run.created_at ? new Date(run.created_at).getTime() / 1e3 : Math.floor(Date.now() / 1e3);
337
+ if (run.run_input) {
338
+ messages.push({
339
+ role: "user",
340
+ content: run.run_input,
341
+ created_at: timestamp
342
+ });
343
+ }
344
+ const toolCalls = [];
345
+ if (run.tools && Array.isArray(run.tools)) {
346
+ for (const tool of run.tools) {
347
+ const toolObj = tool;
348
+ toolCalls.push({
349
+ role: "tool",
350
+ content: toolObj.content ?? "",
351
+ tool_call_id: toolObj.tool_call_id ?? "",
352
+ tool_name: toolObj.tool_name ?? "",
353
+ tool_args: toolObj.tool_args ?? {},
354
+ tool_call_error: toolObj.tool_call_error ?? false,
355
+ metrics: toolObj.metrics ?? { time: 0 },
356
+ created_at: timestamp
357
+ });
358
+ }
359
+ }
360
+ if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
361
+ for (const msg of run.reasoning_messages) {
362
+ const reasoningMsg = msg;
363
+ if (reasoningMsg.role === "tool") {
364
+ toolCalls.push({
365
+ role: "tool",
366
+ content: reasoningMsg.content ?? "",
367
+ tool_call_id: reasoningMsg.tool_call_id ?? "",
368
+ tool_name: reasoningMsg.tool_name ?? "",
369
+ tool_args: reasoningMsg.tool_args ?? {},
370
+ tool_call_error: reasoningMsg.tool_call_error ?? false,
371
+ metrics: reasoningMsg.metrics ?? { time: 0 },
372
+ created_at: reasoningMsg.created_at ?? timestamp
373
+ });
374
+ }
375
+ }
376
+ }
377
+ let contentStr = "";
378
+ if (typeof run.content === "string") {
379
+ contentStr = run.content;
380
+ } else if (run.content && typeof run.content === "object") {
381
+ contentStr = JSON.stringify(run.content);
382
+ }
383
+ const extraData = run.reasoning_messages || run.reasoning_steps || run.references ? {
384
+ reasoning_messages: run.reasoning_messages,
385
+ reasoning_steps: run.reasoning_steps,
386
+ references: run.references
387
+ } : void 0;
388
+ messages.push({
389
+ role: "agent",
390
+ content: contentStr,
391
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
392
+ extra_data: extraData,
393
+ images: run.images,
394
+ videos: run.videos,
395
+ audio: run.audio,
396
+ response_audio: run.response_audio,
397
+ created_at: timestamp + 1
398
+ // Agent response is slightly after user message
399
+ });
400
+ }
401
+ return messages;
402
+ }
403
+ };
404
+
405
+ // src/processors/event-processor.ts
406
+ var import_agno_types = require("@antipopp/agno-types");
407
+
408
+ // src/utils/json-markdown.ts
409
+ function getJsonMarkdown(content) {
410
+ try {
411
+ const jsonString = JSON.stringify(content, null, 2);
412
+ return `\`\`\`json
413
+ ${jsonString}
414
+ \`\`\``;
415
+ } catch {
416
+ return "```\nError formatting JSON\n```";
417
+ }
418
+ }
419
+
420
+ // src/processors/event-processor.ts
421
+ function processToolCall(toolCall, prevToolCalls = []) {
422
+ const toolCallId = toolCall.tool_call_id || `${toolCall.tool_name}-${toolCall.created_at}`;
423
+ const existingToolCallIndex = prevToolCalls.findIndex(
424
+ (tc) => tc.tool_call_id && tc.tool_call_id === toolCall.tool_call_id || !tc.tool_call_id && toolCall.tool_name && toolCall.created_at && `${tc.tool_name}-${tc.created_at}` === toolCallId
425
+ );
426
+ if (existingToolCallIndex >= 0) {
427
+ const updatedToolCalls = [...prevToolCalls];
428
+ updatedToolCalls[existingToolCallIndex] = {
429
+ ...updatedToolCalls[existingToolCallIndex],
430
+ ...toolCall
431
+ };
432
+ return updatedToolCalls;
433
+ } else {
434
+ return [...prevToolCalls, toolCall];
435
+ }
436
+ }
437
+ function processChunkToolCalls(chunk, existingToolCalls = []) {
438
+ let updatedToolCalls = [...existingToolCalls];
439
+ if (chunk.tool) {
440
+ updatedToolCalls = processToolCall(chunk.tool, updatedToolCalls);
441
+ }
442
+ if (chunk.tools && chunk.tools.length > 0) {
443
+ for (const toolCall of chunk.tools) {
444
+ updatedToolCalls = processToolCall(toolCall, updatedToolCalls);
445
+ }
446
+ }
447
+ return updatedToolCalls;
448
+ }
449
+ var EventProcessor = class {
450
+ constructor() {
451
+ this.lastContent = "";
452
+ }
453
+ /**
454
+ * Process a chunk and update the last message
455
+ */
456
+ processChunk(chunk, lastMessage) {
457
+ if (!lastMessage || lastMessage.role !== "agent") {
458
+ return lastMessage;
459
+ }
460
+ const event = chunk.event;
461
+ const updatedMessage = { ...lastMessage };
462
+ switch (event) {
463
+ case import_agno_types.RunEvent.RunStarted:
464
+ case import_agno_types.RunEvent.TeamRunStarted:
465
+ case import_agno_types.RunEvent.ReasoningStarted:
466
+ case import_agno_types.RunEvent.TeamReasoningStarted:
467
+ break;
468
+ case import_agno_types.RunEvent.ToolCallStarted:
469
+ case import_agno_types.RunEvent.TeamToolCallStarted:
470
+ case import_agno_types.RunEvent.ToolCallCompleted:
471
+ case import_agno_types.RunEvent.TeamToolCallCompleted:
472
+ updatedMessage.tool_calls = processChunkToolCalls(
473
+ chunk,
474
+ lastMessage.tool_calls
475
+ );
476
+ break;
477
+ case import_agno_types.RunEvent.RunContent:
478
+ case import_agno_types.RunEvent.TeamRunContent:
479
+ if (typeof chunk.content === "string") {
480
+ const uniqueContent = chunk.content.replace(this.lastContent, "");
481
+ updatedMessage.content = updatedMessage.content + uniqueContent;
482
+ this.lastContent = chunk.content;
483
+ } else if (typeof chunk.content !== "string" && chunk.content !== null) {
484
+ const jsonBlock = getJsonMarkdown(chunk.content);
485
+ updatedMessage.content = updatedMessage.content + jsonBlock;
486
+ this.lastContent = jsonBlock;
487
+ }
488
+ updatedMessage.tool_calls = processChunkToolCalls(
489
+ chunk,
490
+ lastMessage.tool_calls
491
+ );
492
+ if (chunk.extra_data?.reasoning_steps) {
493
+ updatedMessage.extra_data = {
494
+ ...updatedMessage.extra_data,
495
+ reasoning_steps: chunk.extra_data.reasoning_steps
496
+ };
497
+ }
498
+ if (chunk.extra_data?.references) {
499
+ updatedMessage.extra_data = {
500
+ ...updatedMessage.extra_data,
501
+ references: chunk.extra_data.references
502
+ };
503
+ }
504
+ updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
505
+ if (chunk.images) {
506
+ updatedMessage.images = chunk.images;
507
+ }
508
+ if (chunk.videos) {
509
+ updatedMessage.videos = chunk.videos;
510
+ }
511
+ if (chunk.audio) {
512
+ updatedMessage.audio = chunk.audio;
513
+ }
514
+ if (chunk.response_audio?.transcript && typeof chunk.response_audio.transcript === "string") {
515
+ const transcript = chunk.response_audio.transcript;
516
+ updatedMessage.response_audio = {
517
+ ...updatedMessage.response_audio,
518
+ transcript: (updatedMessage.response_audio?.transcript || "") + transcript
519
+ };
520
+ }
521
+ break;
522
+ case import_agno_types.RunEvent.ReasoningStep:
523
+ case import_agno_types.RunEvent.TeamReasoningStep:
524
+ const existingSteps = lastMessage.extra_data?.reasoning_steps ?? [];
525
+ const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
526
+ updatedMessage.extra_data = {
527
+ ...updatedMessage.extra_data,
528
+ reasoning_steps: [...existingSteps, ...incomingSteps]
529
+ };
530
+ break;
531
+ case import_agno_types.RunEvent.ReasoningCompleted:
532
+ case import_agno_types.RunEvent.TeamReasoningCompleted:
533
+ if (chunk.extra_data?.reasoning_steps) {
534
+ updatedMessage.extra_data = {
535
+ ...updatedMessage.extra_data,
536
+ reasoning_steps: chunk.extra_data.reasoning_steps
537
+ };
538
+ }
539
+ break;
540
+ case import_agno_types.RunEvent.RunCompleted:
541
+ case import_agno_types.RunEvent.TeamRunCompleted:
542
+ let updatedContent;
543
+ if (typeof chunk.content === "string") {
544
+ updatedContent = chunk.content;
545
+ } else {
546
+ try {
547
+ updatedContent = JSON.stringify(chunk.content);
548
+ } catch {
549
+ updatedContent = "Error parsing response";
550
+ }
551
+ }
552
+ updatedMessage.content = updatedContent;
553
+ updatedMessage.tool_calls = processChunkToolCalls(
554
+ chunk,
555
+ lastMessage.tool_calls
556
+ );
557
+ updatedMessage.images = chunk.images ?? lastMessage.images;
558
+ updatedMessage.videos = chunk.videos ?? lastMessage.videos;
559
+ updatedMessage.response_audio = chunk.response_audio;
560
+ updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
561
+ updatedMessage.extra_data = {
562
+ reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
563
+ references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
564
+ };
565
+ break;
566
+ case import_agno_types.RunEvent.UpdatingMemory:
567
+ case import_agno_types.RunEvent.TeamMemoryUpdateStarted:
568
+ case import_agno_types.RunEvent.TeamMemoryUpdateCompleted:
569
+ break;
570
+ case import_agno_types.RunEvent.RunPaused:
571
+ break;
572
+ case import_agno_types.RunEvent.RunError:
573
+ case import_agno_types.RunEvent.TeamRunError:
574
+ case import_agno_types.RunEvent.TeamRunCancelled:
575
+ updatedMessage.streamingError = true;
576
+ break;
577
+ }
578
+ return updatedMessage;
579
+ }
580
+ /**
581
+ * Reset the processor state (e.g., between messages)
582
+ */
583
+ reset() {
584
+ this.lastContent = "";
585
+ }
586
+ };
587
+
588
+ // src/parsers/stream-parser.ts
589
+ function isLegacyFormat(data) {
590
+ return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
591
+ }
592
+ function convertNewFormatToLegacy(newFormatData) {
593
+ const { event, data } = newFormatData;
594
+ let parsedData;
595
+ if (typeof data === "string") {
596
+ try {
597
+ parsedData = JSON.parse(data);
598
+ } catch {
599
+ parsedData = {};
600
+ }
601
+ } else {
602
+ parsedData = data;
603
+ }
604
+ return {
605
+ event,
606
+ ...parsedData
607
+ };
608
+ }
609
+ function processChunk(chunk, onChunk) {
610
+ onChunk(chunk);
611
+ }
612
+ function parseBuffer(buffer, onChunk) {
613
+ let currentIndex = 0;
614
+ let jsonStartIndex = buffer.indexOf("{", currentIndex);
615
+ while (jsonStartIndex !== -1 && jsonStartIndex < buffer.length) {
616
+ let braceCount = 0;
617
+ let inString = false;
618
+ let escapeNext = false;
619
+ let jsonEndIndex = -1;
620
+ let i = jsonStartIndex;
621
+ for (; i < buffer.length; i++) {
622
+ const char = buffer[i];
623
+ if (inString) {
624
+ if (escapeNext) {
625
+ escapeNext = false;
626
+ } else if (char === "\\") {
627
+ escapeNext = true;
628
+ } else if (char === '"') {
629
+ inString = false;
630
+ }
631
+ } else {
632
+ if (char === '"') {
633
+ inString = true;
634
+ } else if (char === "{") {
635
+ braceCount++;
636
+ } else if (char === "}") {
637
+ braceCount--;
638
+ if (braceCount === 0) {
639
+ jsonEndIndex = i;
640
+ break;
641
+ }
642
+ }
643
+ }
644
+ }
645
+ if (jsonEndIndex !== -1) {
646
+ const jsonString = buffer.slice(jsonStartIndex, jsonEndIndex + 1);
647
+ try {
648
+ const parsed = JSON.parse(jsonString);
649
+ if (isLegacyFormat(parsed)) {
650
+ processChunk(parsed, onChunk);
651
+ } else {
652
+ const legacyChunk = convertNewFormatToLegacy(parsed);
653
+ processChunk(legacyChunk, onChunk);
654
+ }
655
+ } catch (error) {
656
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
657
+ console.error("Failed to parse JSON chunk:", {
658
+ error,
659
+ chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
660
+ position: jsonStartIndex
661
+ });
662
+ }
663
+ if (jsonString.length > 1e4) {
664
+ throw new Error(`Failed to parse large JSON chunk at position ${jsonStartIndex}`);
665
+ }
666
+ jsonStartIndex = buffer.indexOf("{", jsonStartIndex + 1);
667
+ continue;
668
+ }
669
+ currentIndex = jsonEndIndex + 1;
670
+ buffer = buffer.slice(currentIndex).trim();
671
+ currentIndex = 0;
672
+ jsonStartIndex = buffer.indexOf("{", currentIndex);
673
+ } else {
674
+ break;
675
+ }
676
+ }
677
+ return buffer;
678
+ }
679
+ async function streamResponse(options) {
680
+ const {
681
+ apiUrl,
682
+ headers = {},
683
+ requestBody,
684
+ onChunk,
685
+ onError,
686
+ onComplete,
687
+ signal
688
+ } = options;
689
+ let buffer = "";
690
+ try {
691
+ const response = await fetch(apiUrl, {
692
+ method: "POST",
693
+ headers: {
694
+ ...!(requestBody instanceof FormData) && {
695
+ "Content-Type": "application/json"
696
+ },
697
+ ...headers
698
+ },
699
+ body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
700
+ signal
701
+ });
702
+ if (!response.ok) {
703
+ let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
704
+ const contentType = response.headers.get("content-type");
705
+ if (contentType?.includes("application/json")) {
706
+ try {
707
+ const errorData = await response.json();
708
+ errorMessage = errorData.detail || errorData.message || errorMessage;
709
+ } catch {
710
+ }
711
+ }
712
+ throw new Error(errorMessage);
713
+ }
714
+ if (!response.body) {
715
+ throw new Error("No response body");
716
+ }
717
+ const reader = response.body.getReader();
718
+ const decoder = new TextDecoder();
719
+ const processStream = async () => {
720
+ while (true) {
721
+ const { done, value } = await reader.read();
722
+ if (done) {
723
+ buffer = parseBuffer(buffer, onChunk);
724
+ onComplete();
725
+ return;
726
+ }
727
+ buffer += decoder.decode(value, { stream: true });
728
+ buffer = parseBuffer(buffer, onChunk);
729
+ }
730
+ };
731
+ await processStream();
732
+ } catch (error) {
733
+ if (error instanceof Error && error.name === "AbortError") {
734
+ return;
735
+ }
736
+ if (typeof error === "object" && error !== null && "detail" in error) {
737
+ onError(new Error(String(error.detail)));
738
+ } else {
739
+ onError(new Error(String(error)));
740
+ }
741
+ }
742
+ }
743
+
744
+ // src/utils/logger.ts
745
+ var SENSITIVE_KEYS = ["authToken", "Authorization", "token", "password", "apiKey"];
746
+ function sanitizeObject(obj) {
747
+ if (obj === null || obj === void 0) {
748
+ return obj;
749
+ }
750
+ if (typeof obj !== "object") {
751
+ return obj;
752
+ }
753
+ if (Array.isArray(obj)) {
754
+ return obj.map(sanitizeObject);
755
+ }
756
+ const sanitized = {};
757
+ for (const [key, value] of Object.entries(obj)) {
758
+ if (SENSITIVE_KEYS.some(
759
+ (sensitiveKey) => key.toLowerCase().includes(sensitiveKey.toLowerCase())
760
+ )) {
761
+ sanitized[key] = value ? "[REDACTED]" : void 0;
762
+ } else if (typeof value === "object" && value !== null) {
763
+ sanitized[key] = sanitizeObject(value);
764
+ } else {
765
+ sanitized[key] = value;
766
+ }
767
+ }
768
+ return sanitized;
769
+ }
770
+ function isDevelopment() {
771
+ return typeof process !== "undefined" && process.env?.NODE_ENV === "development";
772
+ }
773
+ var Logger = class {
774
+ /**
775
+ * Log debug information (only in development)
776
+ */
777
+ static debug(message, data) {
778
+ if (isDevelopment()) {
779
+ const sanitized = data ? sanitizeObject(data) : void 0;
780
+ console.debug(`[DEBUG] ${message}`, sanitized || "");
781
+ }
782
+ }
783
+ /**
784
+ * Log informational messages (only in development)
785
+ */
786
+ static info(message, data) {
787
+ if (isDevelopment()) {
788
+ const sanitized = data ? sanitizeObject(data) : void 0;
789
+ console.info(`[INFO] ${message}`, sanitized || "");
790
+ }
791
+ }
792
+ /**
793
+ * Log warnings (always logs)
794
+ */
795
+ static warn(message, data) {
796
+ const sanitized = data ? sanitizeObject(data) : void 0;
797
+ console.warn(`[WARN] ${message}`, sanitized || "");
798
+ }
799
+ /**
800
+ * Log errors (always logs)
801
+ */
802
+ static error(message, data) {
803
+ const sanitized = data ? sanitizeObject(data) : void 0;
804
+ console.error(`[ERROR] ${message}`, sanitized || "");
805
+ }
806
+ };
807
+
808
+ // src/client.ts
809
+ function toSafeISOString(timestamp) {
810
+ const now = Date.now();
811
+ const ts = timestamp ? timestamp * 1e3 : now;
812
+ const MIN_TIMESTAMP = 9466848e5;
813
+ const MAX_TIMESTAMP = 41024448e5;
814
+ if (ts < MIN_TIMESTAMP || ts > MAX_TIMESTAMP || !Number.isFinite(ts)) {
815
+ Logger.warn(`Invalid timestamp: ${timestamp}, using current time`);
816
+ return new Date(now).toISOString();
817
+ }
818
+ return new Date(ts).toISOString();
819
+ }
820
+ var AgnoClient = class extends import_eventemitter3.default {
821
+ constructor(config) {
822
+ super();
823
+ this.messageStore = new MessageStore();
824
+ this.configManager = new ConfigManager(config);
825
+ this.sessionManager = new SessionManager();
826
+ this.eventProcessor = new EventProcessor();
827
+ this.state = {
828
+ isStreaming: false,
829
+ isEndpointActive: false,
830
+ agents: [],
831
+ teams: [],
832
+ sessions: [],
833
+ isPaused: false,
834
+ pausedRunId: void 0,
835
+ toolsAwaitingExecution: void 0
836
+ };
837
+ }
838
+ /**
839
+ * Get current messages
840
+ */
841
+ getMessages() {
842
+ return this.messageStore.getMessages();
843
+ }
844
+ /**
845
+ * Get current configuration
846
+ */
847
+ getConfig() {
848
+ return this.configManager.getConfig();
849
+ }
850
+ /**
851
+ * Get current state
852
+ */
853
+ getState() {
854
+ return { ...this.state };
855
+ }
856
+ /**
857
+ * Update configuration
858
+ */
859
+ updateConfig(updates) {
860
+ this.configManager.updateConfig(updates);
861
+ this.emit("config:change", this.configManager.getConfig());
862
+ }
863
+ /**
864
+ * Clear all messages
865
+ */
866
+ clearMessages() {
867
+ this.messageStore.clear();
868
+ this.configManager.setSessionId(void 0);
869
+ this.emit("message:update", this.messageStore.getMessages());
870
+ this.emit("state:change", this.getState());
871
+ }
872
+ /**
873
+ * Send a message to the agent/team (streaming)
874
+ */
875
+ async sendMessage(message, options) {
876
+ if (this.state.isStreaming) {
877
+ throw new Error("Already streaming a message");
878
+ }
879
+ const runUrl = this.configManager.getRunUrl();
880
+ if (!runUrl) {
881
+ throw new Error("No agent or team selected");
882
+ }
883
+ this.state.isStreaming = true;
884
+ this.state.errorMessage = void 0;
885
+ this.emit("stream:start");
886
+ this.emit("state:change", this.getState());
887
+ const formData = message instanceof FormData ? message : new FormData();
888
+ if (typeof message === "string") {
889
+ formData.append("message", message);
890
+ }
891
+ const lastMessage = this.messageStore.getLastMessage();
892
+ if (lastMessage?.streamingError) {
893
+ const secondLast = this.messageStore.getMessages()[this.messageStore.getMessages().length - 2];
894
+ if (secondLast?.role === "user") {
895
+ this.messageStore.removeLastMessages(2);
896
+ }
897
+ }
898
+ this.messageStore.addMessage({
899
+ role: "user",
900
+ content: formData.get("message"),
901
+ created_at: Math.floor(Date.now() / 1e3)
902
+ });
903
+ this.messageStore.addMessage({
904
+ role: "agent",
905
+ content: "",
906
+ tool_calls: [],
907
+ streamingError: false,
908
+ created_at: Math.floor(Date.now() / 1e3) + 1
909
+ });
910
+ this.emit("message:update", this.messageStore.getMessages());
911
+ this.eventProcessor.reset();
912
+ let newSessionId = this.configManager.getSessionId();
913
+ try {
914
+ formData.append("stream", "true");
915
+ formData.append("session_id", newSessionId ?? "");
916
+ const headers = { ...options?.headers };
917
+ const authToken = this.configManager.getAuthToken();
918
+ if (authToken) {
919
+ headers["Authorization"] = `Bearer ${authToken}`;
920
+ }
921
+ await streamResponse({
922
+ apiUrl: runUrl,
923
+ headers,
924
+ requestBody: formData,
925
+ onChunk: (chunk) => {
926
+ this.handleChunk(chunk, newSessionId, formData.get("message"));
927
+ if (chunk.event === import_agno_types2.RunEvent.RunStarted || chunk.event === import_agno_types2.RunEvent.TeamRunStarted || chunk.event === import_agno_types2.RunEvent.ReasoningStarted || chunk.event === import_agno_types2.RunEvent.TeamReasoningStarted) {
928
+ if (chunk.session_id) {
929
+ newSessionId = chunk.session_id;
930
+ this.configManager.setSessionId(chunk.session_id);
931
+ }
932
+ }
933
+ },
934
+ onError: (error) => {
935
+ this.handleError(error, newSessionId);
936
+ },
937
+ onComplete: () => {
938
+ this.state.isStreaming = false;
939
+ this.emit("stream:end");
940
+ this.emit("message:complete", this.messageStore.getMessages());
941
+ this.emit("state:change", this.getState());
942
+ }
943
+ });
944
+ } catch (error) {
945
+ this.handleError(
946
+ error instanceof Error ? error : new Error(String(error)),
947
+ newSessionId
948
+ );
949
+ }
950
+ }
951
+ /**
952
+ * Handle streaming chunk
953
+ */
954
+ handleChunk(chunk, currentSessionId, messageContent) {
955
+ const event = chunk.event;
956
+ if (event === import_agno_types2.RunEvent.RunStarted || event === import_agno_types2.RunEvent.TeamRunStarted || event === import_agno_types2.RunEvent.ReasoningStarted || event === import_agno_types2.RunEvent.TeamReasoningStarted) {
957
+ if (chunk.session_id && (!currentSessionId || currentSessionId !== chunk.session_id)) {
958
+ const sessionData = {
959
+ session_id: chunk.session_id,
960
+ session_name: messageContent,
961
+ created_at: toSafeISOString(chunk.created_at)
962
+ };
963
+ const sessionExists = this.state.sessions.some(
964
+ (s) => s.session_id === chunk.session_id
965
+ );
966
+ if (!sessionExists) {
967
+ this.state.sessions = [sessionData, ...this.state.sessions];
968
+ this.emit("session:created", sessionData);
969
+ }
970
+ }
971
+ }
972
+ if (event === import_agno_types2.RunEvent.RunPaused) {
973
+ this.state.isStreaming = false;
974
+ this.state.isPaused = true;
975
+ this.state.pausedRunId = chunk.run_id;
976
+ this.state.toolsAwaitingExecution = chunk.tools_awaiting_external_execution || chunk.tools_requiring_confirmation || chunk.tools_requiring_user_input || chunk.tools || [];
977
+ this.emit("run:paused", {
978
+ runId: chunk.run_id,
979
+ sessionId: chunk.session_id,
980
+ tools: this.state.toolsAwaitingExecution
981
+ });
982
+ this.emit("state:change", this.getState());
983
+ return;
984
+ }
985
+ if (event === import_agno_types2.RunEvent.RunError || event === import_agno_types2.RunEvent.TeamRunError || event === import_agno_types2.RunEvent.TeamRunCancelled) {
986
+ const errorContent = chunk.content || (event === import_agno_types2.RunEvent.TeamRunCancelled ? "Run cancelled" : "Error during run");
987
+ this.state.errorMessage = errorContent;
988
+ this.messageStore.updateLastMessage((msg) => ({
989
+ ...msg,
990
+ streamingError: true
991
+ }));
992
+ if (chunk.session_id) {
993
+ this.state.sessions = this.state.sessions.filter(
994
+ (s) => s.session_id !== chunk.session_id
995
+ );
996
+ }
997
+ this.emit("message:error", errorContent);
998
+ return;
999
+ }
1000
+ this.messageStore.updateLastMessage((lastMessage) => {
1001
+ const updated = this.eventProcessor.processChunk(chunk, lastMessage);
1002
+ return updated || lastMessage;
1003
+ });
1004
+ this.emit("message:update", this.messageStore.getMessages());
1005
+ }
1006
+ /**
1007
+ * Handle error
1008
+ */
1009
+ handleError(error, sessionId) {
1010
+ this.state.isStreaming = false;
1011
+ this.state.errorMessage = error.message;
1012
+ this.messageStore.updateLastMessage((msg) => ({
1013
+ ...msg,
1014
+ streamingError: true
1015
+ }));
1016
+ if (sessionId) {
1017
+ this.state.sessions = this.state.sessions.filter(
1018
+ (s) => s.session_id !== sessionId
1019
+ );
1020
+ }
1021
+ this.emit("message:error", error.message);
1022
+ this.emit("stream:end");
1023
+ this.emit("state:change", this.getState());
1024
+ }
1025
+ /**
1026
+ * Load a session
1027
+ */
1028
+ async loadSession(sessionId) {
1029
+ Logger.debug("[AgnoClient] loadSession called with sessionId:", sessionId);
1030
+ const config = this.configManager.getConfig();
1031
+ const entityType = this.configManager.getMode();
1032
+ const dbId = this.configManager.getDbId() || "";
1033
+ Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId });
1034
+ const response = await this.sessionManager.fetchSession(
1035
+ config.endpoint,
1036
+ entityType,
1037
+ sessionId,
1038
+ dbId,
1039
+ config.authToken
1040
+ );
1041
+ const messages = this.sessionManager.convertSessionToMessages(response);
1042
+ Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
1043
+ this.messageStore.setMessages(messages);
1044
+ this.configManager.setSessionId(sessionId);
1045
+ Logger.debug("[AgnoClient] Emitting events...");
1046
+ this.emit("session:loaded", sessionId);
1047
+ this.emit("message:update", this.messageStore.getMessages());
1048
+ this.emit("state:change", this.getState());
1049
+ Logger.debug("[AgnoClient] Events emitted, returning messages");
1050
+ return messages;
1051
+ }
1052
+ /**
1053
+ * Fetch all sessions
1054
+ */
1055
+ async fetchSessions() {
1056
+ const config = this.configManager.getConfig();
1057
+ const entityType = this.configManager.getMode();
1058
+ const entityId = this.configManager.getCurrentEntityId();
1059
+ const dbId = this.configManager.getDbId() || "";
1060
+ if (!entityId) {
1061
+ throw new Error("Entity ID must be configured");
1062
+ }
1063
+ const sessions = await this.sessionManager.fetchSessions(
1064
+ config.endpoint,
1065
+ entityType,
1066
+ entityId,
1067
+ dbId,
1068
+ config.authToken
1069
+ );
1070
+ this.state.sessions = sessions;
1071
+ this.emit("state:change", this.getState());
1072
+ return sessions;
1073
+ }
1074
+ /**
1075
+ * Delete a session
1076
+ */
1077
+ async deleteSession(sessionId) {
1078
+ const config = this.configManager.getConfig();
1079
+ const dbId = this.configManager.getDbId() || "";
1080
+ await this.sessionManager.deleteSession(
1081
+ config.endpoint,
1082
+ sessionId,
1083
+ dbId,
1084
+ config.authToken
1085
+ );
1086
+ this.state.sessions = this.state.sessions.filter(
1087
+ (s) => s.session_id !== sessionId
1088
+ );
1089
+ if (this.configManager.getSessionId() === sessionId) {
1090
+ this.clearMessages();
1091
+ }
1092
+ this.emit("state:change", this.getState());
1093
+ }
1094
+ /**
1095
+ * Delete a team session
1096
+ */
1097
+ async deleteTeamSession(teamId, sessionId) {
1098
+ const config = this.configManager.getConfig();
1099
+ await this.sessionManager.deleteTeamSession(
1100
+ config.endpoint,
1101
+ teamId,
1102
+ sessionId,
1103
+ config.authToken
1104
+ );
1105
+ this.state.sessions = this.state.sessions.filter(
1106
+ (s) => s.session_id !== sessionId
1107
+ );
1108
+ if (this.configManager.getSessionId() === sessionId) {
1109
+ this.clearMessages();
1110
+ }
1111
+ this.emit("state:change", this.getState());
1112
+ }
1113
+ /**
1114
+ * Continue a paused run after executing external tools
1115
+ */
1116
+ async continueRun(tools, options) {
1117
+ if (!this.state.isPaused || !this.state.pausedRunId) {
1118
+ throw new Error("No paused run to continue");
1119
+ }
1120
+ const runUrl = this.configManager.getRunUrl();
1121
+ if (!runUrl) {
1122
+ throw new Error("No agent or team selected");
1123
+ }
1124
+ const continueUrl = `${runUrl}/${this.state.pausedRunId}/continue`;
1125
+ this.state.isPaused = false;
1126
+ this.state.isStreaming = true;
1127
+ this.emit("run:continued", { runId: this.state.pausedRunId });
1128
+ this.emit("state:change", this.getState());
1129
+ const formData = new FormData();
1130
+ formData.append("tools", JSON.stringify(tools));
1131
+ formData.append("stream", "true");
1132
+ const currentSessionId = this.configManager.getSessionId();
1133
+ if (currentSessionId) {
1134
+ formData.append("session_id", currentSessionId);
1135
+ }
1136
+ const headers = { ...options?.headers };
1137
+ const authToken = this.configManager.getAuthToken();
1138
+ if (authToken) {
1139
+ headers["Authorization"] = `Bearer ${authToken}`;
1140
+ }
1141
+ try {
1142
+ await streamResponse({
1143
+ apiUrl: continueUrl,
1144
+ headers,
1145
+ requestBody: formData,
1146
+ onChunk: (chunk) => {
1147
+ this.handleChunk(chunk, currentSessionId, "");
1148
+ },
1149
+ onError: (error) => {
1150
+ this.handleError(error, currentSessionId);
1151
+ },
1152
+ onComplete: () => {
1153
+ this.state.isStreaming = false;
1154
+ this.state.pausedRunId = void 0;
1155
+ this.state.toolsAwaitingExecution = void 0;
1156
+ this.emit("stream:end");
1157
+ this.emit("message:complete", this.messageStore.getMessages());
1158
+ this.emit("state:change", this.getState());
1159
+ }
1160
+ });
1161
+ } catch (error) {
1162
+ this.handleError(
1163
+ error instanceof Error ? error : new Error(String(error)),
1164
+ currentSessionId
1165
+ );
1166
+ }
1167
+ }
1168
+ /**
1169
+ * Check endpoint status
1170
+ */
1171
+ async checkStatus() {
1172
+ try {
1173
+ const response = await fetch(`${this.configManager.getEndpoint()}/health`);
1174
+ const isActive = response.ok;
1175
+ this.state.isEndpointActive = isActive;
1176
+ this.emit("state:change", this.getState());
1177
+ return isActive;
1178
+ } catch {
1179
+ this.state.isEndpointActive = false;
1180
+ this.emit("state:change", this.getState());
1181
+ return false;
1182
+ }
1183
+ }
1184
+ /**
1185
+ * Fetch agents from endpoint
1186
+ */
1187
+ async fetchAgents() {
1188
+ const config = this.configManager.getConfig();
1189
+ const headers = {};
1190
+ if (config.authToken) {
1191
+ headers["Authorization"] = `Bearer ${config.authToken}`;
1192
+ }
1193
+ const response = await fetch(`${config.endpoint}/agents`, { headers });
1194
+ if (!response.ok) {
1195
+ throw new Error("Failed to fetch agents");
1196
+ }
1197
+ const agents = await response.json();
1198
+ this.state.agents = agents;
1199
+ this.emit("state:change", this.getState());
1200
+ return agents;
1201
+ }
1202
+ /**
1203
+ * Fetch teams from endpoint
1204
+ */
1205
+ async fetchTeams() {
1206
+ const config = this.configManager.getConfig();
1207
+ const headers = {};
1208
+ if (config.authToken) {
1209
+ headers["Authorization"] = `Bearer ${config.authToken}`;
1210
+ }
1211
+ const response = await fetch(`${config.endpoint}/teams`, { headers });
1212
+ if (!response.ok) {
1213
+ throw new Error("Failed to fetch teams");
1214
+ }
1215
+ const teams = await response.json();
1216
+ this.state.teams = teams;
1217
+ this.emit("state:change", this.getState());
1218
+ return teams;
1219
+ }
1220
+ /**
1221
+ * Initialize client (check status and fetch agents/teams)
1222
+ * Automatically selects the first available agent or team if none is configured
1223
+ */
1224
+ async initialize() {
1225
+ const isActive = await this.checkStatus();
1226
+ if (!isActive) {
1227
+ return { agents: [], teams: [] };
1228
+ }
1229
+ const [agents, teams] = await Promise.all([
1230
+ this.fetchAgents(),
1231
+ this.fetchTeams()
1232
+ ]);
1233
+ const currentConfig = this.configManager.getConfig();
1234
+ const hasAgentConfigured = currentConfig.agentId;
1235
+ const hasTeamConfigured = currentConfig.teamId;
1236
+ if (!hasAgentConfigured && !hasTeamConfigured) {
1237
+ if (agents.length > 0) {
1238
+ const firstAgent = agents[0];
1239
+ this.configManager.updateConfig({
1240
+ mode: "agent",
1241
+ agentId: firstAgent.id,
1242
+ dbId: firstAgent.db_id || void 0
1243
+ });
1244
+ this.emit("config:change", this.configManager.getConfig());
1245
+ } else if (teams.length > 0) {
1246
+ const firstTeam = teams[0];
1247
+ this.configManager.updateConfig({
1248
+ mode: "team",
1249
+ teamId: firstTeam.id,
1250
+ dbId: firstTeam.db_id || void 0
1251
+ });
1252
+ this.emit("config:change", this.configManager.getConfig());
1253
+ }
1254
+ }
1255
+ return { agents, teams };
1256
+ }
1257
+ };
1258
+
1259
+ // src/index.ts
1260
+ var import_agno_types3 = require("@antipopp/agno-types");
1261
+ // Annotate the CommonJS export names for ESM import in node:
1262
+ 0 && (module.exports = {
1263
+ AgnoClient,
1264
+ Logger,
1265
+ RunEvent
1266
+ });