@pyxmate/memory 0.20.4 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,233 +0,0 @@
1
- # pyx-memory SDK Integration Guide
2
-
3
- Reference for integrating pyx-memory into TypeScript/Bun projects.
4
- Runtime requirement: **Bun v1.2+** (not Node.js). Uses `bun:sqlite` natively.
5
-
6
- ## Quick Decision Tree
7
-
8
- ```
9
- Building pyx-memory itself or its server?
10
- → Embedded mode: import { Memory } from '@pyx-memory/core'
11
-
12
- Consuming pyx-memory from another project?
13
- → Sidecar mode: import { MemoryClient } from '@pyx-memory/client'
14
- → ONLY depend on @pyx-memory/client + @pyx-memory/shared
15
- → Do NOT import @pyx-memory/core — that's pyx-memory's internal implementation
16
- → See patterns/consumer.md
17
-
18
- Need memory in your process (best perf, full feature set)?
19
- → Embedded mode: import { Memory } from '@pyx-memory/core'
20
-
21
- Need memory as a separate service (HTTP)?
22
- → Sidecar mode: import { MemoryClient } from '@pyx-memory/client'
23
-
24
- Need to switch modes via config?
25
- → Factory: import { createMemory } from '@pyx-memory/core'
26
- - Returns MemoryInterface (base interface — no lifecycle methods)
27
- - If you need consolidate/decay/summarize, use `new Memory()` directly
28
-
29
- Need lifecycle methods (consolidate, decay, summarize)?
30
- → Use `new Memory(opts)` — returns ExtendedMemoryInterface
31
- → Or `new MemoryClient(url)` — also implements ExtendedMemoryInterface
32
- → NOT createMemory() — it returns MemoryInterface (missing lifecycle methods)
33
-
34
- Need dashboard features (consolidation log, graph visualization)?
35
- → Use `DashboardClient` from '@pyx-memory/dashboard'
36
- → Extends MemoryClient with additional methods
37
- ```
38
-
39
- ## Minimal Working Example (Embedded)
40
-
41
- ```typescript
42
- import { Memory } from '@pyx-memory/core';
43
-
44
- const memory = new Memory({ dataDir: './data' });
45
- await memory.initialize(); // REQUIRED — throws if you skip this
46
-
47
- await memory.store({
48
- content: 'User prefers dark mode',
49
- type: 'long-term',
50
- metadata: { source: 'settings' },
51
- });
52
-
53
- // Store with entities — graph is populated automatically when graphStore configured
54
- await memory.store({
55
- content: 'Alice works at Acme Corp',
56
- type: 'long-term',
57
- metadata: {},
58
- entities: [
59
- { name: 'Alice', type: 'PERSON' },
60
- { name: 'Acme Corp', type: 'ORGANIZATION' },
61
- ],
62
- relationships: [{ source: 'Alice', target: 'Acme Corp', type: 'WORKS_AT' }],
63
- });
64
-
65
- const results = await memory.search({ query: 'user preferences', limit: 5 });
66
-
67
- await memory.shutdown(); // REQUIRED — releases SQLite + LanceDB resources
68
- ```
69
-
70
- ## Minimal Working Example (Sidecar / HTTP)
71
-
72
- ```typescript
73
- import { MemoryClient } from '@pyx-memory/client';
74
-
75
- const memory = new MemoryClient('http://localhost:7822');
76
-
77
- // With auth (production)
78
- const authedMemory = new MemoryClient('http://localhost:7822', process.env.MEMORY_API_KEY);
79
-
80
- // With auth + multi-tenant headers (production, multi-tenant mode)
81
- const tenantMemory = new MemoryClient('http://localhost:7822', {
82
- apiKey: process.env.MEMORY_API_KEY,
83
- defaultHeaders: {
84
- 'X-Tenant-Id': 'tenant-abc',
85
- 'X-User-Id': 'user-123',
86
- },
87
- });
88
-
89
- await memory.initialize(); // verifies server connectivity via /health
90
-
91
- await memory.store({ content: 'Important fact', type: 'long-term', metadata: {} });
92
- const results = await memory.search({ query: 'fact', limit: 5 });
93
- ```
94
-
95
- Start the server: `bun packages/server/src/index.ts`
96
-
97
- ## Package Map
98
-
99
- ```
100
- @pyx-memory/shared → Types + constants only (zero runtime code)
101
- ↑ ↑
102
- | |
103
- @pyx-memory/client → MemoryInterface, ExtendedMemoryInterface, MemoryClient
104
-
105
- |
106
- @pyx-memory/core → Memory class, embeddings, graph, RAG, ingestion, lifecycle
107
- ↑ (re-exports everything from client and shared)
108
- |
109
- @pyx-memory/server → HTTP sidecar server (25 endpoints)
110
-
111
- @pyx-memory/dashboard → DashboardClient (extends MemoryClient), React hooks,
112
- Poller, aggregations, graph transforms (D3/Graphology)
113
- ```
114
-
115
- **Import rules:**
116
- - **Embedded mode**: Import everything from `@pyx-memory/core` (it re-exports client + shared)
117
- - **Sidecar mode (client only)**: Import from `@pyx-memory/client` (+ types from `@pyx-memory/shared`)
118
- - **Dashboard features**: Import from `@pyx-memory/dashboard` (extends client with extra methods)
119
- - **Types only**: Import from `@pyx-memory/shared`
120
- - **Consumer projects**: ONLY use `@pyx-memory/client` + `@pyx-memory/shared` — never `@pyx-memory/core`
121
-
122
- ## DO / DON'T
123
-
124
- ### DO
125
-
126
- - **DO** call `await memory.initialize()` before any operation
127
- - **DO** call `await memory.shutdown()` when done (releases SQLite + LanceDB)
128
- - **DO** provide `entities` to populate the graph
129
- - **DO** initialize GraphStore BEFORE constructing Memory
130
- - **DO** use `new Memory()` when you need lifecycle methods (ExtendedMemoryInterface)
131
- - **DO** use `':memory:'` dataDir for tests
132
- - **DO** handle `MemoryServerError` in sidecar mode (has `.status` and `.isNotFound`)
133
- - **DO** implement `DisabledMemory` (no-op) for graceful degradation when memory is unavailable
134
- - **DO** set `tenantId` on `MemoryOptions` or pass `X-Tenant-Id` header for multi-tenant deployments
135
- - **DO** use `MemoryClientOptions` with `defaultHeaders` for tenant/access-level headers in sidecar mode
136
-
137
- ### DON'T
138
-
139
- - **DON'T** assume `createMemory()` returns `ExtendedMemoryInterface` — it returns `MemoryInterface`
140
- - **DON'T** use `targets: ['graph']` without a configured `graphStore` — throws MemoryError
141
- - **DON'T** use `strategy: 'graph'` without passing `graphStore`
142
- - **DON'T** use `strategy: 'agentic'` without passing `reasoningProvider`
143
- - **DON'T** construct multiple Memory instances with the same `dataDir` — LanceDB singleton causes conflicts
144
- - **DON'T** use `':memory:'` in production — LanceDB still writes to `/tmp/autonomy-vectors`
145
- - **DON'T** expose the server without configuring `API_KEY` for network deployments
146
- - **DON'T** run `TENANT_MODE=multi` without `API_KEY` — multi-tenant without auth is dangerous
147
- - **DON'T** import `@pyx-memory/core` in consumer projects — use `@pyx-memory/client`
148
- - **DON'T** expect `filters`, `enableHyDE`, or `enableRerank` to work in sidecar mode
149
-
150
- ## Post-Integration Checklist
151
-
152
- ```bash
153
- bun .claude/skills/pyx-memory/scripts/diagnose-integration.ts --json
154
- ```
155
-
156
- Interpret `verdict`: `"healthy"` = done, otherwise fix each `criticalIssues` entry and re-run.
157
-
158
- **Common failure: DisabledMemory (no-op)**
159
- If `MEMORY_URL` is not set, the client silently falls back to a no-op implementation. The diagnostic tool detects this via checks S5 and I1.
160
-
161
- ## Error Types
162
-
163
- ```
164
- MemoryError (base)
165
- ├── MemoryStoreError — SQLite store failures
166
- ├── MemoryNotFoundError — entry not found
167
- ├── MemorySearchError — search failures
168
- ├── VectorProviderError — LanceDB/vector issues
169
- ├── EmbeddingError — embedding generation failures
170
- ├── MigrationError — schema migration issues
171
- ├── IngestionError — file parsing / ingestion failures
172
- ├── LifecycleError — consolidation / decay failures
173
- └── GraphError — graph store operations
174
-
175
- MemoryServerError — HTTP client errors (has .status, .isNotFound)
176
- ```
177
-
178
- All from `@pyx-memory/core` except `MemoryServerError` from `@pyx-memory/client`.
179
-
180
- ## Two-Phase PDF Enrichment
181
-
182
- When ingesting PDFs that contain images, `ingestFileEvents()` runs a three-phase enrichment flow via `EnrichmentCallbacks`. The SDK handles all phases automatically and emits typed `IngestEvent`s as it goes:
183
-
184
- 1. **Server upload** — text extracted and stored immediately; server emits `progress` events with stage `parsing` then `storing`
185
- 2. **Image description** — each extracted image is fetched and described via your LLM vision callback (batched, 5 concurrent); SDK emits `progress`/`heartbeat` events with stage `enrichment`
186
- 3. **Enrichment write** — descriptions + entities POSTed back to the server's `/enrich` endpoint; SDK emits the terminal `result` event
187
-
188
- ```typescript
189
- import { MemoryClient, type EnrichmentCallbacks, type FileIngestResult } from '@pyxmate/memory';
190
-
191
- const memory = new MemoryClient('http://localhost:7822', apiKey);
192
-
193
- const enrichment: EnrichmentCallbacks = {
194
- // Optional: describe each image using LLM vision
195
- describeImage: async (imageBuffer, meta) => {
196
- // imageBuffer is ArrayBuffer of the extracted PNG/JPEG
197
- // meta has: imageId, pageNumber, width, height, mimeType
198
- return await myVisionModel.describe(imageBuffer);
199
- },
200
- // Optional: extract entities from text windows + image descriptions
201
- extractEntitiesV2: async ({ textWindows, imageDescriptions, filename, mimeType }) => ({
202
- entities: [{ name: 'Revenue', type: 'METRIC' }],
203
- relationships: [{ source: 'Revenue', target: 'Q4', type: 'RELATED_TO' }],
204
- }),
205
- };
206
-
207
- let result: FileIngestResult | null = null;
208
- for await (const event of memory.ingestFileEvents(pdfFile, { enrichment })) {
209
- if (event.type === 'progress') {
210
- console.log(`[${event.stage}] ${event.message ?? ''}`);
211
- continue;
212
- }
213
- if (event.type === 'error') {
214
- // Enrichment-stage errors (e.g. extractEntitiesV2 throws on a 401 storm)
215
- // carry the server's pre-enrichment FileIngestResult under
216
- // `partialResult` — the chunks/entryIds/catalog are durably stored.
217
- // Persist them BEFORE surfacing the error so vector retrieval keeps
218
- // working on the file. Parsing/storing/transport errors do not set it.
219
- if (event.partialResult) {
220
- result = event.partialResult;
221
- // surface a "partial" status to the user, then throw to mark failure
222
- }
223
- throw new Error(event.message ?? event.error);
224
- }
225
- if (event.type === 'result') {
226
- const { schemaVersion: _v, type: _t, stage: _s, message: _m, ...payload } = event;
227
- result = payload;
228
- }
229
- }
230
- if (!result) throw new Error('memory ingest stream ended without a result');
231
- ```
232
-
233
- Without `enrichment` callbacks, the stream still emits `parsing` → `storing` progress events and a terminal `result` — the SDK just skips Phase 2/3.
@@ -1,344 +0,0 @@
1
- # pyx-memory Type Reference
2
-
3
- ## Contents
4
- - Type Cheat Sheet
5
- - MemoryInterface (9 methods)
6
- - ExtendedMemoryInterface (10 lifecycle methods)
7
- - MemoryClient Constructor and Concrete Methods
8
- - DashboardClient
9
- - MemorySearchResult, MemoryEntry, MemorySearchParams
10
- - MemoryOptions Reference
11
- - Embedding Dimension Defaults
12
-
13
- ## Type Cheat Sheet
14
-
15
- | Type | Signature | Import From |
16
- |------|-----------|-------------|
17
- | `LLMCallback` | `(prompt: string) => Promise<string>` | `@pyx-memory/core` |
18
- | `ReasoningProvider` | `(prompt: string) => Promise<string>` | `@pyx-memory/core` |
19
- | `StoreInput` | `Omit<MemoryEntry, 'id' \| 'createdAt'> & { targets?, entities?, relationships? }` | `@pyx-memory/core` |
20
- | `MemoryType` | `'short-term' \| 'long-term' \| 'working' \| 'episodic' \| 'summary'` | `@pyx-memory/shared` |
21
- | `RAGStrategy` | `'naive' \| 'graph' \| 'agentic' \| 'hybrid'` | `@pyx-memory/shared` |
22
- | `VectorProvider` | `'lancedb'` | `@pyx-memory/shared` |
23
- | `StoreTarget` | `'sqlite' \| 'vector' \| 'graph'` | `@pyx-memory/shared` |
24
- | `IngestEntity` | `{ name, type, properties? }` | `@pyx-memory/shared` |
25
- | `IngestRelationship` | `{ source, target, type, properties? }` | `@pyx-memory/shared` |
26
- | `EntityType` | `'PERSON' \| 'ORGANIZATION' \| 'CONCEPT' \| 'TOOL' \| 'LOCATION' \| 'EVENT'` | `@pyx-memory/core` |
27
- | `RelationType` | `'USES' \| 'OWNS' \| 'DEPENDS_ON' \| 'RELATED_TO' \| 'CREATED_BY' \| 'PART_OF' \| 'IS_A' \| 'WORKS_AT' \| 'LOCATED_IN'` | `@pyx-memory/core` |
28
- | `TenantScopeOptions` | `{ tenantId? }` | `@pyx-memory/client` |
29
- | `SensitivityLevel` | `'public' \| 'internal' \| 'secret'` | `@pyx-memory/shared` |
30
- | `MemoryClientOptions` | `{ apiKey?, defaultHeaders? }` | `@pyx-memory/client` |
31
- | `MemoryListParams` | `{ page?, limit?, type?, agentId?, tenantId? }` | `@pyx-memory/client` |
32
- | `MemoryListResult` | `{ entries, totalCount, page, limit }` | `@pyx-memory/client` |
33
- | `IngestionResult` | `{ filename, chunks, totalCharacters }` | `@pyx-memory/client` |
34
- | `FileIngestResult` | `IngestionResult & { enrichment?: EnrichmentPending }` | `@pyx-memory/shared` |
35
- | `EnrichmentPending` | `{ fileId, token, expiresAt, images: ExtractedImageMeta[] }` | `@pyx-memory/shared` |
36
- | `ExtractedImageMeta` | `{ imageId, pageNumber, width, height, mimeType }` | `@pyx-memory/shared` |
37
- | `EnrichmentCallbacks` | `{ describeImage, extractEntities? }` | `@pyx-memory/client` |
38
- | `EnrichRequest` | `{ imageDescriptions, entities?, relationships? }` | `@pyx-memory/shared` |
39
- | `EnrichResult` | `{ entryIds, entitiesStored, relationshipsStored }` | `@pyx-memory/shared` |
40
- | `ImageDescription` | `{ imageId, description }` | `@pyx-memory/shared` |
41
- | `MemoryServerError` | `Error` with `.status` and `.isNotFound` | `@pyx-memory/client` |
42
- | `GraphNode` | `{ id, name, type, properties, memoryEntryIds }` | `@pyx-memory/shared` |
43
- | `GraphTraversalResult` | `{ nodes, relationships, paths }` | `@pyx-memory/shared` |
44
-
45
- ---
46
-
47
- ## MemoryInterface (9 methods)
48
-
49
- ```typescript
50
- interface MemoryInterface {
51
- initialize(): Promise<void>;
52
- store(entry: Omit<MemoryEntry, 'id' | 'createdAt'> & { id?: string; createdAt?: string; targets?: StoreTarget[]; entities?: IngestEntity[]; relationships?: IngestRelationship[] }): Promise<MemoryEntry>;
53
- search(params: MemorySearchParams): Promise<MemorySearchResult>;
54
- list(params?: MemoryListParams): Promise<MemoryListResult>; // paginated entry listing
55
- get(id: string, options?: TenantScopeOptions): Promise<MemoryEntry | null>;
56
- delete(id: string, options?: TenantScopeOptions): Promise<boolean>;
57
- clearSession(sessionId: string, options?: TenantScopeOptions): Promise<number>;
58
- stats(options?: TenantScopeOptions): Promise<MemoryStats>;
59
- queryAsOf(asOfDate: string, filters?: TemporalQueryFilters): Promise<MemoryEntry[]>;
60
- queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry[]>;
61
- shutdown(): Promise<void>;
62
- }
63
- ```
64
-
65
- ## ExtendedMemoryInterface (adds 10 lifecycle methods)
66
-
67
- ```typescript
68
- interface ExtendedMemoryInterface extends MemoryInterface {
69
- consolidate(): Promise<ConsolidationRunResult>;
70
- forget(id: string, reason?: string): Promise<boolean>;
71
- summarizeSession(sessionId: string): Promise<MemoryEntry | null>;
72
- runDecay(): Promise<number>;
73
- reindex(): Promise<void>;
74
- deleteBySource(source: string): Promise<number>;
75
- // v0.18.0 — read-only memory-wide lint report (graph orphans, decay
76
- // candidates, stale syntheses, content-hash dedup candidates).
77
- lint(options?: { limit?: number }): Promise<WikiLintReport>;
78
- // v0.18.1 — chronological feed (Karpathy log.md primitive). Cursor-style
79
- // via `since` (created_at lower bound). No totalCount.
80
- log(filters?: MemoryLogFilters): Promise<MemoryEntry[]>;
81
- // v0.19.0 — entity synthesis (Karpathy "wiki page" primitive).
82
- // summarizeEntity is LLM-driven and caller-triggered; it stores a pinned
83
- // `_kind:'entity-summary'` entry with `_search_visibility:'on-demand'`
84
- // (excluded from search). getEntitySynthesis is the O(1) read path.
85
- summarizeEntity(name: string): Promise<MemoryEntry>;
86
- getEntitySynthesis(name: string): Promise<MemoryEntry | null>;
87
- }
88
- ```
89
-
90
- `MemoryLogFilters` = `{ since?: string; limit?: number; type?: MemoryType; agentId?: string; source?: string }`.
91
-
92
- ### Reserved metadata conventions
93
-
94
- Some `metadata` keys carry behavior, not just data:
95
-
96
- | Key | Value | Effect |
97
- |-----|-------|--------|
98
- | `_search_visibility` | `'on-demand'` | Entry is excluded from every RAG engine's retrieval pool (v0.18.2 hook). Still reachable via `get` / `list` / `log` and deterministic-id fetch. Field absent ⇒ visible. |
99
- | `_kind` | `'entity-summary'` | Marks an entity synthesis. `Memory.lint` flags stale ones; the `synthesis:` id prefix is reserved for entries carrying this. |
100
- | `_sourceEntryIds` | `string[]` | Provenance — the entries a synthesis was built from. |
101
- | `_maxEventTime` | ISO string \| null | Staleness contract — `lint` flags the synthesis when a source's eventTime later exceeds this. |
102
-
103
- ## MemoryClient Constructor and Concrete Methods
104
-
105
- ```typescript
106
- // Constructor: URL required, second param is string (apiKey) or MemoryClientOptions
107
- const client = new MemoryClient('http://localhost:7822'); // no auth
108
- const client = new MemoryClient('http://localhost:7822', 'my-api-key'); // with auth (string shorthand)
109
- const client = new MemoryClient('http://localhost:7822', process.env.MEMORY_API_KEY); // from env
110
-
111
- // Advanced: options object with default headers (e.g., multi-tenant access control)
112
- const client = new MemoryClient('http://localhost:7822', {
113
- apiKey: 'my-api-key',
114
- defaultHeaders: {
115
- 'X-Tenant-Id': 'tenant-abc',
116
- 'X-Caller-Access-Level': 'internal',
117
- },
118
- });
119
- ```
120
-
121
- When `apiKey` is provided, all requests include `Authorization: Bearer <key>`. Empty or whitespace-only keys are ignored. Default headers are merged into every request.
122
-
123
- `MemoryClient` implements `ExtendedMemoryInterface` AND has additional methods not on any interface.
124
- Graph queries and file ingestion are available without `@pyx-memory/core`.
125
-
126
- ```typescript
127
- class MemoryClient implements ExtendedMemoryInterface {
128
- // ... all 19 interface methods (9 base + 10 lifecycle) ...
129
-
130
- // Graph operations (call pyx-memory server's graph endpoints)
131
- graphNodes(): Promise<GraphNode[]>;
132
- graphEdges(): Promise<{ stats: { nodeCount: number; edgeCount: number } }>;
133
- graphQuery(query: { nodeId: string; depth?: number }): Promise<GraphTraversalResult>;
134
-
135
- // File ingestion — native NDJSON streaming (v0.15.0+)
136
- // Yields typed IngestEvents (progress / heartbeat / result / error).
137
- // With enrichment callbacks: fetches extracted images, calls describeImage,
138
- // calls extractEntitiesV2, posts /enrich, then yields the terminal `result`.
139
- ingestFileEvents(file: File, options?: IngestFileOptions): AsyncIterable<IngestEvent>;
140
-
141
- // Bi-temporal queries
142
- queryAsOf(asOf: string, filters?: TemporalQueryFilters): Promise<MemoryEntry[]>;
143
- queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry[]>;
144
- }
145
- ```
146
-
147
- **Key insight for consumers**: You do NOT need `@pyx-memory/core` for graph queries or file ingestion.
148
- `MemoryClient` already proxies these through the HTTP API.
149
-
150
- ## DashboardClient (extends MemoryClient)
151
-
152
- `DashboardClient` from `@pyx-memory/dashboard` adds dashboard-specific methods:
153
-
154
- ```typescript
155
- import { DashboardClient } from '@pyx-memory/dashboard';
156
-
157
- class DashboardClient extends MemoryClient {
158
- consolidationLog(limit?: number): Promise<ConsolidationLogEntry[]>;
159
- graphRelationships(limit?: number): Promise<{ relationships: GraphRelationship[]; totalCount: number }>;
160
- graphFull(limit?: number): Promise<{ nodes: GraphNode[]; relationships: GraphRelationship[] }>;
161
- listEntriesPaginated(filters?: EntryFilters): Promise<PaginatedEntries>;
162
- fetchHealthRaw(): Promise<RawHealthResponse>;
163
- }
164
- ```
165
-
166
- The dashboard package also provides: `Poller` (auto-polling), `computeMetrics()`, `computeTypeDistribution()`,
167
- `enrichHealth()`, `transformGraphData()`, `toD3ForceFormat()`, `toGraphologyFormat()`, and React hooks
168
- (`useMemoryStats`, `useMemoryEntries`, `useKnowledgeGraph`, `useConsolidationLog`, `useMemoryHealth`, `useTypeDistribution`).
169
-
170
- ## MemorySearchResult
171
-
172
- ```typescript
173
- interface MemorySearchResult {
174
- entries: MemoryEntry[];
175
- totalCount: number;
176
- strategy: RAGStrategy;
177
- scoredEntries?: Array<{ entry: MemoryEntry; score: number }>; // ranked results with relevance scores
178
- confidence?: { // present when abstentionThreshold is set or strategy uses scoring
179
- confidence: number; // 0-1 confidence score
180
- shouldAbstain: boolean; // true when confidence < abstentionThreshold
181
- signals: {
182
- topScore: number; // magnitude of the highest-scoring result
183
- scoreGap: number; // difference between #1 and #2 results
184
- scoreStdDev: number; // spread of scores (high = clear winner)
185
- resultCount: number; // how many results were returned
186
- aboveThresholdRatio: number; // fraction of results above threshold
187
- scoreSeparation: number; // how much top-1 stands out from the pack
188
- };
189
- };
190
- }
191
- ```
192
-
193
- ## MemoryEntry (full shape)
194
-
195
- ```typescript
196
- interface MemoryEntry {
197
- id: string;
198
- content: string;
199
- type: MemoryType;
200
- agentId?: string;
201
- sessionId?: string;
202
- metadata: Record<string, unknown>;
203
- embedding?: number[]; // @deprecated — managed internally by vector store
204
- createdAt: string; // ISO 8601
205
- contentHash?: string; // SHA-256
206
- importance?: number; // 1-10
207
- accessCount?: number;
208
- lastAccessed?: string; // ISO 8601
209
- parentId?: string; // hierarchical storage
210
- source?: string; // filename, URL, session ID
211
- eventTime?: string; // when event happened (bi-temporal)
212
- ingestTime?: string; // when stored (bi-temporal)
213
- tenantId?: string; // multi-tenant isolation (hard boundary)
214
- userId?: string; // user within tenant (legacy soft-scope)
215
- teamId?: string; // team/group within tenant (legacy soft-scope)
216
- namespaceId?: string; // ReBAC resource coordinate; NULL = legacy tenant-root bucket
217
- sensitivity?: SensitivityLevel; // auto-classified: 'public' | 'internal' | 'secret'
218
- encrypted?: boolean; // true when content is encrypted at rest
219
- pinned?: boolean; // exempt from consolidation (decay-archive + dedup-merge); use for stable anchors referenced by external systems
220
- }
221
- ```
222
-
223
- ## MemorySearchParams + SearchFilters
224
-
225
- ```typescript
226
- interface MemorySearchParams {
227
- query: string;
228
- type?: MemoryType;
229
- agentId?: string;
230
- limit?: number; // default varies by engine
231
- strategy?: RAGStrategy; // default: 'naive'
232
- filters?: SearchFilters;
233
- enableHyDE?: boolean; // Hypothetical Document Embedding for query expansion
234
- enableRerank?: boolean; // Cross-encoder reranking of results
235
- tenantId?: string; // multi-tenant scoping
236
- userId?: string; // user-level scoping
237
- teamId?: string; // team-level scoping
238
- /** Calling principal — drives ReBAC AuthzPlan. Search applies it as a
239
- * native pre-filter on SQLite/FTS, vector, and graph layers; forbidden
240
- * entries never enter RRF / reranker / abstention. Optional. */
241
- principal?: PrincipalContext;
242
- namespaceIds?: string[]; // populated internally from AuthzPlan — do not set directly
243
- maxSensitivity?: SensitivityLevel; // filter by max sensitivity level
244
- abstentionThreshold?: number; // 0-1, below this confidence → shouldAbstain=true (default: 0.3)
245
- }
246
-
247
- interface SearchFilters {
248
- source?: string;
249
- importanceMin?: number;
250
- eventTimeRange?: [string, string]; // [start, end] ISO timestamps
251
- parentId?: string;
252
- contentType?: string;
253
- excludePinned?: boolean; // SQL-side `pinned = 0` filter (used internally by consolidation/decay; available to callers too)
254
- }
255
- ```
256
-
257
- ## PrincipalContext + ReBAC Types (v0.16.0+)
258
-
259
- The calling identity used to compute search-time AuthzPlan. Comes from
260
- authenticated request context (`X-Tenant-Id` + `X-User-Id` / `X-Agent-Id`),
261
- NEVER from request bodies.
262
-
263
- ```typescript
264
- interface PrincipalContext {
265
- tenantId: string; // hard boundary; SINGLE_TENANT_ID sentinel in single mode
266
- principalId: string; // userId | agentId | service identifier
267
- kind: 'user' | 'agent' | 'service';
268
- }
269
-
270
- interface Namespace {
271
- id: string;
272
- tenantId: string;
273
- name: string;
274
- parentId?: string; // adjacency tree, max-depth 8
275
- createdAt: string;
276
- createdBy?: string;
277
- metadata: Record<string, unknown>;
278
- }
279
-
280
- interface Principal {
281
- id: string;
282
- tenantId: string;
283
- kind: 'user' | 'team' | 'group' | 'agent' | 'service' | 'everyone';
284
- externalId?: string; // maps to userId / agentId / teamId on entries
285
- displayName?: string;
286
- createdAt: string;
287
- metadata: Record<string, unknown>;
288
- }
289
-
290
- interface AuthzTuple {
291
- tenantId: string;
292
- subjectKind: PrincipalKind;
293
- subjectId: string;
294
- subjectRelation?: string; // for usersets like "members of team-eng"
295
- relation: 'viewer' | 'editor' | 'owner' | string;
296
- objectKind: 'namespace'; // v1 only supports namespace-level grants
297
- objectId: string;
298
- createdAt: string;
299
- createdBy?: string;
300
- }
301
-
302
- interface AuthzPlan {
303
- tenantId: string;
304
- visibleNamespaceIds: string[]; // resolved + transitively expanded
305
- visibleEntryOverrides: string[]; // reserved for v1.1
306
- revision: string; // bumps on every tuple/principal/membership mutation
307
- }
308
- ```
309
-
310
- Built-in relation rewrite: `owner ⊇ editor ⊇ viewer`. Adding new relations
311
- is a code change, not a schema migration.
312
-
313
- In-process API: `Memory.authz` exposes `AuthzStore` with `createNamespace`,
314
- `upsertPrincipal`, `addMember`, `writeTuple`, `deleteTuple`, `buildAuthzPlan`
315
- etc. Sidecar / HTTP API: see [`http-api.md`](./http-api.md) §ReBAC Admin.
316
-
317
- ## MemoryOptions Reference
318
-
319
- > **Embedding is internal** — pyx-memory uses `LocalEmbeddingProvider` with BGE-M3 (1024d) automatically. You do NOT pass an `embedder` option.
320
-
321
- | Field | Type | Required | Default | Notes |
322
- |-------|------|----------|---------|-------|
323
- | `dataDir` | `string` | no | `'./data'` | Use `':memory:'` for tests (LanceDB still writes to `/tmp`) |
324
- | `vectorProvider` | `VectorProvider` | no | `'lancedb'` | |
325
- | `dimensions` | `number` | no | `1024` | Default: 1024 (matches internal BGE-M3 model) |
326
- | `graphStore` | `GraphStore` | no | `undefined` | Enables graph target in store routing |
327
- | `reasoningProvider` | `ReasoningProvider` | no | `undefined` | Enables agentic RAG |
328
- | `llm` | `LLMCallback` | no | `undefined` | Enables LLM-powered lifecycle (consolidation, summarization, scoring) |
329
- | `skipDuplicates` | `boolean` | no | `false` | Content-hash dedup on store |
330
- | `agentId` | `string` | no | `undefined` | Auto-scopes ALL store/search/stats/decay operations to this agent |
331
- | `tenantId` | `string` | no | `undefined` | Auto-scopes ALL operations to this tenant (multi-tenant isolation) |
332
- | `encryptionKey` | `Buffer` | no | `undefined` | 32-byte AES-256-GCM key for encrypting `secret` entries at rest |
333
- | `qdrantUrl` | `string` | no | `undefined` | @deprecated — Qdrant support is vestigial |
334
-
335
- ## Embedding Dimension Defaults by Provider
336
-
337
- > **Memory always uses `LocalEmbeddingProvider` internally.** The other providers are available for standalone use but are not used by the `Memory` class.
338
-
339
- | Provider | Default Dimensions | Model |
340
- |----------|-------------------|-------|
341
- | `StubEmbeddingProvider` | 1024 | hash-based (testing only) |
342
- | `OpenAIEmbeddingProvider` | 1536 | text-embedding-3-small |
343
- | `AnthropicEmbeddingProvider` | 1024 | voyage-3 (Voyage AI) |
344
- | `LocalEmbeddingProvider` | 1024 | BGE-M3 (ONNX int8 quantized) |