@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 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, authToken) {
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, authToken) {
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
- const headers = {};
300
- if (authToken) {
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, authToken) {
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 = { ...options?.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
- Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId });
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
- config.authToken
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
- config.authToken
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
- config.authToken
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 = { ...options?.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 response = await fetch(`${this.configManager.getEndpoint()}/health`);
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 config = this.configManager.getConfig();
1304
- const headers = {};
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 config = this.configManager.getConfig();
1322
- const headers = {};
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, authToken) {
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, authToken) {
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
- const headers = {};
262
- if (authToken) {
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, authToken) {
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 = { ...options?.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
- Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId });
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
- config.authToken
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
- config.authToken
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
- config.authToken
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 = { ...options?.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 response = await fetch(`${this.configManager.getEndpoint()}/health`);
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 config = this.configManager.getConfig();
1266
- const headers = {};
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 config = this.configManager.getConfig();
1284
- const headers = {};
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.6.1",
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.6.1"
37
+ "@antipopp/agno-types": "0.8.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "tsup": "^8.0.1",