The Jean Memory React SDK provides two powerful ways to integrate: a simple, out-of-the-box UI component for rapid development, and a flexible hook for building completely custom experiences.
Getting Context: The getContext
Function
The primary way to retrieve context from Jean Memory is with the getContext
function. It provides four distinct speed modes, allowing you to choose the right balance of speed and quality for your application.
const { getContext } = useJean();
// Fast: Direct memory search (0.5-1s)
const fastContext = await getContext("What was my recent idea about AI?", { mode: 'fast' });
// Balanced: AI synthesis with Gemini 2.5 Flash (3-5s) - Recommended
const balancedContext = await getContext("How should I approach this project?", { mode: 'balanced' });
// Autonomous: Intelligent orchestration with adaptive decision-making (variable latency)
const smartContext = await getContext("Help me plan my week based on my goals", { mode: 'autonomous' });
// Comprehensive: Deep document analysis (20-30s)
const deepContext = await getContext("Analyze my writing style across my recent essays.", { mode: 'comprehensive' });
Speed Modes
fast
: Direct memory search returning raw memories. Ideal for real-time applications where speed is critical.
balanced
: AI synthesis using Gemini 2.5 Flash for conversational responses. Recommended for most use cases.
autonomous
: Intelligent orchestration that adaptively determines context analysis depth. May take longer for complex reasoning.
comprehensive
: Deep document analysis with extensive memory search. Best for research and detailed analysis.
Learn more about speed modes →
Installation
npm install @jeanmemory/react
Three Integration Approaches
The Jean Memory React SDK provides three levels of integration complexity, allowing you to choose the right approach for your use case.
Level 1: Complete Drop-in Solution (2 lines)
The fastest way to get a full-featured chatbot with authentication running in your app.
import { JeanProvider, JeanChatComplete } from '@jeanmemory/react';
export default function Home() {
return (
<JeanProvider apiKey={process.env.NEXT_PUBLIC_JEAN_API_KEY}>
<JeanChatComplete />
</JeanProvider>
);
}
The JeanChatComplete
component includes everything you need out of the box:
- Automatic OAuth 2.1 PKCE authentication flow
- Complete chat interface with professional styling
- Sign-in and sign-out buttons
- Loading states and error handling
- Welcome message and example prompts
Styling Options:
<JeanChatComplete
placeholder="Ask me anything..."
welcomeMessage="Welcome to your AI assistant"
examplePrompts={["What's my schedule?", "Remember this meeting"]}
showSignOut={true}
showExamples={true}
chatHeight={500}
style={{ maxWidth: '600px', margin: '0 auto' }}
className="my-custom-chat"
header={<CustomHeader />}
/>
Current Limitations: JeanChatComplete
uses inline styles for rapid prototyping. For production applications requiring extensive brand customization, consider Level 2 or Level 3 approaches.
Level 2: Authentication Guard with Custom UI (5 lines)
When you want your own UI but simplified authentication management.
import { JeanProvider, JeanAuthGuard, useJean } from '@jeanmemory/react';
export default function Home() {
return (
<JeanProvider apiKey={process.env.NEXT_PUBLIC_JEAN_API_KEY}>
<JeanAuthGuard>
<MyCustomChatApp />
</JeanAuthGuard>
</JeanProvider>
);
}
function MyCustomChatApp() {
const { sendMessage, messages, user, signOut } = useJean();
// Your custom UI implementation
return <div>Your custom chat interface</div>;
}
JeanAuthGuard
automatically handles:
- Loading states while checking authentication
- Sign-in UI when user is not authenticated
- Displaying your custom app when authenticated
- Customizable loading and fallback components
Customization Options:
<JeanAuthGuard
loadingComponent={<div>Checking authentication...</div>}
fallback={<CustomSignInPage />}
showDefaultSignIn={false}
>
<MyApp />
</JeanAuthGuard>
Level 3: Full Control (Advanced)
Complete control over authentication flow and UI implementation.
Authentication: Completely Automated
The React SDK uses a robust Universal OAuth 2.1 PKCE system that handles all authentication complexity for you. Users get secure, persistent sessions with zero configuration required from developers.
What You Get Automatically:
- OAuth 2.1 PKCE Flow - Industry-standard security with Google authentication
- Universal Identity - Same user account across all Jean Memory applications
- Session Persistence - Users stay logged in across browser refreshes and tabs
- Automatic Token Management - JWT tokens handled invisibly
- Error Recovery - Graceful handling of network issues and token expiration
Simple Setup for Any API Key:
<JeanProvider apiKey="jean_sk_your_api_key">
<JeanChat /> {/* Automatically handles authentication */}
</JeanProvider>
For Production Apps:
Users will see a “Sign In with Jean” button that triggers secure OAuth authentication.
For Development/Testing:
Test API keys (containing test
) automatically create isolated test users, so you can start coding immediately without any authentication setup.
import { JeanProvider, SignInWithJean, useJean } from '@jeanmemory/react';
function App() {
return (
<JeanProvider apiKey="jean_sk_your_api_key">
<AuthenticatedApp />
</JeanProvider>
);
}
function AuthenticatedApp() {
const { sendMessage, isAuthenticated, user, signOut } = useJean();
if (!isAuthenticated) {
return (
<SignInWithJean
onSuccess={(user) => console.log('Signed in:', user)}
>
Custom Sign In Button
</SignInWithJean>
);
}
// Your completely custom app implementation
return (
<div>
<h1>Welcome, {user?.name}</h1>
<button onClick={signOut}>Sign Out</button>
{/* Your custom chat interface */}
</div>
);
}
The useJean
Hook
The useJean
hook provides access to all core functionality for building custom interfaces.
const {
// Authentication State
isAuthenticated: boolean,
isLoading: boolean,
user: JeanUser | null,
// Conversation State
messages: JeanMessage[],
error: string | null,
// Core Methods
sendMessage: (message: string, options?: MessageOptions) => Promise<void>,
signOut: () => void,
clearConversation: () => void,
// Document Management
storeDocument: (title: string, content: string) => Promise<void>,
connect: (service: 'notion' | 'slack' | 'gdrive') => void,
// Direct Memory Tools
tools: {
add_memory: (content: string) => Promise<any>;
search_memory: (query: string) => Promise<any>;
deep_memory_query: (query: string) => Promise<any>;
store_document: (title: string, content: string, document_type?: string) => Promise<any>;
};
} = useJean();
Building a Custom Chat Interface
Example implementation showing authentication handling and message management:
import { useJean, SignInWithJean } from '@jeanmemory/react';
import { useState } from 'react';
function CustomChatInterface() {
const { isAuthenticated, messages, sendMessage, signOut, user } = useJean();
const [input, setInput] = useState('');
if (!isAuthenticated) {
return (
<div className="auth-container">
<h2>Sign in to continue</h2>
<SignInWithJean onSuccess={(user) => console.log('Welcome:', user.email)}>
Sign In with Jean
</SignInWithJean>
</div>
);
}
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
try {
await sendMessage(input);
setInput('');
} catch (error) {
console.error('Failed to send message:', error);
}
};
return (
<div className="chat-container">
<header>
<span>Welcome, {user?.name}</span>
<button onClick={signOut}>Sign Out</button>
</header>
<div className="messages">
{messages.map((message) => (
<div key={message.id} className={`message ${message.role}`}>
<strong>{message.role === 'user' ? 'You' : 'Jean'}:</strong>
{message.content}
</div>
))}
</div>
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask Jean anything..."
/>
<button type="submit">Send</button>
</form>
</div>
);
}
Configuration Options (Optional)
For 99% of use cases, the defaults work perfectly. But when you need control:
const { sendMessage } = useJean();
// Speed-optimized (faster, less comprehensive)
await sendMessage("What's my schedule?", { speed: "fast" });
// Different tools for specific needs
await sendMessage("What's my schedule?", { tool: "search_memory" });
// Simple text response instead of full metadata
await sendMessage("What's my schedule?", { format: "simple" });
Primary Method: For most use cases, we strongly recommend using the new getContext
function to retrieve context. It provides a simpler interface with predictable performance.
For advanced use cases where you need fine-grained control over Jean Memory, you can use the tools
namespace from the useJean
hook.
import { useJean } from '@jeanmemory/react';
function AdvancedComponent() {
const { tools, isAuthenticated } = useJean();
const handleDirectMemoryAdd = async () => {
if (!isAuthenticated) return;
// Direct tool call
const result = await tools.add_memory("My dog's name is Max.");
console.log('Memory added:', result);
};
const handleSearch = async () => {
if (!isAuthenticated) return;
const results = await tools.search_memory("information about my pets");
console.log('Search results:', results);
};
// Store documents directly
const handleStoreDocument = async () => {
if (!isAuthenticated) return;
await tools.store_document(
"Meeting Notes",
"# Team Meeting\n\n- Discussed project timeline\n- Next steps defined",
"markdown"
);
};
// Deep memory queries for complex relationship discovery
const handleDeepQuery = async () => {
if (!isAuthenticated) return;
const insights = await tools.deep_memory_query(
"connections between my preferences and goals"
);
console.log('Deep insights:', insights);
};
}
tools.add_memory(content)
- Add a specific memory
tools.search_memory(query)
- Search existing memories
tools.deep_memory_query(query)
- Complex relationship queries
tools.store_document(title, content, type?)
- Store structured documents
Note: These tools automatically handle authentication and use your user context. No manual token management required.
Session Management
Sign Out
User sign-out is handled automatically through the useJean
hook:
function MyComponent() {
const { signOut, user } = useJean();
const handleSignOut = async () => {
await signOut();
// User is automatically signed out and state is cleared
};
return (
<div>
<span>Welcome, {user?.name}</span>
<button onClick={handleSignOut}>Sign Out</button>
</div>
);
}
The signOut()
method:
- Clears all authentication tokens and session data
- Resets the authentication state
- Removes locally stored user information
- Prepares the application for a fresh sign-in
Alternative Manual Approach:
import { signOutFromJean } from '@jeanmemory/react';
// Direct function call (not recommended for most use cases)
const handleManualSignOut = () => {
signOutFromJean();
window.location.reload();
};