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
modelstringModel ID (e.g. meta-llama/llama-3.3-70b-instruct)
temperaturenumberSampling temperature (0-2)
max_tokensnumberMaximum response tokens
onError(error: AINativeError) => voidCalled on error
onSuccess(response: ChatCompletionResponse) => voidCalled 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