@antipopp/agno-client 0.2.0 → 0.3.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 +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +148 -14
- package/dist/index.mjs +148 -14
- package/package.json +2 -2
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
|
*/
|
|
@@ -321,9 +336,7 @@ var SessionManager = class {
|
|
|
321
336
|
* Convert session runs array to chat messages
|
|
322
337
|
*/
|
|
323
338
|
convertSessionToMessages(runs) {
|
|
324
|
-
console.log("[SessionManager] convertSessionToMessages received:", runs.length, "runs");
|
|
325
339
|
const messages = this.convertRunsToMessages(runs);
|
|
326
|
-
console.log("[SessionManager] Converted to messages:", messages.length, "messages");
|
|
327
340
|
return messages;
|
|
328
341
|
}
|
|
329
342
|
/**
|
|
@@ -345,7 +358,7 @@ var SessionManager = class {
|
|
|
345
358
|
if (run.tools && Array.isArray(run.tools)) {
|
|
346
359
|
for (const tool of run.tools) {
|
|
347
360
|
const toolObj = tool;
|
|
348
|
-
|
|
361
|
+
const toolCall = {
|
|
349
362
|
role: "tool",
|
|
350
363
|
content: toolObj.content ?? "",
|
|
351
364
|
tool_call_id: toolObj.tool_call_id ?? "",
|
|
@@ -354,7 +367,8 @@ var SessionManager = class {
|
|
|
354
367
|
tool_call_error: toolObj.tool_call_error ?? false,
|
|
355
368
|
metrics: toolObj.metrics ?? { time: 0 },
|
|
356
369
|
created_at: timestamp
|
|
357
|
-
}
|
|
370
|
+
};
|
|
371
|
+
toolCalls.push(toolCall);
|
|
358
372
|
}
|
|
359
373
|
}
|
|
360
374
|
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
@@ -501,6 +515,28 @@ var EventProcessor = class {
|
|
|
501
515
|
references: chunk.extra_data.references
|
|
502
516
|
};
|
|
503
517
|
}
|
|
518
|
+
if (chunk.extra_data?.generated_ui) {
|
|
519
|
+
const existingUI = updatedMessage.extra_data?.generated_ui ?? [];
|
|
520
|
+
const incomingUI = chunk.extra_data.generated_ui;
|
|
521
|
+
const mergedUI = [...existingUI];
|
|
522
|
+
for (const uiData of incomingUI) {
|
|
523
|
+
const existingIndex = mergedUI.findIndex(
|
|
524
|
+
(ui) => ui.tool_call_id === uiData.tool_call_id
|
|
525
|
+
);
|
|
526
|
+
if (existingIndex >= 0) {
|
|
527
|
+
mergedUI[existingIndex] = {
|
|
528
|
+
...mergedUI[existingIndex],
|
|
529
|
+
...uiData
|
|
530
|
+
};
|
|
531
|
+
} else {
|
|
532
|
+
mergedUI.push(uiData);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
updatedMessage.extra_data = {
|
|
536
|
+
...updatedMessage.extra_data,
|
|
537
|
+
generated_ui: mergedUI
|
|
538
|
+
};
|
|
539
|
+
}
|
|
504
540
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
505
541
|
if (chunk.images) {
|
|
506
542
|
updatedMessage.images = chunk.images;
|
|
@@ -560,7 +596,8 @@ var EventProcessor = class {
|
|
|
560
596
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
561
597
|
updatedMessage.extra_data = {
|
|
562
598
|
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
563
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
599
|
+
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references,
|
|
600
|
+
generated_ui: chunk.extra_data?.generated_ui ?? lastMessage.extra_data?.generated_ui
|
|
564
601
|
};
|
|
565
602
|
break;
|
|
566
603
|
case import_agno_types.RunEvent.UpdatingMemory:
|
|
@@ -818,12 +855,14 @@ function toSafeISOString(timestamp) {
|
|
|
818
855
|
return new Date(ts).toISOString();
|
|
819
856
|
}
|
|
820
857
|
var AgnoClient = class extends import_eventemitter3.default {
|
|
858
|
+
// toolCallId -> UIComponentSpec
|
|
821
859
|
constructor(config) {
|
|
822
860
|
super();
|
|
823
861
|
this.messageStore = new MessageStore();
|
|
824
862
|
this.configManager = new ConfigManager(config);
|
|
825
863
|
this.sessionManager = new SessionManager();
|
|
826
864
|
this.eventProcessor = new EventProcessor();
|
|
865
|
+
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
827
866
|
this.state = {
|
|
828
867
|
isStreaming: false,
|
|
829
868
|
isEndpointActive: false,
|
|
@@ -866,6 +905,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
866
905
|
clearMessages() {
|
|
867
906
|
this.messageStore.clear();
|
|
868
907
|
this.configManager.setSessionId(void 0);
|
|
908
|
+
this.pendingUISpecs.clear();
|
|
869
909
|
this.emit("message:update", this.messageStore.getMessages());
|
|
870
910
|
this.emit("state:change", this.getState());
|
|
871
911
|
}
|
|
@@ -970,18 +1010,10 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
970
1010
|
}
|
|
971
1011
|
}
|
|
972
1012
|
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
1013
|
this.state.isStreaming = false;
|
|
980
1014
|
this.state.isPaused = true;
|
|
981
1015
|
this.state.pausedRunId = chunk.run_id;
|
|
982
1016
|
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
1017
|
this.emit("run:paused", {
|
|
986
1018
|
runId: chunk.run_id,
|
|
987
1019
|
sessionId: chunk.session_id,
|
|
@@ -1009,6 +1041,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1009
1041
|
const updated = this.eventProcessor.processChunk(chunk, lastMessage);
|
|
1010
1042
|
return updated || lastMessage;
|
|
1011
1043
|
});
|
|
1044
|
+
this.applyPendingUISpecs();
|
|
1012
1045
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1013
1046
|
}
|
|
1014
1047
|
/**
|
|
@@ -1118,6 +1151,103 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1118
1151
|
}
|
|
1119
1152
|
this.emit("state:change", this.getState());
|
|
1120
1153
|
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Add tool calls to the last message
|
|
1156
|
+
* Used by frontend execution to add tool calls that were executed locally
|
|
1157
|
+
*/
|
|
1158
|
+
addToolCallsToLastMessage(toolCalls) {
|
|
1159
|
+
const lastMessage = this.messageStore.getLastMessage();
|
|
1160
|
+
if (!lastMessage || lastMessage.role !== "agent") {
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
const existingToolCalls = lastMessage.tool_calls || [];
|
|
1164
|
+
const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
|
|
1165
|
+
const newToolCalls = toolCalls.filter((t) => !existingIds.has(t.tool_call_id));
|
|
1166
|
+
if (newToolCalls.length > 0) {
|
|
1167
|
+
this.messageStore.updateLastMessage((msg) => ({
|
|
1168
|
+
...msg,
|
|
1169
|
+
tool_calls: [...existingToolCalls, ...newToolCalls]
|
|
1170
|
+
}));
|
|
1171
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Hydrate a specific tool call with its UI component
|
|
1176
|
+
* If tool call doesn't exist yet, stores UI spec as pending
|
|
1177
|
+
*/
|
|
1178
|
+
hydrateToolCallUI(toolCallId, uiSpec) {
|
|
1179
|
+
const messages = this.messageStore.getMessages();
|
|
1180
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1181
|
+
const message = messages[i];
|
|
1182
|
+
if (message.tool_calls) {
|
|
1183
|
+
const toolIndex = message.tool_calls.findIndex(
|
|
1184
|
+
(t) => t.tool_call_id === toolCallId
|
|
1185
|
+
);
|
|
1186
|
+
if (toolIndex !== -1) {
|
|
1187
|
+
this.messageStore.updateMessage(i, (msg) => {
|
|
1188
|
+
const updatedToolCalls = [...msg.tool_calls || []];
|
|
1189
|
+
updatedToolCalls[toolIndex] = {
|
|
1190
|
+
...updatedToolCalls[toolIndex],
|
|
1191
|
+
ui_component: uiSpec
|
|
1192
|
+
};
|
|
1193
|
+
return {
|
|
1194
|
+
...msg,
|
|
1195
|
+
tool_calls: updatedToolCalls
|
|
1196
|
+
};
|
|
1197
|
+
});
|
|
1198
|
+
this.pendingUISpecs.delete(toolCallId);
|
|
1199
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
this.pendingUISpecs.set(toolCallId, uiSpec);
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Apply any pending UI specs to tool calls that have just been added
|
|
1208
|
+
* Called after message updates to attach UI to newly arrived tool calls
|
|
1209
|
+
* Batches all updates to emit only one message:update event
|
|
1210
|
+
*/
|
|
1211
|
+
applyPendingUISpecs() {
|
|
1212
|
+
if (this.pendingUISpecs.size === 0)
|
|
1213
|
+
return;
|
|
1214
|
+
const messages = this.messageStore.getMessages();
|
|
1215
|
+
const updatedMessages = [];
|
|
1216
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1217
|
+
const message = messages[i];
|
|
1218
|
+
if (message.tool_calls) {
|
|
1219
|
+
let messageUpdated = false;
|
|
1220
|
+
const updatedToolCalls = [...message.tool_calls];
|
|
1221
|
+
for (let j = 0; j < updatedToolCalls.length; j++) {
|
|
1222
|
+
const toolCall = updatedToolCalls[j];
|
|
1223
|
+
const pendingUI = this.pendingUISpecs.get(toolCall.tool_call_id);
|
|
1224
|
+
if (pendingUI && !toolCall.ui_component) {
|
|
1225
|
+
updatedToolCalls[j] = {
|
|
1226
|
+
...updatedToolCalls[j],
|
|
1227
|
+
ui_component: pendingUI
|
|
1228
|
+
};
|
|
1229
|
+
this.pendingUISpecs.delete(toolCall.tool_call_id);
|
|
1230
|
+
messageUpdated = true;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (messageUpdated) {
|
|
1234
|
+
updatedMessages.push({
|
|
1235
|
+
index: i,
|
|
1236
|
+
message: {
|
|
1237
|
+
...message,
|
|
1238
|
+
tool_calls: updatedToolCalls
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
if (updatedMessages.length > 0) {
|
|
1245
|
+
updatedMessages.forEach(({ index, message }) => {
|
|
1246
|
+
this.messageStore.updateMessage(index, () => message);
|
|
1247
|
+
});
|
|
1248
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1121
1251
|
/**
|
|
1122
1252
|
* Continue a paused run after executing external tools
|
|
1123
1253
|
*/
|
|
@@ -1134,8 +1264,12 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1134
1264
|
this.state.isStreaming = true;
|
|
1135
1265
|
this.emit("run:continued", { runId: this.state.pausedRunId });
|
|
1136
1266
|
this.emit("state:change", this.getState());
|
|
1267
|
+
const cleanedTools = tools.map((tool) => {
|
|
1268
|
+
const { ui_component, ...backendTool } = tool;
|
|
1269
|
+
return backendTool;
|
|
1270
|
+
});
|
|
1137
1271
|
const formData = new FormData();
|
|
1138
|
-
formData.append("tools", JSON.stringify(
|
|
1272
|
+
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1139
1273
|
formData.append("stream", "true");
|
|
1140
1274
|
const currentSessionId = this.configManager.getSessionId();
|
|
1141
1275
|
if (currentSessionId) {
|
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
|
*/
|
|
@@ -283,9 +298,7 @@ var SessionManager = class {
|
|
|
283
298
|
* Convert session runs array to chat messages
|
|
284
299
|
*/
|
|
285
300
|
convertSessionToMessages(runs) {
|
|
286
|
-
console.log("[SessionManager] convertSessionToMessages received:", runs.length, "runs");
|
|
287
301
|
const messages = this.convertRunsToMessages(runs);
|
|
288
|
-
console.log("[SessionManager] Converted to messages:", messages.length, "messages");
|
|
289
302
|
return messages;
|
|
290
303
|
}
|
|
291
304
|
/**
|
|
@@ -307,7 +320,7 @@ var SessionManager = class {
|
|
|
307
320
|
if (run.tools && Array.isArray(run.tools)) {
|
|
308
321
|
for (const tool of run.tools) {
|
|
309
322
|
const toolObj = tool;
|
|
310
|
-
|
|
323
|
+
const toolCall = {
|
|
311
324
|
role: "tool",
|
|
312
325
|
content: toolObj.content ?? "",
|
|
313
326
|
tool_call_id: toolObj.tool_call_id ?? "",
|
|
@@ -316,7 +329,8 @@ var SessionManager = class {
|
|
|
316
329
|
tool_call_error: toolObj.tool_call_error ?? false,
|
|
317
330
|
metrics: toolObj.metrics ?? { time: 0 },
|
|
318
331
|
created_at: timestamp
|
|
319
|
-
}
|
|
332
|
+
};
|
|
333
|
+
toolCalls.push(toolCall);
|
|
320
334
|
}
|
|
321
335
|
}
|
|
322
336
|
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
@@ -463,6 +477,28 @@ var EventProcessor = class {
|
|
|
463
477
|
references: chunk.extra_data.references
|
|
464
478
|
};
|
|
465
479
|
}
|
|
480
|
+
if (chunk.extra_data?.generated_ui) {
|
|
481
|
+
const existingUI = updatedMessage.extra_data?.generated_ui ?? [];
|
|
482
|
+
const incomingUI = chunk.extra_data.generated_ui;
|
|
483
|
+
const mergedUI = [...existingUI];
|
|
484
|
+
for (const uiData of incomingUI) {
|
|
485
|
+
const existingIndex = mergedUI.findIndex(
|
|
486
|
+
(ui) => ui.tool_call_id === uiData.tool_call_id
|
|
487
|
+
);
|
|
488
|
+
if (existingIndex >= 0) {
|
|
489
|
+
mergedUI[existingIndex] = {
|
|
490
|
+
...mergedUI[existingIndex],
|
|
491
|
+
...uiData
|
|
492
|
+
};
|
|
493
|
+
} else {
|
|
494
|
+
mergedUI.push(uiData);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
updatedMessage.extra_data = {
|
|
498
|
+
...updatedMessage.extra_data,
|
|
499
|
+
generated_ui: mergedUI
|
|
500
|
+
};
|
|
501
|
+
}
|
|
466
502
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
467
503
|
if (chunk.images) {
|
|
468
504
|
updatedMessage.images = chunk.images;
|
|
@@ -522,7 +558,8 @@ var EventProcessor = class {
|
|
|
522
558
|
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
523
559
|
updatedMessage.extra_data = {
|
|
524
560
|
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
525
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
561
|
+
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references,
|
|
562
|
+
generated_ui: chunk.extra_data?.generated_ui ?? lastMessage.extra_data?.generated_ui
|
|
526
563
|
};
|
|
527
564
|
break;
|
|
528
565
|
case RunEventEnum.UpdatingMemory:
|
|
@@ -780,12 +817,14 @@ function toSafeISOString(timestamp) {
|
|
|
780
817
|
return new Date(ts).toISOString();
|
|
781
818
|
}
|
|
782
819
|
var AgnoClient = class extends EventEmitter {
|
|
820
|
+
// toolCallId -> UIComponentSpec
|
|
783
821
|
constructor(config) {
|
|
784
822
|
super();
|
|
785
823
|
this.messageStore = new MessageStore();
|
|
786
824
|
this.configManager = new ConfigManager(config);
|
|
787
825
|
this.sessionManager = new SessionManager();
|
|
788
826
|
this.eventProcessor = new EventProcessor();
|
|
827
|
+
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
789
828
|
this.state = {
|
|
790
829
|
isStreaming: false,
|
|
791
830
|
isEndpointActive: false,
|
|
@@ -828,6 +867,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
828
867
|
clearMessages() {
|
|
829
868
|
this.messageStore.clear();
|
|
830
869
|
this.configManager.setSessionId(void 0);
|
|
870
|
+
this.pendingUISpecs.clear();
|
|
831
871
|
this.emit("message:update", this.messageStore.getMessages());
|
|
832
872
|
this.emit("state:change", this.getState());
|
|
833
873
|
}
|
|
@@ -932,18 +972,10 @@ var AgnoClient = class extends EventEmitter {
|
|
|
932
972
|
}
|
|
933
973
|
}
|
|
934
974
|
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
975
|
this.state.isStreaming = false;
|
|
942
976
|
this.state.isPaused = true;
|
|
943
977
|
this.state.pausedRunId = chunk.run_id;
|
|
944
978
|
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
979
|
this.emit("run:paused", {
|
|
948
980
|
runId: chunk.run_id,
|
|
949
981
|
sessionId: chunk.session_id,
|
|
@@ -971,6 +1003,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
971
1003
|
const updated = this.eventProcessor.processChunk(chunk, lastMessage);
|
|
972
1004
|
return updated || lastMessage;
|
|
973
1005
|
});
|
|
1006
|
+
this.applyPendingUISpecs();
|
|
974
1007
|
this.emit("message:update", this.messageStore.getMessages());
|
|
975
1008
|
}
|
|
976
1009
|
/**
|
|
@@ -1080,6 +1113,103 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1080
1113
|
}
|
|
1081
1114
|
this.emit("state:change", this.getState());
|
|
1082
1115
|
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Add tool calls to the last message
|
|
1118
|
+
* Used by frontend execution to add tool calls that were executed locally
|
|
1119
|
+
*/
|
|
1120
|
+
addToolCallsToLastMessage(toolCalls) {
|
|
1121
|
+
const lastMessage = this.messageStore.getLastMessage();
|
|
1122
|
+
if (!lastMessage || lastMessage.role !== "agent") {
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
const existingToolCalls = lastMessage.tool_calls || [];
|
|
1126
|
+
const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
|
|
1127
|
+
const newToolCalls = toolCalls.filter((t) => !existingIds.has(t.tool_call_id));
|
|
1128
|
+
if (newToolCalls.length > 0) {
|
|
1129
|
+
this.messageStore.updateLastMessage((msg) => ({
|
|
1130
|
+
...msg,
|
|
1131
|
+
tool_calls: [...existingToolCalls, ...newToolCalls]
|
|
1132
|
+
}));
|
|
1133
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Hydrate a specific tool call with its UI component
|
|
1138
|
+
* If tool call doesn't exist yet, stores UI spec as pending
|
|
1139
|
+
*/
|
|
1140
|
+
hydrateToolCallUI(toolCallId, uiSpec) {
|
|
1141
|
+
const messages = this.messageStore.getMessages();
|
|
1142
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1143
|
+
const message = messages[i];
|
|
1144
|
+
if (message.tool_calls) {
|
|
1145
|
+
const toolIndex = message.tool_calls.findIndex(
|
|
1146
|
+
(t) => t.tool_call_id === toolCallId
|
|
1147
|
+
);
|
|
1148
|
+
if (toolIndex !== -1) {
|
|
1149
|
+
this.messageStore.updateMessage(i, (msg) => {
|
|
1150
|
+
const updatedToolCalls = [...msg.tool_calls || []];
|
|
1151
|
+
updatedToolCalls[toolIndex] = {
|
|
1152
|
+
...updatedToolCalls[toolIndex],
|
|
1153
|
+
ui_component: uiSpec
|
|
1154
|
+
};
|
|
1155
|
+
return {
|
|
1156
|
+
...msg,
|
|
1157
|
+
tool_calls: updatedToolCalls
|
|
1158
|
+
};
|
|
1159
|
+
});
|
|
1160
|
+
this.pendingUISpecs.delete(toolCallId);
|
|
1161
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
this.pendingUISpecs.set(toolCallId, uiSpec);
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Apply any pending UI specs to tool calls that have just been added
|
|
1170
|
+
* Called after message updates to attach UI to newly arrived tool calls
|
|
1171
|
+
* Batches all updates to emit only one message:update event
|
|
1172
|
+
*/
|
|
1173
|
+
applyPendingUISpecs() {
|
|
1174
|
+
if (this.pendingUISpecs.size === 0)
|
|
1175
|
+
return;
|
|
1176
|
+
const messages = this.messageStore.getMessages();
|
|
1177
|
+
const updatedMessages = [];
|
|
1178
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1179
|
+
const message = messages[i];
|
|
1180
|
+
if (message.tool_calls) {
|
|
1181
|
+
let messageUpdated = false;
|
|
1182
|
+
const updatedToolCalls = [...message.tool_calls];
|
|
1183
|
+
for (let j = 0; j < updatedToolCalls.length; j++) {
|
|
1184
|
+
const toolCall = updatedToolCalls[j];
|
|
1185
|
+
const pendingUI = this.pendingUISpecs.get(toolCall.tool_call_id);
|
|
1186
|
+
if (pendingUI && !toolCall.ui_component) {
|
|
1187
|
+
updatedToolCalls[j] = {
|
|
1188
|
+
...updatedToolCalls[j],
|
|
1189
|
+
ui_component: pendingUI
|
|
1190
|
+
};
|
|
1191
|
+
this.pendingUISpecs.delete(toolCall.tool_call_id);
|
|
1192
|
+
messageUpdated = true;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (messageUpdated) {
|
|
1196
|
+
updatedMessages.push({
|
|
1197
|
+
index: i,
|
|
1198
|
+
message: {
|
|
1199
|
+
...message,
|
|
1200
|
+
tool_calls: updatedToolCalls
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
if (updatedMessages.length > 0) {
|
|
1207
|
+
updatedMessages.forEach(({ index, message }) => {
|
|
1208
|
+
this.messageStore.updateMessage(index, () => message);
|
|
1209
|
+
});
|
|
1210
|
+
this.emit("message:update", this.messageStore.getMessages());
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1083
1213
|
/**
|
|
1084
1214
|
* Continue a paused run after executing external tools
|
|
1085
1215
|
*/
|
|
@@ -1096,8 +1226,12 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1096
1226
|
this.state.isStreaming = true;
|
|
1097
1227
|
this.emit("run:continued", { runId: this.state.pausedRunId });
|
|
1098
1228
|
this.emit("state:change", this.getState());
|
|
1229
|
+
const cleanedTools = tools.map((tool) => {
|
|
1230
|
+
const { ui_component, ...backendTool } = tool;
|
|
1231
|
+
return backendTool;
|
|
1232
|
+
});
|
|
1099
1233
|
const formData = new FormData();
|
|
1100
|
-
formData.append("tools", JSON.stringify(
|
|
1234
|
+
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1101
1235
|
formData.append("stream", "true");
|
|
1102
1236
|
const currentSessionId = this.configManager.getSessionId();
|
|
1103
1237
|
if (currentSessionId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antipopp/agno-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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.3.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"tsup": "^8.0.1",
|