@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 +301 -0
- package/dist/adapter.d.ts +51 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +411 -0
- package/dist/adapter.js.map +1 -0
- package/dist/associations.d.ts +23 -0
- package/dist/associations.d.ts.map +1 -0
- package/dist/associations.js +109 -0
- package/dist/associations.js.map +1 -0
- package/dist/digests.d.ts +13 -0
- package/dist/digests.d.ts.map +1 -0
- package/dist/digests.js +154 -0
- package/dist/digests.js.map +1 -0
- package/dist/episodes.d.ts +25 -0
- package/dist/episodes.d.ts.map +1 -0
- package/dist/episodes.js +260 -0
- package/dist/episodes.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations.d.ts +27 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +650 -0
- package/dist/migrations.js.map +1 -0
- package/dist/procedural.d.ts +17 -0
- package/dist/procedural.d.ts.map +1 -0
- package/dist/procedural.js +195 -0
- package/dist/procedural.js.map +1 -0
- package/dist/search.d.ts +10 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +16 -0
- package/dist/search.js.map +1 -0
- package/dist/semantic.d.ts +17 -0
- package/dist/semantic.d.ts.map +1 -0
- package/dist/semantic.js +184 -0
- package/dist/semantic.js.map +1 -0
- package/package.json +24 -0
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"}
|