React Integration
Integrate the Fig1 AI SDK into your React or Next.js application.
Installation
No npm package required—the SDK is a REST API. Use fetch or any HTTP client.
For TypeScript, copy the types from the Types Reference.
API Client
Create a reusable client:
// lib/fig1-client.ts
const API_BASE = 'https://app.fig1.ai/api/sdk';
export class Fig1Client {
private apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const response = await fetch(`${API_BASE}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',
'X-Fig1-API-Key': this.apiKey,
...options.headers,
},
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error || 'API request failed');
}
return data.data;
}
async chat(message: string, sessionId?: string, options?: {
personaId?: string;
preferences?: Record<string, any>;
context?: Record<string, any>;
}) {
return this.request<{
message: string;
sessionId: string;
actions?: any[];
metadata: { model: string; tokensUsed: number };
}>('/agent/chat', {
method: 'POST',
body: JSON.stringify({ message, sessionId, ...options }),
});
}
async search(query: string, options?: {
searchType?: 'hybrid' | 'standard' | 'expanded';
maxResults?: number;
}) {
return this.request<{
results: any[];
totalResults: number;
}>('/rag/search', {
method: 'POST',
body: JSON.stringify({ query, ...options }),
});
}
}
// Singleton instance
export const fig1 = new Fig1Client(process.env.NEXT_PUBLIC_FIG1_API_KEY!);
useAgent Hook
// hooks/useAgent.ts
import { useState, useCallback } from 'react';
import { fig1 } from '@/lib/fig1-client';
interface Message {
role: 'user' | 'assistant';
content: string;
}
export function useAgent(personaId?: string) {
const [messages, setMessages] = useState<Message[]>([]);
const [sessionId, setSessionId] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const sendMessage = useCallback(async (
text: string,
preferences?: Record<string, any>
) => {
setIsLoading(true);
setError(null);
// Add user message immediately
setMessages(prev => [...prev, { role: 'user', content: text }]);
try {
const response = await fig1.chat(text, sessionId || undefined, {
personaId,
preferences,
});
setSessionId(response.sessionId);
setMessages(prev => [
...prev,
{ role: 'assistant', content: response.message }
]);
return response;
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to send';
setError(message);
setMessages(prev => prev.slice(0, -1)); // Remove optimistic message
throw err;
} finally {
setIsLoading(false);
}
}, [sessionId, personaId]);
const clearChat = useCallback(() => {
setMessages([]);
setSessionId(null);
setError(null);
}, []);
return { messages, sendMessage, clearChat, isLoading, error, sessionId };
}
useAgentActions Hook
Handle agent-triggered actions like navigation:
// hooks/useAgentActions.ts
import { useCallback } from 'react';
import { useRouter } from 'next/navigation';
interface ClientAction {
type: string;
payload: {
route?: string;
url?: string;
productId?: string;
modalId?: string;
};
immediate?: boolean;
}
export function useAgentActions(options: {
onNavigate?: (route: string) => void;
onShowProduct?: (productId: string) => void;
onOpenModal?: (modalId: string) => void;
} = {}) {
const router = useRouter();
const handleActions = useCallback((actions: ClientAction[]) => {
for (const action of actions) {
if (action.immediate === false) continue;
switch (action.type) {
case 'navigate':
if (action.payload.route) {
options.onNavigate?.(action.payload.route) ?? router.push(action.payload.route);
}
break;
case 'open_url':
if (action.payload.url) {
window.open(action.payload.url, '_blank');
}
break;
case 'show_product':
if (action.payload.productId) {
options.onShowProduct?.(action.payload.productId);
}
break;
case 'open_modal':
if (action.payload.modalId) {
options.onOpenModal?.(action.payload.modalId);
}
break;
}
}
}, [router, options]);
return { handleActions };
}
Chat Component
// components/Chat.tsx
'use client';
import { useState } from 'react';
import { useAgent } from '@/hooks/useAgent';
export function Chat({ personaId }: { personaId?: string }) {
const [input, setInput] = useState('');
const { messages, sendMessage, isLoading, error } = useAgent(personaId);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || isLoading) return;
const message = input;
setInput('');
await sendMessage(message);
};
return (
<div className="flex flex-col h-[500px]">
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((msg, i) => (
<div
key={i}
className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-[80%] rounded-lg p-3 ${
msg.role === 'user'
? 'bg-blue-500 text-white'
: 'bg-gray-100 text-gray-900'
}`}
>
{msg.content}
</div>
</div>
))}
{isLoading && (
<div className="flex justify-start">
<div className="bg-gray-100 rounded-lg p-3">
<span className="animate-pulse">Thinking...</span>
</div>
</div>
)}
</div>
{error && <div className="px-4 py-2 text-red-500 text-sm">{error}</div>}
{/* Input */}
<form onSubmit={handleSubmit} className="p-4 border-t">
<div className="flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type your message..."
className="flex-1 border rounded-lg px-4 py-2"
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading || !input.trim()}
className="bg-blue-500 text-white px-4 py-2 rounded-lg disabled:opacity-50"
>
Send
</button>
</div>
</form>
</div>
);
}
Next.js API Route (Recommended)
For security, proxy requests through your backend:
// app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const body = await request.json();
const response = await fetch('https://app.fig1.ai/api/sdk/agent/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Fig1-API-Key': process.env.FIG1_API_KEY!, // Server-side only
},
body: JSON.stringify(body),
});
const data = await response.json();
return NextResponse.json(data);
}
Then update your client to use your API route:
// Use your backend instead of Fig1 directly
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, sessionId }),
});
Environment Variables
# .env.local
FIG1_API_KEY=fig1_sdk_your_api_key
# Only if calling from client (not recommended)
NEXT_PUBLIC_FIG1_API_KEY=fig1_sdk_your_api_key