> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usesatori.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct Client Usage

> Use the MemoryClient directly for custom integrations and advanced use cases

## Overview

While the `memoryTools()` helper is great for Vercel AI SDK integration, you can also use the `MemoryClient` directly for more control over memory operations. This is useful for:

* Custom AI frameworks
* Background jobs that manage memories
* Admin interfaces for viewing/managing memories
* Non-LLM use cases

## Installation

```bash theme={null}
npm install @usesatori/tools
```

## Basic Usage

### Creating a Client

```typescript theme={null}
import { MemoryClient } from '@usesatori/tools';

const client = new MemoryClient({
  apiKey: process.env.SATORI_API_KEY!,
  baseUrl: process.env.SATORI_URL!,
  userId: 'user-123',
});
```

### Adding Memories

```typescript theme={null}
const memory = await client.addMemory(
  'User prefers TypeScript over JavaScript'
);

console.log('Saved memory:', memory.id);
```

With metadata:

```typescript theme={null}
const memory = await client.addMemory(
  'User prefers dark mode in all applications',
  {
    metadata: {
      category: 'preference',
      tags: ['ui', 'theme'],
      importance: 'high',
    },
  }
);
```

### Searching Memories

```typescript theme={null}
const memories = await client.searchMemories('programming languages');

memories.forEach((memory) => {
  console.log(`${memory.content} (similarity: ${memory.similarity})`);
});
```

With options:

```typescript theme={null}
const memories = await client.searchMemories('preferences', {
  limit: 5,
  threshold: 0.8, // Only very similar memories
});
```

### Getting All Memories

```typescript theme={null}
const allMemories = await client.getAllMemories();

console.log(`Total memories: ${allMemories.length}`);
```

With limit:

```typescript theme={null}
const recentMemories = await client.getAllMemories({ limit: 10 });
```

### Deleting Memories

```typescript theme={null}
await client.deleteMemory('memory-uuid');
console.log('Memory deleted');
```

## Complete API Reference

### Constructor

<ParamField path="apiKey" type="string" required>
  Your Satori API key
</ParamField>

<ParamField path="baseUrl" type="string" required>
  Satori server URL (e.g., `https://api.usesatori.sh`)
</ParamField>

<ParamField path="userId" type="string" required>
  User identifier for memory isolation
</ParamField>

### Methods

#### addMemory(content, options?)

Saves a new memory.

<ParamField body="content" type="string" required>
  The text content to save
</ParamField>

<ParamField body="options.metadata" type="object">
  Optional metadata for organization

  ```typescript theme={null}
  {
    category: 'preference',
    tags: ['important'],
    customField: 'value'
  }
  ```
</ParamField>

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

```typescript theme={null}
{
  id: 'uuid',
  content: 'User prefers TypeScript',
  userId: 'user-123',
  metadata: { category: 'preference' },
  createdAt: '2024-01-15T10:30:00Z',
  updatedAt: '2024-01-15T10:30:00Z'
}
```

#### searchMemories(query, options?)

Searches for semantically similar memories.

<ParamField body="query" type="string" required>
  Natural language search query
</ParamField>

<ParamField body="options.limit" type="number" default="10">
  Maximum number of results (1-100)
</ParamField>

<ParamField body="options.threshold" type="number" default="0.7">
  Minimum similarity score (0-1)
</ParamField>

**Returns:** `Promise<MemoryWithSimilarity[]>`

```typescript theme={null}
[
  {
    id: 'uuid',
    content: 'User prefers TypeScript',
    similarity: 0.92,
    userId: 'user-123',
    metadata: {},
    createdAt: '2024-01-15T10:30:00Z',
    updatedAt: '2024-01-15T10:30:00Z'
  }
]
```

#### getAllMemories(options?)

Retrieves all memories for the user.

<ParamField body="options.limit" type="number" default="100">
  Maximum number of memories to return
</ParamField>

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

#### deleteMemory(id)

Deletes a specific memory.

<ParamField body="id" type="string" required>
  UUID of the memory to delete
</ParamField>

**Returns:** `Promise<void>`

## Advanced Use Cases

### Building an Admin Dashboard

```typescript theme={null}
import { MemoryClient } from '@usesatori/tools';

export async function GET(req: Request) {
  const { searchParams } = new URL(req.url);
  const userId = searchParams.get('userId');
  
  if (!userId) {
    return new Response('Missing userId', { status: 400 });
  }
  
  const client = new MemoryClient({
    apiKey: process.env.SATORI_API_KEY!,
    baseUrl: process.env.SATORI_URL!,
    userId,
  });
  
  const memories = await client.getAllMemories();
  
  return Response.json({
    userId,
    totalMemories: memories.length,
    memories: memories.map((m) => ({
      id: m.id,
      content: m.content,
      createdAt: m.createdAt,
      metadata: m.metadata,
    })),
  });
}
```

### Background Memory Processing

```typescript theme={null}
// Cron job to clean up old memories
import { MemoryClient } from '@usesatori/tools';

async function cleanupOldMemories(userId: string) {
  const client = new MemoryClient({
    apiKey: process.env.SATORI_API_KEY!,
    baseUrl: process.env.SATORI_URL!,
    userId,
  });
  
  const memories = await client.getAllMemories();
  const sixMonthsAgo = Date.now() - 6 * 30 * 24 * 60 * 60 * 1000;
  
  for (const memory of memories) {
    const createdAt = new Date(memory.createdAt).getTime();
    
    if (createdAt < sixMonthsAgo) {
      await client.deleteMemory(memory.id);
      console.log(`Deleted old memory: ${memory.id}`);
    }
  }
}
```

### Memory Export

