npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@agno-hq/chat-react

v0.1.0

Published

Headless React hook (useAgnoChat) + UI components for streaming Agno agents, teams, and workflows from an AgentOS backend.

Downloads

96

Readme

@agno-hq/chat-react

Headless React hook (useAgnoChat) plus drop-in UI components for streaming any Agno agent, team, or workflow from an AgentOS backend.

It speaks the AgentOS HTTP run protocol directly: it POSTs to the run endpoint, parses the streamed events, and accumulates them into render-ready messages — content, tool calls, reasoning, citations, media — while exposing the raw event feed, live status, and human-in-the-loop pauses.

import { AgnoChat } from '@agno-hq/chat-react'
import '@agno-hq/chat-react/styles.css'

export default function Page() {
  return <AgnoChat baseUrl="http://localhost:7777" showEventLog allowFiles />
}

That's the zero-wiring widget: it discovers the agents/teams/workflows on your AgentOS, shows a selector, and runs a full chat. For full control, use the hook.


Install

npm install @agno-hq/chat-react

react and react-dom (>=18) are peer dependencies. The library ships compiled ESM + CommonJS bundles with bundled type declarations, so it works out of the box in any modern bundler (Vite, Next.js, Webpack, etc.) with no extra config. Import the stylesheet once (see below).


The hook: useAgnoChat

import { useAgnoChat, ChatWindow } from '@agno-hq/chat-react'
import '@agno-hq/chat-react/styles.css'

function Chat() {
  const chat = useAgnoChat({
    baseUrl: 'http://localhost:7777',
    entity: { type: 'agent', id: 'agno_assist', name: 'Agno Assist' },
    userId: 'user-123',
  })

  return <ChatWindow chat={chat} />
}

entity.type is 'agent' | 'team' | 'workflow' and entity.id is the agent/team/workflow id — the same hook drives all three.

What the hook returns

| Value | Type | Description | |---|---|---| | messages | ChatMessage[] | Full transcript, oldest first. | | streamingMessage | ChatMessage \| null | The agent message currently streaming. | | events | RunEventData[] | Every raw event from the latest run, in order. | | currentEvent | RunEventData \| null | The most recent event. | | status | 'idle' \| 'streaming' \| 'paused' \| 'completed' \| 'error' \| 'cancelled' | Run lifecycle. | | activity | string \| null | Live label, e.g. "Calling get_weather", "Reasoning". | | isStreaming / isPaused | boolean | Convenience flags. | | error | string \| null | Last error message. | | sessionId | string \| undefined | Auto-captured from the first run. | | tools | ToolExecution[] | Tool calls of the active message. | | reasoning | ReasoningStep[] | Reasoning steps of the active message. | | pendingRequirements | RunRequirement[] | Outstanding human-in-the-loop asks. |

Actions

| Action | Description | |---|---| | sendMessage(text, { files? }) | Send a message and stream the response. | | cancel() | Abort the active run (also calls the cancel endpoint). | | continueRun({ tools?, stepRequirements? }) | Resume a paused run with resolved requirements. | | respondToConfirmation(approve) | Approve/reject pending tool confirmations, then continue. | | submitUserInput(values) | Provide values for pending input fields, then continue. | | reset() | Clear the transcript and start a new session. | | setMessages(...) | Replace the transcript (e.g. after restoring a session). | | client | The underlying AgnoClient for discovery/session calls. |


Components

All components are styled by @agno-hq/chat-react/styles.css (dark by default; add the agno-light class on a wrapper for light mode). Every piece is exported so you can compose your own layout.

| Component | Purpose | |---|---| | <AgnoChat> | All-in-one widget: discovery, selector, chat, optional event log. | | <ChatWindow chat={chat}> | Full chat surface built from a useAgnoChat result. | | <MessageList> | Auto-scrolling transcript with live status + footer slot. | | <Message> | A single message: content, tools, reasoning, media, citations. | | <ChatInput> | Multiline input with file attach, send, and stop. | | <ToolCalls> | Collapsible tool-call cards (name, args, result, status). | | <Reasoning> | Collapsible reasoning-steps panel. | | <Citations> | References / source URLs. | | <Multimedia> | Images, video, and audio attachments. | | <StatusIndicator> | Animated "what is it doing now" line. | | <EventLog> | Developer feed of every raw run event. | | <HumanInput> | Human-in-the-loop panel (confirm / reject / input). | | <EntitySelector> | Dropdown of agents, teams, and workflows. | | <SessionList> | Sidebar of past sessions — click to load, trash to delete. | | <Markdown> | The built-in lightweight Markdown renderer. |

