@engram-mem/supabase 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,301 @@
1
+ # @engram/supabase
2
+
3
+ Cloud storage adapter for Engram using Supabase PostgreSQL and pgvector. Enables distributed agents with shared memory.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @engram/supabase
9
+ npm install @engram/core
10
+ npm install @engram/openai # Optional but recommended
11
+ ```
12
+
13
+ ## Setup
14
+
15
+ ### 1. Create a Supabase Project
16
+
17
+ 1. Go to https://supabase.com
18
+ 2. Create a new project
19
+ 3. Wait for it to provision (~2 min)
20
+ 4. Copy your project URL and anon key
21
+
22
+ ### 2. Enable Vector Extension
23
+
24
+ Run this in the Supabase SQL Editor:
25
+
26
+ ```sql
27
+ CREATE EXTENSION IF NOT EXISTS vector;
28
+ ```
29
+
30
+ ### 3. Run Migrations
31
+
32
+ Get your DATABASE_URL from Supabase settings, then:
33
+
34
+ ```bash
35
+ export SUPABASE_URL="https://your-project.supabase.co"
36
+ export SUPABASE_KEY="your-anon-key"
37
+
38
+ # Run migrations (instructions below)
39
+ psql $DATABASE_URL < packages/supabase/migrations/001_initial_schema.sql
40
+ psql $DATABASE_URL < packages/supabase/migrations/002_vector_indexes.sql
41
+ ```
42
+
43
+ ### 4. Configure in Your App
44
+
45
+ ```javascript
46
+ import { createMemory } from '@engram/core'
47
+ import { supabaseAdapter } from '@engram/supabase'
48
+
49
+ const memory = createMemory({
50
+ storage: supabaseAdapter({
51
+ url: process.env.SUPABASE_URL,
52
+ key: process.env.SUPABASE_KEY
53
+ })
54
+ })
55
+
56
+ await memory.initialize()
57
+ // ... use as normal
58
+ ```
59
+
60
+ ## Configuration
61
+
62
+ ```typescript
63
+ interface SupabaseAdapterOptions {
64
+ url: string // Supabase project URL (required)
65
+ key: string // Supabase anon key (required)
66
+ schema?: string // Default: 'engram'
67
+ }
68
+
69
+ const adapter = supabaseAdapter({
70
+ url: process.env.SUPABASE_URL,
71
+ key: process.env.SUPABASE_KEY,
72
+ schema: 'my_engram' // Optional custom schema
73
+ })
74
+ ```
75
+
76
+ ## Schema Overview
77
+
78
+ Supabase provides PostgreSQL with pgvector extension for vector search:
79
+
80
+ ```
81
+ TABLES (same structure as SQLite, but with vector columns):
82
+ ├── episodes — With embedding vectors
83
+ ├── digests — With embedding vectors
84
+ ├── semantic — With embedding vectors
85
+ ├── procedural — With embedding vectors
86
+ ├── associations — Edge graph
87
+ ├── sensory_snapshots — JSONB snapshots
88
+
89
+ INDEXES (HNSW for vector search):
90
+ ├── episodes_embedding_idx — Vector similarity search
91
+ ├── semantic_embedding_idx — Semantic fact search
92
+ ├── digest_embedding_idx — Summary search
93
+ ├── associations_source_target_idx — Graph traversal
94
+ ```
95
+
96
+ ## Advantages Over SQLite
97
+
98
+ ### Scalability
99
+ - Handle billions of memories (no single-file size limits)
100
+ - Distributed agents sharing the same memory
101
+ - Horizontal scaling via Supabase infrastructure
102
+
103
+ ### Vector Search
104
+ - HNSW (Hierarchical Navigable Small World) indexes
105
+ - Sub-millisecond vector similarity at scale
106
+ - Better than SQLite FTS5 for semantic search
107
+
108
+ ### Concurrency
109
+ - Built-in row-level security
110
+ - Proper ACID guarantees
111
+ - Multiple writers without conflict
112
+
113
+ ### Durability
114
+ - Automated backups and PITR (point-in-time recovery)
115
+ - Replicas for HA
116
+ - Managed service (you don't maintain it)
117
+
118
+ ## HNSW Index Configuration
119
+
120
+ HNSW indexes are created automatically on embedding columns:
121
+
122
+ ```sql
123
+ CREATE INDEX episodes_embedding_idx ON episodes
124
+ USING hnsw (embedding vector_cosine_ops)
125
+ WITH (m=16, ef_construction=64);
126
+ ```
127
+
128
+ These settings are good defaults. For massive databases (>10M memories), consider:
129
+
130
+ ```sql
131
+ WITH (m=32, ef_construction=200) -- Higher accuracy, slower build
132
+ WITH (m=8, ef_construction=32) -- Lower accuracy, faster build
133
+ ```
134
+
135
+ Adjust via Supabase SQL Editor if needed.
136
+
137
+ ## Cost Estimation
138
+
139
+ Supabase pricing (as of 2026):
140
+
141
+ | Component | Cost |
142
+ |-----------|------|
143
+ | Database storage | $0.25 per GB/month |
144
+ | API egress | $0.11 per GB |
145
+ | Realtime (optional) | $10-100/month |
146
+
147
+ For a typical agent with 100K memories (~500MB):
148
+ - Storage: ~$0.12/month
149
+ - API egress (during consolidation): ~$0.05/month
150
+ - **Total: ~$0.20/month**
151
+
152
+ This is very economical for distributed multi-agent systems.
153
+
154
+ ## Distributed Agents
155
+
156
+ One of Engram's killer features: **shared memory between agents**.
157
+
158
+ ```javascript
159
+ // Agent 1
160
+ const memory1 = createMemory({
161
+ storage: supabaseAdapter({ url: '...', key: '...' })
162
+ })
163
+
164
+ // Agent 2 (different process, same database)
165
+ const memory2 = createMemory({
166
+ storage: supabaseAdapter({ url: '...', key: '...' })
167
+ })
168
+
169
+ // Agent 1 ingests knowledge
170
+ await memory1.ingest({
171
+ role: 'assistant',
172
+ content: 'Found that TypeScript strict mode requires...'
173
+ })
174
+
175
+ // Agent 2 recalls it
176
+ const result = await memory2.recall('TypeScript strict mode')
177
+ // => Finds Agent 1's ingested knowledge
178
+ ```
179
+
180
+ Sessions still partition by sessionId, but facts (semantic/procedural) are shared.
181
+
182
+ ## Level 2 Setup
183
+
184
+ ```javascript
185
+ import { createMemory } from '@engram/core'
186
+ import { supabaseAdapter } from '@engram/supabase'
187
+ import { openaiIntelligence } from '@engram/openai'
188
+
189
+ const memory = createMemory({
190
+ storage: supabaseAdapter({
191
+ url: process.env.SUPABASE_URL,
192
+ key: process.env.SUPABASE_KEY
193
+ }),
194
+ intelligence: openaiIntelligence({
195
+ apiKey: process.env.OPENAI_API_KEY
196
+ })
197
+ })
198
+
199
+ await memory.initialize()
200
+ // Now you have:
201
+ // - Cloud storage (shared between agents)
202
+ // - Vector embeddings (semantic search)
203
+ // - BM25 fallback (keyword search on episodes)
204
+ ```
205
+
206
+ ## Level 3 Setup (Future)
207
+
208
+ When auto-consolidation is ready:
209
+
210
+ ```javascript
211
+ const memory = createMemory({
212
+ storage: supabaseAdapter({ url: '...', key: '...' }),
213
+ intelligence: openaiIntelligence({
214
+ apiKey: process.env.OPENAI_API_KEY,
215
+ intentAnalysis: true,
216
+ summarization: true
217
+ }),
218
+ consolidation: { schedule: 'auto' }
219
+ })
220
+ ```
221
+
222
+ Consolidation will run on a schedule, automatically creating digests and extracting knowledge.
223
+
224
+ ## Row-Level Security (RLS)
225
+
226
+ By default, Supabase RLS is disabled (anon key has full access). For production:
227
+
228
+ 1. **Enable RLS** on all tables in Supabase dashboard
229
+ 2. **Create policies** restricting access by sessionId or agent ID
230
+
231
+ Example policy:
232
+
233
+ ```sql
234
+ CREATE POLICY episodes_owner_access ON episodes
235
+ FOR ALL USING (auth.uid() = user_id) -- Restrict to user's own data
236
+ ```
237
+
238
+ This requires setting up Supabase auth and passing user ID during schema setup.
239
+
240
+ ## Backup and Recovery
241
+
242
+ Supabase handles backups automatically. Access them via:
243
+
244
+ 1. Project settings → Backups
245
+ 2. Create new project from backup
246
+ 3. Use pg_dump for manual export:
247
+
248
+ ```bash
249
+ pg_dump $DATABASE_URL > engram_backup.sql
250
+ ```
251
+
252
+ ## Troubleshooting
253
+
254
+ **Q: Connection timeout**
255
+
256
+ A: Check your Supabase project is running and firewall rules allow connections. Verify URL and key are correct.
257
+
258
+ **Q: Vector index not being used**
259
+
260
+ A: pgvector queries use indexes automatically for large tables (>10K rows). For testing, check query EXPLAIN PLAN:
261
+
262
+ ```sql
263
+ EXPLAIN (ANALYZE) SELECT * FROM semantic
264
+ ORDER BY embedding <=> '<your-vector>'::vector
265
+ LIMIT 10;
266
+ ```
267
+
268
+ If not using index, run `ANALYZE semantic;` to update statistics.
269
+
270
+ **Q: High query costs**
271
+
272
+ A: Each recall() triggers API calls. For high-frequency agents, consider:
273
+ 1. Batch recalls into fewer requests
274
+ 2. Use longer consolidation intervals to reduce overhead
275
+ 3. Cache results client-side
276
+
277
+ **Q: Can I migrate from SQLite to Supabase?**
278
+
279
+ A: Export SQLite and import via pg_load_data (future tooling). For now, do it manually.
280
+
281
+ **Q: Is Supabase always online?**
282
+
283
+ A: Supabase runs on AWS with 99.99% uptime SLA. Check status at https://status.supabase.com.
284
+
285
+ ## API Reference
286
+
287
+ All methods are internal to the StorageAdapter. Use the Memory class API instead. See @engram/core README.
288
+
289
+ The only public function is:
290
+
291
+ ```typescript
292
+ export function supabaseAdapter(opts: SupabaseAdapterOptions): StorageAdapter
293
+ ```
294
+
295
+ ## Contributing
296
+
297
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md) at repo root.
298
+
299
+ ## License
300
+
301
+ MIT
@@ -0,0 +1,51 @@
1
+ import type { MemoryType, TypedMemory, SensorySnapshot, SearchResult } from '@engram-mem/core';
2
+ import type { StorageAdapter } from '@engram-mem/core';
3
+ import { SupabaseEpisodeStorage } from './episodes.js';
4
+ import { SupabaseDigestStorage } from './digests.js';
5
+ import { SupabaseSemanticStorage } from './semantic.js';
6
+ import { SupabaseProceduralStorage } from './procedural.js';
7
+ import { SupabaseAssociationStorage } from './associations.js';
8
+ export interface SupabaseAdapterOptions {
9
+ url: string;
10
+ key: string;
11
+ embeddingDimensions?: number;
12
+ }
13
+ export declare class SupabaseStorageAdapter implements StorageAdapter {
14
+ private client;
15
+ private _isLegacy;
16
+ private _episodes;
17
+ private _digests;
18
+ private _semantic;
19
+ private _procedural;
20
+ private _associations;
21
+ constructor(opts: SupabaseAdapterOptions);
22
+ initialize(): Promise<void>;
23
+ dispose(): Promise<void>;
24
+ get episodes(): SupabaseEpisodeStorage;
25
+ get digests(): SupabaseDigestStorage;
26
+ get semantic(): SupabaseSemanticStorage;
27
+ get procedural(): SupabaseProceduralStorage;
28
+ get associations(): SupabaseAssociationStorage;
29
+ getById(id: string, type: MemoryType): Promise<TypedMemory | null>;
30
+ getByIds(ids: Array<{
31
+ id: string;
32
+ type: MemoryType;
33
+ }>): Promise<TypedMemory[]>;
34
+ saveSensorySnapshot(sessionId: string, snapshot: SensorySnapshot): Promise<void>;
35
+ loadSensorySnapshot(sessionId: string): Promise<SensorySnapshot | null>;
36
+ vectorSearch(embedding: number[], opts?: {
37
+ limit?: number;
38
+ sessionId?: string;
39
+ tiers?: MemoryType[];
40
+ }): Promise<SearchResult<TypedMemory>[]>;
41
+ textBoost(terms: string[], opts?: {
42
+ limit?: number;
43
+ sessionId?: string;
44
+ }): Promise<Array<{
45
+ id: string;
46
+ type: MemoryType;
47
+ boost: number;
48
+ }>>;
49
+ private assertInitialized;
50
+ }
51
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAE9D,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,qBAAa,sBAAuB,YAAW,cAAc;IAC3D,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,aAAa,CAA0C;gBAEnD,IAAI,EAAE,sBAAsB;IAIlC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,IAAI,QAAQ,IAAI,sBAAsB,CAKrC;IAED,IAAI,OAAO,IAAI,qBAAqB,CAKnC;IAED,IAAI,QAAQ,IAAI,uBAAuB,CAKtC;IAED,IAAI,UAAU,IAAI,yBAAyB,CAK1C;IAED,IAAI,YAAY,IAAI,0BAA0B,CAK7C;IAEK,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA8ClE,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA0D9E,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhF,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAYvE,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE;QAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;KACrB,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;IAoBlC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE;QACtC,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA0BnE,OAAO,CAAC,iBAAiB;CAK1B"}