Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@syncagent/react

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@syncagent/react

SyncAgent React SDK — AI database chat widget & hooks

latest
Source
npmnpm
Version
0.5.1
Version published
Weekly downloads
55
-65.84%
Maintainers
1
Weekly downloads
 
Created
Source

@syncagent/react

React SDK for SyncAgent — drop-in AI database chat widget and hooks for React apps.

Works with MongoDB, PostgreSQL, MySQL, SQLite, SQL Server, and Supabase.

npm version License: MIT

Get Your API Key

  • Sign up for a free account
  • Go to your DashboardNew Project → choose your database type
  • Copy your API key (starts with sa_)

Every new project gets a 14-day trial with 500 free requests — no credit card required. After the trial, you get 100 free requests/month on the Free plan.

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,
      }}
    />
  );
}

A floating chat button appears in the bottom-right corner. Your users can now query your database in plain English.

<SyncAgentChat> Props

PropTypeDefaultDescription
configSyncAgentConfigRequired*API key, connection string, tools, filter, operations
mode"floating" | "inline""floating"Floating FAB or embedded inline panel
position"bottom-right" | "bottom-left""bottom-right"FAB position (floating mode only)
defaultOpenbooleanfalseStart with the panel open
titlestring"SyncAgent"Header title
subtitlestring"AI Database Assistant"Header subtitle
placeholderstring"Ask anything..."Input placeholder
welcomeMessagestring"Hi! I can query..."Empty state message
accentColorstring"#10b981"Brand color for header, FAB, send button
suggestionsstring[]3 defaultsQuick-start suggestion chips
persistKeystringlocalStorage key for conversation persistence
contextRecord<string, any>Extra context injected into every message
filterRecord<string, any>Mandatory query filter for multi-tenancy
operations("read"|"create"|"update"|"delete")[]Restrict operations for this session
onReaction(idx, reaction, content) => voidCalled when user reacts 👍/👎
onData(data: ToolData) => voidCalled when a DB tool returns structured data

*config is required unless wrapped in <SyncAgentProvider>.

Inline Mode

Embed the chat inside your layout instead of a floating button:

<div style={{ height: 600 }}>
  <SyncAgentChat
    config={{ apiKey: "...", connectionString: "..." }}
    mode="inline"
  />
</div>

Custom UI with useSyncAgent

Build your own chat UI with full control:

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 && <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 Returns

ReturnTypeDescription
messagesMessage[]Full conversation history
isLoadingbooleantrue while streaming
errorError | nullLast error
status{ step, label } | nullLive status while agent is working
lastDataToolData | nullLast structured data from a DB tool
sendMessage(content: string) => voidSend a user message
stop() => voidAbort the current stream
reset() => voidClear all messages

Features

  • Auto page detection — detects current page, record ID, and query params from the URL
  • Live status — shows ● Querying users... while the agent works
  • Markdown rendering — tables, code blocks, bold, italic, lists
  • Streaming — blinking cursor while text streams in
  • Copy button — on every AI response
  • Reactions — 👍/👎 on AI messages
  • Conversation persistence — saves history to localStorage
  • Suggestion chips — configurable quick-start prompts
  • Export CSV — download tables as CSV
  • Bar charts — auto-renders aggregation results
  • Resize handle — drag to resize the floating panel
  • Mobile responsive — full-width on small screens
  • Dark mode — respects prefers-color-scheme

Multi-tenant SaaS

Pass filter to scope every agent operation to the current user's organization. Enforced server-side.

<SyncAgentChat
  config={{
    apiKey: "sa_your_key",
    connectionString: process.env.DATABASE_URL,
    filter: { organizationId: currentUser.orgId },
    operations: currentUser.isAdmin
      ? ["read", "create", "update", "delete"]
      : ["read"],
  }}
/>

Custom Tools

Give the agent capabilities beyond your database:

<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 };
        },
      },
    },
  }}
/>

Tools-only Mode

Use the agent with only your custom tools — no database access:

