npm package: @recallbricks/sdk
Description: Enterprise-grade TypeScript SDK for RecallBricks API - cognitive memory platform with circuit breaker, telemetry, and batch operations
Author: RecallBricks
Latest version: 2.0.0

# RecallBricks TypeScript SDK

Enterprise-grade TypeScript SDK for the RecallBricks API. Build intelligent memory systems with semantic search, graph relationships, and persistent context.

## What's New in v1.2.0

- **Automatic Metadata Extraction**: New `learn()` method automatically extracts tags, categories, entities, importance scores, and summaries
- **Organized Recall**: Enhanced `recall()` method returns category summaries for 3-5x faster agent reasoning
- **Deprecation**: `saveMemory()` is deprecated in favor of `learn()`

## Features

- **Full TypeScript Support**: Complete type definitions for all API operations
- **Automatic Metadata Extraction**: AI-powered tags, categories, entities, and summaries
- **Organized Recall**: Category summaries for faster agent reasoning (10-15s → 2-3s)
- **Retry Logic**: Automatic exponential backoff for transient failures
- **Error Handling**: Comprehensive error types with detailed context
- **Timeout Configuration**: Configurable request timeouts
- **Production Ready**: 80+ tests covering unit, integration, load/stress, and security
- **Zero Dependencies**: Only axios for HTTP requests

## Installation

```bash
npm install recallbricks
```

Or with yarn:

```bash
yarn add recallbricks
```

## Quick Start

```typescript
import { RecallBricks } from 'recallbricks';

const client = new RecallBricks({ apiKey: 'your-api-key' });

// Learn with automatic metadata extraction (v1.2.0)
const learned = await client.learn({
  text: 'Tyler is building RecallBricks, a cognitive memory platform',
  source: 'demo',
});

console.log(learned.metadata);
// {
//   tags: ['development', 'founder', 'startup'],
//   category: 'Work',
//   entities: ['Tyler', 'RecallBricks'],
//   importance: 0.85,
//   summary: 'Founder building cognitive memory infrastructure'
// }

// Recall with organized results (v1.2.0)
const results = await client.recall({
  query: 'What is Tyler working on?',
  organized: true,
  limit: 10
});

console.log(results.categories);
// {
//   Work: {
//     count: 5,
//     avg_score: 0.87,
//     summary: 'Memories about software development and RecallBricks'
//   }
// }
```

## API Reference

### Client Configuration

```typescript
interface RecallBricksConfig {
  apiKey: string;              // Required: Your API key
  baseUrl?: string;            // Optional: API base URL
  timeout?: number;            // Optional: Request timeout in ms (default: 30000)
  maxRetries?: number;         // Optional: Max retry attempts (default: 3)
  retryDelay?: number;         // Optional: Initial retry delay in ms (default: 1000)
  maxRetryDelay?: number;      // Optional: Max retry delay in ms (default: 10000)
}
```

### Core Methods

#### learn(request) - v1.2.0

Store a memory with automatic metadata extraction. This is the recommended method for storing memories.

```typescript
const learned = await client.learn({
  text: 'Tyler is building RecallBricks, a cognitive memory platform',
  source: 'demo',           // optional, defaults to 'typescript-sdk'
  project_id: 'proj-123',   // optional
  metadata: {               // optional overrides
    importance: 1.0,
    category: 'Security',
  },
});

console.log(learned.id);        // 'mem-123'
console.log(learned.metadata);  // auto-generated metadata
```

**Parameters:**
- `request.text` (string, required): The content to store
- `request.source` (string, optional): Source identifier (default: 'typescript-sdk')
- `request.project_id` (string, optional): Project ID for organization
- `request.metadata` (object, optional): Override auto-generated metadata
- `request.userId` (string, required with service token): User ID for multi-tenant

**Returns:** `Promise<LearnResponse>` with:
- `id`: Memory ID
- `text`: Original text
- `metadata`: Auto-generated metadata (tags, category, entities, importance, summary)
- `created_at`: Timestamp

---

#### recall(request) - v1.2.0

Recall memories with optional organization by category. Enables 3-5x faster agent reasoning.

