@agno-hq/chat-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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agno
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,270 @@
1
+ # @agno-hq/chat-react
2
+
3
+ Headless React hook (`useAgnoChat`) plus drop-in UI components for streaming **any
4
+ Agno agent, team, or workflow** from an [AgentOS](https://docs.agno.com) backend.
5
+
6
+ It speaks the AgentOS HTTP run protocol directly: it POSTs to the run endpoint,
7
+ parses the streamed events, and accumulates them into render-ready messages —
8
+ content, tool calls, reasoning, citations, media — while exposing the raw event
9
+ feed, live status, and human-in-the-loop pauses.
10
+
11
+ ```tsx
12
+ import { AgnoChat } from '@agno-hq/chat-react'
13
+ import '@agno-hq/chat-react/styles.css'
14
+
15
+ export default function Page() {
16
+ return <AgnoChat baseUrl="http://localhost:7777" showEventLog allowFiles />
17
+ }
18
+ ```
19
+
20
+ That's the zero-wiring widget: it discovers the agents/teams/workflows on your
21
+ AgentOS, shows a selector, and runs a full chat. For full control, use the hook.
22
+
23
+ ---
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install @agno-hq/chat-react
29
+ ```
30
+
31
+ `react` and `react-dom` (>=18) are peer dependencies. The library ships
32
+ compiled ESM + CommonJS bundles with bundled type declarations, so it works out
33
+ of the box in any modern bundler (Vite, Next.js, Webpack, etc.) with no extra
34
+ config. Import the stylesheet once (see below).
35
+
36
+ ---
37
+
38
+ ## The hook: `useAgnoChat`
39
+
40
+ ```tsx
41
+ import { useAgnoChat, ChatWindow } from '@agno-hq/chat-react'
42
+ import '@agno-hq/chat-react/styles.css'
43
+
44
+ function Chat() {
45
+ const chat = useAgnoChat({
46
+ baseUrl: 'http://localhost:7777',
47
+ entity: { type: 'agent', id: 'agno_assist', name: 'Agno Assist' },
48
+ userId: 'user-123',
49
+ })
50
+
51
+ return <ChatWindow chat={chat} />
52
+ }
53
+ ```
54
+
55
+ `entity.type` is `'agent' | 'team' | 'workflow'` and `entity.id` is the
56
+ agent/team/workflow id — the same hook drives all three.
57
+
58
+ ### What the hook returns
59
+
60
+ | Value | Type | Description |
61
+ |---|---|---|
62
+ | `messages` | `ChatMessage[]` | Full transcript, oldest first. |
63
+ | `streamingMessage` | `ChatMessage \| null` | The agent message currently streaming. |
64
+ | `events` | `RunEventData[]` | Every raw event from the latest run, in order. |
65
+ | `currentEvent` | `RunEventData \| null` | The most recent event. |
66
+ | `status` | `'idle' \| 'streaming' \| 'paused' \| 'completed' \| 'error' \| 'cancelled'` | Run lifecycle. |
67
+ | `activity` | `string \| null` | Live label, e.g. `"Calling get_weather"`, `"Reasoning"`. |
68
+ | `isStreaming` / `isPaused` | `boolean` | Convenience flags. |
69
+ | `error` | `string \| null` | Last error message. |
70
+ | `sessionId` | `string \| undefined` | Auto-captured from the first run. |
71
+ | `tools` | `ToolExecution[]` | Tool calls of the active message. |
72
+ | `reasoning` | `ReasoningStep[]` | Reasoning steps of the active message. |
73
+ | `pendingRequirements` | `RunRequirement[]` | Outstanding human-in-the-loop asks. |
74
+
75
+ ### Actions
76
+
77
+ | Action | Description |
78
+ |---|---|
79
+ | `sendMessage(text, { files? })` | Send a message and stream the response. |
80
+ | `cancel()` | Abort the active run (also calls the cancel endpoint). |
81
+ | `continueRun({ tools?, stepRequirements? })` | Resume a paused run with resolved requirements. |
82
+ | `respondToConfirmation(approve)` | Approve/reject pending tool confirmations, then continue. |
83
+ | `submitUserInput(values)` | Provide values for pending input fields, then continue. |
84
+ | `reset()` | Clear the transcript and start a new session. |
85
+ | `setMessages(...)` | Replace the transcript (e.g. after restoring a session). |
86
+ | `client` | The underlying `AgnoClient` for discovery/session calls. |
87
+
88
+ ---
89
+
90
+ ## Components
91
+
92
+ All components are styled by `@agno-hq/chat-react/styles.css` (dark by default; add
93
+ the `agno-light` class on a wrapper for light mode). Every piece is exported so
94
+ you can compose your own layout.
95
+
96
+ | Component | Purpose |
97
+ |---|---|
98
+ | `<AgnoChat>` | All-in-one widget: discovery, selector, chat, optional event log. |
99
+ | `<ChatWindow chat={chat}>` | Full chat surface built from a `useAgnoChat` result. |
100
+ | `<MessageList>` | Auto-scrolling transcript with live status + footer slot. |
101
+ | `<Message>` | A single message: content, tools, reasoning, media, citations. |
102
+ | `<ChatInput>` | Multiline input with file attach, send, and stop. |
103
+ | `<ToolCalls>` | Collapsible tool-call cards (name, args, result, status). |
104
+ | `<Reasoning>` | Collapsible reasoning-steps panel. |
105
+ | `<Citations>` | References / source URLs. |
106
+ | `<Multimedia>` | Images, video, and audio attachments. |
107
+ | `<StatusIndicator>` | Animated "what is it doing now" line. |
108
+ | `<EventLog>` | Developer feed of every raw run event. |
109
+ | `<HumanInput>` | Human-in-the-loop panel (confirm / reject / input). |
110
+ | `<EntitySelector>` | Dropdown of agents, teams, and workflows. |
111
+ | `<SessionList>` | Sidebar of past sessions — click to load, trash to delete. |
112
+ | `<Markdown>` | The built-in lightweight Markdown renderer. |
113
+
114
+ ### Bring your own Markdown
115
+
116
+ The built-in renderer covers code blocks, inline code, bold/italic, links,
117
+ headings and lists. For full GFM (tables, etc.), pass `renderMarkdown`:
118
+
119
+ ```tsx
120
+ import ReactMarkdown from 'react-markdown'
121
+ import remarkGfm from 'remark-gfm'
122
+
123
+ <ChatWindow
124
+ chat={chat}
125
+ renderMarkdown={(c) => <ReactMarkdown remarkPlugins={[remarkGfm]}>{c}</ReactMarkdown>}
126
+ />
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Human-in-the-loop
132
+
133
+ When a run pauses for a tool confirmation or for user input, `status` becomes
134
+ `'paused'` and `pendingRequirements` / the paused message's `tool_calls`
135
+ describe what's needed. `<ChatWindow>` renders `<HumanInput>` automatically; to
136
+ build your own UI, call:
137
+
138
+ ```tsx
139
+ await chat.respondToConfirmation(true) // approve pending tool calls
140
+ await chat.respondToConfirmation(false) // reject
141
+ await chat.submitUserInput({ city: 'Lisbon' }) // fill input fields, then continue
142
+ ```
143
+
144
+ Agents and teams resume via the `/continue` endpoint with resolved `tools`;
145
+ workflows resume with `step_requirements`. The hook picks the right one based on
146
+ the selected entity type.
147
+
148
+ ---
149
+
150
+ ## Session history
151
+
152
+ The hook tracks past sessions for the selected entity:
153
+
154
+ ```tsx
155
+ const chat = useAgnoChat({ baseUrl, entity })
156
+
157
+ chat.sessions // SessionEntry[]
158
+ chat.sessionsLoading // boolean
159
+ await chat.refreshSessions() // fetch the list
160
+ await chat.loadSession(sessionId) // load a transcript into the chat
161
+ await chat.deleteSession(sessionId)
162
+ ```
163
+
164
+ Render them with `<SessionList>`:
165
+
166
+ ```tsx
167
+ <SessionList
168
+ sessions={chat.sessions}
169
+ activeSessionId={chat.sessionId}
170
+ loading={chat.sessionsLoading}
171
+ onSelect={chat.loadSession}
172
+ onDelete={chat.deleteSession}
173
+ onNew={chat.reset}
174
+ />
175
+ ```
176
+
177
+ The all-in-one widget shows this sidebar with `showSessions`:
178
+
179
+ ```tsx
180
+ <AgnoChat baseUrl="http://localhost:7777" showSessions showEventLog />
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Lower-level API
186
+
187
+ ```tsx
188
+ import { AgnoClient, streamRun } from '@agno-hq/chat-react'
189
+
190
+ const client = new AgnoClient({ baseUrl: 'http://localhost:7777', headers: { Authorization: 'Bearer …' } })
191
+
192
+ await client.getEntities() // agents + teams + workflows
193
+ await client.getSessions('agent', 'agno_assist')
194
+ await client.getSessionRuns('agent', sessionId) // rehydrate history
195
+ await client.cancelRun('agent', 'agno_assist', runId)
196
+ ```
197
+
198
+ `streamRun` is the raw streaming primitive (parses the wire format and emits
199
+ normalised events) if you want to bypass the hook entirely.
200
+
201
+ ---
202
+
203
+ ## Running the example
204
+
205
+ The `example/` folder is a Vite app demonstrating both the widget and the hook
206
+ (with a live status panel + event log). It imports the library from source.
207
+
208
+ ```bash
209
+ cd example
210
+ npm install
211
+ npm run dev
212
+ ```
213
+
214
+ Then open the app, set your AgentOS URL (default `http://localhost:7777`), and
215
+ pick an agent, team, or workflow.
216
+
217
+ > Start an AgentOS first — see the Agno cookbooks under `cookbook/05_agent_os/`.
218
+
219
+ ### CORS
220
+
221
+ The chat runs in the browser, so **your AgentOS must allow the page's origin**.
222
+ The example dev server is pinned to port **5173** (`strictPort`), so add that
223
+ origin when constructing AgentOS:
224
+
225
+ ```python
226
+ AgentOS(..., cors_allowed_origins=["http://localhost:5173"])
227
+ ```
228
+
229
+ A symptom of a CORS mismatch is an empty entity dropdown and a
230
+ `Disallowed CORS origin` response to the preflight request.
231
+
232
+ ---
233
+
234
+ ## Notes
235
+
236
+ - **Auth / headers** — pass `headers` (or a pre-built `client`) to send an
237
+ `Authorization` header on every request.
238
+ - **Sessions** — `sessionId` is captured automatically on the first run. To
239
+ restore history, call `client.getSessionRuns(...)` and map runs into
240
+ `ChatMessage[]`, then `chat.setMessages(...)`.
241
+ - **Wire format** — handles both AgentOS streaming shapes (the legacy flat event
242
+ objects and the `{ event, data }` SSE envelope).
243
+ - **Dependencies** — the library itself depends only on React (peer). The
244
+ example additionally uses Vite.
245
+
246
+ ---
247
+
248
+ ## Local development
249
+
250
+ ```bash
251
+ git clone https://github.com/agno-agi/agno-chat-react.git
252
+ cd agno-chat-react
253
+ npm install
254
+ npm run typecheck # tsc --noEmit
255
+ npm run build # tsup -> dist/ (ESM + CJS + .d.ts)
256
+ ```
257
+
258
+ The published package is built with [tsup](https://tsup.egoist.dev) into
259
+ `dist/` (ESM `index.js`, CommonJS `index.cjs`, type declarations, and
260
+ `styles.css`). The `example/` app, however, resolves the library straight from
261
+ `src/` via a Vite alias, so you can develop against live changes without
262
+ rebuilding — see [Running the example](#running-the-example). `prepublishOnly`
263
+ runs the typecheck and build automatically, so `npm publish` always ships a
264
+ fresh `dist/`.
265
+
266
+ ---
267
+
268
+ ## License
269
+
270
+ [MIT](./LICENSE) © Agno