feat(memory-v2): restore personal shadow pipeline and candidate store
Recover WIP modules from stash so admin can persist capability config, observe chat writes in shadow mode, and review persisted candidates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
buildPersonalMemoryCandidateSchemaSql,
|
||||
createPersonalMemoryCandidateStore,
|
||||
ensurePersonalMemoryCandidateSchema,
|
||||
} from './memory-v2-personal-store.mjs';
|
||||
|
||||
test('candidate schema is explicit and idempotent', async () => {
|
||||
const calls = [];
|
||||
const pool = { async query(sql, params) { calls.push({ sql, params }); return [[], []]; } };
|
||||
await ensurePersonalMemoryCandidateSchema(pool);
|
||||
assert.match(calls[0].sql, /CREATE TABLE IF NOT EXISTS/);
|
||||
assert.match(calls[0].sql, /h5_memory_v2_candidates/);
|
||||
assert.throws(() => buildPersonalMemoryCandidateSchemaSql({ table: 'bad-name' }), /Invalid/);
|
||||
});
|
||||
|
||||
test('candidate store saves, lists, counts, and reviews with parameterized SQL', async () => {
|
||||
const calls = [];
|
||||
const pool = {
|
||||
async query(sql, params = []) {
|
||||
calls.push({ sql, params });
|
||||
if (sql.startsWith('INSERT')) return [{ affectedRows: 1 }, []];
|
||||
if (sql.startsWith('SELECT *')) return [[{
|
||||
id: 'pmc_1', user_id: 'u1', session_id: 's1', memory_type: 'episodic',
|
||||
content: '决定使用 main 发布', importance: '0.9', confidence: '0.9', status: 'candidate',
|
||||
policy_reason: 'decision_signal', evidence_json: '{"sourceId":"s1:0"}',
|
||||
reviewed_by: null, reviewed_at: null, created_at: 1, updated_at: 1,
|
||||
}], []];
|
||||
if (sql.startsWith('SELECT status')) return [[{ status: 'candidate', count: 1 }], []];
|
||||
if (sql.startsWith('UPDATE')) return [{ affectedRows: 1 }, []];
|
||||
throw new Error(`Unexpected SQL: ${sql}`);
|
||||
},
|
||||
};
|
||||
const store = createPersonalMemoryCandidateStore(pool, { now: () => 10 });
|
||||
assert.deepEqual(await store.saveCandidate({
|
||||
id: 'pmc_1', userId: 'u1', sessionId: 's1', memoryType: 'episodic',
|
||||
content: '决定使用 main 发布', importance: 0.9, confidence: 0.9,
|
||||
policyReason: 'decision_signal', evidence: { sourceId: 's1:0' }, createdAt: 1,
|
||||
}), { inserted: true });
|
||||
const rows = await store.listCandidates({ limit: 20 });
|
||||
assert.equal(rows[0].evidence.sourceId, 's1:0');
|
||||
assert.deepEqual(await store.countByStatus(), { candidate: 1 });
|
||||
assert.equal((await store.reviewCandidate('pmc_1', 'accepted', { reviewedBy: 'admin-1' })).updated, true);
|
||||
assert.ok(calls.every((call) => !call.sql.includes('admin-1')));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user