brian-memory
v0.1.0
Published
TypeScript SDK for Brian Memory — persistent memory for AI agents
Readme
brian-memory
TypeScript/JavaScript SDK for Brian Memory — persistent memory for AI agents.
Zero runtime dependencies. Uses built-in fetch (Node 18+).
Installation
npm install brian-memoryQuick Start
import { BrianMemory } from "brian-memory";
const client = new BrianMemory({ apiKey: "brian_..." });
await client.store({ content: "User prefers dark mode", tags: ["preferences"] });
const results = await client.search({ query: "dark mode" });
console.log(results.results);Authentication
Pass your API key when creating the client. Optionally provide an encryption key for BYOK encryption:
const client = new BrianMemory({
apiKey: "brian_...",
encryptionKey: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2", // optional, 256-bit hex key for server-side BYOK encryption
});The API key is sent via the X-API-Key header on every request.
Core Operations
Store a Memory
const result = await client.store({
content: "PostgreSQL uses MVCC for concurrency control",
memory_type: "semantic", // "semantic", "episodic", or "procedural"
project_id: "my-project",
memory_scope: "project", // "global", "project", "agent", "user", "session"
tags: ["databases", "postgres"],
metadata: { source: "docs" },
confidence: 0.95,
force_store: false, // bypass deduplication
valid_from: "2025-01-01T00:00:00Z",
});
console.log(result.id, result.status); // "stored", "duplicate_found", etc.Search Memories
const results = await client.search({
query: "concurrency control",
memory_type: "semantic",
project_id: "my-project",
tags: ["databases"],
limit: 10,
min_relevance: 0.3,
detail_level: "summary", // "ids", "summary", or "full"
include_archived: false,
as_of: "2025-06-01T00:00:00Z", // point-in-time search
});
for (const memory of results.results) {
console.log(memory.content, memory.relevance_score);
}Get a Memory
const memory = await client.get("memory-uuid");
console.log(memory.content, memory.tags);Update a Memory
await client.update("memory-uuid", { content: "Updated content", tags: ["new-tag"] });Delete and Restore
await client.delete("memory-uuid", { reason: "outdated" });
await client.restore("memory-uuid");List Memories
const result = await client.list({
project_id: "my-project",
memory_type: "semantic",
status: "active", // "active", "archived", "deleted"
tags: ["databases"],
sort_by: "created_at", // "created_at", "last_accessed_at", "access_count", "trust_score"
sort_order: "desc",
limit: 20,
offset: 0,
});
for (const memory of result.results) {
console.log(memory);
}Analysis
Find Related Memories
const related = await client.related({
id: "memory-uuid",
limit: 5,
min_similarity: 0.5,
memory_type: "semantic",
project_id: "my-project",
});Compare Memories
const comparison = await client.compare(["uuid-1", "uuid-2", "uuid-3"]);Timeline
const timeline = await client.timeline({
project_id: "my-project",
after: "2025-01-01T00:00:00Z",
before: "2025-12-31T00:00:00Z",
as_of: "2025-06-01T00:00:00Z",
show_history: true,
});Diff
const changes = await client.diff({
after: "2025-01-01T00:00:00Z",
before: "2025-06-01T00:00:00Z",
project_id: "my-project",
});Consolidate Duplicates
// Preview duplicate groups
const preview = await client.consolidate({ mode: "preview", threshold: 0.85, project_id: "my-project" });
// Merge them
const merged = await client.consolidate({ mode: "merge", threshold: 0.85, project_id: "my-project" });Knowledge Graph
Search Entities
const entities = await client.graphSearch({ query: "PostgreSQL", entity_type: "technology", limit: 20 });Explore Entity Relationships
const graph = await client.graphExplore("entity-uuid", { max_hops: 2, limit: 20 });Get Entity Details
const entity = await client.graphEntity("entity-uuid");Get Entities for a Memory
const entities = await client.memoryEntities("memory-uuid");Mental Models
Mental models are auto-synthesized living documents built from scoped subsets of your memories.
Create a Model
const model = await client.createModel({
name: "Project Architecture",
scope_filter: { project_id: "my-project", tags: ["architecture"] },
description: "Living doc of architectural decisions",
auto_update: true,
update_threshold: 5, // re-synthesize after 5 new matching memories
});
console.log(model.id, model.name);Get a Model
const model = await client.getModel("model-uuid"); // also accepts name
console.log(model.content); // the synthesized documentList, Update, Delete
const models = await client.listModels({ status: "active" });
const updated = await client.updateModel("model-uuid", { name: "New Name", auto_update: false });
await client.deleteModel("model-uuid");Trigger Re-synthesis
await client.synthesizeModel("model-uuid");Export and Import
Streaming Export
for await (const memory of client.exportMemories({ format: "jsonl" })) {
console.log(memory.content);
}
// Get export stats
const stats = await client.exportStats();Bulk Import
const jsonlData = '{"content":"fact 1","memory_type":"semantic"}\n{"content":"fact 2","memory_type":"semantic"}';
const result = await client.importMemories(jsonlData, { format: "jsonl", skip_duplicates: true });
console.log(result);API Key Management
// Create a new key
const newKey = await client.createKey("my-agent-key");
console.log(newKey.key); // full key, only shown once
// List keys
const keys = await client.listKeys();
// Revoke a key
await client.revokeKey("key-uuid");Encryption (BYOK)
Brian supports bring-your-own-key encryption. Your data is encrypted server-side with your key — Brian never stores it.
// Enable encryption (256-bit key as 64 hex chars)
await client.enableEncryption("a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2");
// Check status
const status = await client.encryptionStatus();
console.log(status.enabled, status.key_version);
// Rotate key
await client.rotateEncryption(
"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
);
// Disable encryption
await client.disableEncryption("a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2");Once enabled, pass the encryption key on every request via the encryptionKey constructor option.
Configuration
const client = new BrianMemory({
apiKey: "brian_...", // required
baseUrl: "https://memory.example.com", // or set BRIAN_URL env var
timeout: 30_000, // milliseconds, default 30000
maxRetries: 3, // default 3, exponential backoff
encryptionKey: undefined, // optional BYOK encryption key
});Error Handling
All errors extend BrianError, which includes status and body properties:
import {
BrianError,
AuthenticationError, // 401 — invalid or missing API key
ValidationError, // 400 — invalid request parameters
NotFoundError, // 404 — memory or resource not found
SensitiveContentError, // 422 — blocked by sensitive content guard
RateLimitError, // 429 — rate/plan limit exceeded
ServerError, // 5xx — server error
} from "brian-memory";
try {
await client.store({ content: "some content" });
} catch (e) {
if (e instanceof RateLimitError) {
console.log(`Rate limited. Retry after: ${e.retryAfter}s`);
} else if (e instanceof SensitiveContentError) {
console.log("Content blocked — contains sensitive data like API keys or passwords");
} else if (e instanceof BrianError) {
console.log(`Error ${e.status}: ${e.message}`);
}
}The client automatically retries on 429 (respecting Retry-After) and 5xx errors with exponential backoff, up to maxRetries attempts.
Requirements
- Node.js 18+ (uses built-in
fetch) - Zero runtime dependencies
Documentation
Full API reference and guides: https://memory.example.com/docs
