@syncagent/react
React SDK for SyncAgent — drop-in AI database chat widget and hooks.
Install
npm install @syncagent/react @syncagent/js
Quick Start
import { SyncAgentChat } from "@syncagent/react";
export default function App() {
return (
<SyncAgentChat
config={{
apiKey: "sa_your_api_key",
connectionString: process.env.DATABASE_URL,
// baseUrl: "http://localhost:3100", // dev only
}}
/>
);
}
<SyncAgentChat> Props
config | SyncAgentConfig | Required* | API key, connection string, tools, baseUrl |
mode | "floating" | "inline" | "floating" | Floating FAB or embedded inline panel |
position | "bottom-right" | "bottom-left" | "bottom-right" | FAB position (floating mode only) |
defaultOpen | boolean | false | Start with the panel open |
title | string | "SyncAgent" | Header title |
subtitle | string | "AI Database Assistant" | Header subtitle (replaced by status while active) |
placeholder | string | "Ask anything..." | Input placeholder |
welcomeMessage | string | "Hi! I can query..." | Empty state message |
accentColor | string | "#10b981" | Brand color for header, FAB, send button |
suggestions | string[] | ["Show all records", ...] | Quick-start suggestion chips |
persistKey | string | — | localStorage key for conversation persistence |
context | Record<string, any> | — | Extra context injected into every message |
filter | Record<string, any> | — | Mandatory query filter — scopes ALL DB operations. Use for multi-tenant SaaS. |
operations | ("read"|"create"|"update"|"delete")[] | — | Restrict operations for this session. Subset of project's configured ops. |
onReaction | (idx, reaction, content) => void | — | Called when user reacts 👍/👎 to a message |
onData | (data: ToolData) => void | — | Called when a DB tool returns structured data |
className | string | — | CSS class on the panel container |
style | CSSProperties | — | Inline styles on the panel container |
*config is required unless wrapped in <SyncAgentProvider>.
Features
- Live status — header subtitle shows
● Querying users... while the agent works
- Markdown rendering — tables, code blocks, bold, italic, lists, headers
- Streaming cursor — blinking cursor while text streams in
- Copy button — on every AI response
- Reactions — 👍/👎 on AI messages, fires
onReaction
- Retry — retry button on failed messages
- Conversation persistence — pass
persistKey to save history to localStorage
- New conversation — "New" button in header clears history
- Suggestion chips — configurable quick-start prompts, with pin/unpin to localStorage
- Query history — ↑/↓ in input to cycle through previous messages
- Export CSV — "⬇ CSV" button on messages containing markdown tables
- Bar charts — auto-renders aggregation results as a mini bar chart
- Resize handle — drag the top edge to resize the floating panel
- Mobile responsive — full-width on small screens
- Dark mode — respects
prefers-color-scheme
Multi-tenant SaaS — scoping queries per organization
Pass filter to scope every agent operation to the current user's organization. Enforced server-side — the agent cannot query outside this scope.
<SyncAgentChat
config={{
apiKey: "sa_your_key",
connectionString: process.env.DATABASE_URL,
filter: { organizationId: currentUser.orgId },
}}
/>
Without filter — agent queries everything (single-tenant or admin tools).
With filter — every read, write, update, and delete is strictly scoped.
filter: { organizationId: org.id }
filter: { tenant: "acme-corp" }
filter: { userId: currentUser.id }
filter: { orgId: org.id, deleted: false }
Conversation Persistence
<SyncAgentChat
config={{ apiKey: "...", connectionString: "..." }}
persistKey="project-123"
/>
History saves to localStorage under sa_chat_project-123. The "New" button clears it.
Context injection
<SyncAgentChat
config={{ apiKey: "...", connectionString: "..." }}
context={{ userId: currentUser.id, page: "orders" }}
/>
onData — react to query results
<SyncAgentChat
config={{ apiKey: "...", connectionString: "..." }}
onData={(data) => {
if (data.collection === "orders") setOrders(data.data);
}}
/>
Custom Tools
<SyncAgentChat
config={{
apiKey: "sa_your_key",
connectionString: process.env.DATABASE_URL,
tools: {
createInvoice: {
description: "Create a Stripe invoice for a customer",
inputSchema: {
customerId: { type: "string", description: "Stripe customer ID" },
amount: { type: "number", description: "Amount in cents" },
},
execute: async ({ customerId, amount }) => {
const inv = await stripe.invoices.create({ customer: customerId });
return { invoiceId: inv.id };
},
},
},
}}
/>
Custom UI with useSyncAgent
import { SyncAgentProvider, useSyncAgent } from "@syncagent/react";
export default function App() {
return (
<SyncAgentProvider config={{ apiKey: "...", connectionString: "..." }}>
<MyChat />
</SyncAgentProvider>
);
}
function MyChat() {
const { messages, isLoading, error, status, lastData, sendMessage, stop, reset } = useSyncAgent();
return (
<div>
{/* status.label shows "Querying users..." etc. */}
{status && <div>⏳ {status.label}</div>}
{messages.map((msg, i) => (
<div key={i}><strong>{msg.role}:</strong> {msg.content}</div>
))}
<button onClick={() => sendMessage("Show all users")}>Ask</button>
<button onClick={stop}>Stop</button>
<button onClick={reset}>Clear</button>
</div>
);
}
useSyncAgent options
useSyncAgent({
client?: SyncAgentClient,
context?: Record<string, any>,
onData?: (data: ToolData) => void,
})
useSyncAgent returns
messages | Message[] | Full conversation history |
isLoading | boolean | true while streaming |
error | Error | null | Last error |
status | { step, label } | null | Live status while agent is working |
lastData | ToolData | null | Last structured data from a DB tool |
sendMessage | (content: string) => void | Send a user message |
stop | () => void | Abort the current stream |
reset | () => void | Clear all messages |
Vanilla JS Widget
No npm required — drop a script tag into any HTML page:
<script src="https://syncagent.dev/api/v1/widget"></script>
<script>
SyncAgent.init({
apiKey: "sa_your_key",
connectionString: "your_database_url",
position: "right",
accentColor: "#10b981",
title: "AI Assistant",
persistKey: "my-app",
open: false,
});
SyncAgent.open();
SyncAgent.close();
SyncAgent.toggle();
SyncAgent.clearHistory();
</script>
TypeScript types
import type {
SyncAgentConfig, Message, ChatOptions, ToolDefinition,
ToolParameter, ToolData, SyncAgentChatProps,
} from "@syncagent/react";
License
MIT