<SyncAgentChat
  config={{
    apiKey: "sa_your_key",
    toolsOnly: true,
    tools: {
      searchProducts: {
        description: "Search products by name",
        inputSchema: { query: { type: "string", description: "Search query" } },
        execute: async ({ query }) => {
          const res = await fetch(`/api/products?q=${query}`);
          return res.json();
        },
      },
    },
  }}
/>

Customer Agent Mode

Use the useCustomerChat hook to build customer-facing support interfaces powered by SyncAgent's customer agent pipeline — including persona, flows, knowledge base, escalation, and AI fallback.

import { SyncAgentProvider, useCustomerChat } from "@syncagent/react";

function App() {
  return (
    <SyncAgentProvider
      config={{
        apiKey: "sa_your_api_key",
        connectionString: process.env.DATABASE_URL,
        externalUserId: currentUser.id,
      }}
    >
      <CustomerChat />
    </SyncAgentProvider>
  );
}

function CustomerChat() {
  const {
    messages,
    conversationId,
    isLoading,
    isEscalated,
    isResolved,
    error,
    welcomeMessage,
    sendMessage,
    rateConversation,
    reset,
  } = useCustomerChat({
    onEscalated: () => console.log("Escalated to human agent"),
    onResolved: (id) => console.log("Conversation resolved:", id),
  });

  return (
    <div>
      {welcomeMessage && <p>{welcomeMessage}</p>}
      {messages.map((msg, i) => (
        <div key={i}>
          <strong>{msg.role}:</strong> {msg.content}
        </div>
      ))}
      {isEscalated && <p>You've been connected to a human agent.</p>}
      {isResolved && (
        <div>
          <p>Conversation resolved!</p>
          <button onClick={() => rateConversation(5)}>⭐ Rate 5/5</button>
        </div>
      )}
      {error && <p>Error: {error.message}</p>}
      <button onClick={() => sendMessage("I need help with my order")}>
        Send
      </button>
      <button onClick={reset}>New Conversation</button>
    </div>
  );
}

useCustomerChat Return Values

ReturnTypeDescription
messagesMessage[]Full conversation history (user and assistant messages)
conversationIdstring | nullCurrent conversation ID, set after first message
isLoadingbooleantrue while waiting for a response
isEscalatedbooleantrue when conversation has been escalated to a human agent
isResolvedbooleantrue when the conversation has been resolved
errorError | nullLast error encountered, or null
welcomeMessagestring | nullWelcome message returned on first interaction
sendMessage(content: string, metadata?: Record<string, any>) => Promise<void>Send a message to the customer agent
rateConversation(rating: number) => Promise<void>Rate the conversation (1-5). Throws if no active conversation.
reset() => voidClear all state and start a new conversation

UseCustomerChatOptions

FieldTypeDescription
clientSyncAgentClient?Optional client instance. If omitted, uses the client from SyncAgentProvider context.
onEscalated() => void?Called when the conversation is escalated to a human agent
onResolved(conversationId: string) => void?Called when the conversation is resolved

Client resolution: useCustomerChat first checks for a client passed directly in options. If none is provided, it falls back to the client from the nearest <SyncAgentProvider>. If neither is available, it throws an error prompting you to provide one.

Guest Identification

When no externalUserId is provided in the config, the customer chat enters guest mode — anonymous visitors must identify themselves before sending messages. The useCustomerChat hook exposes guest identification state and a method to submit guest data programmatically.

Hook Fields

ReturnTypeDescription
isIdentifiedbooleantrue if the user has an externalUserId or has completed guest identification
guestIdentityGuestIdentity | nullThe stored guest identity object, or null if not yet identified
identifyGuest(data: { name: string; email: string; phone?: string }) => voidSubmit guest form data — validates, generates a guest ID, persists to localStorage, and transitions to identified state

Using GuestIdentificationForm

The GuestIdentificationForm component provides a ready-made form with built-in validation, accessibility attributes, and customizable text:

import { useCustomerChat, GuestIdentificationForm } from "@syncagent/react";

function CustomerChat() {
  const {
    messages,
    isIdentified,
    identifyGuest,
    sendMessage,
  } = useCustomerChat({
    onGuestIdentified: (identity) => {
      console.log("Guest identified:", identity.guestId);
    },
  });

  if (!isIdentified) {
    return (
      <GuestIdentificationForm
        onSubmit={(identity) => identifyGuest(identity)}
        config={{
          title: "Welcome!",
          subtitle: "Tell us a bit about yourself",
          submitButtonText: "Start Chat",
          namePlaceholder: "Your name",
          emailPlaceholder: "you@example.com",
          phonePlaceholder: "Phone (optional)",
        }}
        className="my-guest-form"
      />
    );
  }

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i}><strong>{msg.role}:</strong> {msg.content}</div>
      ))}
      <button onClick={() => sendMessage("Hello!")}>Send</button>
    </div>
  );
}

