{"version":3,"file":"memory.mjs","names":[],"sources":["../../../src/batteries/tools/memory/index.ts"],"sourcesContent":["/**\n * Pre-constructed CRUD tools for model-visible ADK memory management.\n *\n * @module @nhtio/adk/batteries/tools/memory\n *\n * @remarks\n * Pre-constructed CRUD tools that expose the ADK's {@link @nhtio/adk!Memory} surface to the model.\n * Each tool delegates to the corresponding callback on the active {@link @nhtio/adk!DispatchContext}\n * (`fetchMemories`, `storeMemory`, `mutateMemory`, `deleteMemory`) — the persistence layer is\n * whatever the consumer wired into the runner.\n *\n * Memory entries carry agent-internal `confidence` / `importance` scores and are rendered\n * through the LLM battery's recall-tier envelope. Letting the model author and curate its own\n * memories is the canonical use case for these tools; deployers who do not want the model to\n * mutate memory should simply not register the relevant tools.\n *\n * Output is JSON for every tool so consumers can parse the result without re-tokenising — the\n * artifact constructor is set to {@link @nhtio/adk!SpooledJsonArtifact}.\n *\n * Tools:\n * - {@link listMemoriesTool} — read-only list of every memory currently held by the context.\n * - {@link storeMemoryTool} — create a new memory (auto-generates `id` / `createdAt` /\n *   `updatedAt` unless explicit values are supplied).\n * - {@link updateMemoryTool} — replace an existing memory by `id`. Bumps `updatedAt`.\n * - {@link deleteMemoryTool} — remove a memory by `id`.\n */\n\nimport { DateTime } from 'luxon'\nimport { v6 as uuidv6 } from 'uuid'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { Memory, SpooledJsonArtifact, Tool } from '@nhtio/adk/common'\n\nconst serialiseMemory = (m: Memory): Record<string, unknown> => ({\n  id: m.id,\n  content: m.content.toString(),\n  confidence: m.confidence,\n  importance: m.importance,\n  createdAt: m.createdAt.toISO(),\n  updatedAt: m.updatedAt.toISO(),\n})\n\n/**\n * List every memory currently held by the active execution context.\n *\n * @remarks\n * Delegates to `ctx.fetchMemories()`. Returns a JSON-encoded array of memory records (id,\n * content, confidence, importance, createdAt, updatedAt). The model can use the `id` values\n * to drive subsequent `update_memory` / `delete_memory` calls.\n */\nexport const listMemoriesTool = new Tool({\n  name: 'list_memories',\n  description:\n    'List every memory currently held by the agent. Returns a JSON array of memory records with id, content, confidence, importance, createdAt, and updatedAt.',\n  inputSchema: validator.object({}),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (_args, ctx) => {\n    try {\n      const memories = await ctx.fetchMemories()\n      return JSON.stringify(memories.map(serialiseMemory), null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Create a new {@link @nhtio/adk!Memory} record and persist it via the context's `storeMemory` callback.\n *\n * @remarks\n * When `id` is omitted, a UUID v6 is generated. When `createdAt` / `updatedAt` are omitted,\n * the current time is used. The model authors `content`, `confidence`, and `importance`\n * directly. The resulting record is added to `ctx.turnMemories` and flushed to the consumer's\n * persistence layer.\n */\nexport const storeMemoryTool = new Tool({\n  name: 'store_memory',\n  description:\n    'Store a new memory record. Provide the content, your confidence (0–1) that the memory is accurate, and the importance (0–1) of the memory for future recall. id and timestamps are auto-generated if omitted.',\n  inputSchema: validator.object({\n    content: validator.string().required().description('The memory content as a plain string.'),\n    confidence: validator\n      .number()\n      .min(0)\n      .max(1)\n      .required()\n      .description('Confidence in [0, 1] that this memory is accurate.'),\n    importance: validator\n      .number()\n      .min(0)\n      .max(1)\n      .required()\n      .description('Importance in [0, 1] — how much weight the memory should carry on recall.'),\n    id: validator\n      .string()\n      .optional()\n      .allow('')\n      .description('Optional stable id. Auto-generated when absent or an empty string.'),\n  }),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (args, ctx) => {\n    const { content, confidence, importance, id } = args as {\n      content: string\n      confidence: number\n      importance: number\n      id?: string\n    }\n    try {\n      const now = DateTime.now()\n      const memory = new Memory({\n        id: (id || undefined) ?? uuidv6(),\n        content,\n        confidence,\n        importance,\n        createdAt: now,\n        updatedAt: now,\n      })\n      await ctx.storeMemory(memory)\n      return JSON.stringify({ ok: true, memory: serialiseMemory(memory) }, null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Replace an existing {@link @nhtio/adk!Memory} by `id`.\n *\n * @remarks\n * The model supplies `id` plus any subset of `content` / `confidence` / `importance`; fields\n * left undefined retain their prior values. `updatedAt` is always bumped to the current time;\n * `createdAt` is preserved. Returns an error when no memory with the supplied `id` is found.\n */\nexport const updateMemoryTool = new Tool({\n  name: 'update_memory',\n  description:\n    'Update an existing memory by id. Supply any subset of content / confidence / importance — omitted fields retain their prior values. updatedAt is always refreshed.',\n  inputSchema: validator.object({\n    id: validator.string().required().description('Id of the memory to update.'),\n    content: validator\n      .string()\n      .optional()\n      .allow('')\n      .description('Replacement content. Omit or send an empty string to leave it unchanged.'),\n    confidence: validator\n      .number()\n      .min(0)\n      .max(1)\n      .optional()\n      .description('Replacement confidence in [0, 1].'),\n    importance: validator\n      .number()\n      .min(0)\n      .max(1)\n      .optional()\n      .description('Replacement importance in [0, 1].'),\n  }),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (args, ctx) => {\n    const { id, content, confidence, importance } = args as {\n      id: string\n      content?: string\n      confidence?: number\n      importance?: number\n    }\n    try {\n      const memories = await ctx.fetchMemories()\n      const existing = memories.find((m) => m.id === id)\n      if (!existing) {\n        return `Error: No memory found with id \"${id}\".`\n      }\n      const updated = new Memory({\n        id: existing.id,\n        content: (content || undefined) ?? existing.content,\n        confidence: confidence ?? existing.confidence,\n        importance: importance ?? existing.importance,\n        createdAt: existing.createdAt,\n        updatedAt: DateTime.now(),\n      })\n      await ctx.mutateMemory(updated)\n      return JSON.stringify({ ok: true, memory: serialiseMemory(updated) }, null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Remove an existing {@link @nhtio/adk!Memory} by `id`.\n *\n * @remarks\n * Delegates to `ctx.deleteMemory(id)`. Returns `{ ok: true, id }` on success regardless of\n * whether a memory was actually present — `deleteMemory` is idempotent at the ADK level.\n */\nexport const deleteMemoryTool = new Tool({\n  name: 'delete_memory',\n  description: 'Delete a memory by id.',\n  inputSchema: validator.object({\n    id: validator.string().required().description('Id of the memory to delete.'),\n  }),\n  artifactConstructor: () => SpooledJsonArtifact,\n  handler: async (args, ctx) => {\n    const { id } = args as { id: string }\n    try {\n      await ctx.deleteMemory(id)\n      return JSON.stringify({ ok: true, id }, null, 2)\n    } catch (err) {\n      return `Error: ${isError(err) ? err.message : String(err)}`\n    }\n  },\n})\n\n/**\n * Convenience tuple of every memory CRUD tool. Spread into a {@link @nhtio/adk!ToolRegistry} to register\n * the entire category at once: `registry.register(...memoryTools)`.\n */\nexport const memoryTools = [\n  listMemoriesTool,\n  storeMemoryTool,\n  updateMemoryTool,\n  deleteMemoryTool,\n] as const\n"],"mappings":"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"}