@shadowforge0/aquifer-memory 0.7.0 → 0.9.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 +167 -83
- package/consumers/cli.js +74 -78
- package/consumers/mcp.js +69 -5
- package/consumers/openclaw-plugin.js +18 -5
- package/consumers/shared/config.js +3 -3
- package/consumers/shared/factory.js +6 -4
- package/core/aquifer.js +157 -17
- package/core/storage.js +12 -3
- package/docs/setup.md +194 -0
- package/index.js +2 -1
- package/package.json +8 -8
- package/pipeline/normalize/adapters/claude-code.js +90 -0
- package/pipeline/normalize/adapters/gateway.js +67 -0
- package/pipeline/normalize/constants.js +12 -0
- package/pipeline/normalize/detect.js +52 -0
- package/pipeline/normalize/extract.js +49 -0
- package/pipeline/normalize/index.js +129 -0
- package/pipeline/normalize/timestamp.js +33 -0
- package/scripts/smoke.mjs +115 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Aquifer smoke test — validates the full write → enrich → recall cycle.
|
|
5
|
+
*
|
|
6
|
+
* Prerequisites:
|
|
7
|
+
* - DATABASE_URL set to a PostgreSQL database with pgvector
|
|
8
|
+
* - AQUIFER_EMBED_BASE_URL + AQUIFER_EMBED_MODEL set (e.g., Ollama bge-m3)
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/smoke.mjs
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createRequire } from 'module';
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
|
|
17
|
+
const { createAquifer, createEmbedder } = require('../index.js');
|
|
18
|
+
const { loadConfig } = require('../consumers/shared/config.js');
|
|
19
|
+
|
|
20
|
+
const config = loadConfig();
|
|
21
|
+
|
|
22
|
+
if (!config.db.url) {
|
|
23
|
+
console.error('ERROR: DATABASE_URL is not set.');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!config.embed.baseUrl || !config.embed.model) {
|
|
28
|
+
console.error('ERROR: AQUIFER_EMBED_BASE_URL and AQUIFER_EMBED_MODEL must be set.');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Build embedder
|
|
33
|
+
const isOllama = config.embed.baseUrl.includes('11434') || config.embed.baseUrl.includes('ollama');
|
|
34
|
+
const embedder = isOllama
|
|
35
|
+
? createEmbedder({
|
|
36
|
+
provider: 'ollama',
|
|
37
|
+
ollamaUrl: config.embed.baseUrl.replace(/\/v1\/?$/, ''),
|
|
38
|
+
model: config.embed.model,
|
|
39
|
+
})
|
|
40
|
+
: createEmbedder({
|
|
41
|
+
provider: 'openai',
|
|
42
|
+
openaiApiKey: config.embed.apiKey || '',
|
|
43
|
+
openaiModel: config.embed.model,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const aquifer = createAquifer({
|
|
47
|
+
db: config.db.url,
|
|
48
|
+
schema: config.schema || 'aquifer',
|
|
49
|
+
tenantId: config.tenantId || 'default',
|
|
50
|
+
embed: { fn: (texts) => embedder.embedBatch(texts), dim: config.embed.dim || null },
|
|
51
|
+
entities: { enabled: false },
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const SESSION_ID = `smoke-test-${Date.now()}`;
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// 1. Migrate
|
|
58
|
+
console.log('1. Running migrations...');
|
|
59
|
+
await aquifer.migrate();
|
|
60
|
+
console.log(' OK');
|
|
61
|
+
|
|
62
|
+
// 2. Commit a test session
|
|
63
|
+
console.log('2. Committing test session...');
|
|
64
|
+
const commitResult = await aquifer.commit(SESSION_ID, [
|
|
65
|
+
{ role: 'user', content: 'We decided to use PostgreSQL with pgvector for the AI memory store instead of a separate vector database.' },
|
|
66
|
+
{ role: 'assistant', content: 'Good choice. PG gives us ACID transactions, full-text search, and vector similarity all in one place.' },
|
|
67
|
+
{ role: 'user', content: 'The main advantage is turn-level embedding — we can find the exact moment a decision was made.' },
|
|
68
|
+
], { agentId: 'smoke-test', source: 'smoke' });
|
|
69
|
+
console.log(` OK — session ${commitResult.isNew ? 'created' : 'updated'}`);
|
|
70
|
+
|
|
71
|
+
// 3. Enrich (skip summary since LLM may not be configured)
|
|
72
|
+
console.log('3. Enriching (turn embeddings, skip summary)...');
|
|
73
|
+
const enrichResult = await aquifer.enrich(SESSION_ID, {
|
|
74
|
+
agentId: 'smoke-test',
|
|
75
|
+
skipSummary: true,
|
|
76
|
+
skipEntities: true,
|
|
77
|
+
});
|
|
78
|
+
console.log(` OK — ${enrichResult.turnsEmbedded} turns embedded`);
|
|
79
|
+
|
|
80
|
+
// 4. Recall
|
|
81
|
+
console.log('4. Recalling "PostgreSQL memory store"...');
|
|
82
|
+
const results = await aquifer.recall('PostgreSQL memory store', { limit: 3 });
|
|
83
|
+
if (results.length === 0) {
|
|
84
|
+
console.error(' FAIL — no results returned');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
console.log(` OK — ${results.length} result(s), top score: ${results[0].score?.toFixed(3)}`);
|
|
88
|
+
if (results[0].matchedTurnText) {
|
|
89
|
+
console.log(` Matched turn: "${results[0].matchedTurnText.slice(0, 100)}..."`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 5. Stats
|
|
93
|
+
console.log('5. Checking stats...');
|
|
94
|
+
const stats = await aquifer.getStats();
|
|
95
|
+
console.log(` Sessions: ${stats.sessionTotal}, Turn embeddings: ${stats.turnEmbeddings}`);
|
|
96
|
+
|
|
97
|
+
// 6. Cleanup — remove smoke test session
|
|
98
|
+
console.log('6. Cleaning up...');
|
|
99
|
+
const { Pool } = require('pg');
|
|
100
|
+
const pool = new Pool({ connectionString: config.db.url });
|
|
101
|
+
const schema = config.schema || 'aquifer';
|
|
102
|
+
await pool.query(`DELETE FROM ${schema}.turn_embeddings WHERE session_id IN (SELECT id FROM ${schema}.sessions WHERE session_id = $1)`, [SESSION_ID]);
|
|
103
|
+
await pool.query(`DELETE FROM ${schema}.session_summaries WHERE session_id IN (SELECT id FROM ${schema}.sessions WHERE session_id = $1)`, [SESSION_ID]);
|
|
104
|
+
await pool.query(`DELETE FROM ${schema}.sessions WHERE session_id = $1`, [SESSION_ID]);
|
|
105
|
+
await pool.end();
|
|
106
|
+
console.log(' OK');
|
|
107
|
+
|
|
108
|
+
console.log('\n✓ smoke test passed');
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error(`\n✗ smoke test failed: ${err.message}`);
|
|
111
|
+
if (err.stack) console.error(err.stack);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
} finally {
|
|
114
|
+
await aquifer.close();
|
|
115
|
+
}
|