GuestIdentificationFormProps

PropTypeRequiredDescription
onSubmit(identity: GuestIdentity) => voidYesCalled with the complete GuestIdentity (including generated guestId) on valid submission
configGuestFormConfigNoCustomize title, subtitle, button text, and placeholder strings
classNamestringNoCustom CSS class applied to the form container

Manual Guest Identification

If you prefer to build your own form UI, use the identifyGuest method directly:

import { useState } from "react";
import { useCustomerChat } from "@syncagent/react";

function CustomGuestForm() {
  const { isIdentified, identifyGuest, error } = useCustomerChat();
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");

  if (isIdentified) return null;

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        identifyGuest({ name, email });
      }}
    >
      <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
      <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
      <button type="submit">Continue</button>
      {error && <p>{error.message}</p>}
    </form>
  );
}

The identifyGuest method validates the input using validateGuestForm from @syncagent/js. If validation fails, it sets the error state with a descriptive message. On success, it generates a deterministic guest identifier from the email, persists the identity to localStorage, and sets isIdentified to true.

Dual Mode (Database + Customer Agent)

⚠️ Deprecated: createDual() will be removed in a future major version. Use useDualChat() instead — pass externalUserId directly to enable both modes on a single instance.

Before (deprecated):

import { SyncAgentClient } from "@syncagent/js";
import { SyncAgentProvider, useCustomerChat, useSyncAgent } from "@syncagent/react";

const { db, support } = SyncAgentClient.createDual({
  apiKey: "sa_your_key",
  connectionString: process.env.DATABASE_URL,
  externalUserId: currentUser.id,
});

function AdminChat() {
  return <SyncAgentProvider config={db}><AdminPanel /></SyncAgentProvider>;
}

function CustomerWidget() {
  const chat = useCustomerChat({ client: support });
  return <div>{/* customer chat UI */}</div>;
}

After (recommended):

import { SyncAgentProvider, useDualChat } from "@syncagent/react";

function App() {
  return (
    <SyncAgentProvider
      config={{
        apiKey: "sa_your_key",
        connectionString: process.env.DATABASE_URL,
        externalUserId: currentUser.id,
      }}
    >
      <DualChatUI />
    </SyncAgentProvider>
  );
}

function DualChatUI() {
  const { db, support } = useDualChat();
  // Use db.sendMessage(), support.sendMessage(), etc.
}

Legacy pattern (deprecated):

import { SyncAgentClient } from "@syncagent/js";
import { SyncAgentProvider, useCustomerChat, useSyncAgent } from "@syncagent/react";

const { db, support } = SyncAgentClient.createDual({
  apiKey: "sa_your_key",
  connectionString: process.env.DATABASE_URL,
  externalUserId: currentUser.id,
});

// Admin panel — database agent
function AdminChat() {
  return <SyncAgentProvider config={db}><AdminPanel /></SyncAgentProvider>;
}

// Customer widget — support agent
function CustomerWidget() {
  const chat = useCustomerChat({ client: support });
  return <div>{/* customer chat UI */}</div>;
}

