@antipopp/agno-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,384 @@
1
+ // src/context/AgnoContext.tsx
2
+ import { createContext, useContext, useMemo, useEffect } from "react";
3
+ import { AgnoClient } from "@antipopp/agno-client";
4
+ import { jsx } from "react/jsx-runtime";
5
+ var AgnoContext = createContext(null);
6
+ function AgnoProvider({ config, children }) {
7
+ const client = useMemo(() => new AgnoClient(config), []);
8
+ useEffect(() => {
9
+ return () => {
10
+ client.removeAllListeners();
11
+ };
12
+ }, [client]);
13
+ return /* @__PURE__ */ jsx(AgnoContext.Provider, { value: client, children });
14
+ }
15
+ function useAgnoClient() {
16
+ const client = useContext(AgnoContext);
17
+ if (!client) {
18
+ throw new Error("useAgnoClient must be used within an AgnoProvider");
19
+ }
20
+ return client;
21
+ }
22
+
23
+ // src/hooks/useAgnoChat.ts
24
+ import { useState, useEffect as useEffect2, useCallback } from "react";
25
+ function useAgnoChat() {
26
+ const client = useAgnoClient();
27
+ const [messages, setMessages] = useState(client.getMessages());
28
+ const [state, setState] = useState(client.getState());
29
+ const [error, setError] = useState();
30
+ useEffect2(() => {
31
+ const handleMessageUpdate = (updatedMessages) => {
32
+ console.log("[useAgnoChat] message:update event received, messages:", updatedMessages.length);
33
+ setMessages(updatedMessages);
34
+ };
35
+ const handleMessageComplete = (updatedMessages) => {
36
+ console.log("[useAgnoChat] message:complete event received, messages:", updatedMessages.length);
37
+ setMessages(updatedMessages);
38
+ };
39
+ const handleMessageError = (errorMessage) => {
40
+ console.log("[useAgnoChat] message:error event received:", errorMessage);
41
+ setError(errorMessage);
42
+ };
43
+ const handleStateChange = (newState) => {
44
+ console.log("[useAgnoChat] state:change event received");
45
+ setState(newState);
46
+ };
47
+ client.on("message:update", handleMessageUpdate);
48
+ client.on("message:complete", handleMessageComplete);
49
+ client.on("message:error", handleMessageError);
50
+ client.on("state:change", handleStateChange);
51
+ console.log("[useAgnoChat] Initializing with messages:", client.getMessages().length);
52
+ setMessages(client.getMessages());
53
+ setState(client.getState());
54
+ return () => {
55
+ client.off("message:update", handleMessageUpdate);
56
+ client.off("message:complete", handleMessageComplete);
57
+ client.off("message:error", handleMessageError);
58
+ client.off("state:change", handleStateChange);
59
+ };
60
+ }, [client]);
61
+ const sendMessage = useCallback(
62
+ async (message, options) => {
63
+ setError(void 0);
64
+ try {
65
+ await client.sendMessage(message, options);
66
+ } catch (err) {
67
+ const errorMessage = err instanceof Error ? err.message : String(err);
68
+ setError(errorMessage);
69
+ throw err;
70
+ }
71
+ },
72
+ [client]
73
+ );
74
+ const clearMessages = useCallback(() => {
75
+ client.clearMessages();
76
+ setMessages([]);
77
+ setError(void 0);
78
+ }, [client]);
79
+ return {
80
+ messages,
81
+ sendMessage,
82
+ clearMessages,
83
+ isStreaming: state.isStreaming,
84
+ isPaused: state.isPaused,
85
+ error,
86
+ state
87
+ };
88
+ }
89
+
90
+ // src/hooks/useAgnoSession.ts
91
+ import { useState as useState2, useEffect as useEffect3, useCallback as useCallback2 } from "react";
92
+ function useAgnoSession() {
93
+ const client = useAgnoClient();
94
+ const [sessions, setSessions] = useState2([]);
95
+ const [currentSessionId, setCurrentSessionId] = useState2(
96
+ client.getConfig().sessionId
97
+ );
98
+ const [isLoading, setIsLoading] = useState2(false);
99
+ const [error, setError] = useState2();
100
+ useEffect3(() => {
101
+ const handleSessionLoaded = (sessionId) => {
102
+ setCurrentSessionId(sessionId);
103
+ };
104
+ const handleSessionCreated = (session) => {
105
+ setSessions((prev) => [session, ...prev]);
106
+ setCurrentSessionId(session.session_id);
107
+ };
108
+ const handleStateChange = () => {
109
+ const config = client.getConfig();
110
+ setCurrentSessionId(config.sessionId);
111
+ setSessions(client.getState().sessions);
112
+ };
113
+ client.on("session:loaded", handleSessionLoaded);
114
+ client.on("session:created", handleSessionCreated);
115
+ client.on("state:change", handleStateChange);
116
+ setSessions(client.getState().sessions);
117
+ setCurrentSessionId(client.getConfig().sessionId);
118
+ return () => {
119
+ client.off("session:loaded", handleSessionLoaded);
120
+ client.off("session:created", handleSessionCreated);
121
+ client.off("state:change", handleStateChange);
122
+ };
123
+ }, [client]);
124
+ const loadSession = useCallback2(
125
+ async (sessionId) => {
126
+ setIsLoading(true);
127
+ setError(void 0);
128
+ try {
129
+ const messages = await client.loadSession(sessionId);
130
+ setCurrentSessionId(sessionId);
131
+ return messages;
132
+ } catch (err) {
133
+ const errorMessage = err instanceof Error ? err.message : String(err);
134
+ setError(errorMessage);
135
+ throw err;
136
+ } finally {
137
+ setIsLoading(false);
138
+ }
139
+ },
140
+ [client]
141
+ );
142
+ const fetchSessions = useCallback2(async () => {
143
+ setIsLoading(true);
144
+ setError(void 0);
145
+ try {
146
+ const fetchedSessions = await client.fetchSessions();
147
+ setSessions(fetchedSessions);
148
+ return fetchedSessions;
149
+ } catch (err) {
150
+ const errorMessage = err instanceof Error ? err.message : String(err);
151
+ setError(errorMessage);
152
+ throw err;
153
+ } finally {
154
+ setIsLoading(false);
155
+ }
156
+ }, [client]);
157
+ return {
158
+ sessions,
159
+ currentSessionId,
160
+ loadSession,
161
+ fetchSessions,
162
+ isLoading,
163
+ error
164
+ };
165
+ }
166
+
167
+ // src/hooks/useAgnoActions.ts
168
+ import { useState as useState3, useCallback as useCallback3 } from "react";
169
+ function useAgnoActions() {
170
+ const client = useAgnoClient();
171
+ const [isInitializing, setIsInitializing] = useState3(false);
172
+ const [error, setError] = useState3();
173
+ const initialize = useCallback3(async () => {
174
+ setIsInitializing(true);
175
+ setError(void 0);
176
+ try {
177
+ const result = await client.initialize();
178
+ return result;
179
+ } catch (err) {
180
+ const errorMessage = err instanceof Error ? err.message : String(err);
181
+ setError(errorMessage);
182
+ throw err;
183
+ } finally {
184
+ setIsInitializing(false);
185
+ }
186
+ }, [client]);
187
+ const checkStatus = useCallback3(async () => {
188
+ setError(void 0);
189
+ try {
190
+ return await client.checkStatus();
191
+ } catch (err) {
192
+ const errorMessage = err instanceof Error ? err.message : String(err);
193
+ setError(errorMessage);
194
+ return false;
195
+ }
196
+ }, [client]);
197
+ const fetchAgents = useCallback3(async () => {
198
+ setError(void 0);
199
+ try {
200
+ return await client.fetchAgents();
201
+ } catch (err) {
202
+ const errorMessage = err instanceof Error ? err.message : String(err);
203
+ setError(errorMessage);
204
+ throw err;
205
+ }
206
+ }, [client]);
207
+ const fetchTeams = useCallback3(async () => {
208
+ setError(void 0);
209
+ try {
210
+ return await client.fetchTeams();
211
+ } catch (err) {
212
+ const errorMessage = err instanceof Error ? err.message : String(err);
213
+ setError(errorMessage);
214
+ throw err;
215
+ }
216
+ }, [client]);
217
+ const updateConfig = useCallback3(
218
+ (updates) => {
219
+ client.updateConfig(updates);
220
+ },
221
+ [client]
222
+ );
223
+ return {
224
+ initialize,
225
+ checkStatus,
226
+ fetchAgents,
227
+ fetchTeams,
228
+ updateConfig,
229
+ isInitializing,
230
+ error
231
+ };
232
+ }
233
+
234
+ // src/hooks/useAgnoToolExecution.ts
235
+ import { useState as useState4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
236
+ function useAgnoToolExecution(handlers, autoExecute = true) {
237
+ const client = useAgnoClient();
238
+ const [pendingTools, setPendingTools] = useState4([]);
239
+ const [isPaused, setIsPaused] = useState4(false);
240
+ const [isExecuting, setIsExecuting] = useState4(false);
241
+ const [executionError, setExecutionError] = useState4();
242
+ useEffect4(() => {
243
+ const handleRunPaused = (event) => {
244
+ console.log("[useAgnoToolExecution] Run paused, tools:", event.tools);
245
+ setIsPaused(true);
246
+ setPendingTools(event.tools);
247
+ setExecutionError(void 0);
248
+ };
249
+ const handleRunContinued = () => {
250
+ console.log("[useAgnoToolExecution] Run continued");
251
+ setIsPaused(false);
252
+ setPendingTools([]);
253
+ setIsExecuting(false);
254
+ setExecutionError(void 0);
255
+ };
256
+ client.on("run:paused", handleRunPaused);
257
+ client.on("run:continued", handleRunContinued);
258
+ return () => {
259
+ client.off("run:paused", handleRunPaused);
260
+ client.off("run:continued", handleRunContinued);
261
+ };
262
+ }, [client]);
263
+ const executeAndContinue = useCallback4(async () => {
264
+ if (!isPaused || pendingTools.length === 0) {
265
+ console.warn("[useAgnoToolExecution] Cannot execute: no pending tools");
266
+ return;
267
+ }
268
+ setIsExecuting(true);
269
+ setExecutionError(void 0);
270
+ try {
271
+ console.log("[useAgnoToolExecution] Executing", pendingTools.length, "tools");
272
+ const updatedTools = await Promise.all(
273
+ pendingTools.map(async (tool) => {
274
+ const handler = handlers[tool.tool_name];
275
+ if (!handler) {
276
+ console.warn(`[useAgnoToolExecution] No handler for tool: ${tool.tool_name}`);
277
+ return {
278
+ ...tool,
279
+ result: JSON.stringify({
280
+ error: `No handler registered for ${tool.tool_name}`
281
+ })
282
+ };
283
+ }
284
+ try {
285
+ console.log(`[useAgnoToolExecution] Executing tool: ${tool.tool_name}`, tool.tool_args);
286
+ const result = await handler(tool.tool_args);
287
+ console.log(`[useAgnoToolExecution] Tool result:`, result);
288
+ return {
289
+ ...tool,
290
+ result: typeof result === "string" ? result : JSON.stringify(result)
291
+ };
292
+ } catch (error) {
293
+ console.error(`[useAgnoToolExecution] Tool execution error:`, error);
294
+ return {
295
+ ...tool,
296
+ result: JSON.stringify({
297
+ error: error instanceof Error ? error.message : String(error)
298
+ })
299
+ };
300
+ }
301
+ })
302
+ );
303
+ console.log("[useAgnoToolExecution] Continuing run with results");
304
+ await client.continueRun(updatedTools);
305
+ } catch (error) {
306
+ const errorMessage = error instanceof Error ? error.message : String(error);
307
+ console.error("[useAgnoToolExecution] Failed to continue run:", errorMessage);
308
+ setExecutionError(errorMessage);
309
+ setIsExecuting(false);
310
+ throw error;
311
+ }
312
+ }, [client, handlers, isPaused, pendingTools]);
313
+ const executeTools = useCallback4(
314
+ async (tools) => {
315
+ return Promise.all(
316
+ tools.map(async (tool) => {
317
+ const handler = handlers[tool.tool_name];
318
+ if (!handler)
319
+ return tool;
320
+ try {
321
+ const result = await handler(tool.tool_args);
322
+ return {
323
+ ...tool,
324
+ result: typeof result === "string" ? result : JSON.stringify(result)
325
+ };
326
+ } catch (error) {
327
+ return {
328
+ ...tool,
329
+ result: JSON.stringify({
330
+ error: error instanceof Error ? error.message : String(error)
331
+ })
332
+ };
333
+ }
334
+ })
335
+ );
336
+ },
337
+ [handlers]
338
+ );
339
+ const continueWithResults = useCallback4(
340
+ async (tools) => {
341
+ if (!isPaused) {
342
+ throw new Error("No paused run to continue");
343
+ }
344
+ setIsExecuting(true);
345
+ try {
346
+ await client.continueRun(tools);
347
+ } catch (error) {
348
+ setIsExecuting(false);
349
+ throw error;
350
+ }
351
+ },
352
+ [client, isPaused]
353
+ );
354
+ useEffect4(() => {
355
+ if (autoExecute && isPaused && !isExecuting && pendingTools.length > 0) {
356
+ console.log("[useAgnoToolExecution] Auto-executing tools");
357
+ executeAndContinue();
358
+ }
359
+ }, [autoExecute, isPaused, isExecuting, pendingTools.length, executeAndContinue]);
360
+ return {
361
+ /** Whether the run is currently paused awaiting tool execution */
362
+ isPaused,
363
+ /** Whether tools are currently being executed */
364
+ isExecuting,
365
+ /** Tools awaiting execution */
366
+ pendingTools,
367
+ /** Execute all pending tools and continue the run */
368
+ executeAndContinue,
369
+ /** Execute specific tools and return results without continuing */
370
+ executeTools,
371
+ /** Continue the run with manually provided tool results */
372
+ continueWithResults,
373
+ /** Error from tool execution, if any */
374
+ executionError
375
+ };
376
+ }
377
+ export {
378
+ AgnoProvider,
379
+ useAgnoActions,
380
+ useAgnoChat,
381
+ useAgnoClient,
382
+ useAgnoSession,
383
+ useAgnoToolExecution
384
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@antipopp/agno-react",
3
+ "version": "0.1.0",
4
+ "description": "React hooks for Agno client with frontend tool execution (HITL) support",
5
+ "author": "antipopp",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/antipopp/agno-client.git",
10
+ "directory": "packages/react"
11
+ },
12
+ "keywords": [
13
+ "agno",
14
+ "agent",
15
+ "ai",
16
+ "react",
17
+ "hooks",
18
+ "hitl",
19
+ "tool-execution",
20
+ "streaming"
21
+ ],
22
+ "main": "./dist/index.js",
23
+ "module": "./dist/index.mjs",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "import": "./dist/index.mjs",
28
+ "require": "./dist/index.js",
29
+ "types": "./dist/index.d.ts"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "dependencies": {
37
+ "@antipopp/agno-client": "0.1.0",
38
+ "@antipopp/agno-types": "0.1.0"
39
+ },
40
+ "peerDependencies": {
41
+ "react": "^18.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/react": "^18.2.45",
45
+ "react": "^18.2.0",
46
+ "tsup": "^8.0.1",
47
+ "typescript": "^5.3.3"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup src/index.ts --format cjs,esm --dts --external react",
51
+ "dev": "tsup src/index.ts --format cjs,esm --dts --external react --watch",
52
+ "typecheck": "tsc --noEmit"
53
+ }
54
+ }