```typescript
// Basic recall
const results = await client.recall({
  query: 'What is Tyler working on?',
  limit: 10,
});

// Organized recall with category summaries
const results = await client.recall({
  query: 'What is Tyler working on?',
  organized: true,
  limit: 10,
  min_helpfulness_score: 0.5,
  decay_old_memories: true,
  weight_by_usage: true,
});

console.log(results.memories);   // Array of RecallMemory
console.log(results.categories); // { Work: { count, avg_score, summary }, ... }
console.log(results.total);      // Total matching memories
```

**Parameters:**
- `request.query` (string, required): Search query
- `request.limit` (number, optional): Max results (default: 10)
- `request.organized` (boolean, optional): Return category summaries
- `request.min_helpfulness_score` (number, optional): Min score filter (0-1)
- `request.decay_old_memories` (boolean, optional): Apply time decay
- `request.weight_by_usage` (boolean, optional): Weight by usage frequency
- `request.project_id` (string, optional): Filter by project
- `request.userId` (string, required with service token): User ID for multi-tenant

**Returns:** `Promise<RecallResponse>` with:
- `memories`: Array of RecallMemory with metadata and scores
- `categories`: Category summaries (when organized=true)
- `total`: Total count

---

#### createMemory(text, options?) - Legacy

Create a new memory with optional metadata and tags.

```typescript
const memory = await client.createMemory('Important information', {
  tags: ['important', 'work'],
  metadata: {
    userId: '123',
    category: 'business'
  },
  timestamp: '2025-01-01T12:00:00Z' // Optional
});
```

**Parameters:**
- `text` (string): The content of the memory
- `options` (object, optional):
  - `tags` (string[]): Array of tags for categorization
  - `metadata` (object): Key-value pairs for additional context
  - `timestamp` (string): ISO 8601 timestamp

**Returns:** `Promise<Memory>`

---

#### listMemories(options?)

List memories with filtering and pagination.

```typescript
const result = await client.listMemories({
  limit: 10,
  offset: 0,
  tags: ['important'],
  metadata: { userId: '123' },
  sort: 'desc',
  sortBy: 'created_at'
});

console.log(`Found ${result.total} memories`);
result.memories.forEach(memory => {
  console.log(`- ${memory.text}`);
});
```

**Parameters:**
- `options` (object, optional):
  - `limit` (number): Max number of results
  - `offset` (number): Pagination offset
  - `tags` (string[]): Filter by tags
  - `metadata` (object): Filter by metadata
  - `sort` ('asc' | 'desc'): Sort order
  - `sortBy` (string): Field to sort by

**Returns:** `Promise<ListMemoriesResponse>`

---

#### search(query, options?)

Semantic search across memories.

```typescript
const results = await client.search('user preferences', {
  limit: 5,
  threshold: 0.7,
  tags: ['preference'],
  metadata: { userId: '123' }
});

results.memories.forEach(memory => {
  console.log(`[${memory.similarity.toFixed(2)}] ${memory.text}`);
});
```

**Parameters:**
- `query` (string): Search query
- `options` (object, optional):
  - `limit` (number): Max results to return
  - `threshold` (number): Minimum similarity score (0-1)
  - `tags` (string[]): Filter by tags
  - `metadata` (object): Filter by metadata

**Returns:** `Promise<SearchResponse>`

---

#### getRelationships(memoryId)

Get all relationships for a memory.

```typescript
const result = await client.getRelationships('mem-123');

console.log(`Memory: ${result.memoryId}`);
console.log(`Relationships: ${result.count}`);

result.relationships.forEach(rel => {
  console.log(`  ${rel.source_id} -> ${rel.target_id} (${rel.type}, strength: ${rel.strength})`);
});
```

**Parameters:**
- `memoryId` (string): ID of the memory

**Returns:** `Promise<RelationshipsResponse>`

---

#### getGraphContext(memoryId, depth?)

Get the graph context around a memory up to a specified depth.

```typescript
const result = await client.getGraphContext('mem-123', 3);

console.log(`Root: ${result.rootMemoryId}`);
console.log(`Nodes: ${result.stats.nodeCount}`);
console.log(`Edges: ${result.stats.edgeCount}`);
console.log(`Depth: ${result.stats.depth}`);

result.graph.nodes.forEach(node => {
  console.log(`Node: ${node.id} - ${node.text}`);
});

result.graph.edges.forEach(edge => {
  console.log(`Edge: ${edge.source} -> ${edge.target} (${edge.type})`);
});
```

