@agno-hq/chat-react 0.1.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/README.md +327 -22
- package/dist/chat/index.cjs +314 -0
- package/dist/chat/index.cjs.map +1 -0
- package/dist/chat/index.d.cts +1225 -0
- package/dist/chat/index.d.ts +1225 -0
- package/dist/chat/index.js +5 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chunk-2WM3CCFE.cjs +106 -0
- package/dist/chunk-2WM3CCFE.cjs.map +1 -0
- package/dist/chunk-62IEW2HM.js +506 -0
- package/dist/chunk-62IEW2HM.js.map +1 -0
- package/dist/chunk-ERCKKOF4.cjs +3308 -0
- package/dist/chunk-ERCKKOF4.cjs.map +1 -0
- package/dist/chunk-MUOMZG4V.js +3226 -0
- package/dist/chunk-MUOMZG4V.js.map +1 -0
- package/dist/chunk-RE7ZT73K.js +102 -0
- package/dist/chunk-RE7ZT73K.js.map +1 -0
- package/dist/chunk-ROFIOWGX.cjs +530 -0
- package/dist/chunk-ROFIOWGX.cjs.map +1 -0
- package/dist/client-DUyVqxU9.d.cts +413 -0
- package/dist/client-DUyVqxU9.d.ts +413 -0
- package/dist/core/index.cjs +94 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +108 -0
- package/dist/core/index.d.ts +108 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/fonts.css +18 -0
- package/dist/index.cjs +395 -1959
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -835
- package/dist/index.d.ts +12 -835
- package/dist/index.js +3 -1925
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1898 -662
- package/dist/tokens.css +111 -0
- package/package.json +52 -7
package/README.md
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
# @agno-hq/chat-react
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Composable, embeddable React components for [AgentOS](https://docs.agno.com) —
|
|
4
|
+
a headless hook, a provider for building your own layout, and drop-in embeds for
|
|
5
|
+
streaming **any Agno agent, team, or workflow**.
|
|
6
|
+
|
|
7
|
+
| Subpath | Contents |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `@agno-hq/chat-react` | Everything below. |
|
|
10
|
+
| `@agno-hq/chat-react/core` | `AgnoClient`, run streaming, event helpers, types. No React rendering. |
|
|
11
|
+
| `@agno-hq/chat-react/chat` | `useAgnoChat`, `ChatProvider`, `AgnoChat`, and every building block. |
|
|
12
|
+
| `@agno-hq/chat-react/styles.css` | Tokens + component styles. |
|
|
13
|
+
| `@agno-hq/chat-react/tokens.css` | CSS variables only. |
|
|
14
|
+
| `@agno-hq/chat-react/fonts.css` | Inter + DM Mono (optional). |
|
|
5
15
|
|
|
6
16
|
It speaks the AgentOS HTTP run protocol directly: it POSTs to the run endpoint,
|
|
7
17
|
parses the streamed events, and accumulates them into render-ready messages —
|
|
@@ -9,16 +19,69 @@ content, tool calls, reasoning, citations, media — while exposing the raw even
|
|
|
9
19
|
feed, live status, and human-in-the-loop pauses.
|
|
10
20
|
|
|
11
21
|
```tsx
|
|
12
|
-
import { AgnoChat } from '@agno-hq/chat-react'
|
|
22
|
+
import { AgnoChat } from '@agno-hq/chat-react/chat'
|
|
13
23
|
import '@agno-hq/chat-react/styles.css'
|
|
24
|
+
import '@agno-hq/chat-react/fonts.css' // optional — Inter + DM Mono
|
|
14
25
|
|
|
15
26
|
export default function Page() {
|
|
16
|
-
return <AgnoChat baseUrl="http://localhost:7777"
|
|
27
|
+
return <AgnoChat baseUrl="http://localhost:7777" allowFiles />
|
|
17
28
|
}
|
|
18
29
|
```
|
|
19
30
|
|
|
20
|
-
That's the zero-wiring
|
|
21
|
-
AgentOS
|
|
31
|
+
That's the zero-wiring embed: it discovers the agents/teams/workflows on your
|
|
32
|
+
AgentOS and runs a full chat. It renders **no header** and fills its container,
|
|
33
|
+
so it drops into a page, a card, a drawer or a modal without fighting your
|
|
34
|
+
layout — put your own chrome in the `header` slot.
|
|
35
|
+
|
|
36
|
+
Support chat on every page is the same component in launcher mode:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<AgnoChat mode="launcher" baseUrl="..." launcherLabel="Chat with us" />
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Compose it instead
|
|
43
|
+
|
|
44
|
+
`<ChatProvider>` runs the chat and shares it through context, so every component
|
|
45
|
+
below reads it with no props:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { ChatProvider, MessageList, ChatInput } from '@agno-hq/chat-react/chat'
|
|
49
|
+
|
|
50
|
+
<ChatProvider baseUrl="http://localhost:7777" entity={agent}>
|
|
51
|
+
<MyOwnHeader />
|
|
52
|
+
<MessageList />
|
|
53
|
+
<ChatInput />
|
|
54
|
+
</ChatProvider>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Reach for `useChatContext()` to drive it from your own components, or call
|
|
58
|
+
`useAgnoChat` directly and render nothing of ours.
|
|
59
|
+
|
|
60
|
+
### Customize it
|
|
61
|
+
|
|
62
|
+
Three independent levers:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
/* 1. Tokens — palette, radii and shadows from agno-os/globals.css */
|
|
66
|
+
:root { --color-brand-brand: 99, 102, 241; --agno-radius-lg: 1.25rem; }
|
|
67
|
+
|
|
68
|
+
/* 2. Slots — every element is addressable by name */
|
|
69
|
+
<AgnoChat classNames={{ root: 'rounded-2xl', textarea: 'font-mono' }} />
|
|
70
|
+
|
|
71
|
+
/* 3. Replacement — swap any piece for your own */
|
|
72
|
+
<ChatWindow composer={<MyComposer />} header={<MyBar />} />
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The built-in classes stay on the elements, so Tailwind utilities layer on top
|
|
76
|
+
rather than replacing them. Import only `tokens.css` (or nothing) to style from
|
|
77
|
+
scratch.
|
|
78
|
+
|
|
79
|
+
### Storybook
|
|
80
|
+
|
|
81
|
+
`npm run storybook` runs the component gallery locally; every story streams
|
|
82
|
+
against a scripted in-memory backend, so it exercises the real hook and the real
|
|
83
|
+
event reducers without an AgentOS running. Pushes to `main` publish it to GitHub
|
|
84
|
+
Pages via `.github/workflows/storybook.yml`.
|
|
22
85
|
|
|
23
86
|
---
|
|
24
87
|
|
|
@@ -89,32 +152,248 @@ agent/team/workflow id — the same hook drives all three.
|
|
|
89
152
|
|
|
90
153
|
## Components
|
|
91
154
|
|
|
92
|
-
All components are styled by `@agno-hq/chat-react/styles.css
|
|
93
|
-
|
|
94
|
-
|
|
155
|
+
All components are styled by `@agno-hq/chat-react/styles.css`, which carries the
|
|
156
|
+
Agno OS design system — the same colour tokens, radii, Inter/DM Mono type scale
|
|
157
|
+
and chat layout as the AgentOS chat page. It is dark by default; add the
|
|
158
|
+
`agno-light` class on a wrapper for light mode (`agno-dark` is accepted too, for
|
|
159
|
+
apps that toggle both). Every piece is exported so you can compose your own
|
|
160
|
+
layout.
|
|
161
|
+
|
|
162
|
+
Theme it by overriding the tokens on your wrapper — they are the AgentOS ones,
|
|
163
|
+
as `R, G, B` triples:
|
|
164
|
+
|
|
165
|
+
```css
|
|
166
|
+
.agno-root.my-brand {
|
|
167
|
+
--color-brand-brand: 255, 64, 23;
|
|
168
|
+
--color-background: 17, 17, 19;
|
|
169
|
+
--color-background-secondary: 39, 39, 42;
|
|
170
|
+
}
|
|
171
|
+
```
|
|
95
172
|
|
|
96
173
|
| Component | Purpose |
|
|
97
174
|
|---|---|
|
|
98
|
-
| `<AgnoChat>` | All-in-one widget: discovery, selector, chat, optional event
|
|
175
|
+
| `<AgnoChat>` | All-in-one widget: discovery, selector, chat, optional per-run event feed. |
|
|
99
176
|
| `<ChatWindow chat={chat}>` | Full chat surface built from a `useAgnoChat` result. |
|
|
177
|
+
| `<ChatLauncher>` | Floating support-widget shell: a corner bubble that opens any chat surface. |
|
|
178
|
+
| `<QuickPrompts>` | Suggested-prompt chips. |
|
|
100
179
|
| `<MessageList>` | Auto-scrolling transcript with live status + footer slot. |
|
|
101
|
-
| `<Message>` | A single message: content,
|
|
180
|
+
| `<Message>` | A single message: content, behind-the-scenes panel, media, citations, follow-ups. |
|
|
181
|
+
| `<BehindTheScenes>` | One collapsible timeline over a run's reasoning, tools, member turns, steps and events — doubles as the live status line. |
|
|
102
182
|
| `<ChatInput>` | Multiline input with file attach, send, and stop. |
|
|
103
183
|
| `<ToolCalls>` | Collapsible tool-call cards (name, args, result, status). |
|
|
104
184
|
| `<Reasoning>` | Collapsible reasoning-steps panel. |
|
|
105
|
-
| `<Citations>` |
|
|
185
|
+
| `<Citations>` | The sources behind an answer, as linked cards. |
|
|
186
|
+
| `<Followups>` | "Related questions" — the follow-up prompts an agent suggests after its answer. |
|
|
106
187
|
| `<Multimedia>` | Images, video, and audio attachments. |
|
|
107
188
|
| `<StatusIndicator>` | Animated "what is it doing now" line. |
|
|
108
|
-
| `<EventLog>` | Developer feed of
|
|
189
|
+
| `<EventLog>` | Developer feed of raw run events — render it yourself from `chat.events`. |
|
|
109
190
|
| `<HumanInput>` | Human-in-the-loop panel (confirm / reject / input). |
|
|
110
191
|
| `<EntitySelector>` | Dropdown of agents, teams, and workflows. |
|
|
111
192
|
| `<SessionList>` | Sidebar of past sessions — click to load, trash to delete. |
|
|
112
|
-
| `<Markdown>` |
|
|
193
|
+
| `<Markdown>` | Markdown, rendered by Streamdown — GFM, and repair for half-written text mid-stream. |
|
|
194
|
+
|
|
195
|
+
### Inline, or a floating support widget
|
|
196
|
+
|
|
197
|
+
`<AgnoChat>` renders inline by default — a panel wherever you put it, sized by
|
|
198
|
+
`width` and `height`:
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
<AgnoChat baseUrl="http://localhost:7777" width={720} height={560} />
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`mode="launcher"` turns it into the support-chat layout instead: a bubble pinned
|
|
205
|
+
to a corner of the viewport that opens the chat. Mount it once, anywhere in your
|
|
206
|
+
app — it renders into `document.body`, so no wrapper can clip it.
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
<AgnoChat
|
|
210
|
+
baseUrl="http://localhost:7777"
|
|
211
|
+
mode="launcher"
|
|
212
|
+
position="bottom-right"
|
|
213
|
+
launcherLabel="Chat with us"
|
|
214
|
+
width={400}
|
|
215
|
+
height={620}
|
|
216
|
+
/>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
| Prop | Default | Description |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `mode` | `'inline'` | `'inline'` renders in place; `'launcher'` pins a bubble to a corner. |
|
|
222
|
+
| `position` | `'bottom-right'` | Corner to pin to: also `bottom-left`, `top-right`, `top-left`. |
|
|
223
|
+
| `offset` | `24` | Distance from both edges of that corner. Number means px. |
|
|
224
|
+
| `panel` | `'popover'` | How far it opens: a corner popover, or `'fullscreen'` over the page. |
|
|
225
|
+
| `width` / `height` | `400` / `620` | Size of the popover (and of the inline panel). |
|
|
226
|
+
| `launcherLabel` | — | Text beside the bubble glyph. Icon-only without it. |
|
|
227
|
+
| `launcherIcon` | speech bubble | Replaces the default glyph. |
|
|
228
|
+
| `defaultOpen` | `false` | Open on first render. |
|
|
229
|
+
| `open` / `onOpenChange` | — | Control the open state yourself (e.g. from your own "Help" button). |
|
|
230
|
+
|
|
231
|
+
A `'fullscreen'` panel covers the page and closes from an X in the chat header;
|
|
232
|
+
a popover closes from the bubble, which becomes an X. Escape closes either, and
|
|
233
|
+
below 480px wide a popover goes full-screen on its own. The conversation is kept
|
|
234
|
+
across close/open — a run that is still streaming keeps streaming.
|
|
235
|
+
|
|
236
|
+
To give your own layout the same behaviour, wrap it in `<ChatLauncher>`:
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
<ChatLauncher position="bottom-left" panel="fullscreen" label="Support">
|
|
240
|
+
<ChatWindow chat={chat} />
|
|
241
|
+
</ChatLauncher>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Errors
|
|
245
|
+
|
|
246
|
+
A failed run leaves its message on `chat.error`, but nothing is rendered by
|
|
247
|
+
default — raw backend errors are long, and they crowd a narrow window. Opt in
|
|
248
|
+
with `showErrors` on `<AgnoChat>` or `<ChatWindow>`:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
<AgnoChat baseUrl="http://localhost:7777" showErrors />
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Or render it wherever suits your layout — a toast, say:
|
|
255
|
+
|
|
256
|
+
```tsx
|
|
257
|
+
{chat.error && <Toast>{chat.error}</Toast>}
|
|
258
|
+
```
|
|
113
259
|
|
|
114
|
-
###
|
|
260
|
+
### Quick prompts
|
|
115
261
|
|
|
116
|
-
|
|
117
|
-
|
|
262
|
+
`quickPrompts` offers suggested prompts while the transcript is empty. Clicking
|
|
263
|
+
one sends it. A chip is either the prompt itself, or a short label that sends
|
|
264
|
+
something longer:
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
<AgnoChat
|
|
268
|
+
baseUrl="http://localhost:7777"
|
|
269
|
+
quickPrompts={[
|
|
270
|
+
'What can you do?',
|
|
271
|
+
{ label: 'Pricing', prompt: 'How does pricing work?' },
|
|
272
|
+
{ label: 'Talk to a human', prompt: 'I would like to talk to a human.' },
|
|
273
|
+
]}
|
|
274
|
+
/>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
`<ChatWindow>` takes the same prop, plus `onQuickPrompt` to do something other
|
|
278
|
+
than send the text. Render `<QuickPrompts>` yourself to place the chips
|
|
279
|
+
elsewhere.
|
|
280
|
+
|
|
281
|
+
### Run events
|
|
282
|
+
|
|
283
|
+
Every run keeps the events that produced it on its own message
|
|
284
|
+
(`message.events`) — live, and for runs restored from session history when the
|
|
285
|
+
agent stores them. `<BehindTheScenes>` builds its steps from those events the
|
|
286
|
+
way the AgentOS chat does: content deltas, model-request and reasoning-delta
|
|
287
|
+
events are dropped, started/completed pairs collapse into one step, and run
|
|
288
|
+
lifecycle events read as "Run Started" / "Run Completed" with the reported
|
|
289
|
+
duration. A message with no events falls back to what it does carry (tools,
|
|
290
|
+
reasoning, member turns, workflow steps).
|
|
291
|
+
|
|
292
|
+
The raw feed is not part of that panel. `chat.events` holds the latest run's
|
|
293
|
+
events, and every message keeps its own in `message.events` — render either
|
|
294
|
+
with `<EventLog>` wherever you want it:
|
|
295
|
+
|
|
296
|
+
```tsx
|
|
297
|
+
<EventLog events={chat.events} maxHeight={240} />
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Citations, sources and link previews
|
|
301
|
+
|
|
302
|
+
Whatever a run cites — knowledge-base chunks in `references`, browsed links in
|
|
303
|
+
`citations.urls` — is flattened into one numbered list and rendered as cards
|
|
304
|
+
under the answer: the site's favicon and the title, linking to the source. A
|
|
305
|
+
`[1]` in the answer text becomes a chip pointing at card one, and hovering
|
|
306
|
+
either the chip or a link opens a preview with the URL and the cited passage:
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
<Message message={message} /> // markers, cards and previews, no props
|
|
310
|
+
<Message message={message} hideSources /> // just the answer
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The hostname and favicon come from the URL itself, and the title and passage
|
|
314
|
+
from the citation payload, so previews need no network of their own. To fill in
|
|
315
|
+
OpenGraph metadata, hand the provider a `resolveLinkPreview` — the browser can't
|
|
316
|
+
read another origin's meta tags, so back it with an endpoint of your own. It is
|
|
317
|
+
called once per URL, on first hover:
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
<ChatProvider
|
|
321
|
+
baseUrl="http://localhost:7777"
|
|
322
|
+
resolveLinkPreview={async (url) => {
|
|
323
|
+
const res = await fetch(`/api/og?url=${encodeURIComponent(url)}`)
|
|
324
|
+
return res.ok ? res.json() : null // { title, description, image, siteName, favicon }
|
|
325
|
+
}}
|
|
326
|
+
>
|
|
327
|
+
<ChatWindow />
|
|
328
|
+
</ChatProvider>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Plenty of runs carry no `references` or `citations` at all — the model cites in
|
|
332
|
+
the answer itself, as numbered links, and lists the titles at the end:
|
|
333
|
+
|
|
334
|
+
```text
|
|
335
|
+
Call `Agent.run()` in production. [1](https://docs.agno.com/agents/building-agents)
|
|
336
|
+
|
|
337
|
+
Sources: [Building Agents](https://docs.agno.com/agents/building-agents)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
That reads the same way: the numbered link becomes the chip, the labelled link
|
|
341
|
+
names the card, and the numbering stays exactly as the model wrote it. Links in
|
|
342
|
+
prose are left alone — only numbered ones count as citations.
|
|
343
|
+
|
|
344
|
+
Rendering sources yourself? `collectSources(references, citations)` and
|
|
345
|
+
`sourcesFromMarkdown(content)` are the same numbering the components use, and
|
|
346
|
+
`<SourceCard>`, `<LinkPreviewCard>` and `<HoverPreview>` are exported to build
|
|
347
|
+
with.
|
|
348
|
+
|
|
349
|
+
### Follow-ups
|
|
350
|
+
|
|
351
|
+
An agent built with `followups=True` suggests what to ask next once it has
|
|
352
|
+
answered. They sit above the composer as "Related questions", one line each —
|
|
353
|
+
the full text is on hover — and clicking one sends it:
|
|
354
|
+
|
|
355
|
+
```tsx
|
|
356
|
+
<AgnoChat baseUrl="http://localhost:7777" /> // on by default
|
|
357
|
+
<AgnoChat baseUrl="http://localhost:7777" hideFollowups /> // off
|
|
358
|
+
<AgnoChat baseUrl="http://localhost:7777" followupsTitle="Ask next" /> // your own heading
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Only the latest answer offers them; earlier ones have been answered by the
|
|
362
|
+
conversation moving on. They arrive as a `FollowupsCompleted` event and are
|
|
363
|
+
stored on the run, so a reloaded session still shows them. To put them under
|
|
364
|
+
the answer instead, pass `<Message onFollowup={chat.sendMessage}>`; to place
|
|
365
|
+
them anywhere else, render `<Followups>` yourself from `message.followups` —
|
|
366
|
+
`lines` lets them wrap instead of clamping.
|
|
367
|
+
|
|
368
|
+
### Markdown
|
|
369
|
+
|
|
370
|
+
Answers are rendered by [Streamdown](https://streamdown.ai), which is built for
|
|
371
|
+
text that arrives a token at a time: mid-stream it repairs the unterminated
|
|
372
|
+
bold, the half-written link and the unclosed fence instead of showing you the
|
|
373
|
+
raw characters. GFM comes with it — tables, task lists, strikethrough — along
|
|
374
|
+
with a sanitising pass over the HTML.
|
|
375
|
+
|
|
376
|
+
Streamdown styles itself with Tailwind utility classes. Every element is mapped
|
|
377
|
+
back onto this package's own `agno-md-*` classes, so **Tailwind is not
|
|
378
|
+
required** and the shipped stylesheet and tokens still govern the look.
|
|
379
|
+
|
|
380
|
+
Fenced code blocks get a header naming the language, a line-number gutter and
|
|
381
|
+
syntax highlighting by [Shiki](https://shiki.style). The highlighter loads on
|
|
382
|
+
the first fenced block, not before, and grammars load one at a time as
|
|
383
|
+
languages appear; a language Shiki doesn't know renders plain. Colours follow
|
|
384
|
+
the theme class like everything else. `--agno-code-max-height` (default `32rem`)
|
|
385
|
+
caps a block before it scrolls.
|
|
386
|
+
|
|
387
|
+
The header also holds a copy button. Turn it off per-renderer or for a whole
|
|
388
|
+
tree:
|
|
389
|
+
|
|
390
|
+
```tsx
|
|
391
|
+
<Markdown content={answer} codeCopy={false} />
|
|
392
|
+
<ChatProvider codeCopy={false}>…</ChatProvider>
|
|
393
|
+
<AgnoChat codeCopy={false} />
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Prefer a different renderer? `renderMarkdown` replaces it entirely:
|
|
118
397
|
|
|
119
398
|
```tsx
|
|
120
399
|
import ReactMarkdown from 'react-markdown'
|
|
@@ -126,6 +405,10 @@ import remarkGfm from 'remark-gfm'
|
|
|
126
405
|
/>
|
|
127
406
|
```
|
|
128
407
|
|
|
408
|
+
Note that `streamdown` is ESM-only, as is the remark/rehype ecosystem under it.
|
|
409
|
+
Bundlers resolve that fine; a bare `require()` of the CJS entry needs Node
|
|
410
|
+
22.12+.
|
|
411
|
+
|
|
129
412
|
---
|
|
130
413
|
|
|
131
414
|
## Human-in-the-loop
|
|
@@ -161,12 +444,20 @@ await chat.loadSession(sessionId) // load a transcript into the chat
|
|
|
161
444
|
await chat.deleteSession(sessionId)
|
|
162
445
|
```
|
|
163
446
|
|
|
447
|
+
The list updates optimistically, as the AgentOS chat does: the moment a run
|
|
448
|
+
reports its session id, that session moves to the top of `chat.sessions` —
|
|
449
|
+
created on the spot, named after the message that started it, if the backend
|
|
450
|
+
just made it — rather than only appearing after the next `refreshSessions()`.
|
|
451
|
+
A later refresh keeps the in-flight session even if the backend has not
|
|
452
|
+
persisted it yet.
|
|
453
|
+
|
|
164
454
|
Render them with `<SessionList>`:
|
|
165
455
|
|
|
166
456
|
```tsx
|
|
167
457
|
<SessionList
|
|
168
458
|
sessions={chat.sessions}
|
|
169
459
|
activeSessionId={chat.sessionId}
|
|
460
|
+
streamingSessionIds={chat.streamingSessionIds}
|
|
170
461
|
loading={chat.sessionsLoading}
|
|
171
462
|
onSelect={chat.loadSession}
|
|
172
463
|
onDelete={chat.deleteSession}
|
|
@@ -174,10 +465,22 @@ Render them with `<SessionList>`:
|
|
|
174
465
|
/>
|
|
175
466
|
```
|
|
176
467
|
|
|
468
|
+
`streamingSessionIds` marks the sessions with a run in flight — each shows a
|
|
469
|
+
spinner in place of the delete button.
|
|
470
|
+
|
|
471
|
+
### Switching session does not stop the run
|
|
472
|
+
|
|
473
|
+
Selecting another session (or starting a new chat) while a run is streaming
|
|
474
|
+
*parks* that run instead of cancelling it, as the AgentOS chat does: it keeps
|
|
475
|
+
streaming in the background, stays listed in `chat.streamingSessionIds`, and
|
|
476
|
+
`loadSession` restores it — mid-stream or finished — when you switch back,
|
|
477
|
+
rather than refetching a transcript that is still being written. Only
|
|
478
|
+
`chat.cancel()` stops a run.
|
|
479
|
+
|
|
177
480
|
The all-in-one widget shows this sidebar with `showSessions`:
|
|
178
481
|
|
|
179
482
|
```tsx
|
|
180
|
-
<AgnoChat baseUrl="http://localhost:7777" showSessions
|
|
483
|
+
<AgnoChat baseUrl="http://localhost:7777" showSessions />
|
|
181
484
|
```
|
|
182
485
|
|
|
183
486
|
---
|
|
@@ -202,8 +505,9 @@ normalised events) if you want to bypass the hook entirely.
|
|
|
202
505
|
|
|
203
506
|
## Running the example
|
|
204
507
|
|
|
205
|
-
The `example/` folder is a Vite app demonstrating
|
|
206
|
-
(with a live status panel + event log).
|
|
508
|
+
The `example/` folder is a Vite app demonstrating the widget, the floating
|
|
509
|
+
launcher, every component, and the hook (with a live status panel + event log).
|
|
510
|
+
It imports the library from source.
|
|
207
511
|
|
|
208
512
|
```bash
|
|
209
513
|
cd example
|
|
@@ -251,6 +555,7 @@ A symptom of a CORS mismatch is an empty entity dropdown and a
|
|
|
251
555
|
git clone https://github.com/agno-agi/agno-chat-react.git
|
|
252
556
|
cd agno-chat-react
|
|
253
557
|
npm install
|
|
558
|
+
npm test # Node test runner
|
|
254
559
|
npm run typecheck # tsc --noEmit
|
|
255
560
|
npm run build # tsup -> dist/ (ESM + CJS + .d.ts)
|
|
256
561
|
```
|
|
@@ -260,8 +565,8 @@ The published package is built with [tsup](https://tsup.egoist.dev) into
|
|
|
260
565
|
`styles.css`). The `example/` app, however, resolves the library straight from
|
|
261
566
|
`src/` via a Vite alias, so you can develop against live changes without
|
|
262
567
|
rebuilding — see [Running the example](#running-the-example). `prepublishOnly`
|
|
263
|
-
runs the typecheck and build automatically, so `npm publish` always
|
|
264
|
-
fresh `dist/`.
|
|
568
|
+
runs the tests, typecheck, and build automatically, so `npm publish` always
|
|
569
|
+
ships a fresh `dist/`.
|
|
265
570
|
|
|
266
571
|
---
|
|
267
572
|
|