Customer Chat Component

The <SyncAgentCustomerChat> component is a pre-built, drop-in customer support chat widget. It provides a complete experience including guest identification, real-time messaging with AI and human agents, escalation display, and satisfaction rating — all as a single component.

import { SyncAgentCustomerChat } from "@syncagent/react";

export default function App() {
  return (
    <SyncAgentCustomerChat
      apiKey="sa_your_api_key"
      connectionString={process.env.DATABASE_URL!}
    />
  );
}

<SyncAgentCustomerChat> Props

PropTypeDefaultDescription
configSyncAgentConfigServer config object. When provided, apiKey/connectionString are ignored.
apiKeystringAPI key for authentication (ignored if config provided)
connectionStringstringDatabase connection string (ignored if config provided)
externalUserIdstringAuthenticated user ID — skips guest form when provided
mode"floating" | "inline""floating"Floating toggle button or embedded inline panel
position"bottom-right" | "bottom-left""bottom-right"Position of the floating widget (floating mode only)
defaultOpenbooleanfalseWhether the floating panel starts open (floating mode only)
titlestring"Customer Support"Header title text (max 100 chars)
subtitlestring"How can we help you?"Header subtitle text (max 200 chars)
placeholderstring"Type your message..."Input placeholder text (max 150 chars)
welcomeMessagestringInitial welcome message displayed before any interaction
accentColorstring"#6366f1"Primary accent color (hex, rgb, or hsl)
darkModebooleanfalseEnable dark mode color scheme
classNamestringAdditional CSS class on root container
styleCSSPropertiesInline styles merged onto root container
guestFormGuestFormConfigCustom guest form configuration (title, subtitle, placeholders, button text)
pusherKeystringPusher app key for real-time human agent messages
pusherClusterstring"us2"Pusher cluster
metadataRecord<string, any>Custom metadata attached to conversations
onEscalated() => voidCalled when conversation is escalated to a human agent
onResolved(conversationId: string) => voidCalled when conversation is resolved
onGuestIdentified(identity: GuestIdentity) => voidCalled after guest form submission

Basic Usage

<SyncAgentCustomerChat
  apiKey="sa_your_api_key"
  connectionString={process.env.DATABASE_URL!}
/>

Using a Config Object

import { SyncAgentCustomerChat } from "@syncagent/react";

// Config from server (e.g., Next.js createCustomerServerConfig)
<SyncAgentCustomerChat config={serverConfig} />

Floating Mode (default)

<SyncAgentCustomerChat
  apiKey="sa_your_api_key"
  connectionString={process.env.DATABASE_URL!}
  mode="floating"
  position="bottom-right"
  defaultOpen={false}
/>

Inline Mode

Embed the chat inside your layout — the panel fills its parent container and is always visible:

<div style={{ height: 600, width: 400 }}>
  <SyncAgentCustomerChat
    apiKey="sa_your_api_key"
    connectionString={process.env.DATABASE_URL!}
    mode="inline"
  />
</div>

Dark Mode with Custom Accent Color

<SyncAgentCustomerChat
  apiKey="sa_your_api_key"
  connectionString={process.env.DATABASE_URL!}
  darkMode
  accentColor="#8b5cf6"
/>

Custom Guest Form

<SyncAgentCustomerChat
  apiKey="sa_your_api_key"
  connectionString={process.env.DATABASE_URL!}
  guestForm={{
    title: "Welcome!",
    subtitle: "Tell us about yourself to get started",
    submitButtonText: "Start Chat",
    namePlaceholder: "Your name",
    emailPlaceholder: "you@company.com",
    phonePlaceholder: "+1 (555) 000-0000",
  }}
  onGuestIdentified={(identity) => {
    console.log("Guest identified:", identity.guestId);
  }}
/>

useCustomerChat Hook

For full control over the UI, use the useCustomerChat hook directly to build a custom chat interface:

import { SyncAgentProvider, useCustomerChat } from "@syncagent/react";

function App() {
  return (
    <SyncAgentProvider config={{ apiKey: "sa_...", connectionString: "..." }}>
      <CustomChat />
    </SyncAgentProvider>
  );
}

function CustomChat() {
  const {
    messages,
    isLoading,
    isEscalated,
    isResolved,
    isIdentified,
    identifyGuest,
    sendMessage,
    rateConversation,
    error,
    welcomeMessage,
  } = useCustomerChat({
    onEscalated: () => console.log("Escalated"),
    onResolved: (id) => console.log("Resolved:", id),
    onGuestIdentified: (identity) => console.log("Guest:", identity),
  });

  if (!isIdentified) {
    return (
      <form onSubmit={(e) => {
        e.preventDefault();
        identifyGuest({ name: "Jane", email: "jane@example.com" });
      }}>
        <button type="submit">Identify</button>
      </form>
    );
  }

  return (
    <div>
      {welcomeMessage && <p>{welcomeMessage}</p>}
      {messages.map((msg, i) => (
        <div key={i}><strong>{msg.role}:</strong> {msg.content}</div>
      ))}
      {isEscalated && <p>Connected to a human agent</p>}
      {isResolved && <button onClick={() => rateConversation(5)}>⭐ Rate</button>}
      {error && <p>Error: {error.message}</p>}
      <button onClick={() => sendMessage("Hello!")} disabled={isLoading}>
        Send
      </button>
    </div>
  );
}

UseCustomerChatOptions

OptionTypeDescription
clientSyncAgentClientOptional client instance. If omitted, uses the client from SyncAgentProvider context.
externalUserIdstringWhen provided, the hook considers the user pre-authenticated (bypasses guest flow).
onEscalated() => voidCalled when the conversation is escalated to a human agent.
onResolved(conversationId: string) => voidCalled when the conversation is resolved.
onGuestIdentified(identity: GuestIdentity) => voidCalled when a guest completes identification.

useCustomerChat Return Values

ReturnTypeDescription
messagesMessage[]Full conversation history
conversationIdstring | nullCurrent conversation ID, set after first message
isLoadingbooleantrue while waiting for a response
isEscalatedbooleantrue when conversation has been escalated to a human agent
isResolvedbooleantrue when the conversation has been resolved
errorError | nullLast error encountered
welcomeMessagestring | nullWelcome message returned on first interaction
sendMessage(content: string, metadata?: Record<string, any>) => Promise<void>Send a message to the customer agent
rateConversation(rating: number) => Promise<void>Rate the conversation (1–5). Throws if no active conversation.
reset() => voidClear all state and start a new conversation
isIdentifiedbooleantrue if the user has an externalUserId or has completed guest identification
guestIdentityGuestIdentity | nullThe stored guest identity object
identifyGuest(data: { name: string; email: string; phone?: string }) => voidSubmit guest form data — validates, generates a guest ID, persists to localStorage

Theming

The <SyncAgentCustomerChat> component uses a built-in theme engine to generate a complete color palette from two inputs:

  • accentColor — any valid CSS color (hex, rgb, hsl). Used for buttons, user message bubbles, focus outlines, and the floating toggle button. Default: "#6366f1".
  • darkMode — when true, renders a dark color scheme with light text on dark backgrounds.

The theme engine (computeTheme() from @syncagent/js) automatically adjusts all derived colors to meet WCAG AA contrast requirements:

  • Text contrast: All text-on-background pairs maintain a minimum 4.5:1 contrast ratio
  • Focus indicators: Focus outlines maintain a minimum 3:1 contrast ratio against adjacent colors
  • Accent contrast: The accent color against the background maintains a minimum 3:1 contrast ratio

All styles are applied inline — no external CSS is required and no styles leak to or from your application.

// Light mode with custom accent
<SyncAgentCustomerChat accentColor="#059669" />

// Dark mode with default accent
<SyncAgentCustomerChat darkMode />