```typescript theme={null}
// Export user data for GDPR compliance
async function exportUserMemories(userId: string) {
  const client = new MemoryClient({
    apiKey: process.env.SATORI_API_KEY!,
    baseUrl: process.env.SATORI_URL!,
    userId,
  });
  
  const memories = await client.getAllMemories();
  
  const exportData = {
    userId,
    exportDate: new Date().toISOString(),
    totalMemories: memories.length,
    memories: memories.map((m) => ({
      content: m.content,
      createdAt: m.createdAt,
      metadata: m.metadata,
    })),
  };
  
  return JSON.stringify(exportData, null, 2);
}
```

### Custom AI Framework Integration

```typescript theme={null}
import { MemoryClient } from '@usesatori/tools';
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY!,
});

const memoryClient = new MemoryClient({
  apiKey: process.env.SATORI_API_KEY!,
  baseUrl: process.env.SATORI_URL!,
  userId: 'user-123',
});

async function chatWithMemory(userMessage: string) {
  // Search for relevant context
  const relevantMemories = await memoryClient.searchMemories(userMessage, {
    limit: 5,
  });
  
  const context = relevantMemories
    .map((m) => m.content)
    .join('\n');
  
  // Call Claude with context
  const response = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 1024,
    messages: [
      {
        role: 'user',
        content: `Context about the user:\n${context}\n\nUser message: ${userMessage}`,
      },
    ],
  });
  
  // Extract and save any important information
  const responseText = response.content[0].text;
  
  // Simple heuristic: if user said "remember" or "I am/like/prefer"
  if (/remember|I am|I like|I prefer/i.test(userMessage)) {
    await memoryClient.addMemory(userMessage);
  }
  
  return responseText;
}
```

## Error Handling

Handle errors appropriately:

```typescript theme={null}
try {
  const memories = await client.searchMemories('query');
} catch (error) {
  if (error instanceof Error) {
    if (error.message.includes('Unauthorized')) {
      console.error('Invalid API key');
    } else if (error.message.includes('rate limit')) {
      console.error('Rate limit exceeded');
      // Implement exponential backoff
    } else if (error.message.includes('Not Found')) {
      console.error('Memory not found');
    } else {
      console.error('Unknown error:', error.message);
    }
  }
  
  throw error;
}
```

## TypeScript Types

The client exports TypeScript types for all operations:

```typescript theme={null}
import type { 
  Memory, 
  MemoryWithSimilarity,
  AddMemoryOptions,
  SearchOptions 
} from '@usesatori/tools';

const memory: Memory = {
  id: 'uuid',
  content: 'User prefers TypeScript',
  userId: 'user-123',
  clerkUserId: 'user_372Icb...',
  metadata: {},
  createdAt: '2024-01-15T10:30:00Z',
  updatedAt: '2024-01-15T10:30:00Z',
};

const searchResult: MemoryWithSimilarity = {
  ...memory,
  similarity: 0.92,
};
```

## Testing

Mock the client for testing:

```typescript theme={null}
import { MemoryClient } from '@usesatori/tools';

// Mock the client
jest.mock('@usesatori/tools', () => ({
  MemoryClient: jest.fn().mockImplementation(() => ({
    addMemory: jest.fn().mockResolvedValue({
      id: 'test-uuid',
      content: 'Test memory',
      userId: 'test-user',
      metadata: {},
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
    }),
    searchMemories: jest.fn().mockResolvedValue([]),
    getAllMemories: jest.fn().mockResolvedValue([]),
    deleteMemory: jest.fn().mockResolvedValue(undefined),
  })),
}));

describe('Memory operations', () => {
  it('saves a memory', async () => {
    const client = new MemoryClient({
      apiKey: 'test-key',
      baseUrl: 'http://localhost:3001',
      userId: 'test-user',
    });
    
    const memory = await client.addMemory('Test content');
    expect(memory.content).toBe('Test memory');
  });
});
```

## Best Practices

<AccordionGroup>
  <Accordion title="Reuse client instances">
    Create one client per user and reuse it:

    ```typescript theme={null}
    // ✅ Good: Reuse client
    const client = new MemoryClient(config);
    await client.addMemory('Memory 1');
    await client.addMemory('Memory 2');

    // ❌ Bad: Create new client each time
    await new MemoryClient(config).addMemory('Memory 1');
    await new MemoryClient(config).addMemory('Memory 2');
    ```
  </Accordion>

  <Accordion title="Use descriptive memory content">
    Store complete, self-contained information:

    ```typescript theme={null}
    // ✅ Good
    await client.addMemory('User prefers dark mode in all applications');

    // ❌ Bad
    await client.addMemory('dark mode'); // Too vague
    ```
  </Accordion>

  <Accordion title="Add metadata for organization">
    Use metadata to categorize and filter memories:

    ```typescript theme={null}
    await client.addMemory('User prefers TypeScript', {
      metadata: {
        category: 'preference',
        subcategory: 'programming',
        tags: ['language', 'typescript'],
        importance: 'high',
      },
    });
    ```
  </Accordion>

  <Accordion title="Handle errors gracefully">
    Always wrap operations in try-catch blocks:

    ```typescript theme={null}
    try {
      await client.addMemory(content);
    } catch (error) {
      console.error('Failed to save memory:', error);
      // Fallback behavior
    }
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Vercel AI SDK" icon="wand-magic-sparkles" href="/guides/vercel-ai-sdk">
    Learn about the AI SDK integration
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/memory/add">
    Explore the complete API documentation
  </Card>

  <Card title="Examples" icon="code" href="/examples/chat-with-memory">
    See complete implementations
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/troubleshooting">
    Fix common issues
  </Card>
</CardGroup>
