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 { 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 { 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, }; } }