@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/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/index.d.mts +120 -0
- package/dist/index.d.ts +120 -0
- package/dist/index.js +1266 -0
- package/dist/index.mjs +1227 -0
- package/package.json +48 -0
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
|
+
});
|