Skip to main content

React Hooks

@rickydata/react provides hooks and components for building wallet-aware UIs with agent chat, balance tracking, free-tier status, and more.

Setup

npm install @rickydata/react

Wrap your app with RickyDataProvider:

import { RickyDataProvider } from '@rickydata/react';

function App() {
return (
<RickyDataProvider
gatewayUrl="https://agents.rickydata.org"
token="mcpwt_..."
>
<YourApp />
</RickyDataProvider>
);
}

Access the provider context anywhere:

import { useRickyData } from '@rickydata/react';

function Status() {
const { isConnected, walletAddress } = useRickyData();
return <p>{isConnected ? walletAddress : 'Not connected'}</p>;
}

Free tier and usage

useFreeTierStatus

Track daily free-tier usage:

import { useFreeTierStatus } from '@rickydata/react';

function UsageBar() {
const { data } = useFreeTierStatus();
if (!data) return null;

return (
<div>
<p>{data.requestsUsed} / {data.requestsTotal} requests today</p>
<p>{data.remainingRequests} remaining</p>
</div>
);
}

useWalletPlan

Get the current wallet plan level:

import { useWalletPlan } from '@rickydata/react';

function PlanBadge() {
const { data: plan } = useWalletPlan();
return <span>{plan?.tier ?? 'free'}</span>;
}

Wallet and balance

useWalletBalance

import { useWalletBalance } from '@rickydata/react';

function Balance() {
const { data } = useWalletBalance();
if (!data) return null;

return (
<div>
<p>USDC: {data.usdcBalance}</p>
<p>Deposit address: {data.depositAddress}</p>
</div>
);
}

useWalletTransactions

import { useWalletTransactions } from '@rickydata/react';

function Transactions() {
const { data: txns } = useWalletTransactions();
return (
<ul>
{txns?.map((tx) => (
<li key={tx.id}>{tx.type}: ${tx.amount}</li>
))}
</ul>
);
}

useWalletSettings

import { useWalletSettings } from '@rickydata/react';

function Settings() {
const { data: settings } = useWalletSettings();
if (!settings) return null;

return (
<div>
<p>Auto-improve: {settings.autoImprove ? 'on' : 'off'}</p>
<p>Schedule: {settings.improveSchedule}</p>
</div>
);
}

Agents

useAgents / useAgent

import { useAgents, useAgent } from '@rickydata/react';

function AgentList() {
const { data: agents } = useAgents();
return (
<ul>
{agents?.map((a) => <li key={a.id}>{a.name}</li>)}
</ul>
);
}

function AgentDetail({ id }: { id: string }) {
const { data: agent } = useAgent(id);
if (!agent) return null;
return <p>{agent.name}: {agent.description}</p>;
}

Chat

useAgentChat

SSE streaming chat with an agent:

import { useAgentChat } from '@rickydata/react';
import type { UseAgentChatOptions } from '@rickydata/react';

function Chat() {
const {
messages,
sendMessage,
isStreaming,
error,
} = useAgentChat({
agentId: 'erc8004-expert',
sessionId: undefined, // auto-creates a new session
});

return (
<div>
{messages.map((msg, i) => (
<div key={i} className={msg.role}>
{msg.parts.map((p, j) =>
p.type === 'text' ? <p key={j}>{p.text}</p> : null
)}
</div>
))}

<form onSubmit={(e) => {
e.preventDefault();
const input = e.currentTarget.elements.namedItem('msg') as HTMLInputElement;
sendMessage(input.value);
input.value = '';
}}>
<input name="msg" disabled={isStreaming} placeholder="Ask something..." />
</form>
</div>
);
}

useAgentVoiceChat

LiveKit-based voice chat with narration:

import { useAgentVoiceChat } from '@rickydata/react';

function VoiceChat() {
const {
isConnected,
phase,
transcripts,
connect,
disconnect,
} = useAgentVoiceChat({
agentId: 'erc8004-expert',
});

return (
<div>
<p>Phase: {phase}</p>
<button onClick={isConnected ? disconnect : connect}>
{isConnected ? 'Disconnect' : 'Connect Voice'}
</button>
{transcripts.map((t, i) => (
<p key={i}>{t.speaker}: {t.text}</p>
))}
</div>
);
}

Sessions

useSessions / useSession / useDeleteSession

import { useSessions, useSession, useDeleteSession } from '@rickydata/react';

function SessionList() {
const { data: sessions } = useSessions();
const deleteSession = useDeleteSession();

return (
<ul>
{sessions?.map((s) => (
<li key={s.id}>
{s.agentId}{s.createdAt}
<button onClick={() => deleteSession.mutate(s.id)}>Delete</button>
</li>
))}
</ul>
);
}

API keys

useApiKeyStatus / useSetApiKey / useDeleteApiKey

Manage the BYOK Anthropic API key stored in the encrypted vault:

import { useApiKeyStatus, useSetApiKey, useDeleteApiKey } from '@rickydata/react';

function ApiKeyManager() {
const { data: status } = useApiKeyStatus();
const setKey = useSetApiKey();
const deleteKey = useDeleteApiKey();

if (status?.configured) {
return (
<div>
<p>API key configured</p>
<button onClick={() => deleteKey.mutate()}>Remove key</button>
</div>
);
}

return (
<form onSubmit={(e) => {
e.preventDefault();
const input = e.currentTarget.elements.namedItem('key') as HTMLInputElement;
setKey.mutate(input.value);
}}>
<input name="key" type="password" placeholder="sk-ant-..." />
<button type="submit">Store key</button>
</form>
);
}

Secrets

useSecrets

Manage MCP server secrets:

import { useSecrets } from '@rickydata/react';

function SecretStatus({ serverId }: { serverId: string }) {
const { data } = useSecrets(serverId);
return (
<ul>
{data?.map((s) => (
<li key={s.name}>{s.name}: {s.configured ? 'set' : 'missing'}</li>
))}
</ul>
);
}

Components

@rickydata/react also exports ready-made components:

ComponentPurpose
FreeTierBarVisual bar showing daily free-tier usage
ProviderSettingsCardBYOK provider selection (MiniMax, Anthropic, OpenAI)
WalletStatusBadgeConnected/disconnected wallet indicator
UsageDashboardFull usage overview with charts
WalletChipCompact wallet address display
DepositPanelUSDC deposit UI with QR code
SecretFormForm for storing server secrets
SecretOrchestratorMulti-secret setup flow
Connect wallet to see your account dashboard

Next steps