@rodrigocoliveira/agno-react 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 rodrigocoliveira
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,391 @@
1
+ # @rodrigocoliveira/agno-react
2
+
3
+ React hooks for Agno client with full TypeScript support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @rodrigocoliveira/agno-react
9
+ ```
10
+
11
+ This package includes `@rodrigocoliveira/agno-client` and `@rodrigocoliveira/agno-types` as dependencies.
12
+
13
+ ## Features
14
+
15
+ - ✅ **Easy Integration** - Drop-in React hooks for Agno agents
16
+ - ✅ **Context Provider** - Manages client lifecycle automatically
17
+ - ✅ **Real-time Updates** - React state synced with streaming updates
18
+ - ✅ **Type-Safe** - Full TypeScript support
19
+ - ✅ **Familiar API** - Matches the original Agno React hooks design
20
+
21
+ ## Quick Start
22
+
23
+ ### 1. Wrap Your App with AgnoProvider
24
+
25
+ ```tsx
26
+ import { AgnoProvider } from '@rodrigocoliveira/agno-react';
27
+
28
+ function App() {
29
+ return (
30
+ <AgnoProvider
31
+ config={{
32
+ endpoint: 'http://localhost:7777',
33
+ mode: 'agent',
34
+ agentId: 'your-agent-id',
35
+ userId: 'user-123', // Optional: Link sessions to a user
36
+ headers: { // Optional: Global headers for all requests
37
+ 'X-API-Version': 'v2'
38
+ },
39
+ params: { // Optional: Global query params for all requests
40
+ locale: 'en-US'
41
+ }
42
+ }}
43
+ >
44
+ <YourComponents />
45
+ </AgnoProvider>
46
+ );
47
+ }
48
+ ```
49
+
50
+ ### 2. Use Hooks in Your Components
51
+
52
+ ```tsx
53
+ import { useAgnoChat, useAgnoActions } from '@rodrigocoliveira/agno-react';
54
+
55
+ function ChatComponent() {
56
+ const { messages, sendMessage, isStreaming, error } = useAgnoChat();
57
+ const { initialize } = useAgnoActions();
58
+
59
+ useEffect(() => {
60
+ initialize();
61
+ }, [initialize]);
62
+
63
+ const handleSend = async () => {
64
+ await sendMessage('Hello, agent!');
65
+ };
66
+
67
+ return (
68
+ <div>
69
+ {messages.map((msg, i) => (
70
+ <div key={i}>
71
+ <strong>{msg.role}:</strong> {msg.content}
72
+ </div>
73
+ ))}
74
+ {error && <div>Error: {error}</div>}
75
+ <button onClick={handleSend} disabled={isStreaming}>
76
+ {isStreaming ? 'Sending...' : 'Send'}
77
+ </button>
78
+ </div>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ## API Reference
84
+
85
+ ### AgnoProvider
86
+
87
+ Provider component that creates and manages an `AgnoClient` instance.
88
+
89
+ ```tsx
90
+ <AgnoProvider config={config}>
91
+ {children}
92
+ </AgnoProvider>
93
+ ```
94
+
95
+ **Props:**
96
+ - `config` (AgnoClientConfig) - Client configuration
97
+ - `children` (ReactNode) - Child components
98
+
99
+ ### useAgnoClient()
100
+
101
+ Access the underlying `AgnoClient` instance.
102
+
103
+ ```tsx
104
+ const client = useAgnoClient();
105
+
106
+ // Use client methods directly
107
+ await client.sendMessage('Hello!');
108
+ ```
109
+
110
+ ### useAgnoChat()
111
+
112
+ Main hook for chat interactions.
113
+
114
+ ```tsx
115
+ const {
116
+ messages, // ChatMessage[] - Current messages
117
+ sendMessage, // (message, options?) => Promise<void>
118
+ clearMessages, // () => void
119
+ isStreaming, // boolean - Is currently streaming
120
+ error, // string | undefined - Current error
121
+ state, // ClientState - Full client state
122
+ } = useAgnoChat();
123
+ ```
124
+
125
+ **Methods:**
126
+
127
+ #### `sendMessage(message, options?)`
128
+
129
+ ```tsx
130
+ // Send a text message
131
+ await sendMessage('Hello!');
132
+
133
+ // Send with FormData (for file uploads)
134
+ const formData = new FormData();
135
+ formData.append('message', 'Hello!');
136
+ formData.append('file', file);
137
+ await sendMessage(formData);
138
+
139
+ // Send with custom headers
140
+ await sendMessage('Hello!', {
141
+ headers: { 'X-Custom': 'value' }
142
+ });
143
+
144
+ // Send with query parameters
145
+ await sendMessage('Hello!', {
146
+ params: { temperature: '0.7', max_tokens: '500' }
147
+ });
148
+
149
+ // Send with both headers and params
150
+ await sendMessage('Hello!', {
151
+ headers: { 'X-Request-ID': '12345' },
152
+ params: { debug: 'true' }
153
+ });
154
+ ```
155
+
156
+ #### `clearMessages()`
157
+
158
+ ```tsx
159
+ clearMessages(); // Clears all messages and resets session
160
+ ```
161
+
162
+ ### useAgnoSession()
163
+
164
+ Hook for session management.
165
+
166
+ ```tsx
167
+ const {
168
+ sessions, // SessionEntry[] - Available sessions
169
+ currentSessionId, // string | undefined - Current session ID
170
+ loadSession, // (sessionId) => Promise<ChatMessage[]>
171
+ fetchSessions, // () => Promise<SessionEntry[]>
172
+ isLoading, // boolean - Is loading session
173
+ error, // string | undefined - Current error
174
+ } = useAgnoSession();
175
+ ```
176
+
177
+ **Example:**
178
+
179
+ ```tsx
180
+ function SessionList() {
181
+ const { sessions, loadSession, fetchSessions } = useAgnoSession();
182
+
183
+ useEffect(() => {
184
+ // Fetch sessions with optional query params
185
+ fetchSessions({ params: { limit: '50', status: 'active' } });
186
+ }, [fetchSessions]);
187
+
188
+ const handleLoadSession = (sessionId: string) => {
189
+ // Load session with optional params
190
+ loadSession(sessionId, { params: { include_metadata: 'true' } });
191
+ };
192
+
193
+ return (
194
+ <ul>
195
+ {sessions.map((session) => (
196
+ <li key={session.session_id}>
197
+ <button onClick={() => handleLoadSession(session.session_id)}>
198
+ {session.session_name}
199
+ </button>
200
+ </li>
201
+ ))}
202
+ </ul>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ### useAgnoActions()
208
+
209
+ Hook for common actions and initialization.
210
+
211
+ ```tsx
212
+ const {
213
+ initialize, // () => Promise<{ agents, teams }>
214
+ checkStatus, // () => Promise<boolean>
215
+ fetchAgents, // () => Promise<AgentDetails[]>
216
+ fetchTeams, // () => Promise<TeamDetails[]>
217
+ updateConfig, // (updates) => void
218
+ isInitializing, // boolean
219
+ error, // string | undefined
220
+ } = useAgnoActions();
221
+ ```
222
+
223
+ **Example:**
224
+
225
+ ```tsx
226
+ function InitComponent() {
227
+ const { initialize, fetchAgents, updateConfig, isInitializing } = useAgnoActions();
228
+ const { state } = useAgnoChat();
229
+
230
+ useEffect(() => {
231
+ // Initialize with optional params
232
+ initialize({ params: { filter: 'active' } });
233
+ }, [initialize]);
234
+
235
+ const loadMoreAgents = () => {
236
+ // Fetch agents with custom params
237
+ fetchAgents({ params: { page: '2', limit: '20' } });
238
+ };
239
+
240
+ const switchAgent = (agentId: string) => {
241
+ updateConfig({ agentId, mode: 'agent' });
242
+ };
243
+
244
+ if (isInitializing) return <div>Loading...</div>;
245
+
246
+ return (
247
+ <div>
248
+ <h3>Agents</h3>
249
+ {state.agents.map((agent) => (
250
+ <button key={agent.id} onClick={() => switchAgent(agent.id)}>
251
+ {agent.name}
252
+ </button>
253
+ ))}
254
+ <button onClick={loadMoreAgents}>Load More</button>
255
+ </div>
256
+ );
257
+ }
258
+ ```
259
+
260
+ ## Complete Example
261
+
262
+ ```tsx
263
+ import { useState, useEffect } from 'react';
264
+ import {
265
+ AgnoProvider,
266
+ useAgnoChat,
267
+ useAgnoSession,
268
+ useAgnoActions,
269
+ } from '@rodrigocoliveira/agno-react';
270
+
271
+ function App() {
272
+ return (
273
+ <AgnoProvider
274
+ config={{
275
+ endpoint: 'http://localhost:7777',
276
+ mode: 'agent',
277
+ agentId: 'my-agent',
278
+ }}
279
+ >
280
+ <ChatApp />
281
+ </AgnoProvider>
282
+ );
283
+ }
284
+
285
+ function ChatApp() {
286
+ const [input, setInput] = useState('');
287
+ const { messages, sendMessage, isStreaming, error, clearMessages } = useAgnoChat();
288
+ const { sessions, loadSession, fetchSessions } = useAgnoSession();
289
+ const { initialize, state } = useAgnoActions();
290
+
291
+ useEffect(() => {
292
+ initialize().then(() => fetchSessions());
293
+ }, [initialize, fetchSessions]);
294
+
295
+ const handleSubmit = async (e: React.FormEvent) => {
296
+ e.preventDefault();
297
+ if (!input.trim() || isStreaming) return;
298
+
299
+ await sendMessage(input);
300
+ setInput('');
301
+ };
302
+
303
+ return (
304
+ <div>
305
+ <aside>
306
+ <h2>Sessions</h2>
307
+ <button onClick={() => clearMessages()}>New Chat</button>
308
+ <ul>
309
+ {sessions.map((session) => (
310
+ <li key={session.session_id}>
311
+ <button onClick={() => loadSession(session.session_id)}>
312
+ {session.session_name}
313
+ </button>
314
+ </li>
315
+ ))}
316
+ </ul>
317
+ </aside>
318
+
319
+ <main>
320
+ <div className="messages">
321
+ {messages.map((msg, i) => (
322
+ <div key={i} className={`message ${msg.role}`}>
323
+ <strong>{msg.role}:</strong>
324
+ <p>{msg.content}</p>
325
+ {msg.tool_calls && (
326
+ <details>
327
+ <summary>Tool Calls</summary>
328
+ <pre>{JSON.stringify(msg.tool_calls, null, 2)}</pre>
329
+ </details>
330
+ )}
331
+ </div>
332
+ ))}
333
+ {error && <div className="error">Error: {error}</div>}
334
+ </div>
335
+
336
+ <form onSubmit={handleSubmit}>
337
+ <input
338
+ value={input}
339
+ onChange={(e) => setInput(e.target.value)}
340
+ placeholder="Type a message..."
341
+ disabled={isStreaming}
342
+ />
343
+ <button type="submit" disabled={isStreaming}>
344
+ {isStreaming ? 'Sending...' : 'Send'}
345
+ </button>
346
+ </form>
347
+ </main>
348
+ </div>
349
+ );
350
+ }
351
+
352
+ export default App;
353
+ ```
354
+
355
+ ## TypeScript
356
+
357
+ All hooks and components are fully typed. Import types as needed:
358
+
359
+ ```typescript
360
+ import type {
361
+ AgnoClientConfig,
362
+ ChatMessage,
363
+ SessionEntry,
364
+ AgentDetails,
365
+ TeamDetails,
366
+ } from '@rodrigocoliveira/agno-react';
367
+ ```
368
+
369
+ ## Publishing
370
+
371
+ To publish this package to npm:
372
+
373
+ ```bash
374
+ # Login to npm (first time only)
375
+ npm login
376
+
377
+ # Build the package
378
+ pnpm build
379
+
380
+ # Publish (use --access public for scoped packages)
381
+ pnpm publish --access public
382
+ ```
383
+
384
+ **Publish order:** This package depends on both `@rodrigocoliveira/agno-types` and `@rodrigocoliveira/agno-client`, so publish them first:
385
+ 1. `@rodrigocoliveira/agno-types`
386
+ 2. `@rodrigocoliveira/agno-client`
387
+ 3. `@rodrigocoliveira/agno-react` (this package)
388
+
389
+ ## License
390
+
391
+ MIT