Files
oh-my-pi/packages/coding-agent/src/tools/memory-edit.ts
T
can1357 ca68daa81c 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
2026-07-09 18:27:23 +02:00

62 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
import { type } from "arktype";
import memoryEditDescription from "../prompts/tools/memory-edit.md" with { type: "text" };
import type { ToolSession } from ".";
const memoryEditSchema = type({
op: type("'update' | 'forget' | 'invalidate'").describe("memory edit operation"),
id: type("string").describe("memory id from recall output"),
"content?": type("string").describe("replacement content for update"),
"importance?": type("number").describe("replacement importance for update (0–1)"),
"replacement_id?": type("string").describe("replacement memory id for invalidate"),
});
export type MemoryEditParams = typeof memoryEditSchema.infer;
export class MemoryEditTool implements AgentTool<typeof memoryEditSchema> {
readonly name = "memory_edit";
readonly approval = "read" as const;
readonly label = "Memory Edit";
readonly description = memoryEditDescription;
readonly parameters = memoryEditSchema;
readonly strict = true;
readonly loadMode = "discoverable";
readonly summary = "Update, forget, or invalidate Mnemopi memories";
constructor(private readonly session: ToolSession) {}
static createIf(session: ToolSession): MemoryEditTool | null {
const backend = session.settings.get("memory.backend");
if (backend !== "mnemopi") return null;
return new MemoryEditTool(session);
}
async execute(_id: string, params: MemoryEditParams): Promise<AgentToolResult> {
const state = this.session.getMnemopiSessionState?.();
if (!state) {
throw new Error("Mnemopi backend is not initialised for this session.");
}
if (params.op === "update" && params.content === undefined && params.importance === undefined) {
throw new Error("memory_edit update requires content or importance.");
}
const importance = params.importance === undefined ? undefined : Math.max(0, Math.min(1, params.importance));
const result = state.editScopedMemory(params.op, params.id, {
content: params.content,
importance,
replacementId: params.replacement_id,
});
const location = result.bank ? ` in bank ${result.bank}${result.store ? ` (${result.store})` : ""}` : "";
const text =
result.status === "not_found"
? `Memory ${params.id} was not found${location}.`
: result.status === "not_editable"
? `Memory ${params.id} is a read-only fact${location}; it cannot be edited. Read it with memory://${params.id}.`
: `Memory ${params.id} ${result.status}${location}.`;
return {
content: [{ type: "text", text }],
details: result,
};
}
}