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