Skip to main content

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>
);
}
tip

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​

OptionTypeDefaultDescription
modelstring—Model ID (e.g. meta-llama/llama-3.3-70b-instruct)
temperaturenumber—Sampling temperature (0-2)
max_tokensnumber—Maximum response tokens
onError(error: AINativeError) => void—Called on error
onSuccess(response: ChatCompletionResponse) => void—Called on successful completion

Return Value​

FieldTypeDescription
messagesMessage[]Full conversation history
isLoadingbooleantrue while waiting for a response
errorAINativeError | nullLast error, if any
responseChatCompletionResponse | nullLast raw API response
sendMessage(messages: Message[]) => PromiseSend messages and get a completion
reset() => voidClear 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​

FieldTypeDescription
balanceCreditBalance | nullBalance data (see below)
isLoadingbooleantrue while fetching
errorAINativeError | nullLast 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​

MethodSignatureDescription
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​