// Dark mode with custom accent
<SyncAgentCustomerChat darkMode accentColor="#f59e0b" />

Accessibility

The <SyncAgentCustomerChat> component is built with WCAG AA compliance:

ARIA Roles and Labels:

  • The chat container uses role="region" with aria-label="Customer chat"
  • The message list uses role="log" to indicate a chronological message stream
  • All interactive elements have descriptive ARIA labels

Keyboard Navigation:

  • Tab moves focus through all interactive elements (buttons, inputs, rating stars)
  • Enter or Space activates buttons and submits forms
  • Arrow keys navigate the satisfaction rating stars

Focus Management:

  • When the guest form transitions to the chat panel, focus moves to the message input within 100ms
  • All interactive elements have visible focus indicators with a minimum 2px outline width
  • Focus indicator contrast meets the 3:1 minimum ratio against adjacent colors

Screen Reader Support:

  • New messages are announced via an ARIA live region (aria-live="polite")
  • Loading states, errors, and escalation status changes are communicated to assistive technology

Contrast Requirements:

  • All text maintains a minimum 4.5:1 contrast ratio against its background
  • Focus indicators maintain a minimum 3:1 contrast ratio
  • These guarantees hold in both light and dark mode, regardless of the accent color chosen

Unified Dual Mode

The useDualChat() hook provides a single interface for managing both database agent and customer support agent conversations from within a <SyncAgentProvider>. When your config includes externalUserId, both modes are available through namespaced db and support objects.

import { SyncAgentProvider, useDualChat } from "@syncagent/react";

function App() {
  return (
    <SyncAgentProvider
      config={{
        apiKey: "sa_your_api_key",
        connectionString: process.env.DATABASE_URL,
        externalUserId: currentUser.id,
      }}
    >
      <DualChatUI />
    </SyncAgentProvider>
  );
}

function DualChatUI() {
  const { db, support } = useDualChat({
    context: { tenant: currentUser.orgId },
    onData: (data) => console.log("DB tool result:", data),
    onEscalated: () => console.log("Escalated to human"),
    onResolved: (id) => console.log("Resolved:", id),
  });

  return (
    <div>
      {/* Database agent panel */}
      <section>
        <h2>Admin Database Chat</h2>
        {db.messages.map((msg, i) => (
          <div key={i}><strong>{msg.role}:</strong> {msg.content}</div>
        ))}
        {db.isLoading && <p>Loading...</p>}
        {db.error && <p>Error: {db.error.message}</p>}
        <button onClick={() => db.sendMessage("Show all orders")}>
          Query DB
        </button>
        <button onClick={db.stop}>Stop</button>
        <button onClick={db.reset}>Clear</button>
      </section>

      {/* Customer support panel */}
      <section>
        <h2>Customer Support</h2>
        {support.welcomeMessage && <p>{support.welcomeMessage}</p>}
        {support.messages.map((msg, i) => (
          <div key={i}><strong>{msg.role}:</strong> {msg.content}</div>
        ))}
        {support.isLoading && <p>Loading...</p>}
        {support.isEscalated && <p>Connected to a human agent.</p>}
        {support.isResolved && (
          <button onClick={() => support.rateConversation(5)}>⭐ Rate</button>
        )}
        {support.error && <p>Error: {support.error.message}</p>}
        <button onClick={() => support.sendMessage("I need help")}>
          Send
        </button>
        <button onClick={support.reset}>New Conversation</button>
      </section>
    </div>
  );
}

Error Handling

If useDualChat() is called outside of a <SyncAgentProvider>, it throws:

useDualChat must be used within a <SyncAgentProvider>

Ensure your component is wrapped in a <SyncAgentProvider> with a valid config that includes externalUserId.

DualChatReturn

The useDualChat() hook returns an object with two namespaces: db for database agent state and support for customer agent state.

db Properties