**Parameters:**
- `memoryId` (string): Root memory ID
- `depth` (number, optional): Max traversal depth (1-10, default: 2)

**Returns:** `Promise<GraphContextResponse>`

---

#### updateMemory(memoryId, updates)

Update an existing memory.

```typescript
const updated = await client.updateMemory('mem-123', {
  text: 'Updated text',
  tags: ['updated', 'important'],
  metadata: { version: 2 }
});

console.log(`Updated at: ${updated.updated_at}`);
```

**Parameters:**
- `memoryId` (string): ID of the memory to update
- `updates` (object): Fields to update
  - `text` (string, optional): New text content
  - `tags` (string[], optional): New tags
  - `metadata` (object, optional): New metadata

**Returns:** `Promise<Memory>`

---

#### deleteMemory(memoryId)

Delete a memory by ID.

```typescript
await client.deleteMemory('mem-123');
console.log('Memory deleted successfully');
```

**Parameters:**
- `memoryId` (string): ID of the memory to delete

**Returns:** `Promise<boolean>`

---

## Usage Examples

### Building a User Preference System

```typescript
import { RecallBricks } from 'recallbricks';

const client = new RecallBricks({ apiKey: process.env.RECALLBRICKS_API_KEY! });

// Store user preferences
async function savePreference(userId: string, preference: string, value: any) {
  return await client.createMemory(
    `User ${userId} set ${preference} to ${value}`,
    {
      tags: ['preference', preference],
      metadata: { userId, preference, value: String(value) }
    }
  );
}

// Retrieve user preferences
async function getUserPreferences(userId: string) {
  const results = await client.listMemories({
    tags: ['preference'],
    metadata: { userId },
    limit: 100
  });
  return results.memories;
}

// Find similar preferences across users
async function findSimilarPreferences(preferenceDescription: string) {
  const results = await client.search(preferenceDescription, {
    tags: ['preference'],
    threshold: 0.8,
    limit: 10
  });
  return results.memories;
}
```

### Conversation Memory System

```typescript
// Store conversation turns
async function saveConversation(conversationId: string, role: string, content: string) {
  return await client.createMemory(content, {
    tags: ['conversation', role],
    metadata: {
      conversationId,
      role,
      timestamp: new Date().toISOString()
    }
  });
}

// Retrieve conversation history
async function getConversationHistory(conversationId: string) {
  const results = await client.listMemories({
    tags: ['conversation'],
    metadata: { conversationId },
    sort: 'asc',
    sortBy: 'created_at'
  });
  return results.memories;
}

// Find relevant context from past conversations
async function findRelevantContext(query: string, conversationId: string) {
  return await client.search(query, {
    tags: ['conversation'],
    metadata: { conversationId },
    threshold: 0.7,
    limit: 5
  });
}
```

### Knowledge Graph Exploration

```typescript
// Create interconnected memories
async function buildKnowledgeGraph() {
  const concept1 = await client.createMemory('Machine learning is a subset of AI', {
    tags: ['concept', 'ml', 'ai']
  });

  const concept2 = await client.createMemory('Deep learning uses neural networks', {
    tags: ['concept', 'deep-learning']
  });

  const concept3 = await client.createMemory('Neural networks mimic brain structure', {
    tags: ['concept', 'neural-networks']
  });

  return [concept1, concept2, concept3];
}

// Explore relationships
async function exploreRelationships(memoryId: string) {
  // Get immediate relationships
  const relationships = await client.getRelationships(memoryId);

  // Get broader context
  const graph = await client.getGraphContext(memoryId, 3);

  return { relationships, graph };
}
```

### Pagination Example

```typescript
async function getAllMemories() {
  const allMemories = [];
  let offset = 0;
  const limit = 100;
  let hasMore = true;

  while (hasMore) {
    const result = await client.listMemories({ limit, offset });
    allMemories.push(...result.memories);
    offset += limit;
    hasMore = result.memories.length === limit;
  }

  return allMemories;
}
```

