@aganzefelicite/responsekit-react
v0.4.0
Published
Render your AI backend's responses as interactive React UI: branded AiChat, login, AiRenderer, AiStream, useChat, admin client.
Maintainers
Readme
@aganzefelicite/responsekit-react
Render your AI backend's responses as interactive React UI. Point it at your backend and it turns the standardized response contract (streamed as SSE or a single object) into components — safely, and without ever crashing on unknown or invalid data.
- Renders only — never calls an AI model or generates responses.
- Never crashes — unknown block types / missing fields degrade to a safe fallback.
- Safe by default — AI text is GitHub-flavored Markdown with no raw HTML; data
values are escaped. No
dangerouslySetInnerHTML. - Lean bundle — tree-shakeable ESM, React as a peer dep; charts (Recharts) are lazy-loaded into their own chunk.
Full walkthrough: Adding ResponseKit to an existing project.
Install
pnpm add @aganzefelicite/responsekit-react react react-domimport "@aganzefelicite/responsekit-react/styles.css"; // optional default stylingThe response-contract package (types + zod validators + SSE reducer) is bundled in and
re-exported, so there's nothing else to install. react/react-dom are peer deps (>=18).
Drop-in branded chat (<AiChat />)
The fastest path: paste the URL the admin platform generated and get a fully branded,
authenticated chat. <AiChat> fetches the branding (name, theme, colors, logo) from the
backend, shows a login form, then renders the chat — scoped to that user's own conversations.
import { AiChat } from "@aganzefelicite/responsekit-react";
import "@aganzefelicite/responsekit-react/styles.css";
// The URL an admin generated in the admin console.
<AiChat baseUrl="https://assistant.acme.com" />;floating(defaulttrue) renders the draggable widget; setfalseto embed inline.- The session token is persisted in
localStorage; aLog outbutton clears it. - Theme comes from the admin's branding (
data-theme+--rk-primary/--rk-accent).
Prefer to build your own UI? Use the pieces directly:
import { useAuth, useWorkspaceConfig, useChat } from "@aganzefelicite/responsekit-react";
const { config } = useWorkspaceConfig(baseUrl); // branding
const { token, user, login, logout, headers } = useAuth({ baseUrl }); // login + token
const chat = useChat({ baseUrl, headers }); // authenticated chatAdmin client
For building an admin console (or scripts), admin.* wraps the platform's /api/admin/**
endpoints. Every call takes an ADMIN token.
import { admin } from "@aganzefelicite/responsekit-react";
await admin.updateWorkspace({ baseUrl, token, name: "Acme Insights", theme: "dark" });
await admin.uploadLogo({ baseUrl, token, file });
await admin.createUser({ baseUrl, token, username: "bob", password: "••••••••", role: "USER" });
await admin.updateContext({ baseUrl, token, text: "Orders = one row per order…" });
await admin.testDatabase({ baseUrl, token, uri: "postgresql://readonly:••@db/analytics" });
await admin.updateDatabase({ baseUrl, token, uri }); // probes, persists, reconnects MCPQuick start
import { AiRenderer, AiStream, useChat } from "@aganzefelicite/responsekit-react";
// 1) Render a response you already have
<AiRenderer response={response} onAction={(a) => {}} />;
// 2) Stream one message
<AiStream baseUrl="" conversationId={id} message="How many open cases?" onAction={(a) => {}} />;
// 3) A whole conversation
const { turns, send, isStreaming, newConversation } = useChat({ baseUrl: "" });baseUrl is prepended to the API paths; "" means same-origin (proxy /api to your
backend). The message endpoint is POST + text/event-stream; the SDK drives
fetch + ReadableStream internally (native EventSource can't POST).
API
Components — AiRenderer, AiStream, AiWidget (draggable/resizable pop-up)
Hooks — useAiStream, useChat
Actions — withDefaultActions, runDefaultAction, performDownload, performOpenLink, triggerDownload
Registry — registerBlock, unregisterBlock, resolveBlockComponent
Default blocks — TextBlock, KpiBlock, ChartBlock, TableBlock, InsightBlock,
RecommendationBlock, FilterBlock, FallbackBlock, defaultBlockComponents
Conversation REST — createConversation, listConversations, getConversation,
renameConversation, deleteConversation, getMessages
Transport — streamMessage, messageUrl
Misc — Markdown, ErrorBoundary, action types, and everything re-exported from
@responsekit/schema (types, validators, the stream reducer).
Overrides & custom blocks
// override built-ins for one render
<AiRenderer response={r} components={{ KPI: MyKpi, CHART: MyChart }} />;
// register a custom/unknown block type globally
import { registerBlock } from "@aganzefelicite/responsekit-react";
registerBlock({ type: "MAP", component: RwandaMap });Resolution order per block type: components prop → globally registered → built-in default
→ graceful fallback.
Floating widget
Wrap any content in a draggable, resizable pop-up with a launcher button:
import { AiWidget } from "@aganzefelicite/responsekit-react";
<AiWidget title="Assistant" defaultOpen>
{/* useChat + AiRenderer, a single AiRenderer, or your own chat UI */}
</AiWidget>;Drag by the header, resize from the bottom-right corner, toggle via the launcher (or
control open/onOpenChange). Chrome only — it never touches your data flow.
Actions
Blocks emit intent through one onAction(action) callback (DOWNLOAD, OPEN_LINK,
REFRESH, CUSTOM, or host-defined). The SDK never runs business logic — but for the two
actions with an obvious browser behavior it ships a default. Wrap your handler with
withDefaultActions and CSV/JSON/Blob downloads and link-opens work out of the box:
import { withDefaultActions } from "@aganzefelicite/responsekit-react";
<AiRenderer response={r} onAction={withDefaultActions((a) => track(a))} />;License
MIT
