{"version":3,"file":"agent-memory.mjs","names":[],"sources":["../../../src/tools/agent-memory.ts"],"sourcesContent":["/**\n * Agent Memory Tool — LLM-facing interface to the agent memory service.\n *\n * Lets the agent persist and manage declarative memories (environment facts,\n * tool quirks, user preferences, lessons learned).\n *\n * Actions:\n *   add         — Save a new memory entry\n *   replace     — Update an existing entry (find by substring, replace)\n *   remove      — Remove an entry (find by substring)\n *   list        — Show all agent memories\n *   user_add    — Save a user profile entry\n *   user_list   — Show a user's profile entries\n *   user_remove — Remove a user profile entry\n *   stats       — Show memory usage stats\n *\n * Only write actions are gated by evolution mode.\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, textResult, errorResult, readStringParam } from '../lib/tool-helpers.js';\nimport { getAgentMemory } from '../services/agent-memory.js';\n\nconst ACTIONS = [\n  'add', 'replace', 'remove', 'list',\n  'user_add', 'user_list', 'user_remove',\n  'stats',\n] as const;\n\nconst AgentMemorySchema = Type.Object({\n  action: stringEnum(ACTIONS, { description: 'Operation to perform' }),\n  entry: Type.Optional(Type.String({\n    description: 'Memory content to add or replace with (for add/replace/user_add).',\n  })),\n  search: Type.Optional(Type.String({\n    description: 'Substring to search for (for replace/remove/user_remove). Matches are case-insensitive.',\n  })),\n  user_id: Type.Optional(Type.String({\n    description: 'User ID for user_add/user_list/user_remove actions.',\n  })),\n});\n\nexport function createAgentMemoryTool() {\n  return {\n    name: 'agent_memory',\n    label: 'Agent Memory',\n    ownerOnly: false,\n    description:\n      'Persist and manage your declarative memory. ' +\n      'WHEN TO SAVE (do this proactively, don\\'t wait to be asked): ' +\n      '(1) You discover something about the environment (chain IDs, gas patterns, tool quirks). ' +\n      '(2) User shares a preference or corrects you. ' +\n      '(3) You learn a workaround for a recurring issue. ' +\n      '(4) You find a useful DeFi strategy or protocol detail. ' +\n      'Actions: add, replace, remove, list, user_add, user_list, user_remove, stats. ' +\n      'Only available in evolving mode (/evolve).',\n    parameters: AgentMemorySchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      const params = args as Record<string, unknown>;\n      const action = readStringParam(params, 'action', { required: true })!;\n\n      const memory = getAgentMemory();\n\n      switch (action) {\n        case 'add': {\n          const entry = readStringParam(params, 'entry');\n          if (!entry) return errorResult('entry is required for add action.');\n          const result = memory.addAgentMemory(entry);\n          if (!result.ok) return errorResult(result.error!);\n          return jsonResult({ status: 'saved', message: 'Memory entry saved. It will appear in your context next session.' });\n        }\n\n        case 'replace': {\n          const search = readStringParam(params, 'search');\n          const entry = readStringParam(params, 'entry');\n          if (!search) return errorResult('search is required (substring to find in existing entry).');\n          if (!entry) return errorResult('entry is required (new content to replace with).');\n          const result = memory.replaceAgentMemory(search, entry);\n          if (!result.ok) return errorResult(result.error!);\n          return jsonResult({ status: 'replaced', message: 'Memory entry updated.' });\n        }\n\n        case 'remove': {\n          const search = readStringParam(params, 'search');\n          if (!search) return errorResult('search is required (substring to find in entry to remove).');\n          const result = memory.removeAgentMemory(search);\n          if (!result.ok) return errorResult(result.error!);\n          return jsonResult({ status: 'removed', removed: result.removed, message: 'Memory entry removed.' });\n        }\n\n        case 'list': {\n          const entries = memory.getAgentMemory();\n          if (entries.length === 0) {\n            return textResult('No agent memories saved yet. Use action \"add\" to save a discovery or lesson.');\n          }\n          const stats = memory.getAgentMemoryStats();\n          const lines = [\n            `**Agent Memory** (${stats.entries} entries, ${stats.chars}/${stats.limit} chars)`,\n            '',\n            ...entries.map((e, i) => `${i + 1}. ${e}`),\n          ];\n          return textResult(lines.join('\\n'));\n        }\n\n        case 'user_add': {\n          const userId = readStringParam(params, 'user_id');\n          const entry = readStringParam(params, 'entry');\n          if (!userId) return errorResult('user_id is required for user_add.');\n          if (!entry) return errorResult('entry is required for user_add.');\n          const result = memory.addUserMemory(userId, entry);\n          if (!result.ok) return errorResult(result.error!);\n          return jsonResult({ status: 'saved', message: `User profile entry saved for ${userId}.` });\n        }\n\n        case 'user_list': {\n          const userId = readStringParam(params, 'user_id');\n          if (!userId) return errorResult('user_id is required for user_list.');\n          const entries = memory.getUserMemory(userId);\n          if (entries.length === 0) {\n            return textResult(`No profile entries for user ${userId}.`);\n          }\n          const stats = memory.getUserMemoryStats(userId);\n          const lines = [\n            `**User Profile: ${userId}** (${stats.entries} entries, ${stats.chars}/${stats.limit} chars)`,\n            '',\n            ...entries.map((e, i) => `${i + 1}. ${e}`),\n          ];\n          return textResult(lines.join('\\n'));\n        }\n\n        case 'user_remove': {\n          const userId = readStringParam(params, 'user_id');\n          const search = readStringParam(params, 'search');\n          if (!userId) return errorResult('user_id is required for user_remove.');\n          if (!search) return errorResult('search is required (substring to find in entry to remove).');\n          const result = memory.removeUserMemory(userId, search);\n          if (!result.ok) return errorResult(result.error!);\n          return jsonResult({ status: 'removed', removed: result.removed });\n        }\n\n        case 'stats': {\n          const status = memory.getStatus();\n          return jsonResult(status);\n        }\n\n        default:\n          return errorResult(`Unknown action: ${action}`);\n      }\n    },\n  };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,oBAAoB,KAAK,OAAO;CACpC,QAAQ,WAPM;EACd;EAAO;EAAW;EAAU;EAC5B;EAAY;EAAa;EACzB;EACD,EAG6B,EAAE,aAAa,wBAAwB,CAAC;CACpE,OAAO,KAAK,SAAS,KAAK,OAAO,EAC/B,aAAa,qEACd,CAAC,CAAC;CACH,QAAQ,KAAK,SAAS,KAAK,OAAO,EAChC,aAAa,2FACd,CAAC,CAAC;CACH,SAAS,KAAK,SAAS,KAAK,OAAO,EACjC,aAAa,uDACd,CAAC,CAAC;CACJ,CAAC;AAEF,SAAgB,wBAAwB;AACtC,QAAO;EACL,MAAM;EACN,OAAO;EACP,WAAW;EACX,aACE;EAQF,YAAY;EACZ,SAAS,OAAO,aAAqB,SAAkB;GACrD,MAAM,SAAS;GACf,MAAM,SAAS,gBAAgB,QAAQ,UAAU,EAAE,UAAU,MAAM,CAAC;GAEpE,MAAM,SAAS,gBAAgB;AAE/B,WAAQ,QAAR;IACE,KAAK,OAAO;KACV,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ;AAC9C,SAAI,CAAC,MAAO,QAAO,YAAY,oCAAoC;KACnE,MAAM,SAAS,OAAO,eAAe,MAAM;AAC3C,SAAI,CAAC,OAAO,GAAI,QAAO,YAAY,OAAO,MAAO;AACjD,YAAO,WAAW;MAAE,QAAQ;MAAS,SAAS;MAAoE,CAAC;;IAGrH,KAAK,WAAW;KACd,MAAM,SAAS,gBAAgB,QAAQ,SAAS;KAChD,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ;AAC9C,SAAI,CAAC,OAAQ,QAAO,YAAY,4DAA4D;AAC5F,SAAI,CAAC,MAAO,QAAO,YAAY,mDAAmD;KAClF,MAAM,SAAS,OAAO,mBAAmB,QAAQ,MAAM;AACvD,SAAI,CAAC,OAAO,GAAI,QAAO,YAAY,OAAO,MAAO;AACjD,YAAO,WAAW;MAAE,QAAQ;MAAY,SAAS;MAAyB,CAAC;;IAG7E,KAAK,UAAU;KACb,MAAM,SAAS,gBAAgB,QAAQ,SAAS;AAChD,SAAI,CAAC,OAAQ,QAAO,YAAY,6DAA6D;KAC7F,MAAM,SAAS,OAAO,kBAAkB,OAAO;AAC/C,SAAI,CAAC,OAAO,GAAI,QAAO,YAAY,OAAO,MAAO;AACjD,YAAO,WAAW;MAAE,QAAQ;MAAW,SAAS,OAAO;MAAS,SAAS;MAAyB,CAAC;;IAGrG,KAAK,QAAQ;KACX,MAAM,UAAU,OAAO,gBAAgB;AACvC,SAAI,QAAQ,WAAW,EACrB,QAAO,WAAW,iFAA+E;KAEnG,MAAM,QAAQ,OAAO,qBAAqB;AAM1C,YAAO,WALO;MACZ,qBAAqB,MAAM,QAAQ,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM;MAC1E;MACA,GAAG,QAAQ,KAAK,GAAG,MAAM,GAAG,IAAI,EAAE,IAAI,IAAI;MAC3C,CACuB,KAAK,KAAK,CAAC;;IAGrC,KAAK,YAAY;KACf,MAAM,SAAS,gBAAgB,QAAQ,UAAU;KACjD,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ;AAC9C,SAAI,CAAC,OAAQ,QAAO,YAAY,oCAAoC;AACpE,SAAI,CAAC,MAAO,QAAO,YAAY,kCAAkC;KACjE,MAAM,SAAS,OAAO,cAAc,QAAQ,MAAM;AAClD,SAAI,CAAC,OAAO,GAAI,QAAO,YAAY,OAAO,MAAO;AACjD,YAAO,WAAW;MAAE,QAAQ;MAAS,SAAS,gCAAgC,OAAO;MAAI,CAAC;;IAG5F,KAAK,aAAa;KAChB,MAAM,SAAS,gBAAgB,QAAQ,UAAU;AACjD,SAAI,CAAC,OAAQ,QAAO,YAAY,qCAAqC;KACrE,MAAM,UAAU,OAAO,cAAc,OAAO;AAC5C,SAAI,QAAQ,WAAW,EACrB,QAAO,WAAW,+BAA+B,OAAO,GAAG;KAE7D,MAAM,QAAQ,OAAO,mBAAmB,OAAO;AAM/C,YAAO,WALO;MACZ,mBAAmB,OAAO,MAAM,MAAM,QAAQ,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM;MACrF;MACA,GAAG,QAAQ,KAAK,GAAG,MAAM,GAAG,IAAI,EAAE,IAAI,IAAI;MAC3C,CACuB,KAAK,KAAK,CAAC;;IAGrC,KAAK,eAAe;KAClB,MAAM,SAAS,gBAAgB,QAAQ,UAAU;KACjD,MAAM,SAAS,gBAAgB,QAAQ,SAAS;AAChD,SAAI,CAAC,OAAQ,QAAO,YAAY,uCAAuC;AACvE,SAAI,CAAC,OAAQ,QAAO,YAAY,6DAA6D;KAC7F,MAAM,SAAS,OAAO,iBAAiB,QAAQ,OAAO;AACtD,SAAI,CAAC,OAAO,GAAI,QAAO,YAAY,OAAO,MAAO;AACjD,YAAO,WAAW;MAAE,QAAQ;MAAW,SAAS,OAAO;MAAS,CAAC;;IAGnE,KAAK,QAEH,QAAO,WADQ,OAAO,WAAW,CACR;IAG3B,QACE,QAAO,YAAY,mBAAmB,SAAS;;;EAGtD"}