React SDK
The React SDK provides hooks for chat completions, credit management, ZeroMemory, and more.
npm install @ainative/react-sdk
Setup
Wrap your app with AINativeProvider. The apiKey is the only required config option. Optionally pass baseUrl to point at a different API endpoint.
import { AINativeProvider } from '@ainative/react-sdk';
function App() {
return (
<AINativeProvider config={{ apiKey: process.env.REACT_APP_AINATIVE_KEY! }}>
<YourApp />
</AINativeProvider>
);
}
Never hard-code API keys. Use environment variables (REACT_APP_AINATIVE_KEY for CRA, VITE_AINATIVE_KEY for Vite) and keep them out of version control.
useChat
Send chat completions and manage conversation state.
import { useChat } from '@ainative/react-sdk';
function Chat() {
const { messages, sendMessage, isLoading, error, reset } = useChat({
model: 'meta-llama/llama-3.3-70b-instruct',
temperature: 0.7,
onError: (err) => console.error('Chat error:', err.message),
});
const [input, setInput] = React.useState('');
const handleSend = async () => {
if (!input.trim()) return;
const userMessage = { role: 'user' as const, content: input };
setInput('');
await sendMessage([...messages, userMessage]);
};
return (
<div>
<div style={{ minHeight: 300, overflowY: 'auto' }}>
{messages.map((msg, i) => (
<div key={i} style={{ margin: '8px 0' }}>
<strong>{msg.role === 'user' ? 'You' : 'AI'}:</strong> {msg.content}
</div>
))}
{isLoading && <div>Thinking...</div>}
{error && <div style={{ color: 'red' }}>Error: {error.message}</div>}
</div>
<div style={{ display: 'flex', gap: 8 }}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
placeholder="Type a message..."
style={{ flex: 1 }}
/>
<button onClick={handleSend} disabled={isLoading}>Send</button>
<button onClick={reset}>Clear</button>
</div>
</div>
);
}
Options
| Option | Type | Default | Description |
|---|---|---|---|
model | string | — | Model ID (e.g. meta-llama/llama-3.3-70b-instruct) |
temperature | number | — | Sampling temperature (0-2) |
max_tokens | number | — | Maximum response tokens |
onError | (error: AINativeError) => void | — | Called on error |
onSuccess | (response: ChatCompletionResponse) => void | — | Called on successful completion |
Return Value
| Field | Type | Description |
|---|---|---|
messages | Message[] | Full conversation history |
isLoading | boolean | true while waiting for a response |
error | AINativeError | null | Last error, if any |
response | ChatCompletionResponse | null | Last raw API response |
sendMessage | (messages: Message[]) => Promise | Send messages and get a completion |
reset | () => void | Clear conversation state |
The sendMessage function accepts the full message array (including history). The hook automatically appends the assistant's reply.
useCredits
Fetch and monitor your API credit balance. The balance is fetched on mount and can be refreshed manually.
import { useCredits } from '@ainative/react-sdk';
function CreditDisplay() {
const { balance, isLoading, error, refetch } = useCredits();
if (isLoading) return <span>Loading credits...</span>;
if (error) return <span style={{ color: 'red' }}>Error: {error.message}</span>;
return (
<div>
<h3>Credits: {balance?.remaining_credits.toLocaleString()}</h3>
<p>Plan: {balance?.plan}</p>
<p>Used: {balance?.usage_percentage.toFixed(1)}%</p>
<button onClick={refetch}>Refresh</button>
</div>
);
}
Return Value
| Field | Type | Description |
|---|---|---|
balance | CreditBalance | null | Balance data (see below) |
isLoading | boolean | true while fetching |
error | AINativeError | null | Last error |
refetch | () => Promise<void> | Re-fetch balance |
CreditBalance fields: total_credits, used_credits, remaining_credits, plan, period_start, period_end, usage_percentage.
useMemory
Store and recall memories with ZeroMemory. Pass an optional entityId to scope all operations to a specific entity (e.g. a user ID). When an entityId is provided, existing memories for that entity are loaded automatically on mount.
import { useMemory } from '@ainative/react-sdk';
function MemoryPanel({ userId }: { userId: string }) {
const { memories, remember, recall, forget, isLoading, error } = useMemory(userId);
const [query, setQuery] = React.useState('');
const handleRemember = async () => {
await remember('User prefers dark mode', {
tags: ['preference', 'ui'],
importance: 0.8,
});
};
const handleSearch = async () => {
const results = await recall(query, { limit: 5 });
console.log('Found', results.length, 'memories');
};
return (
<div>
<h3>Memories ({memories.length})</h3>
{isLoading && <p>Loading...</p>}
{error && <p style={{ color: 'red' }}>{error.message}</p>}
{memories.map((m) => (
<div key={m.id} style={{ margin: '4px 0', padding: 8, border: '1px solid #eee' }}>
<p>{m.content}</p>
<small>
Type: {m.memory_type} | Importance: {m.importance} |{' '}
{m.tags.join(', ')}
</small>
<button onClick={() => forget(m.id)} style={{ marginLeft: 8 }}>
Forget
</button>
</div>
))}
<div style={{ marginTop: 16 }}>
<button onClick={handleRemember}>Remember preference</button>
</div>
<div style={{ marginTop: 8, display: 'flex', gap: 8 }}>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search memories..."
/>
<button onClick={handleSearch}>Recall</button>
</div>
</div>
);
}
API
| Method | Signature | Description |
|---|---|---|
remember | (content: string, options?: RememberOptions) => Promise<Memory | null> | Store a new memory |
recall | (query: string, options?: RecallOptions) => Promise<Memory[]> | Semantic search over memories |
forget | (memoryId: string) => Promise<boolean> | Delete a memory |
refetch | () => Promise<void> | Re-load entity memories |
RememberOptions: entity_id, memory_type, importance (0-1), tags (string[]), metadata (Record).
RecallOptions: entity_id, layer, limit.
Error Handling
All hooks return an error object with the shape { message, status?, code? }. The API also returns structured error responses with next_action hints in the body.
import { useChat } from '@ainative/react-sdk';
function ChatWithErrorHandling() {
const { messages, sendMessage, error } = useChat({
onError: (err) => {
switch (err.status) {
case 401:
// Token expired — redirect to login or refresh
window.location.href = '/login';
break;
case 429:
// Rate limited — show retry message
alert('Too many requests. Please wait a moment.');
break;
case 503:
// Service unavailable — the API suggests a fallback model
console.log('Try a different model');
break;
default:
console.error('Chat error:', err.message);
}
},
});
// ... render UI
}
Full Working Example
A complete chat application with credits display and memory:
import React, { useState } from 'react';
import { AINativeProvider, useChat, useCredits, useMemory } from '@ainative/react-sdk';
function ChatApp() {
const { messages, sendMessage, isLoading, reset } = useChat({
model: 'meta-llama/llama-3.3-70b-instruct',
});
const { balance } = useCredits();
const { remember } = useMemory('current-user');
const [input, setInput] = useState('');
const handleSend = async () => {
if (!input.trim()) return;
const text = input;
setInput('');
const response = await sendMessage([
...messages,
{ role: 'user', content: text },
]);
// Optionally remember the conversation turn
if (response) {
await remember(`User asked: ${text}`, { tags: ['conversation'] });
}
};
return (
<div style={{ maxWidth: 600, margin: '0 auto', padding: 24 }}>
<header style={{ display: 'flex', justifyContent: 'space-between' }}>
<h2>AI Chat</h2>
{balance && <span>{balance.remaining_credits} credits</span>}
</header>
<div style={{ minHeight: 400, border: '1px solid #ddd', padding: 16, overflowY: 'auto' }}>
{messages.map((msg, i) => (
<div key={i} style={{
textAlign: msg.role === 'user' ? 'right' : 'left',
margin: '8px 0',
}}>
<span style={{
display: 'inline-block',
padding: '8px 12px',
borderRadius: 12,
background: msg.role === 'user' ? '#0066ff' : '#f0f0f0',
color: msg.role === 'user' ? '#fff' : '#000',
}}>
{msg.content}
</span>
</div>
))}
{isLoading && <div style={{ color: '#888' }}>Thinking...</div>}
</div>
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
placeholder="Type a message..."
style={{ flex: 1, padding: 8 }}
/>
<button onClick={handleSend} disabled={isLoading}>Send</button>
<button onClick={reset}>Clear</button>
</div>
</div>
);
}
// Entry point
export default function App() {
return (
<AINativeProvider config={{ apiKey: process.env.REACT_APP_AINATIVE_KEY! }}>
<ChatApp />
</AINativeProvider>
);
}
TypeScript Types
Import types directly:
import type {
AINativeConfig,
Message,
ChatCompletionResponse,
CreditBalance,
AINativeError,
UseChatOptions,
UseCreditsReturn,
} from '@ainative/react-sdk';
import type {
Memory,
RememberOptions,
RecallOptions,
UseMemoryReturn,
} from '@ainative/react-sdk';
Next Steps
- Next.js SDK -- Server-side client and auth middleware
- Build a Chatbot -- Step-by-step tutorial
- ZeroMemory -- Learn about the memory system
- API Reference -- REST API documentation