TypeScript Agent SDK
Full-featured TypeScript SDK for building AI agents with persistent memory, local SQLite storage, cloud sync, and offline-first architecture.
@rekall/agent-sdk
Installation
npm install @rekall/agent-sdk
Prerequisites
The Agent SDK requires Node.js 18+ and includes a bundled SQLite binary via better-sqlite3. No additional native dependencies are needed on most platforms.
Initialization
Create a RekallAgent instance with your API key and agent configuration. Call initialize() to set up the local database and establish the cloud connection.
import { RekallAgent } from '@rekall/agent-sdk';const agent = new RekallAgent({apiKey: process.env.REKALL_API_KEY!,agentId: 'my-assistant',storage: {path: './data/rekall.db', // Local SQLite pathencryptionKey: process.env.REKALL_ENCRYPTION_KEY, // Optional},sync: {enabled: true, // Enable cloud sync (default: true)intervalMs: 30_000, // Sync every 30 secondsstrategy: 'last-write-wins', // Conflict resolution},baseUrl: 'https://api.rekall.ai/v1', // Default});// Initialize local DB and start syncawait agent.initialize();// Always clean up when doneprocess.on('SIGTERM', async () => {await agent.shutdown();});
Environment variables
Store your API key in an environment variable. Never hard-code secrets in source files. The SDK reads REKALL_API_KEY automatically if no apiKey is provided.
Local SQLite Storage
The Agent SDK stores all memories locally in a SQLite database. This provides instant reads, offline capability, and reduced API calls. The local database is automatically synced with the Rekall cloud.
const agent = new RekallAgent({apiKey: process.env.REKALL_API_KEY!,agentId: 'my-assistant',storage: {path: './data/rekall.db',// Optional: encrypt data at restencryptionKey: process.env.REKALL_ENCRYPTION_KEY,// Optional: set max DB size (default: 500MB)maxSizeMb: 1000,// Optional: WAL mode for concurrent reads (default: true)walMode: true,},});
Local queries bypass the network entirely, returning results in microseconds. The SDK maintains a write-ahead log for durability and supports concurrent read access.
Cloud Sync
Cloud sync keeps your local database in sync with the Rekall API. Changes are pushed on a configurable interval and pulled automatically. The SDK tracks a sync cursor to minimize data transfer.
// Trigger an immediate syncawait agent.sync();// Check sync statusconst status = agent.getSyncStatus();console.log(status);// {// lastSyncAt: '2025-01-15T10:30:00Z',// pendingChanges: 3,// connected: true,// strategy: 'last-write-wins'// }// Pause and resume syncagent.pauseSync();agent.resumeSync();
Creating Memories
Store memories locally and sync them to the cloud. The SDK supports all seven memory types: episodic, semantic, procedural, long-term, short-term, execution, and preferences.
const memory = await agent.memories.create({type: 'episodic',content: 'User asked about quarterly revenue trends for Q3 2024.',metadata: {conversationId: 'conv_abc123',userId: 'user_456',tags: ['finance', 'revenue', 'Q3'],},context: 'agent', // 'agent' | 'user' | 'hive'importance: 0.8, // 0.0 - 1.0});console.log(memory.id); // 'mem_...'console.log(memory.createdAt); // ISO timestampconsole.log(memory.syncStatus); // 'pending' | 'synced' | 'conflict'
const memory = await agent.memories.create({type: 'semantic',content: 'Acme Corp is a Fortune 500 company headquartered in San Francisco.',entities: [{ name: 'Acme Corp', type: 'organization' },{ name: 'San Francisco', type: 'location' },],relationships: [{source: 'Acme Corp',target: 'San Francisco',type: 'headquartered_in',},],});
const memory = await agent.memories.create({type: 'procedural',content: 'Deploy to production workflow',steps: [{ order: 1, instruction: 'Run the test suite', command: 'npm test' },{ order: 2, instruction: 'Build the application', command: 'npm run build' },{ order: 3, instruction: 'Deploy to staging', command: 'npm run deploy:staging' },{ order: 4, instruction: 'Run smoke tests', command: 'npm run test:smoke' },{ order: 5, instruction: 'Promote to production', command: 'npm run deploy:prod' },],});
Searching Memories
Search locally or across the cloud. Local searches are instant; cloud searches use vector embeddings for semantic similarity.
const results = await agent.memories.search({query: 'What do we know about the customer onboarding process?',type: 'procedural', // Optional: filter by typecontext: 'agent', // Optional: filter by contextlimit: 10,threshold: 0.7, // Minimum similarity scoreincludeMetadata: true,});for (const result of results) {console.log(result.memory.content);console.log(result.score); // Similarity score 0.0 - 1.0console.log(result.source); // 'local' | 'cloud'}
// Search with metadata filtersconst results = await agent.memories.search({query: 'revenue',filters: {tags: { contains: 'finance' },createdAfter: '2024-06-01T00:00:00Z',importance: { gte: 0.5 },},sort: 'relevance', // 'relevance' | 'recency' | 'importance'});
Entity Management
Manage entities and their relationships in the knowledge graph. Entities are automatically extracted from semantic memories, but you can also create and manage them directly.
// Create an entityconst entity = await agent.entities.create({name: 'Acme Corp',type: 'organization',attributes: {industry: 'Technology',founded: 2010,website: 'https://acme.example.com',},});// Create a relationship between entitiesawait agent.entities.relate({sourceId: entity.id,targetId: 'ent_person_456',type: 'employs',attributes: { role: 'CEO', since: '2018-01-01' },});// Query the knowledge graphconst graph = await agent.entities.graph({rootId: entity.id,depth: 2, // Traverse 2 levelstypes: ['employs', 'headquartered_in', 'acquired'],});// List entities by typeconst orgs = await agent.entities.list({type: 'organization',limit: 50,});
Agent Lifecycle
The SDK provides full agent lifecycle management: spawn child agents, send messages between agents, and terminate agents cleanly.
// Spawn a child agentconst child = await agent.spawn({agentId: 'research-assistant',config: {model: 'claude-3-opus',systemPrompt: 'You are a research assistant...',},memory: {context: 'agent', // Isolated memory contextinheritParent: true, // Copy parent memories},});// Send a message to a child agentconst response = await agent.send(child.agentId, {type: 'task',payload: {query: 'Research the latest AI safety papers from 2024',},});// Terminate a child agentawait agent.terminate(child.agentId, {preserveMemories: true, // Keep memories after termination});
// Get agent statusconst status = await agent.status();// { agentId: 'my-assistant', state: 'running', uptime: 3600, ... }// List all child agentsconst children = await agent.listChildren();for (const child of children) {console.log(child.agentId, child.state);}
Offline Mode
The SDK works fully offline. All memory operations read from and write to the local SQLite database. When connectivity is restored, changes are automatically synced.
// Force offline mode (useful for testing)const agent = new RekallAgent({apiKey: process.env.REKALL_API_KEY!,agentId: 'my-assistant',storage: { path: './rekall.db' },sync: { enabled: false }, // Start in offline mode});await agent.initialize();// All operations work locallyconst memory = await agent.memories.create({type: 'episodic',content: 'Created while offline',});// Later, enable sync to push changesagent.enableSync();await agent.sync(); // Push all pending changes
Conflict resolution
When the same memory is modified locally and remotely, the configured sync strategy determines the outcome. The default last-write-wins strategy uses timestamps. You can also use manual to handle conflicts yourself via the onConflict event listener.
Sync Strategies
Choose a conflict resolution strategy that fits your use case.
| Strategy | Behavior | Use Case |
|---|---|---|
| last-write-wins | Most recent write by timestamp is kept | Single-agent systems, simple setups |
| cloud-wins | Cloud version always takes precedence | Shared memory across multiple clients |
| local-wins | Local version always takes precedence | Authoritative local agent |
| manual | Fires an onConflict event for custom resolution | Complex multi-agent setups |
const agent = new RekallAgent({apiKey: process.env.REKALL_API_KEY!,agentId: 'my-assistant',storage: { path: './rekall.db' },sync: {strategy: 'manual',},});agent.on('conflict', async (event) => {const { localVersion, cloudVersion, memoryId } = event;// Custom merge logicif (localVersion.updatedAt > cloudVersion.updatedAt) {await event.resolveWith(localVersion);} else {await event.resolveWith(cloudVersion);}});
Event Listeners
Subscribe to lifecycle and sync events to react to changes in real time.
// Sync eventsagent.on('sync:start', () => console.log('Sync started'));agent.on('sync:complete', (result) => {console.log(`Synced ${result.pushed} up, ${result.pulled} down`);});agent.on('sync:error', (error) => console.error('Sync failed:', error));// Memory eventsagent.on('memory:created', (memory) => {console.log('New memory:', memory.id);});agent.on('memory:updated', (memory) => {console.log('Updated:', memory.id);});agent.on('memory:deleted', (memoryId) => {console.log('Deleted:', memoryId);});// Conflict events (when strategy is 'manual')agent.on('conflict', async (event) => {console.log('Conflict on:', event.memoryId);});// Agent lifecycle eventsagent.on('agent:spawned', (child) => console.log('Spawned:', child.agentId));agent.on('agent:terminated', (agentId) => console.log('Terminated:', agentId));agent.on('agent:message', (msg) => console.log('Message from:', msg.from));// Remove a listenerconst handler = (m: Memory) => console.log(m);agent.on('memory:created', handler);agent.off('memory:created', handler);
TypeScript Types
The SDK exports all types for full IntelliSense support. Key types are listed below.
import type {// Core typesMemory,MemoryType,MemoryContext,MemoryCreateInput,MemorySearchInput,MemorySearchResult,// Entity typesEntity,EntityCreateInput,Relationship,GraphQueryResult,// Agent typesAgentConfig,AgentStatus,SpawnOptions,AgentMessage,// Sync typesSyncStatus,SyncStrategy,ConflictEvent,// Storage typesStorageConfig,// Event typesRekallEventMap,} from '@rekall/agent-sdk';
interface Memory {id: string;type: MemoryType;content: string;context: MemoryContext;importance: number;metadata: Record<string, unknown>;entities: Entity[];relationships: Relationship[];createdAt: string;updatedAt: string;accessedAt: string;accessCount: number;decayFactor: number;syncStatus: 'pending' | 'synced' | 'conflict';}type MemoryType =| 'episodic'| 'semantic'| 'procedural'| 'long_term'| 'short_term'| 'execution'| 'preferences';type MemoryContext = 'agent' | 'user' | 'hive';
Progressive Disclosure (Infinite Context)
The agent SDK provides three methods for token-efficient memory retrieval. Instead of loading full content for every search result, use the two-step pattern to preview memories first, then load only what you need.
recallIndex()
Returns a lightweight index with snippets, scores, and token estimates.
const index = await agent.recallIndex('project requirements', {tokenBudget: 2000,types: ['ltm', 'episodic', 'procedural'],limit: 50,});// index.index: MemoryIndexEntry[] — lightweight entries// index.indexTokens: number — total tokens used by index// index.totalFullTokens: number — tokens if all were loaded fully// index.hasMore: boolean — more results availablefor (const entry of index.index) {console.log(`[${entry.type}] ${entry.snippet} (score: ${entry.score})`);}
recallFull()
Loads full content for specific memory IDs returned by recallIndex.
// Select the most relevant memoriesconst topIds = index.index.filter(e => e.score > 0.7).map(e => e.id);// Load full content only for selected itemsconst memories = await agent.recallFull(topIds);for (const mem of memories) {console.log(mem.content); // Full memory content}
smartRecall()
Combines both steps automatically — fetches the index, selects memories within your token budget, and returns full content.
// Automatic progressive disclosure within budgetconst memories = await agent.smartRecall('user preferences', {tokenBudget: 4000,progressive: true,});// Returns full content for as many memories as fit in 4000 tokens
observe()
Captures tool outputs, file reads, and API responses. These become searchable via recallIndex in future sessions.
// Capture a file read for future retrievalawait agent.observe(fileContent, {toolName: 'file_read',tags: ['config', 'deployment'],type: 'file_read',});// Later, find it via progressive disclosureconst index = await agent.recallIndex('deployment config');