## Error Handling

The SDK uses a custom `RecallBricksError` class for all API errors:

```typescript
import { RecallBricksError } from 'recallbricks';

try {
  const memory = await client.createMemory('test');
} catch (error) {
  if (error instanceof RecallBricksError) {
    console.error(`Error ${error.statusCode}: ${error.message}`);
    console.error(`Code: ${error.code}`);
    console.error(`Details:`, error.details);
  } else {
    console.error('Unexpected error:', error);
  }
}
```

### Error Properties

- `message` (string): Human-readable error message
- `statusCode` (number): HTTP status code
- `code` (string): Error code from API
- `details` (unknown): Additional error details

## Retry Logic

The SDK automatically retries failed requests with exponential backoff for:

- Network errors (connection refused, timeout, etc.)
- 429 (Rate Limit Exceeded)
- 500+ (Server errors)

**Non-retryable errors** (fail immediately):
- 400 (Bad Request)
- 401 (Unauthorized)
- 403 (Forbidden)
- 404 (Not Found)

Configure retry behavior:

```typescript
const client = new RecallBricks({
  apiKey: 'your-api-key',
  maxRetries: 5,           // Max number of retry attempts
  retryDelay: 500,         // Initial delay in ms
  maxRetryDelay: 30000,    // Max delay in ms (caps exponential backoff)
});
```

## TypeScript Types

All types are exported from the main module:

```typescript
import {
  RecallBricks,
  RecallBricksConfig,
  RecallBricksError,
  Memory,
  CreateMemoryOptions,
  ListMemoriesOptions,
  ListMemoriesResponse,
  SearchOptions,
  SearchResponse,
  SearchMemory,
  Relationship,
  RelationshipsResponse,
  GraphNode,
  GraphEdge,
  Graph,
  GraphStats,
  GraphContextResponse,
  UpdateMemoryOptions,
  MemoryMetadata,
} from 'recallbricks';
```

## Development

```bash
# Install dependencies
npm install

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Build
npm run build

# Lint
npm run lint
```

## Testing

The SDK includes comprehensive test coverage:

- **Unit Tests**: Client initialization, configuration, and individual methods
- **Integration Tests**: Full workflows and real-world scenarios
- **Edge Case Tests**: Boundary conditions, malformed data, and error scenarios
- **Security Tests**: Input validation, injection prevention, and data protection

Run tests:

```bash
npm test
```

View coverage report:

```bash
npm run test:coverage
```

## Requirements

- Node.js 16.0.0 or higher
- TypeScript 5.0+ (for development)

## License

MIT

## Support

For issues and feature requests, please file an issue on the project repository.

## Migration Guide (v1.1.x → v1.2.0)

### Upgrading from saveMemory() to learn()

The `saveMemory()` method is deprecated. Migrate to `learn()` for automatic metadata extraction:

```typescript
// Before (v1.1.x)
const memory = await client.createMemory('Important information', {
  tags: ['important'],
  metadata: { userId: '123' }
});

// After (v1.2.0) - with automatic metadata
const learned = await client.learn({
  text: 'Important information',
});
// Tags, category, entities, and summary are auto-generated!
```

### Using Organized Recall

Replace `search()` with `recall()` for organized results:

```typescript
// Before (v1.1.x)
const results = await client.search('query', { limit: 10 });

// After (v1.2.0) - with category summaries
const results = await client.recall({
  query: 'query',
  organized: true,
  limit: 10,
});
// Access results.categories for 3-5x faster agent reasoning
```

### Service Token Changes

Learn and recall work seamlessly with service tokens:

```typescript
const client = new RecallBricks({ serviceToken: 'your-token' });

// Multi-tenant learn
const learned = await client.learn({
  text: 'User preference',
  userId: 'user-123',  // Required with service token
});

// Multi-tenant recall
const results = await client.recall({
  query: 'preferences',
  userId: 'user-123',  // Required with service token
  organized: true,
});
```

### Breaking Changes

None! v1.2.0 is fully backward compatible with v1.1.x.

## Contributing

Contributions are welcome! Please ensure all tests pass and coverage remains high:

```bash
npm test
npm run test:coverage
```