@antipopp/agno-client 0.6.1 → 0.8.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.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +140 -44
- package/dist/index.mjs +140 -44
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -13,6 +13,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
13
13
|
private eventProcessor;
|
|
14
14
|
private state;
|
|
15
15
|
private pendingUISpecs;
|
|
16
|
+
private runCompletedSuccessfully;
|
|
16
17
|
constructor(config: AgnoClientConfig);
|
|
17
18
|
/**
|
|
18
19
|
* Get current messages
|
|
@@ -48,6 +49,13 @@ declare class AgnoClient extends EventEmitter {
|
|
|
48
49
|
* Handle error
|
|
49
50
|
*/
|
|
50
51
|
private handleError;
|
|
52
|
+
/**
|
|
53
|
+
* Refresh messages from the session API after run completion.
|
|
54
|
+
* Replaces streamed messages with authoritative session data.
|
|
55
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
private refreshSessionMessages;
|
|
51
59
|
/**
|
|
52
60
|
* Load a session
|
|
53
61
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
13
13
|
private eventProcessor;
|
|
14
14
|
private state;
|
|
15
15
|
private pendingUISpecs;
|
|
16
|
+
private runCompletedSuccessfully;
|
|
16
17
|
constructor(config: AgnoClientConfig);
|
|
17
18
|
/**
|
|
18
19
|
* Get current messages
|
|
@@ -48,6 +49,13 @@ declare class AgnoClient extends EventEmitter {
|
|
|
48
49
|
* Handle error
|
|
49
50
|
*/
|
|
50
51
|
private handleError;
|
|
52
|
+
/**
|
|
53
|
+
* Refresh messages from the session API after run completion.
|
|
54
|
+
* Replaces streamed messages with authoritative session data.
|
|
55
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
private refreshSessionMessages;
|
|
51
59
|
/**
|
|
52
60
|
* Load a session
|
|
53
61
|
*/
|
package/dist/index.js
CHANGED
|
@@ -238,6 +238,18 @@ var ConfigManager = class {
|
|
|
238
238
|
setUserId(userId) {
|
|
239
239
|
this.updateField("userId", userId);
|
|
240
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Get custom headers
|
|
243
|
+
*/
|
|
244
|
+
getHeaders() {
|
|
245
|
+
return this.config.headers;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Set custom headers
|
|
249
|
+
*/
|
|
250
|
+
setHeaders(headers) {
|
|
251
|
+
this.updateField("headers", headers);
|
|
252
|
+
}
|
|
241
253
|
/**
|
|
242
254
|
* Get current entity ID (agent or team based on mode)
|
|
243
255
|
*/
|
|
@@ -260,6 +272,31 @@ var ConfigManager = class {
|
|
|
260
272
|
return `${endpoint}/agents/${encodedEntityId}/runs`;
|
|
261
273
|
}
|
|
262
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Build request headers by merging global headers, per-request headers, and auth token.
|
|
277
|
+
* Merge order (lowest to highest precedence):
|
|
278
|
+
* 1. Global headers from config
|
|
279
|
+
* 2. Per-request headers (overrides global)
|
|
280
|
+
* 3. Authorization header from authToken (overrides all)
|
|
281
|
+
*
|
|
282
|
+
* @param perRequestHeaders - Optional headers for this specific request
|
|
283
|
+
* @returns Merged headers object ready for fetch
|
|
284
|
+
*/
|
|
285
|
+
buildRequestHeaders(perRequestHeaders) {
|
|
286
|
+
const headers = {};
|
|
287
|
+
const globalHeaders = this.getHeaders();
|
|
288
|
+
if (globalHeaders) {
|
|
289
|
+
Object.assign(headers, globalHeaders);
|
|
290
|
+
}
|
|
291
|
+
if (perRequestHeaders) {
|
|
292
|
+
Object.assign(headers, perRequestHeaders);
|
|
293
|
+
}
|
|
294
|
+
const authToken = this.getAuthToken();
|
|
295
|
+
if (authToken) {
|
|
296
|
+
headers["Authorization"] = `Bearer ${authToken}`;
|
|
297
|
+
}
|
|
298
|
+
return headers;
|
|
299
|
+
}
|
|
263
300
|
};
|
|
264
301
|
|
|
265
302
|
// src/managers/session-manager.ts
|
|
@@ -267,15 +304,11 @@ var SessionManager = class {
|
|
|
267
304
|
/**
|
|
268
305
|
* Fetch all sessions for an entity
|
|
269
306
|
*/
|
|
270
|
-
async fetchSessions(endpoint, entityType, entityId, dbId,
|
|
307
|
+
async fetchSessions(endpoint, entityType, entityId, dbId, headers) {
|
|
271
308
|
const url = new URL(`${endpoint}/sessions`);
|
|
272
309
|
url.searchParams.set("type", entityType);
|
|
273
310
|
url.searchParams.set("component_id", entityId);
|
|
274
311
|
url.searchParams.set("db_id", dbId);
|
|
275
|
-
const headers = {};
|
|
276
|
-
if (authToken) {
|
|
277
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
278
|
-
}
|
|
279
312
|
const response = await fetch(url.toString(), { headers });
|
|
280
313
|
if (!response.ok) {
|
|
281
314
|
if (response.status === 404) {
|
|
@@ -290,15 +323,14 @@ var SessionManager = class {
|
|
|
290
323
|
* Fetch a specific session's runs
|
|
291
324
|
* Returns an array of RunSchema directly (not wrapped in { data, meta })
|
|
292
325
|
*/
|
|
293
|
-
async fetchSession(endpoint, entityType, sessionId, dbId,
|
|
326
|
+
async fetchSession(endpoint, entityType, sessionId, dbId, headers, userId) {
|
|
294
327
|
const url = new URL(`${endpoint}/sessions/${sessionId}/runs`);
|
|
295
328
|
url.searchParams.set("type", entityType);
|
|
296
329
|
if (dbId) {
|
|
297
330
|
url.searchParams.set("db_id", dbId);
|
|
298
331
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
332
|
+
if (userId) {
|
|
333
|
+
url.searchParams.set("user_id", userId);
|
|
302
334
|
}
|
|
303
335
|
const response = await fetch(url.toString(), { headers });
|
|
304
336
|
if (!response.ok) {
|
|
@@ -309,15 +341,11 @@ var SessionManager = class {
|
|
|
309
341
|
/**
|
|
310
342
|
* Delete a session
|
|
311
343
|
*/
|
|
312
|
-
async deleteSession(endpoint, sessionId, dbId,
|
|
344
|
+
async deleteSession(endpoint, sessionId, dbId, headers) {
|
|
313
345
|
const url = new URL(`${endpoint}/sessions/${sessionId}`);
|
|
314
346
|
if (dbId) {
|
|
315
347
|
url.searchParams.set("db_id", dbId);
|
|
316
348
|
}
|
|
317
|
-
const headers = {};
|
|
318
|
-
if (authToken) {
|
|
319
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
320
|
-
}
|
|
321
349
|
const response = await fetch(url.toString(), {
|
|
322
350
|
method: "DELETE",
|
|
323
351
|
headers
|
|
@@ -826,9 +854,10 @@ function toSafeISOString(timestamp) {
|
|
|
826
854
|
return new Date(ts).toISOString();
|
|
827
855
|
}
|
|
828
856
|
var AgnoClient = class extends import_eventemitter3.default {
|
|
829
|
-
// toolCallId -> UIComponentSpec
|
|
830
857
|
constructor(config) {
|
|
831
858
|
super();
|
|
859
|
+
// toolCallId -> UIComponentSpec
|
|
860
|
+
this.runCompletedSuccessfully = false;
|
|
832
861
|
this.messageStore = new MessageStore();
|
|
833
862
|
this.configManager = new ConfigManager(config);
|
|
834
863
|
this.sessionManager = new SessionManager();
|
|
@@ -836,6 +865,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
836
865
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
837
866
|
this.state = {
|
|
838
867
|
isStreaming: false,
|
|
868
|
+
isRefreshing: false,
|
|
839
869
|
isEndpointActive: false,
|
|
840
870
|
agents: [],
|
|
841
871
|
teams: [],
|
|
@@ -887,6 +917,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
887
917
|
if (this.state.isStreaming) {
|
|
888
918
|
throw new Error("Already streaming a message");
|
|
889
919
|
}
|
|
920
|
+
this.runCompletedSuccessfully = false;
|
|
890
921
|
const runUrl = this.configManager.getRunUrl();
|
|
891
922
|
if (!runUrl) {
|
|
892
923
|
throw new Error("No agent or team selected");
|
|
@@ -928,11 +959,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
928
959
|
if (userId) {
|
|
929
960
|
formData.append("user_id", userId);
|
|
930
961
|
}
|
|
931
|
-
const headers =
|
|
932
|
-
const authToken = this.configManager.getAuthToken();
|
|
933
|
-
if (authToken) {
|
|
934
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
935
|
-
}
|
|
962
|
+
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
936
963
|
await streamResponse({
|
|
937
964
|
apiUrl: runUrl,
|
|
938
965
|
headers,
|
|
@@ -949,11 +976,15 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
949
976
|
onError: (error) => {
|
|
950
977
|
this.handleError(error, newSessionId);
|
|
951
978
|
},
|
|
952
|
-
onComplete: () => {
|
|
979
|
+
onComplete: async () => {
|
|
953
980
|
this.state.isStreaming = false;
|
|
954
981
|
this.emit("stream:end");
|
|
955
982
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
956
983
|
this.emit("state:change", this.getState());
|
|
984
|
+
if (this.runCompletedSuccessfully) {
|
|
985
|
+
this.runCompletedSuccessfully = false;
|
|
986
|
+
await this.refreshSessionMessages();
|
|
987
|
+
}
|
|
957
988
|
}
|
|
958
989
|
});
|
|
959
990
|
} catch (error) {
|
|
@@ -1017,6 +1048,9 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1017
1048
|
return updated || lastMessage;
|
|
1018
1049
|
});
|
|
1019
1050
|
this.applyPendingUISpecs();
|
|
1051
|
+
if (event === import_agno_types2.RunEvent.RunCompleted || event === import_agno_types2.RunEvent.TeamRunCompleted) {
|
|
1052
|
+
this.runCompletedSuccessfully = true;
|
|
1053
|
+
}
|
|
1020
1054
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1021
1055
|
}
|
|
1022
1056
|
/**
|
|
@@ -1038,6 +1072,70 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1038
1072
|
this.emit("stream:end");
|
|
1039
1073
|
this.emit("state:change", this.getState());
|
|
1040
1074
|
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Refresh messages from the session API after run completion.
|
|
1077
|
+
* Replaces streamed messages with authoritative session data.
|
|
1078
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
1079
|
+
* @private
|
|
1080
|
+
*/
|
|
1081
|
+
async refreshSessionMessages() {
|
|
1082
|
+
const sessionId = this.configManager.getSessionId();
|
|
1083
|
+
if (!sessionId) {
|
|
1084
|
+
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
this.state.isRefreshing = true;
|
|
1088
|
+
this.emit("state:change", this.getState());
|
|
1089
|
+
try {
|
|
1090
|
+
const existingUIComponents = /* @__PURE__ */ new Map();
|
|
1091
|
+
for (const message of this.messageStore.getMessages()) {
|
|
1092
|
+
if (message.tool_calls) {
|
|
1093
|
+
for (const toolCall of message.tool_calls) {
|
|
1094
|
+
if (toolCall.ui_component) {
|
|
1095
|
+
existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
const config = this.configManager.getConfig();
|
|
1101
|
+
const entityType = this.configManager.getMode();
|
|
1102
|
+
const dbId = this.configManager.getDbId() || "";
|
|
1103
|
+
const userId = this.configManager.getUserId();
|
|
1104
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1105
|
+
const response = await this.sessionManager.fetchSession(
|
|
1106
|
+
config.endpoint,
|
|
1107
|
+
entityType,
|
|
1108
|
+
sessionId,
|
|
1109
|
+
dbId,
|
|
1110
|
+
headers,
|
|
1111
|
+
userId
|
|
1112
|
+
);
|
|
1113
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1114
|
+
if (existingUIComponents.size > 0) {
|
|
1115
|
+
for (const message of messages) {
|
|
1116
|
+
if (message.tool_calls) {
|
|
1117
|
+
for (let i = 0; i < message.tool_calls.length; i++) {
|
|
1118
|
+
const toolCall = message.tool_calls[i];
|
|
1119
|
+
const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
|
|
1120
|
+
if (uiComponent) {
|
|
1121
|
+
message.tool_calls[i].ui_component = uiComponent;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
this.messageStore.setMessages(messages);
|
|
1128
|
+
Logger.debug("[AgnoClient] Session refreshed:", `${messages.length} messages`);
|
|
1129
|
+
this.emit("message:refreshed", messages);
|
|
1130
|
+
this.emit("message:update", messages);
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
Logger.error("[AgnoClient] Failed to refresh session:", error);
|
|
1133
|
+
this.emit("message:error", `Session refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1134
|
+
} finally {
|
|
1135
|
+
this.state.isRefreshing = false;
|
|
1136
|
+
this.emit("state:change", this.getState());
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1041
1139
|
/**
|
|
1042
1140
|
* Load a session
|
|
1043
1141
|
*/
|
|
@@ -1046,13 +1144,16 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1046
1144
|
const config = this.configManager.getConfig();
|
|
1047
1145
|
const entityType = this.configManager.getMode();
|
|
1048
1146
|
const dbId = this.configManager.getDbId() || "";
|
|
1049
|
-
|
|
1147
|
+
const userId = this.configManager.getUserId();
|
|
1148
|
+
Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId, userId });
|
|
1149
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1050
1150
|
const response = await this.sessionManager.fetchSession(
|
|
1051
1151
|
config.endpoint,
|
|
1052
1152
|
entityType,
|
|
1053
1153
|
sessionId,
|
|
1054
1154
|
dbId,
|
|
1055
|
-
|
|
1155
|
+
headers,
|
|
1156
|
+
userId
|
|
1056
1157
|
);
|
|
1057
1158
|
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1058
1159
|
Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
|
|
@@ -1076,12 +1177,13 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1076
1177
|
if (!entityId) {
|
|
1077
1178
|
throw new Error("Entity ID must be configured");
|
|
1078
1179
|
}
|
|
1180
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1079
1181
|
const sessions = await this.sessionManager.fetchSessions(
|
|
1080
1182
|
config.endpoint,
|
|
1081
1183
|
entityType,
|
|
1082
1184
|
entityId,
|
|
1083
1185
|
dbId,
|
|
1084
|
-
|
|
1186
|
+
headers
|
|
1085
1187
|
);
|
|
1086
1188
|
this.state.sessions = sessions;
|
|
1087
1189
|
this.emit("state:change", this.getState());
|
|
@@ -1093,11 +1195,12 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1093
1195
|
async deleteSession(sessionId) {
|
|
1094
1196
|
const config = this.configManager.getConfig();
|
|
1095
1197
|
const dbId = this.configManager.getDbId() || "";
|
|
1198
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1096
1199
|
await this.sessionManager.deleteSession(
|
|
1097
1200
|
config.endpoint,
|
|
1098
1201
|
sessionId,
|
|
1099
1202
|
dbId,
|
|
1100
|
-
|
|
1203
|
+
headers
|
|
1101
1204
|
);
|
|
1102
1205
|
this.state.sessions = this.state.sessions.filter(
|
|
1103
1206
|
(s) => s.session_id !== sessionId
|
|
@@ -1248,11 +1351,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1248
1351
|
if (userId) {
|
|
1249
1352
|
formData.append("user_id", userId);
|
|
1250
1353
|
}
|
|
1251
|
-
const headers =
|
|
1252
|
-
const authToken = this.configManager.getAuthToken();
|
|
1253
|
-
if (authToken) {
|
|
1254
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
1255
|
-
}
|
|
1354
|
+
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1256
1355
|
try {
|
|
1257
1356
|
await streamResponse({
|
|
1258
1357
|
apiUrl: continueUrl,
|
|
@@ -1264,13 +1363,17 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1264
1363
|
onError: (error) => {
|
|
1265
1364
|
this.handleError(error, currentSessionId);
|
|
1266
1365
|
},
|
|
1267
|
-
onComplete: () => {
|
|
1366
|
+
onComplete: async () => {
|
|
1268
1367
|
this.state.isStreaming = false;
|
|
1269
1368
|
this.state.pausedRunId = void 0;
|
|
1270
1369
|
this.state.toolsAwaitingExecution = void 0;
|
|
1271
1370
|
this.emit("stream:end");
|
|
1272
1371
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
1273
1372
|
this.emit("state:change", this.getState());
|
|
1373
|
+
if (this.runCompletedSuccessfully) {
|
|
1374
|
+
this.runCompletedSuccessfully = false;
|
|
1375
|
+
await this.refreshSessionMessages();
|
|
1376
|
+
}
|
|
1274
1377
|
}
|
|
1275
1378
|
});
|
|
1276
1379
|
} catch (error) {
|
|
@@ -1285,7 +1388,8 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1285
1388
|
*/
|
|
1286
1389
|
async checkStatus() {
|
|
1287
1390
|
try {
|
|
1288
|
-
const
|
|
1391
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1392
|
+
const response = await fetch(`${this.configManager.getEndpoint()}/health`, { headers });
|
|
1289
1393
|
const isActive = response.ok;
|
|
1290
1394
|
this.state.isEndpointActive = isActive;
|
|
1291
1395
|
this.emit("state:change", this.getState());
|
|
@@ -1300,12 +1404,8 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1300
1404
|
* Fetch agents from endpoint
|
|
1301
1405
|
*/
|
|
1302
1406
|
async fetchAgents() {
|
|
1303
|
-
const
|
|
1304
|
-
const
|
|
1305
|
-
if (config.authToken) {
|
|
1306
|
-
headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
1307
|
-
}
|
|
1308
|
-
const response = await fetch(`${config.endpoint}/agents`, { headers });
|
|
1407
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1408
|
+
const response = await fetch(`${this.configManager.getEndpoint()}/agents`, { headers });
|
|
1309
1409
|
if (!response.ok) {
|
|
1310
1410
|
throw new Error("Failed to fetch agents");
|
|
1311
1411
|
}
|
|
@@ -1318,12 +1418,8 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1318
1418
|
* Fetch teams from endpoint
|
|
1319
1419
|
*/
|
|
1320
1420
|
async fetchTeams() {
|
|
1321
|
-
const
|
|
1322
|
-
const
|
|
1323
|
-
if (config.authToken) {
|
|
1324
|
-
headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
1325
|
-
}
|
|
1326
|
-
const response = await fetch(`${config.endpoint}/teams`, { headers });
|
|
1421
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1422
|
+
const response = await fetch(`${this.configManager.getEndpoint()}/teams`, { headers });
|
|
1327
1423
|
if (!response.ok) {
|
|
1328
1424
|
throw new Error("Failed to fetch teams");
|
|
1329
1425
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -200,6 +200,18 @@ var ConfigManager = class {
|
|
|
200
200
|
setUserId(userId) {
|
|
201
201
|
this.updateField("userId", userId);
|
|
202
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Get custom headers
|
|
205
|
+
*/
|
|
206
|
+
getHeaders() {
|
|
207
|
+
return this.config.headers;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Set custom headers
|
|
211
|
+
*/
|
|
212
|
+
setHeaders(headers) {
|
|
213
|
+
this.updateField("headers", headers);
|
|
214
|
+
}
|
|
203
215
|
/**
|
|
204
216
|
* Get current entity ID (agent or team based on mode)
|
|
205
217
|
*/
|
|
@@ -222,6 +234,31 @@ var ConfigManager = class {
|
|
|
222
234
|
return `${endpoint}/agents/${encodedEntityId}/runs`;
|
|
223
235
|
}
|
|
224
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Build request headers by merging global headers, per-request headers, and auth token.
|
|
239
|
+
* Merge order (lowest to highest precedence):
|
|
240
|
+
* 1. Global headers from config
|
|
241
|
+
* 2. Per-request headers (overrides global)
|
|
242
|
+
* 3. Authorization header from authToken (overrides all)
|
|
243
|
+
*
|
|
244
|
+
* @param perRequestHeaders - Optional headers for this specific request
|
|
245
|
+
* @returns Merged headers object ready for fetch
|
|
246
|
+
*/
|
|
247
|
+
buildRequestHeaders(perRequestHeaders) {
|
|
248
|
+
const headers = {};
|
|
249
|
+
const globalHeaders = this.getHeaders();
|
|
250
|
+
if (globalHeaders) {
|
|
251
|
+
Object.assign(headers, globalHeaders);
|
|
252
|
+
}
|
|
253
|
+
if (perRequestHeaders) {
|
|
254
|
+
Object.assign(headers, perRequestHeaders);
|
|
255
|
+
}
|
|
256
|
+
const authToken = this.getAuthToken();
|
|
257
|
+
if (authToken) {
|
|
258
|
+
headers["Authorization"] = `Bearer ${authToken}`;
|
|
259
|
+
}
|
|
260
|
+
return headers;
|
|
261
|
+
}
|
|
225
262
|
};
|
|
226
263
|
|
|
227
264
|
// src/managers/session-manager.ts
|
|
@@ -229,15 +266,11 @@ var SessionManager = class {
|
|
|
229
266
|
/**
|
|
230
267
|
* Fetch all sessions for an entity
|
|
231
268
|
*/
|
|
232
|
-
async fetchSessions(endpoint, entityType, entityId, dbId,
|
|
269
|
+
async fetchSessions(endpoint, entityType, entityId, dbId, headers) {
|
|
233
270
|
const url = new URL(`${endpoint}/sessions`);
|
|
234
271
|
url.searchParams.set("type", entityType);
|
|
235
272
|
url.searchParams.set("component_id", entityId);
|
|
236
273
|
url.searchParams.set("db_id", dbId);
|
|
237
|
-
const headers = {};
|
|
238
|
-
if (authToken) {
|
|
239
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
240
|
-
}
|
|
241
274
|
const response = await fetch(url.toString(), { headers });
|
|
242
275
|
if (!response.ok) {
|
|
243
276
|
if (response.status === 404) {
|
|
@@ -252,15 +285,14 @@ var SessionManager = class {
|
|
|
252
285
|
* Fetch a specific session's runs
|
|
253
286
|
* Returns an array of RunSchema directly (not wrapped in { data, meta })
|
|
254
287
|
*/
|
|
255
|
-
async fetchSession(endpoint, entityType, sessionId, dbId,
|
|
288
|
+
async fetchSession(endpoint, entityType, sessionId, dbId, headers, userId) {
|
|
256
289
|
const url = new URL(`${endpoint}/sessions/${sessionId}/runs`);
|
|
257
290
|
url.searchParams.set("type", entityType);
|
|
258
291
|
if (dbId) {
|
|
259
292
|
url.searchParams.set("db_id", dbId);
|
|
260
293
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
294
|
+
if (userId) {
|
|
295
|
+
url.searchParams.set("user_id", userId);
|
|
264
296
|
}
|
|
265
297
|
const response = await fetch(url.toString(), { headers });
|
|
266
298
|
if (!response.ok) {
|
|
@@ -271,15 +303,11 @@ var SessionManager = class {
|
|
|
271
303
|
/**
|
|
272
304
|
* Delete a session
|
|
273
305
|
*/
|
|
274
|
-
async deleteSession(endpoint, sessionId, dbId,
|
|
306
|
+
async deleteSession(endpoint, sessionId, dbId, headers) {
|
|
275
307
|
const url = new URL(`${endpoint}/sessions/${sessionId}`);
|
|
276
308
|
if (dbId) {
|
|
277
309
|
url.searchParams.set("db_id", dbId);
|
|
278
310
|
}
|
|
279
|
-
const headers = {};
|
|
280
|
-
if (authToken) {
|
|
281
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
282
|
-
}
|
|
283
311
|
const response = await fetch(url.toString(), {
|
|
284
312
|
method: "DELETE",
|
|
285
313
|
headers
|
|
@@ -788,9 +816,10 @@ function toSafeISOString(timestamp) {
|
|
|
788
816
|
return new Date(ts).toISOString();
|
|
789
817
|
}
|
|
790
818
|
var AgnoClient = class extends EventEmitter {
|
|
791
|
-
// toolCallId -> UIComponentSpec
|
|
792
819
|
constructor(config) {
|
|
793
820
|
super();
|
|
821
|
+
// toolCallId -> UIComponentSpec
|
|
822
|
+
this.runCompletedSuccessfully = false;
|
|
794
823
|
this.messageStore = new MessageStore();
|
|
795
824
|
this.configManager = new ConfigManager(config);
|
|
796
825
|
this.sessionManager = new SessionManager();
|
|
@@ -798,6 +827,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
798
827
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
799
828
|
this.state = {
|
|
800
829
|
isStreaming: false,
|
|
830
|
+
isRefreshing: false,
|
|
801
831
|
isEndpointActive: false,
|
|
802
832
|
agents: [],
|
|
803
833
|
teams: [],
|
|
@@ -849,6 +879,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
849
879
|
if (this.state.isStreaming) {
|
|
850
880
|
throw new Error("Already streaming a message");
|
|
851
881
|
}
|
|
882
|
+
this.runCompletedSuccessfully = false;
|
|
852
883
|
const runUrl = this.configManager.getRunUrl();
|
|
853
884
|
if (!runUrl) {
|
|
854
885
|
throw new Error("No agent or team selected");
|
|
@@ -890,11 +921,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
890
921
|
if (userId) {
|
|
891
922
|
formData.append("user_id", userId);
|
|
892
923
|
}
|
|
893
|
-
const headers =
|
|
894
|
-
const authToken = this.configManager.getAuthToken();
|
|
895
|
-
if (authToken) {
|
|
896
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
897
|
-
}
|
|
924
|
+
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
898
925
|
await streamResponse({
|
|
899
926
|
apiUrl: runUrl,
|
|
900
927
|
headers,
|
|
@@ -911,11 +938,15 @@ var AgnoClient = class extends EventEmitter {
|
|
|
911
938
|
onError: (error) => {
|
|
912
939
|
this.handleError(error, newSessionId);
|
|
913
940
|
},
|
|
914
|
-
onComplete: () => {
|
|
941
|
+
onComplete: async () => {
|
|
915
942
|
this.state.isStreaming = false;
|
|
916
943
|
this.emit("stream:end");
|
|
917
944
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
918
945
|
this.emit("state:change", this.getState());
|
|
946
|
+
if (this.runCompletedSuccessfully) {
|
|
947
|
+
this.runCompletedSuccessfully = false;
|
|
948
|
+
await this.refreshSessionMessages();
|
|
949
|
+
}
|
|
919
950
|
}
|
|
920
951
|
});
|
|
921
952
|
} catch (error) {
|
|
@@ -979,6 +1010,9 @@ var AgnoClient = class extends EventEmitter {
|
|
|
979
1010
|
return updated || lastMessage;
|
|
980
1011
|
});
|
|
981
1012
|
this.applyPendingUISpecs();
|
|
1013
|
+
if (event === RunEvent.RunCompleted || event === RunEvent.TeamRunCompleted) {
|
|
1014
|
+
this.runCompletedSuccessfully = true;
|
|
1015
|
+
}
|
|
982
1016
|
this.emit("message:update", this.messageStore.getMessages());
|
|
983
1017
|
}
|
|
984
1018
|
/**
|
|
@@ -1000,6 +1034,70 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1000
1034
|
this.emit("stream:end");
|
|
1001
1035
|
this.emit("state:change", this.getState());
|
|
1002
1036
|
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Refresh messages from the session API after run completion.
|
|
1039
|
+
* Replaces streamed messages with authoritative session data.
|
|
1040
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
1041
|
+
* @private
|
|
1042
|
+
*/
|
|
1043
|
+
async refreshSessionMessages() {
|
|
1044
|
+
const sessionId = this.configManager.getSessionId();
|
|
1045
|
+
if (!sessionId) {
|
|
1046
|
+
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
this.state.isRefreshing = true;
|
|
1050
|
+
this.emit("state:change", this.getState());
|
|
1051
|
+
try {
|
|
1052
|
+
const existingUIComponents = /* @__PURE__ */ new Map();
|
|
1053
|
+
for (const message of this.messageStore.getMessages()) {
|
|
1054
|
+
if (message.tool_calls) {
|
|
1055
|
+
for (const toolCall of message.tool_calls) {
|
|
1056
|
+
if (toolCall.ui_component) {
|
|
1057
|
+
existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
const config = this.configManager.getConfig();
|
|
1063
|
+
const entityType = this.configManager.getMode();
|
|
1064
|
+
const dbId = this.configManager.getDbId() || "";
|
|
1065
|
+
const userId = this.configManager.getUserId();
|
|
1066
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1067
|
+
const response = await this.sessionManager.fetchSession(
|
|
1068
|
+
config.endpoint,
|
|
1069
|
+
entityType,
|
|
1070
|
+
sessionId,
|
|
1071
|
+
dbId,
|
|
1072
|
+
headers,
|
|
1073
|
+
userId
|
|
1074
|
+
);
|
|
1075
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1076
|
+
if (existingUIComponents.size > 0) {
|
|
1077
|
+
for (const message of messages) {
|
|
1078
|
+
if (message.tool_calls) {
|
|
1079
|
+
for (let i = 0; i < message.tool_calls.length; i++) {
|
|
1080
|
+
const toolCall = message.tool_calls[i];
|
|
1081
|
+
const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
|
|
1082
|
+
if (uiComponent) {
|
|
1083
|
+
message.tool_calls[i].ui_component = uiComponent;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
this.messageStore.setMessages(messages);
|
|
1090
|
+
Logger.debug("[AgnoClient] Session refreshed:", `${messages.length} messages`);
|
|
1091
|
+
this.emit("message:refreshed", messages);
|
|
1092
|
+
this.emit("message:update", messages);
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
Logger.error("[AgnoClient] Failed to refresh session:", error);
|
|
1095
|
+
this.emit("message:error", `Session refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1096
|
+
} finally {
|
|
1097
|
+
this.state.isRefreshing = false;
|
|
1098
|
+
this.emit("state:change", this.getState());
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1003
1101
|
/**
|
|
1004
1102
|
* Load a session
|
|
1005
1103
|
*/
|
|
@@ -1008,13 +1106,16 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1008
1106
|
const config = this.configManager.getConfig();
|
|
1009
1107
|
const entityType = this.configManager.getMode();
|
|
1010
1108
|
const dbId = this.configManager.getDbId() || "";
|
|
1011
|
-
|
|
1109
|
+
const userId = this.configManager.getUserId();
|
|
1110
|
+
Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId, userId });
|
|
1111
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1012
1112
|
const response = await this.sessionManager.fetchSession(
|
|
1013
1113
|
config.endpoint,
|
|
1014
1114
|
entityType,
|
|
1015
1115
|
sessionId,
|
|
1016
1116
|
dbId,
|
|
1017
|
-
|
|
1117
|
+
headers,
|
|
1118
|
+
userId
|
|
1018
1119
|
);
|
|
1019
1120
|
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1020
1121
|
Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
|
|
@@ -1038,12 +1139,13 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1038
1139
|
if (!entityId) {
|
|
1039
1140
|
throw new Error("Entity ID must be configured");
|
|
1040
1141
|
}
|
|
1142
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1041
1143
|
const sessions = await this.sessionManager.fetchSessions(
|
|
1042
1144
|
config.endpoint,
|
|
1043
1145
|
entityType,
|
|
1044
1146
|
entityId,
|
|
1045
1147
|
dbId,
|
|
1046
|
-
|
|
1148
|
+
headers
|
|
1047
1149
|
);
|
|
1048
1150
|
this.state.sessions = sessions;
|
|
1049
1151
|
this.emit("state:change", this.getState());
|
|
@@ -1055,11 +1157,12 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1055
1157
|
async deleteSession(sessionId) {
|
|
1056
1158
|
const config = this.configManager.getConfig();
|
|
1057
1159
|
const dbId = this.configManager.getDbId() || "";
|
|
1160
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1058
1161
|
await this.sessionManager.deleteSession(
|
|
1059
1162
|
config.endpoint,
|
|
1060
1163
|
sessionId,
|
|
1061
1164
|
dbId,
|
|
1062
|
-
|
|
1165
|
+
headers
|
|
1063
1166
|
);
|
|
1064
1167
|
this.state.sessions = this.state.sessions.filter(
|
|
1065
1168
|
(s) => s.session_id !== sessionId
|
|
@@ -1210,11 +1313,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1210
1313
|
if (userId) {
|
|
1211
1314
|
formData.append("user_id", userId);
|
|
1212
1315
|
}
|
|
1213
|
-
const headers =
|
|
1214
|
-
const authToken = this.configManager.getAuthToken();
|
|
1215
|
-
if (authToken) {
|
|
1216
|
-
headers["Authorization"] = `Bearer ${authToken}`;
|
|
1217
|
-
}
|
|
1316
|
+
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1218
1317
|
try {
|
|
1219
1318
|
await streamResponse({
|
|
1220
1319
|
apiUrl: continueUrl,
|
|
@@ -1226,13 +1325,17 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1226
1325
|
onError: (error) => {
|
|
1227
1326
|
this.handleError(error, currentSessionId);
|
|
1228
1327
|
},
|
|
1229
|
-
onComplete: () => {
|
|
1328
|
+
onComplete: async () => {
|
|
1230
1329
|
this.state.isStreaming = false;
|
|
1231
1330
|
this.state.pausedRunId = void 0;
|
|
1232
1331
|
this.state.toolsAwaitingExecution = void 0;
|
|
1233
1332
|
this.emit("stream:end");
|
|
1234
1333
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
1235
1334
|
this.emit("state:change", this.getState());
|
|
1335
|
+
if (this.runCompletedSuccessfully) {
|
|
1336
|
+
this.runCompletedSuccessfully = false;
|
|
1337
|
+
await this.refreshSessionMessages();
|
|
1338
|
+
}
|
|
1236
1339
|
}
|
|
1237
1340
|
});
|
|
1238
1341
|
} catch (error) {
|
|
@@ -1247,7 +1350,8 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1247
1350
|
*/
|
|
1248
1351
|
async checkStatus() {
|
|
1249
1352
|
try {
|
|
1250
|
-
const
|
|
1353
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1354
|
+
const response = await fetch(`${this.configManager.getEndpoint()}/health`, { headers });
|
|
1251
1355
|
const isActive = response.ok;
|
|
1252
1356
|
this.state.isEndpointActive = isActive;
|
|
1253
1357
|
this.emit("state:change", this.getState());
|
|
@@ -1262,12 +1366,8 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1262
1366
|
* Fetch agents from endpoint
|
|
1263
1367
|
*/
|
|
1264
1368
|
async fetchAgents() {
|
|
1265
|
-
const
|
|
1266
|
-
const
|
|
1267
|
-
if (config.authToken) {
|
|
1268
|
-
headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
1269
|
-
}
|
|
1270
|
-
const response = await fetch(`${config.endpoint}/agents`, { headers });
|
|
1369
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1370
|
+
const response = await fetch(`${this.configManager.getEndpoint()}/agents`, { headers });
|
|
1271
1371
|
if (!response.ok) {
|
|
1272
1372
|
throw new Error("Failed to fetch agents");
|
|
1273
1373
|
}
|
|
@@ -1280,12 +1380,8 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1280
1380
|
* Fetch teams from endpoint
|
|
1281
1381
|
*/
|
|
1282
1382
|
async fetchTeams() {
|
|
1283
|
-
const
|
|
1284
|
-
const
|
|
1285
|
-
if (config.authToken) {
|
|
1286
|
-
headers["Authorization"] = `Bearer ${config.authToken}`;
|
|
1287
|
-
}
|
|
1288
|
-
const response = await fetch(`${config.endpoint}/teams`, { headers });
|
|
1383
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1384
|
+
const response = await fetch(`${this.configManager.getEndpoint()}/teams`, { headers });
|
|
1289
1385
|
if (!response.ok) {
|
|
1290
1386
|
throw new Error("Failed to fetch teams");
|
|
1291
1387
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antipopp/agno-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Core client library for Agno agents with streaming support and HITL frontend tool execution",
|
|
5
5
|
"author": "antipopp",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"eventemitter3": "^5.0.1",
|
|
37
|
-
"@antipopp/agno-types": "0.
|
|
37
|
+
"@antipopp/agno-types": "0.8.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"tsup": "^8.0.1",
|