@persistent-ai/fireflow-agui-react
React components, hooks, and an optional CopilotKit bridge for building chat UIs on top of FireFlow AG-UI agents.
What it is
The client half of FireFlow's conversational layer. It connects a React UI to a FireFlowServerAgent (from @persistent-ai/fireflow-agui) and renders the live conversation, agent state, tool-call lifecycle, and declarative generative UI from a single AG-UI event stream.
The package wraps a FireFlowAgent (the client transport, SSE or WebSocket) in a forked Effector scope, drives a set of stores from incoming AG-UI events, and exposes that state through React context and hooks. You can build a fully custom chat surface from the hooks, drop in the bundled components, or hand rendering to CopilotKit via the optional bridge.
Provider, hook, and store model
FireFlowProvider
FireFlowProvider is the single entry point. It creates the Effector scope once per mount, wires the agent's AG-UI subscriptions into the stores, and layers the context providers your hooks read from. It accepts either a live FireFlowAgent or a FireFlowAgentConfig (which it constructs and disposes for you).
interface FireFlowProviderProps {
agent: FireFlowAgent | FireFlowAgentConfig
threads?: ThreadsClient | ThreadsClientConfig | false // thread list/history; false = disabled
threadId?: string // initial active thread
toolExecutor?: (name: string, args: Record<string, unknown>) => Promise<string>
onThreadChange?: (threadId: string) => void
copilotKit?: boolean | CopilotKitBridgeConfig // lazy-loads the bridge when set
theme?: Partial<FireFlowTheme>
children: ReactNode
}The provider nests its layers from outermost to innermost as:
Effector Provider (forked scope)
ThemeContext
WiringLayer — subscribes the agent to the stores, syncs client tools, fetches capabilities
ThreadContextProvider — threads, activeThreadId, switch/create/refetch, history
ToolContextProvider — registered tools, renderers, live pendingToolCalls
A2UIContextProvider — A2UI surfaces, dispatchAction()
AgentContextProvider — status, error, executionId, messages, agentState, capabilities, sendMessage, abort
[CopilotKitBridge] — optional, lazy-loaded
{children}WiringLayer connects three subscriptions to the agent: run/message/event subscriptions feeding the stores, a tool subscriber that dispatches each agent tool call (registered handler → toolExecutor prop → human-in-the-loop deferred), and a restorer for unanswered tool calls coming from a MESSAGES_SNAPSHOT. Switching threads aborts the active run and resets the conversation stores.
Effector stores
Incoming AG-UI events are routed (via Effector split()) into stores that accumulate the conversation:
| Store | Holds |
|---|---|
$status, $error, $executionId, $capabilities, $transportMode | Agent run state and transport |
$events, $messages, $isStreaming, $streamingContent, $agentState | Event log, derived messages, live text streaming, agent state |
$threads, $activeThreadId, $threadsLoading, $threadsError | Thread list and selection |
$pendingToolCalls, $deferreds | Live tool-call lifecycle and human-in-the-loop deferreds |
$tools, $renderers, $serializedTools | Frontend tool registry (Zod → JSON schema) |
$surfaces | Active A2UI surfaces keyed by surface ID |
All stores reset on aguiReset (unmount or thread change). The stores are exported for advanced consumers, but most apps interact through the hooks below.
Hooks
| Hook | Returns |
|---|---|
useFireFlowAgent() | agent, status, error, executionId, transportMode, setTransportMode, capabilities |
useAgentStatus() | status, isRunning, isIdle, isError, error, executionId |
useAgentMessages() | messages, isStreaming, streamingContent |
useAgentState<T>() | state, previousState |
useAgentEvents(opts?) | events, latestEvent, clearEvents (optional filter by event type) |
useSendMessage() | sendMessage, abort, isLoading |
useThreads() | threads, activeThreadId, setActiveThread, createNewThread, refetch, isLoading, error |
useThreadHistory(threadId) | messages, state, activeRun, isLoading, error |
useFireFlowTool(def) | Register a raw ToolRegistration |
useAgentTool<T>(def, deps?) | Register an automated frontend tool with a handler |
useAgentHumanInTheLoop<T>(def, deps?) | Register an interactive tool that pauses the run until the user calls respond() in its render component |
useToolRenderers() | The map of registered tool renderers |
useA2UISurface(id) | A single Surface or null |
useA2UISurfaces() | surfaces map and getSurface(id) |
useA2UIAction() | dispatchAction to send a surface action back to the agent |
useAgentTool and useAgentHumanInTheLoop are the AG-UI-native equivalents of CopilotKit's useFrontendTool and useHumanInTheLoop; they work with or without the CopilotKit bridge.
A2UI surface rendering
When the agent emits A2UI activity (ACTIVITY_SNAPSHOT / ACTIVITY_DELTA events), surfaces accumulate in $surfaces. The A2UISurface component renders a single surface by ID via @copilotkit/a2ui-renderer's A2UIViewer, which is lazy-loaded so its peer dependency is only needed when A2UI is actually used. User actions on a surface are routed through dispatchAction(), which writes the action into agent state and calls agent.resume(surfaceId, action) to unblock a waiting interactive node on the server. A2UISurfaceList renders all active surfaces.
Components
Bundled, theme-aware building blocks (exported from .): AgentStatus, EventStream, ThreadList, ToolRenderer, PendingToolsOverlay, A2UISurface, A2UISurfaceList, plus pre-styled variants StyledAgentChat, StyledEventStream, StyledThreadList and the ThemeContext / useTheme / mergeTheme theming helpers.
Optional CopilotKit bridge
Set copilotKit on the provider (or import from @persistent-ai/fireflow-agui-react/copilotkit) to render the conversation with CopilotKit. The bridge wraps children in CopilotKitProvider with the FireFlow agent registered, syncs FireFlow's tool renderers into CopilotKit's inline render registry, and renders A2UI surfaces inline in the assistant message. CopilotKitAgentChat is a pre-wired chat component. @copilotkit/react-core is an optional peer dependency and is only loaded when the bridge is used.
Usage sketch
import { FireFlowProvider, useAgentMessages, useSendMessage, useAgentHumanInTheLoop } from '@persistent-ai/fireflow-agui-react'
import { z } from 'zod'
function Chat() {
const { messages, isStreaming, streamingContent } = useAgentMessages()
const { sendMessage, isLoading } = useSendMessage()
// A human-in-the-loop tool: pauses the run until the user responds.
useAgentHumanInTheLoop({
name: 'confirmAction',
description: 'Ask the user to confirm an action',
parameters: z.object({ summary: z.string() }),
render: ({ args, status, respond }) =>
status === 'executing'
? <button onClick={() => respond?.('confirmed')}>Confirm: {args.summary}</button>
: <span>{args.summary}</span>,
})
return (
<>
{messages.map(m => <div key={m.id}>{m.role}: {/* render content */}</div>)}
{isStreaming && <div>{streamingContent}</div>}
<button disabled={isLoading} onClick={() => sendMessage('Hello')}>Send</button>
</>
)
}
export function App() {
return (
<FireFlowProvider
agent={{ /* FireFlowAgentConfig: endpoint, agentId, transport, ... */ }}
threads={{ /* ThreadsClientConfig */ }}
>
<Chat />
</FireFlowProvider>
)
}To render with CopilotKit instead, pass copilotKit and use the bundled chat:
import { FireFlowProvider } from '@persistent-ai/fireflow-agui-react'
import { CopilotKitAgentChat } from '@persistent-ai/fireflow-agui-react/copilotkit'
<FireFlowProvider agent={config} copilotKit>
<CopilotKitAgentChat />
</FireFlowProvider>Exports
| Entry | Contents |
|---|---|
. | FireFlowProvider, all hooks, Effector stores, components, styled components, theming helpers, and CopilotKit types |
./copilotkit | CopilotKitBridge, CopilotKitAgentChat, useCopilotKitAgent (runtime; requires the @copilotkit/react-core peer dependency) |
CopilotKit runtime exports are kept off the main barrel so the peer dependency is never evaluated for consumers who do not use it.
Peer dependencies
react^19.2.0(required)@copilotkit/react-core>=1.50.0(optional — only for the CopilotKit bridge and A2UI rendering)
Related
@persistent-ai/fireflow-agui— the server agent (FireFlowServerAgent), SSE/WebSocket handlers, thread store, and A2UI processor that this package connects to.
License
Business Source License 1.1 (BUSL-1.1) — see LICENSE.txt