@antipopp/agno-client 0.2.0 → 0.4.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/README.md +3 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +168 -14
- package/dist/index.mjs +168 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ const client = new AgnoClient({
|
|
|
28
28
|
mode: 'agent',
|
|
29
29
|
agentId: 'your-agent-id',
|
|
30
30
|
authToken: 'optional-auth-token',
|
|
31
|
+
userId: 'user-123', // Optional: Link sessions to a user
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
// Listen to message updates
|
|
@@ -66,6 +67,7 @@ new AgnoClient(config: AgnoClientConfig)
|
|
|
66
67
|
- `teamId` (string, optional) - Team ID (required if mode is 'team')
|
|
67
68
|
- `dbId` (string, optional) - Database ID
|
|
68
69
|
- `sessionId` (string, optional) - Current session ID
|
|
70
|
+
- `userId` (string, optional) - User ID to link sessions to a specific user
|
|
69
71
|
|
|
70
72
|
### Methods
|
|
71
73
|
|
|
@@ -136,6 +138,7 @@ Update client configuration.
|
|
|
136
138
|
client.updateConfig({
|
|
137
139
|
agentId: 'new-agent-id',
|
|
138
140
|
authToken: 'new-token',
|
|
141
|
+
userId: 'user-456', // Update user ID
|
|
139
142
|
});
|
|
140
143
|
```
|
|
141
144
|
|
package/dist/index.d.mts
CHANGED
|
@@ -12,6 +12,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
12
12
|
private sessionManager;
|
|
13
13
|
private eventProcessor;
|
|
14
14
|
private state;
|
|
15
|
+
private pendingUISpecs;
|
|
15
16
|
constructor(config: AgnoClientConfig);
|
|
16
17
|
/**
|
|
17
18
|
* Get current messages
|
|
@@ -63,6 +64,22 @@ declare class AgnoClient extends EventEmitter {
|
|
|
63
64
|
* Delete a team session
|
|
64
65
|
*/
|
|
65
66
|
deleteTeamSession(teamId: string, sessionId: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Add tool calls to the last message
|
|
69
|
+
* Used by frontend execution to add tool calls that were executed locally
|
|
70
|
+
*/
|
|
71
|
+
addToolCallsToLastMessage(toolCalls: ToolCall[]): void;
|
|
72
|
+
/**
|
|
73
|
+
* Hydrate a specific tool call with its UI component
|
|
74
|
+
* If tool call doesn't exist yet, stores UI spec as pending
|
|
75
|
+
*/
|
|
76
|
+
hydrateToolCallUI(toolCallId: string, uiSpec: any): void;
|
|
77
|
+
/**
|
|
78
|
+
* Apply any pending UI specs to tool calls that have just been added
|
|
79
|
+
* Called after message updates to attach UI to newly arrived tool calls
|
|
80
|
+
* Batches all updates to emit only one message:update event
|
|
81
|
+
*/
|
|
82
|
+
private applyPendingUISpecs;
|
|
66
83
|
/**
|
|
67
84
|
* Continue a paused run after executing external tools
|
|
68
85
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
12
12
|
private sessionManager;
|
|
13
13
|
private eventProcessor;
|
|
14
14
|
private state;
|
|
15
|
+
private pendingUISpecs;
|
|
15
16
|
constructor(config: AgnoClientConfig);
|
|
16
17
|
/**
|
|
17
18
|
* Get current messages
|
|
@@ -63,6 +64,22 @@ declare class AgnoClient extends EventEmitter {
|
|
|
63
64
|
* Delete a team session
|
|
64
65
|
*/
|
|
65
66
|
deleteTeamSession(teamId: string, sessionId: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Add tool calls to the last message
|
|
69
|
+
* Used by frontend execution to add tool calls that were executed locally
|
|
70
|
+
*/
|
|
71
|
+
addToolCallsToLastMessage(toolCalls: ToolCall[]): void;
|
|
72
|
+
/**
|
|
73
|
+
* Hydrate a specific tool call with its UI component
|
|
74
|
+
* If tool call doesn't exist yet, stores UI spec as pending
|
|
75
|
+
*/
|
|
76
|
+
hydrateToolCallUI(toolCallId: string, uiSpec: any): void;
|
|
77
|
+
/**
|
|
78
|
+
* Apply any pending UI specs to tool calls that have just been added
|
|
79
|
+
* Called after message updates to attach UI to newly arrived tool calls
|
|
80
|
+
* Batches all updates to emit only one message:update event
|
|
81
|
+
*/
|
|
82
|
+
private applyPendingUISpecs;
|
|
66
83
|
/**
|
|
67
84
|
* Continue a paused run after executing external tools
|
|
68
85
|
*/
|
package/dist/index.js
CHANGED
|
@@ -77,6 +77,21 @@ var MessageStore = class {
|
|
|
77
77
|
];
|
|
78
78
|
return updatedMessage;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Update a specific message by index
|
|
82
|
+
*/
|
|
83
|
+
updateMessage(index, updater) {
|
|
84
|
+
if (index < 0 || index >= this.messages.length)
|
|
85
|
+
return void 0;
|
|
86
|
+
const message = this.messages[index];
|
|
87
|
+
const updatedMessage = updater(message);
|
|
88
|
+
this.messages = [
|
|
89
|
+
...this.messages.slice(0, index),
|
|
90
|
+
updatedMessage,
|
|
91
|
+
...this.messages.slice(index + 1)
|
|
92
|
+
];
|
|
93
|
+
return updatedMessage;
|
|
94
|
+
}
|
|
80
95
|
/**
|
|
81
96
|
* Remove last N messages
|
|
82
97
|
*/
|
|
@@ -211,6 +226,18 @@ var ConfigManager = class {
|
|
|
211
226
|
setSessionId(sessionId) {
|
|
212
227
|
this.updateField("sessionId", sessionId);
|
|
213
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Get user ID
|
|
231
|
+
*/
|
|
232
|
+
getUserId() {
|
|
233
|
+
return this.config.userId;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Set user ID
|
|
237
|
+
*/
|
|
238
|
+
setUserId(userId) {
|
|
239
|
+
this.updateField("userId", userId);
|
|
240
|
+
}
|
|
214
241
|
/**
|
|
215
242
|
* Get current entity ID (agent or team based on mode)
|
|
216
243
|
*/
|
|
@@ -321,9 +348,7 @@ var SessionManager = class {
|
|
|
321
348
|
* Convert session runs array to chat messages
|
|
322
349
|
*/
|
|
323
350
|
convertSessionToMessages(runs) {
|
|
324
|
-
console.log("[SessionManager] convertSessionToMessages received:", runs.length, "runs");
|
|
325
351
|
const messages = this.convertRunsToMessages(runs);
|
|
326
|
-
console.log("[SessionManager] Converted to messages:", messages.length, "messages");
|
|
327
352
|
return messages;
|
|
328
353
|
}
|
|
329
354
|
/**
|
|
@@ -345,7 +370,7 @@ var SessionManager = class {
|
|
|
345
370
|
if (run.tools && Array.isArray(run.tools)) {
|
|
346
371
|
for (const tool of run.tools) {
|
|
347
372
|
const toolObj = tool;
|
|
348
|
-
|
|
373
|
+
const toolCall = {
|
|
349
374
|
role: "tool",
|
|
350
375
|
content: toolObj.content ?? "",
|
|
351
376
|
tool_call_id: toolObj.tool_call_id ?? "",
|
|
@@ -354,7 +379,8 @@ var SessionManager = class {
|
|
|
354
379
|
tool_call_error: toolObj.tool_call_error ?? false,
|
|
355
380
|
metrics: toolObj.metrics ?? { time: 0 },
|
|
356
381
|
created_at: timestamp
|
|
357
|
-
}
|
|
382
|
+
};
|
|
383
|
+
toolCalls.push(toolCall);
|
|
358
384
|
}
|
|
359
385
|
}
|
|
360
386
|
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
@@ -501,6 +527,28 @@ var EventProcessor = class {
|
|
|
501
527
|
references: chunk.extra_data.references
|
|
502
528
|
};
|
|
503
529
|
}
|
|
530
|
+
if (chunk.extra_data?.generated_ui) {
|
|
531
|
+
const existingUI = updatedMessage.extra_data?.generated_ui ?? [];
|
|
532
|
+
const incomingUI = chunk.extra_data.generated_ui;
|
|
533
|
+
const mergedUI = [...existingUI];
|
|
534
|
+
for (const uiData of incomingUI) {
|
|
535
|
+
const existingIndex = mergedUI.findIndex(
|
|
536
|
+
(ui) => ui.tool_call_id === uiData.tool_call_id
|
|
537
|
+
);
|
|
538
|
+
if (existingIndex >= 0) {
|
|
539
|
+
mergedUI[existingIndex] = {
|
|
540
|
+
...mergedUI[existingIndex],
|
|
541
|
+
...uiData
|
|
542
|
+
};
|
|
543
|
+
} else {
|
|
544
|
+
mergedUI.push(uiData);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
updatedMessage.extra_data = {
|
|
548
|
+
...updatedMessage.extra_data,
|
|
549
|
+
generated_ui: mergedUI
|
|
550
|
+
};
|
|
551
|
+
}
|
|
504
552
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
505
553
|
if (chunk.images) {
|
|
506
554
|
updatedMessage.images = chunk.images;
|
|
@@ -560,7 +608,8 @@ var EventProcessor = class {
|
|
|
560
608
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
561
609
|
updatedMessage.extra_data = {
|
|
562
610
|
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
563
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
611
|
+
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references,
|
|
612
|
+
generated_ui: chunk.extra_data?.generated_ui ?? lastMessage.extra_data?.generated_ui
|
|
564
613
|
};
|
|
565
614
|
break;
|
|
566
615
|
case import_agno_types.RunEvent.UpdatingMemory:
|
|
@@ -818,12 +867,14 @@ function toSafeISOString(timestamp) {
|
|
|
818
867
|
return new Date(ts).toISOString();
|
|
819
868
|
}
|
|
820
869
|
var AgnoClient = class extends import_eventemitter3.default {
|
|
870
|
+
// toolCallId -> UIComponentSpec
|
|
821
871
|
constructor(config) {
|
|
822
872
|
super();
|
|
823
873
|
this.messageStore = new MessageStore();
|
|
824
874
|
this.configManager = new ConfigManager(config);
|
|
825
875
|
this.sessionManager = new SessionManager();
|
|
826
876
|
this.eventProcessor = new EventProcessor();
|
|
877
|
+
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
827
878
|
this.state = {
|
|
828
879
|
isStreaming: false,
|
|
829
880
|
isEndpointActive: false,
|
|
@@ -866,6 +917,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
866
917
|
clearMessages() {
|
|
867
918
|
this.messageStore.clear();
|
|
868
919
|
this.configManager.setSessionId(void 0);
|
|
920
|
+
this.pendingUISpecs.clear();
|
|
869
921
|
this.emit("message:update", this.messageStore.getMessages());
|
|
870
922
|
this.emit("state:change", this.getState());
|
|
871
923
|
}
|
|
@@ -913,6 +965,10 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
913
965
|
try {
|
|
914
966
|
formData.append("stream", "true");
|
|
915
967
|
formData.append("session_id", newSessionId ?? "");
|
|
968
|
+
const userId = this.configManager.getUserId();
|
|
969
|
+
if (userId) {
|
|
970
|
+
formData.append("user_id", userId);
|
|
971
|
+
}
|
|
916
972
|
const headers = { ...options?.headers };
|
|
917
973
|
const authToken = this.configManager.getAuthToken();
|
|
918
974
|
if (authToken) {
|
|
@@ -970,18 +1026,10 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
970
1026
|
}
|
|
971
1027
|
}
|
|
972
1028
|
if (event === import_agno_types2.RunEvent.RunPaused) {
|
|
973
|
-
console.log("[AgnoClient] RunPaused event detected");
|
|
974
|
-
console.log("[AgnoClient] Chunk:", chunk);
|
|
975
|
-
console.log("[AgnoClient] tools_awaiting_external_execution:", chunk.tools_awaiting_external_execution);
|
|
976
|
-
console.log("[AgnoClient] tools_requiring_confirmation:", chunk.tools_requiring_confirmation);
|
|
977
|
-
console.log("[AgnoClient] tools_requiring_user_input:", chunk.tools_requiring_user_input);
|
|
978
|
-
console.log("[AgnoClient] tools:", chunk.tools);
|
|
979
1029
|
this.state.isStreaming = false;
|
|
980
1030
|
this.state.isPaused = true;
|
|
981
1031
|
this.state.pausedRunId = chunk.run_id;
|
|
982
1032
|
this.state.toolsAwaitingExecution = chunk.tools_awaiting_external_execution || chunk.tools_requiring_confirmation || chunk.tools_requiring_user_input || chunk.tools || [];
|
|
983
|
-
console.log("[AgnoClient] toolsAwaitingExecution:", this.state.toolsAwaitingExecution);
|
|
984
|
-
console.log("[AgnoClient] Emitting run:paused event");
|
|
985
1033
|
this.emit("run:paused", {
|
|
986
1034
|
runId: chunk.run_id,
|
|
987
1035
|
sessionId: chunk.session_id,
|
|
@@ -1009,6 +1057,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1009
1057
|
const updated = this.eventProcessor.processChunk(chunk, lastMessage);
|
|
1010
1058
|
return updated || lastMessage;
|
|
1011
1059
|
});
|
|
1060
|
+
this.applyPendingUISpecs();
|
|
1012
1061
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1013
1062
|
}
|
|
1014
1063
|
/**
|
|
@@ -1118,6 +1167,103 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1118
1167
|
}
|
|
1119
1168
|
this.emit("state:change", this.getState());
|
|
1120
1169
|
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Add tool calls to the last message
|
|
1172
|
+
* Used by frontend execution to add tool calls that were executed locally
|
|
1173
|
+
*/
|
|
1174
|
+
addToolCallsToLastMessage(toolCalls) {
|
|
1175
|
+
const lastMessage = this.messageStore.getLastMessage();
|
|
1176
|
+
if (!lastMessage || lastMessage.role !== "agent") {
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
const existingToolCalls = lastMessage.tool_calls || [];
|
|
1180
|
+
const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
|
|
1181
|
+
const newToolCalls = toolCalls.filter((t) => !existingIds.has(t.tool_call_id));
|
|
1182
|
+
if (newToolCalls.length > 0) {
|
|
1183
|
+
this.messageStore.updateLastMessage((msg) => ({
|
|
1184
|
+
...msg,
|
|
1185
|
+
tool_calls: [...existingToolCalls, ...newToolCalls]
|
|
1186
|
+
}));
|
|
1187
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Hydrate a specific tool call with its UI component
|
|
1192
|
+
* If tool call doesn't exist yet, stores UI spec as pending
|
|
1193
|
+
*/
|
|
1194
|
+
hydrateToolCallUI(toolCallId, uiSpec) {
|
|
1195
|
+
const messages = this.messageStore.getMessages();
|
|
1196
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1197
|
+
const message = messages[i];
|
|
1198
|
+
if (message.tool_calls) {
|
|
1199
|
+
const toolIndex = message.tool_calls.findIndex(
|
|
1200
|
+
(t) => t.tool_call_id === toolCallId
|
|
1201
|
+
);
|
|
1202
|
+
if (toolIndex !== -1) {
|
|
1203
|
+
this.messageStore.updateMessage(i, (msg) => {
|
|
1204
|
+
const updatedToolCalls = [...msg.tool_calls || []];
|
|
1205
|
+
updatedToolCalls[toolIndex] = {
|
|
1206
|
+
...updatedToolCalls[toolIndex],
|
|
1207
|
+
ui_component: uiSpec
|
|
1208
|
+
};
|
|
1209
|
+
return {
|
|
1210
|
+
...msg,
|
|
1211
|
+
tool_calls: updatedToolCalls
|
|
1212
|
+
};
|
|
1213
|
+
});
|
|
1214
|
+
this.pendingUISpecs.delete(toolCallId);
|
|
1215
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
this.pendingUISpecs.set(toolCallId, uiSpec);
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Apply any pending UI specs to tool calls that have just been added
|
|
1224
|
+
* Called after message updates to attach UI to newly arrived tool calls
|
|
1225
|
+
* Batches all updates to emit only one message:update event
|
|
1226
|
+
*/
|
|
1227
|
+
applyPendingUISpecs() {
|
|
1228
|
+
if (this.pendingUISpecs.size === 0)
|
|
1229
|
+
return;
|
|
1230
|
+
const messages = this.messageStore.getMessages();
|
|
1231
|
+
const updatedMessages = [];
|
|
1232
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1233
|
+
const message = messages[i];
|
|
1234
|
+
if (message.tool_calls) {
|
|
1235
|
+
let messageUpdated = false;
|
|
1236
|
+
const updatedToolCalls = [...message.tool_calls];
|
|
1237
|
+
for (let j = 0; j < updatedToolCalls.length; j++) {
|
|
1238
|
+
const toolCall = updatedToolCalls[j];
|
|
1239
|
+
const pendingUI = this.pendingUISpecs.get(toolCall.tool_call_id);
|
|
1240
|
+
if (pendingUI && !toolCall.ui_component) {
|
|
1241
|
+
updatedToolCalls[j] = {
|
|
1242
|
+
...updatedToolCalls[j],
|
|
1243
|
+
ui_component: pendingUI
|
|
1244
|
+
};
|
|
1245
|
+
this.pendingUISpecs.delete(toolCall.tool_call_id);
|
|
1246
|
+
messageUpdated = true;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
if (messageUpdated) {
|
|
1250
|
+
updatedMessages.push({
|
|
1251
|
+
index: i,
|
|
1252
|
+
message: {
|
|
1253
|
+
...message,
|
|
1254
|
+
tool_calls: updatedToolCalls
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
if (updatedMessages.length > 0) {
|
|
1261
|
+
updatedMessages.forEach(({ index, message }) => {
|
|
1262
|
+
this.messageStore.updateMessage(index, () => message);
|
|
1263
|
+
});
|
|
1264
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1121
1267
|
/**
|
|
1122
1268
|
* Continue a paused run after executing external tools
|
|
1123
1269
|
*/
|
|
@@ -1134,13 +1280,21 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1134
1280
|
this.state.isStreaming = true;
|
|
1135
1281
|
this.emit("run:continued", { runId: this.state.pausedRunId });
|
|
1136
1282
|
this.emit("state:change", this.getState());
|
|
1283
|
+
const cleanedTools = tools.map((tool) => {
|
|
1284
|
+
const { ui_component, ...backendTool } = tool;
|
|
1285
|
+
return backendTool;
|
|
1286
|
+
});
|
|
1137
1287
|
const formData = new FormData();
|
|
1138
|
-
formData.append("tools", JSON.stringify(
|
|
1288
|
+
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1139
1289
|
formData.append("stream", "true");
|
|
1140
1290
|
const currentSessionId = this.configManager.getSessionId();
|
|
1141
1291
|
if (currentSessionId) {
|
|
1142
1292
|
formData.append("session_id", currentSessionId);
|
|
1143
1293
|
}
|
|
1294
|
+
const userId = this.configManager.getUserId();
|
|
1295
|
+
if (userId) {
|
|
1296
|
+
formData.append("user_id", userId);
|
|
1297
|
+
}
|
|
1144
1298
|
const headers = { ...options?.headers };
|
|
1145
1299
|
const authToken = this.configManager.getAuthToken();
|
|
1146
1300
|
if (authToken) {
|
package/dist/index.mjs
CHANGED
|
@@ -39,6 +39,21 @@ var MessageStore = class {
|
|
|
39
39
|
];
|
|
40
40
|
return updatedMessage;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Update a specific message by index
|
|
44
|
+
*/
|
|
45
|
+
updateMessage(index, updater) {
|
|
46
|
+
if (index < 0 || index >= this.messages.length)
|
|
47
|
+
return void 0;
|
|
48
|
+
const message = this.messages[index];
|
|
49
|
+
const updatedMessage = updater(message);
|
|
50
|
+
this.messages = [
|
|
51
|
+
...this.messages.slice(0, index),
|
|
52
|
+
updatedMessage,
|
|
53
|
+
...this.messages.slice(index + 1)
|
|
54
|
+
];
|
|
55
|
+
return updatedMessage;
|
|
56
|
+
}
|
|
42
57
|
/**
|
|
43
58
|
* Remove last N messages
|
|
44
59
|
*/
|
|
@@ -173,6 +188,18 @@ var ConfigManager = class {
|
|
|
173
188
|
setSessionId(sessionId) {
|
|
174
189
|
this.updateField("sessionId", sessionId);
|
|
175
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Get user ID
|
|
193
|
+
*/
|
|
194
|
+
getUserId() {
|
|
195
|
+
return this.config.userId;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Set user ID
|
|
199
|
+
*/
|
|
200
|
+
setUserId(userId) {
|
|
201
|
+
this.updateField("userId", userId);
|
|
202
|
+
}
|
|
176
203
|
/**
|
|
177
204
|
* Get current entity ID (agent or team based on mode)
|
|
178
205
|
*/
|
|
@@ -283,9 +310,7 @@ var SessionManager = class {
|
|
|
283
310
|
* Convert session runs array to chat messages
|
|
284
311
|
*/
|
|
285
312
|
convertSessionToMessages(runs) {
|
|
286
|
-
console.log("[SessionManager] convertSessionToMessages received:", runs.length, "runs");
|
|
287
313
|
const messages = this.convertRunsToMessages(runs);
|
|
288
|
-
console.log("[SessionManager] Converted to messages:", messages.length, "messages");
|
|
289
314
|
return messages;
|
|
290
315
|
}
|
|
291
316
|
/**
|
|
@@ -307,7 +332,7 @@ var SessionManager = class {
|
|
|
307
332
|
if (run.tools && Array.isArray(run.tools)) {
|
|
308
333
|
for (const tool of run.tools) {
|
|
309
334
|
const toolObj = tool;
|
|
310
|
-
|
|
335
|
+
const toolCall = {
|
|
311
336
|
role: "tool",
|
|
312
337
|
content: toolObj.content ?? "",
|
|
313
338
|
tool_call_id: toolObj.tool_call_id ?? "",
|
|
@@ -316,7 +341,8 @@ var SessionManager = class {
|
|
|
316
341
|
tool_call_error: toolObj.tool_call_error ?? false,
|
|
317
342
|
metrics: toolObj.metrics ?? { time: 0 },
|
|
318
343
|
created_at: timestamp
|
|
319
|
-
}
|
|
344
|
+
};
|
|
345
|
+
toolCalls.push(toolCall);
|
|
320
346
|
}
|
|
321
347
|
}
|
|
322
348
|
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
@@ -463,6 +489,28 @@ var EventProcessor = class {
|
|
|
463
489
|
references: chunk.extra_data.references
|
|
464
490
|
};
|
|
465
491
|
}
|
|
492
|
+
if (chunk.extra_data?.generated_ui) {
|
|
493
|
+
const existingUI = updatedMessage.extra_data?.generated_ui ?? [];
|
|
494
|
+
const incomingUI = chunk.extra_data.generated_ui;
|
|
495
|
+
const mergedUI = [...existingUI];
|
|
496
|
+
for (const uiData of incomingUI) {
|
|
497
|
+
const existingIndex = mergedUI.findIndex(
|
|
498
|
+
(ui) => ui.tool_call_id === uiData.tool_call_id
|
|
499
|
+
);
|
|
500
|
+
if (existingIndex >= 0) {
|
|
501
|
+
mergedUI[existingIndex] = {
|
|
502
|
+
...mergedUI[existingIndex],
|
|
503
|
+
...uiData
|
|
504
|
+
};
|
|
505
|
+
} else {
|
|
506
|
+
mergedUI.push(uiData);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
updatedMessage.extra_data = {
|
|
510
|
+
...updatedMessage.extra_data,
|
|
511
|
+
generated_ui: mergedUI
|
|
512
|
+
};
|
|
513
|
+
}
|
|
466
514
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
467
515
|
if (chunk.images) {
|
|
468
516
|
updatedMessage.images = chunk.images;
|
|
@@ -522,7 +570,8 @@ var EventProcessor = class {
|
|
|
522
570
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
523
571
|
updatedMessage.extra_data = {
|
|
524
572
|
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
525
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
573
|
+
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references,
|
|
574
|
+
generated_ui: chunk.extra_data?.generated_ui ?? lastMessage.extra_data?.generated_ui
|
|
526
575
|
};
|
|
527
576
|
break;
|
|
528
577
|
case RunEventEnum.UpdatingMemory:
|
|
@@ -780,12 +829,14 @@ function toSafeISOString(timestamp) {
|
|
|
780
829
|
return new Date(ts).toISOString();
|
|
781
830
|
}
|
|
782
831
|
var AgnoClient = class extends EventEmitter {
|
|
832
|
+
// toolCallId -> UIComponentSpec
|
|
783
833
|
constructor(config) {
|
|
784
834
|
super();
|
|
785
835
|
this.messageStore = new MessageStore();
|
|
786
836
|
this.configManager = new ConfigManager(config);
|
|
787
837
|
this.sessionManager = new SessionManager();
|
|
788
838
|
this.eventProcessor = new EventProcessor();
|
|
839
|
+
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
789
840
|
this.state = {
|
|
790
841
|
isStreaming: false,
|
|
791
842
|
isEndpointActive: false,
|
|
@@ -828,6 +879,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
828
879
|
clearMessages() {
|
|
829
880
|
this.messageStore.clear();
|
|
830
881
|
this.configManager.setSessionId(void 0);
|
|
882
|
+
this.pendingUISpecs.clear();
|
|
831
883
|
this.emit("message:update", this.messageStore.getMessages());
|
|
832
884
|
this.emit("state:change", this.getState());
|
|
833
885
|
}
|
|
@@ -875,6 +927,10 @@ var AgnoClient = class extends EventEmitter {
|
|
|
875
927
|
try {
|
|
876
928
|
formData.append("stream", "true");
|
|
877
929
|
formData.append("session_id", newSessionId ?? "");
|
|
930
|
+
const userId = this.configManager.getUserId();
|
|
931
|
+
if (userId) {
|
|
932
|
+
formData.append("user_id", userId);
|
|
933
|
+
}
|
|
878
934
|
const headers = { ...options?.headers };
|
|
879
935
|
const authToken = this.configManager.getAuthToken();
|
|
880
936
|
if (authToken) {
|
|
@@ -932,18 +988,10 @@ var AgnoClient = class extends EventEmitter {
|
|
|
932
988
|
}
|
|
933
989
|
}
|
|
934
990
|
if (event === RunEvent.RunPaused) {
|
|
935
|
-
console.log("[AgnoClient] RunPaused event detected");
|
|
936
|
-
console.log("[AgnoClient] Chunk:", chunk);
|
|
937
|
-
console.log("[AgnoClient] tools_awaiting_external_execution:", chunk.tools_awaiting_external_execution);
|
|
938
|
-
console.log("[AgnoClient] tools_requiring_confirmation:", chunk.tools_requiring_confirmation);
|
|
939
|
-
console.log("[AgnoClient] tools_requiring_user_input:", chunk.tools_requiring_user_input);
|
|
940
|
-
console.log("[AgnoClient] tools:", chunk.tools);
|
|
941
991
|
this.state.isStreaming = false;
|
|
942
992
|
this.state.isPaused = true;
|
|
943
993
|
this.state.pausedRunId = chunk.run_id;
|
|
944
994
|
this.state.toolsAwaitingExecution = chunk.tools_awaiting_external_execution || chunk.tools_requiring_confirmation || chunk.tools_requiring_user_input || chunk.tools || [];
|
|
945
|
-
console.log("[AgnoClient] toolsAwaitingExecution:", this.state.toolsAwaitingExecution);
|
|
946
|
-
console.log("[AgnoClient] Emitting run:paused event");
|
|
947
995
|
this.emit("run:paused", {
|
|
948
996
|
runId: chunk.run_id,
|
|
949
997
|
sessionId: chunk.session_id,
|
|
@@ -971,6 +1019,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
971
1019
|
const updated = this.eventProcessor.processChunk(chunk, lastMessage);
|
|
972
1020
|
return updated || lastMessage;
|
|
973
1021
|
});
|
|
1022
|
+
this.applyPendingUISpecs();
|
|
974
1023
|
this.emit("message:update", this.messageStore.getMessages());
|
|
975
1024
|
}
|
|
976
1025
|
/**
|
|
@@ -1080,6 +1129,103 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1080
1129
|
}
|
|
1081
1130
|
this.emit("state:change", this.getState());
|
|
1082
1131
|
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Add tool calls to the last message
|
|
1134
|
+
* Used by frontend execution to add tool calls that were executed locally
|
|
1135
|
+
*/
|
|
1136
|
+
addToolCallsToLastMessage(toolCalls) {
|
|
1137
|
+
const lastMessage = this.messageStore.getLastMessage();
|
|
1138
|
+
if (!lastMessage || lastMessage.role !== "agent") {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
const existingToolCalls = lastMessage.tool_calls || [];
|
|
1142
|
+
const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
|
|
1143
|
+
const newToolCalls = toolCalls.filter((t) => !existingIds.has(t.tool_call_id));
|
|
1144
|
+
if (newToolCalls.length > 0) {
|
|
1145
|
+
this.messageStore.updateLastMessage((msg) => ({
|
|
1146
|
+
...msg,
|
|
1147
|
+
tool_calls: [...existingToolCalls, ...newToolCalls]
|
|
1148
|
+
}));
|
|
1149
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Hydrate a specific tool call with its UI component
|
|
1154
|
+
* If tool call doesn't exist yet, stores UI spec as pending
|
|
1155
|
+
*/
|
|
1156
|
+
hydrateToolCallUI(toolCallId, uiSpec) {
|
|
1157
|
+
const messages = this.messageStore.getMessages();
|
|
1158
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1159
|
+
const message = messages[i];
|
|
1160
|
+
if (message.tool_calls) {
|
|
1161
|
+
const toolIndex = message.tool_calls.findIndex(
|
|
1162
|
+
(t) => t.tool_call_id === toolCallId
|
|
1163
|
+
);
|
|
1164
|
+
if (toolIndex !== -1) {
|
|
1165
|
+
this.messageStore.updateMessage(i, (msg) => {
|
|
1166
|
+
const updatedToolCalls = [...msg.tool_calls || []];
|
|
1167
|
+
updatedToolCalls[toolIndex] = {
|
|
1168
|
+
...updatedToolCalls[toolIndex],
|
|
1169
|
+
ui_component: uiSpec
|
|
1170
|
+
};
|
|
1171
|
+
return {
|
|
1172
|
+
...msg,
|
|
1173
|
+
tool_calls: updatedToolCalls
|
|
1174
|
+
};
|
|
1175
|
+
});
|
|
1176
|
+
this.pendingUISpecs.delete(toolCallId);
|
|
1177
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
this.pendingUISpecs.set(toolCallId, uiSpec);
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Apply any pending UI specs to tool calls that have just been added
|
|
1186
|
+
* Called after message updates to attach UI to newly arrived tool calls
|
|
1187
|
+
* Batches all updates to emit only one message:update event
|
|
1188
|
+
*/
|
|
1189
|
+
applyPendingUISpecs() {
|
|
1190
|
+
if (this.pendingUISpecs.size === 0)
|
|
1191
|
+
return;
|
|
1192
|
+
const messages = this.messageStore.getMessages();
|
|
1193
|
+
const updatedMessages = [];
|
|
1194
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1195
|
+
const message = messages[i];
|
|
1196
|
+
if (message.tool_calls) {
|
|
1197
|
+
let messageUpdated = false;
|
|
1198
|
+
const updatedToolCalls = [...message.tool_calls];
|
|
1199
|
+
for (let j = 0; j < updatedToolCalls.length; j++) {
|
|
1200
|
+
const toolCall = updatedToolCalls[j];
|
|
1201
|
+
const pendingUI = this.pendingUISpecs.get(toolCall.tool_call_id);
|
|
1202
|
+
if (pendingUI && !toolCall.ui_component) {
|
|
1203
|
+
updatedToolCalls[j] = {
|
|
1204
|
+
...updatedToolCalls[j],
|
|
1205
|
+
ui_component: pendingUI
|
|
1206
|
+
};
|
|
1207
|
+
this.pendingUISpecs.delete(toolCall.tool_call_id);
|
|
1208
|
+
messageUpdated = true;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (messageUpdated) {
|
|
1212
|
+
updatedMessages.push({
|
|
1213
|
+
index: i,
|
|
1214
|
+
message: {
|
|
1215
|
+
...message,
|
|
1216
|
+
tool_calls: updatedToolCalls
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
if (updatedMessages.length > 0) {
|
|
1223
|
+
updatedMessages.forEach(({ index, message }) => {
|
|
1224
|
+
this.messageStore.updateMessage(index, () => message);
|
|
1225
|
+
});
|
|
1226
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1083
1229
|
/**
|
|
1084
1230
|
* Continue a paused run after executing external tools
|
|
1085
1231
|
*/
|
|
@@ -1096,13 +1242,21 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1096
1242
|
this.state.isStreaming = true;
|
|
1097
1243
|
this.emit("run:continued", { runId: this.state.pausedRunId });
|
|
1098
1244
|
this.emit("state:change", this.getState());
|
|
1245
|
+
const cleanedTools = tools.map((tool) => {
|
|
1246
|
+
const { ui_component, ...backendTool } = tool;
|
|
1247
|
+
return backendTool;
|
|
1248
|
+
});
|
|
1099
1249
|
const formData = new FormData();
|
|
1100
|
-
formData.append("tools", JSON.stringify(
|
|
1250
|
+
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1101
1251
|
formData.append("stream", "true");
|
|
1102
1252
|
const currentSessionId = this.configManager.getSessionId();
|
|
1103
1253
|
if (currentSessionId) {
|
|
1104
1254
|
formData.append("session_id", currentSessionId);
|
|
1105
1255
|
}
|
|
1256
|
+
const userId = this.configManager.getUserId();
|
|
1257
|
+
if (userId) {
|
|
1258
|
+
formData.append("user_id", userId);
|
|
1259
|
+
}
|
|
1106
1260
|
const headers = { ...options?.headers };
|
|
1107
1261
|
const authToken = this.configManager.getAuthToken();
|
|
1108
1262
|
if (authToken) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antipopp/agno-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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.4.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"tsup": "^8.0.1",
|