Skip to content

@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).

tsx
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:

StoreHolds
$status, $error, $executionId, $capabilities, $transportModeAgent run state and transport
$events, $messages, $isStreaming, $streamingContent, $agentStateEvent log, derived messages, live text streaming, agent state
$threads, $activeThreadId, $threadsLoading, $threadsErrorThread list and selection
$pendingToolCalls, $deferredsLive tool-call lifecycle and human-in-the-loop deferreds
$tools, $renderers, $serializedToolsFrontend tool registry (Zod → JSON schema)
$surfacesActive 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

HookReturns
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

tsx
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:

tsx
import { FireFlowProvider } from '@persistent-ai/fireflow-agui-react'
import { CopilotKitAgentChat } from '@persistent-ai/fireflow-agui-react/copilotkit'

<FireFlowProvider agent={config} copilotKit>
  <CopilotKitAgentChat />
</FireFlowProvider>

Exports

EntryContents
.FireFlowProvider, all hooks, Effector stores, components, styled components, theming helpers, and CopilotKit types
./copilotkitCopilotKitBridge, 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)
  • @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


View source on GitHub →

Licensed under BUSL-1.1