Bring your own Markdown

The built-in renderer covers code blocks, inline code, bold/italic, links, headings and lists. For full GFM (tables, etc.), pass renderMarkdown:

import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'

<ChatWindow
  chat={chat}
  renderMarkdown={(c) => <ReactMarkdown remarkPlugins={[remarkGfm]}>{c}</ReactMarkdown>}
/>

Human-in-the-loop

When a run pauses for a tool confirmation or for user input, status becomes 'paused' and pendingRequirements / the paused message's tool_calls describe what's needed. <ChatWindow> renders <HumanInput> automatically; to build your own UI, call:

await chat.respondToConfirmation(true)        // approve pending tool calls
await chat.respondToConfirmation(false)       // reject
await chat.submitUserInput({ city: 'Lisbon' }) // fill input fields, then continue

Agents and teams resume via the /continue endpoint with resolved tools; workflows resume with step_requirements. The hook picks the right one based on the selected entity type.


Session history

The hook tracks past sessions for the selected entity:

const chat = useAgnoChat({ baseUrl, entity })

chat.sessions          // SessionEntry[]
chat.sessionsLoading   // boolean
await chat.refreshSessions()      // fetch the list
await chat.loadSession(sessionId) // load a transcript into the chat
await chat.deleteSession(sessionId)

Render them with <SessionList>:

<SessionList
  sessions={chat.sessions}
  activeSessionId={chat.sessionId}
  loading={chat.sessionsLoading}
  onSelect={chat.loadSession}
  onDelete={chat.deleteSession}
  onNew={chat.reset}
/>

The all-in-one widget shows this sidebar with showSessions:

<AgnoChat baseUrl="http://localhost:7777" showSessions showEventLog />

Lower-level API

import { AgnoClient, streamRun } from '@agno-hq/chat-react'

const client = new AgnoClient({ baseUrl: 'http://localhost:7777', headers: { Authorization: 'Bearer …' } })

await client.getEntities()                 // agents + teams + workflows
await client.getSessions('agent', 'agno_assist')
await client.getSessionRuns('agent', sessionId)   // rehydrate history
await client.cancelRun('agent', 'agno_assist', runId)

streamRun is the raw streaming primitive (parses the wire format and emits normalised events) if you want to bypass the hook entirely.


Running the example

The example/ folder is a Vite app demonstrating both the widget and the hook (with a live status panel + event log). It imports the library from source.

cd example
npm install
npm run dev

Then open the app, set your AgentOS URL (default http://localhost:7777), and pick an agent, team, or workflow.

Start an AgentOS first — see the Agno cookbooks under cookbook/05_agent_os/.

CORS

The chat runs in the browser, so your AgentOS must allow the page's origin. The example dev server is pinned to port 5173 (strictPort), so add that origin when constructing AgentOS:

AgentOS(..., cors_allowed_origins=["http://localhost:5173"])

A symptom of a CORS mismatch is an empty entity dropdown and a Disallowed CORS origin response to the preflight request.


Notes

  • Auth / headers — pass headers (or a pre-built client) to send an Authorization header on every request.
  • SessionssessionId is captured automatically on the first run. To restore history, call client.getSessionRuns(...) and map runs into ChatMessage[], then chat.setMessages(...).
  • Wire format — handles both AgentOS streaming shapes (the legacy flat event objects and the { event, data } SSE envelope).
  • Dependencies — the library itself depends only on React (peer). The example additionally uses Vite.

Local development

git clone https://github.com/agno-agi/agno-chat-react.git
cd agno-chat-react
npm install
npm run typecheck          # tsc --noEmit
npm run build              # tsup -> dist/ (ESM + CJS + .d.ts)

The published package is built with tsup into dist/ (ESM index.js, CommonJS index.cjs, type declarations, and styles.css). The example/ app, however, resolves the library straight from src/ via a Vite alias, so you can develop against live changes without rebuilding — see Running the example. prepublishOnly runs the typecheck and build automatically, so npm publish always ships a fresh dist/.


License

MIT © Agno