fix(mnemopi): made recall fact ids resolvable via memory reads
recall (includeFacts) surfaces facts.fact_id as a result id, but
store.get only searched working_memory + episodic_memory, so every
surfaced fact id was a dead end for 'read memory://<id>' and
memory_edit ('not found in any scoped bank').
- store.get now falls back to the facts table (visibility mirrors
factRecall: same-session or scope='global'), returning a read-only
row with memory_store 'fact' and the full triple as content.
- coding-agent labels the store honestly ('fact') in memory:// reads
and reports not_editable (instead of not_found) for memory_edit ops
on fact ids; the facts table stays immutable.
Fixes #4725
This commit is contained in:
@@ -238,6 +238,51 @@ describe("MemoryProtocolHandler — mnemopi bridge (issue #4443)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves memory://<fact-id> to a read-only fact row (issue #4725)", async () => {
|
||||
await withMnemopiSession(async ({ state }) => {
|
||||
const beam = state.memory.beam;
|
||||
beam.db
|
||||
.prepare(
|
||||
"INSERT INTO facts (fact_id, session_id, subject, predicate, object, timestamp, confidence) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.run("0473bbdb8da6df92", beam.sessionId, "Glab", "works-without", "mise prefix", "2026-07-01T00:00:00.000Z", 0.9);
|
||||
|
||||
const router = InternalUrlRouter.instance();
|
||||
const resource = await router.resolve("memory://0473bbdb8da6df92");
|
||||
|
||||
expect(resource.content).toContain("id: 0473bbdb8da6df92");
|
||||
expect(resource.content).toContain("store: fact");
|
||||
expect(resource.content).toContain("Glab works-without mise prefix");
|
||||
});
|
||||
});
|
||||
|
||||
it("reports not_editable (not not_found) for memory_edit ops on a fact id (issue #4725)", async () => {
|
||||
await withMnemopiSession(async ({ state }) => {
|
||||
const beam = state.memory.beam;
|
||||
beam.db
|
||||
.prepare(
|
||||
"INSERT INTO facts (fact_id, session_id, subject, predicate, object, timestamp, confidence) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.run("fact-readonly", beam.sessionId, "service", "uses", "postgres", "2026-07-01T00:00:00.000Z", 0.9);
|
||||
|
||||
expect(state.editScopedMemory("update", "fact-readonly", { content: "x" })).toMatchObject({
|
||||
status: "not_editable",
|
||||
store: "fact",
|
||||
});
|
||||
expect(state.editScopedMemory("forget", "fact-readonly")).toMatchObject({
|
||||
status: "not_editable",
|
||||
store: "fact",
|
||||
});
|
||||
expect(state.editScopedMemory("invalidate", "fact-readonly")).toMatchObject({
|
||||
status: "not_editable",
|
||||
store: "fact",
|
||||
});
|
||||
|
||||
// The fact row itself is untouched by the rejected edits.
|
||||
expect(beam.db.prepare("SELECT fact_id FROM facts WHERE fact_id = ?").get("fact-readonly")).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("routes memory://root to the file-backed summary even when mnemopi is active", async () => {
|
||||
await withMnemopiSession(async () => {
|
||||
const router = InternalUrlRouter.instance();
|
||||
|
||||
Reference in New Issue
Block a user