PropertyTypeDescription
messagesMessage[]Full database agent conversation history
isLoadingbooleantrue while the database agent is streaming
errorError | nullLast error from the database agent, or null
status{ step: string; label: string } | nullLive status while the agent is working (e.g., querying)
lastDataToolData | nullLast structured data returned by a DB tool
sendMessage(content: string) => voidSend a message to the database agent
stop() => voidAbort the current database agent stream
reset() => voidClear all database agent messages and state

support Properties

PropertyTypeDescription
messagesMessage[]Full customer support conversation history
conversationIdstring | nullCurrent conversation ID, set after first message
isLoadingbooleantrue while waiting for a support response
isEscalatedbooleantrue when conversation has been escalated to a human agent
isResolvedbooleantrue when the conversation has been resolved
errorError | nullLast error from the support agent, or null
welcomeMessagestring | nullWelcome message returned on first interaction
sendMessage(content: string, metadata?: Record<string, any>) => Promise<void>Send a message to the customer support agent
rateConversation(rating: number) => Promise<void>Rate the conversation (1-5). Throws if no active conversation.
reset() => voidClear all support state and start a new conversation

UseDualChatOptions

OptionTypeRequiredDescription
contextRecord<string, any>NoExtra context injected into every database agent message
onData(data: ToolData) => voidNoCalled when a DB tool returns structured data
onEscalated() => voidNoCalled when the customer conversation is escalated to a human agent
onResolved(conversationId: string) => voidNoCalled when the customer conversation is resolved

Customization Options

All config options from @syncagent/js work here too:

<SyncAgentChat
  config={{
    apiKey: "sa_your_key",
    connectionString: process.env.DATABASE_URL,
    systemInstruction: "You are a friendly sales assistant for Acme Corp.",
    language: "French",
    confirmWrites: true,
    maxResults: 10,
    sensitiveFields: ["ssn", "salary", "creditCard"],
    onBeforeToolCall: (name, args) => { console.log(`[Audit] ${name}`, args); return true; },
    onAfterToolCall: (name, args, result) => { analytics.track("tool_call", { tool: name }); },
  }}
/>

Conversation Persistence

<SyncAgentChat
  config={{ apiKey: "...", connectionString: "..." }}
  persistKey={currentUser.id}
/>

History saves to localStorage under sa_chat_{persistKey}. The "New" button clears it.

Context & Auto Page Detection

The SDK automatically detects the current page from window.location — zero config needed:

URL: /dashboard/orders/ord_123?tab=details

Auto-detected:
  currentPage: "orders"
  currentPath: "/dashboard/orders/ord_123"
  currentRecordId: "ord_123"
  param_tab: "details"

Pass additional context:

<SyncAgentChat
  config={{ apiKey: "...", connectionString: "..." }}
  context={{ userId: currentUser.id, userRole: "admin" }}
/>

Vanilla JS Widget

No npm required — drop a script tag into any HTML page:

<script src="https://syncagentdev.vercel.app/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",
  });
</script>

Security

  • Your database connection string is never stored on SyncAgent servers
  • Passed at runtime, used once, immediately discarded
  • API keys are hashed with bcrypt
  • Never expose your connection string in client-side code — use server components or API routes

Plans & Pricing

PlanRequests/moCollectionsPrice
Free (+ 14-day trial)100 (500 during trial)5GH₵0
Starter5,00020GH₵150/mo
Pro50,000UnlimitedGH₵500/mo
EnterpriseUnlimitedUnlimitedCustom

View full pricing →

Resources

TypeScript Types

The following types are exported from @syncagent/react for use in your TypeScript projects:

TypeDescriptionImport
DualChatReturnReturn type of the useDualChat() hook containing namespaced db and support objectsimport { DualChatReturn } from "@syncagent/react"
UseDualChatOptionsOptions interface for configuring the useDualChat() hook (context, callbacks)import { UseDualChatOptions } from "@syncagent/react"
import { DualChatReturn, UseDualChatOptions } from "@syncagent/react";

License

MIT

Keywords

syncagent

FAQs

Package last updated on 22 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts