Skip to content

LTM 02: Memory Update & Delete

LLM-initiated replacement or deletion of an existing persistent memory, identified by the ID:N shown in the LLM’s context.

File: src/tools/functionCalls/updateLongTermMemoryTool.ts — class UpdateLongTermMemoryTool, tool name update_long_term_memory

When the LLM identifies an existing memory that needs correction, revision, or removal, it calls update_long_term_memory with the memory’s memory_id, new memory_content (or empty string to delete), and optionally a target_user to indicate the memory is personal rather than server-wide.

UpdateLongTermMemoryTool.execute() runs the following sequence:

  1. Validate parameters (integer ID > 0, content is a string, feature flag on).
  2. Sanitize contentsanitizeUnknownTemplatePlaceholders() strips brace-wrapped non-template tokens. Empty string after sanitization = delete.
  3. Resolve target user (if target_user provided) — same resolveUserTarget() lookup as stage 01, but bridge users are rejected outright for personal updates (they only support server-wide memories).
  4. Scope determinationtarget_user present → personal path; absent → server path.
  5. Privacy / guild membership check (personal path, update only) — PrivacyLevel.PARTIAL/FULL blocks the update. Target user must be in the guild or DM channel.
  6. Find the memory (personal delete/update) — loads the user’s personal memories for this lineage and locates the entry matching memory_id.
  7. DB writeserverMemoryRepository.updateByIdWithLineage() / personalMemoryRepository.updateByIdForUserAndLineage() for updates; serverMemoryRepository.removeByIdWithLineage() / personalMemoryRepository.removeByIdForUserAndLineage() for deletes.
  8. Notify — send an update or delete embed to Discord.
  9. Invalidate cache — same paths as stage 01.

Tool arguments (from LLM):

ArgTypeRequiredDescription
memory_idnumberyesInteger ID as shown in context (ID:N). Must be > 0 and a safe integer.
memory_contentstringyesFull replacement content. Empty string → delete instead of update.
target_userstringwhen personalDisplay name of the memory owner. Absent → server memory path.

Context required: same as stage 01 (tomoriState, channel, userId).

Promise<ToolResult> with data.status indicating outcome:

StatusMeaning
memory_updated_successfullyDB update succeeded
memory_deleted_successfullyDB delete succeeded
memory_update_failed_not_foundNo memory with this ID in the current scope
memory_update_failed_disabledself_teaching_enabled is off
memory_update_failed_privacy_restrictedTarget user has PrivacyLevel.PARTIAL/FULL
memory_update_failed_invalid_scopeBridge-user personal update attempted; or target not in guild
memory_update_failed_ambiguous_userMultiple users matched target_user
memory_update_failed_user_not_foundNo matching user found
memory_update_failed_invalid_targetAttempted to update personal memory about the bot itself
memory_update_failed_db_errorDB operation failed
  • DB row updated or deleted — the row matching (memory_id, server_id, persona_lineage_id) for server memories, or (memory_id, user_id, persona_lineage_id) for personal memories.
  • Discord embed sent — update embed (amber MEMORY_UPDATE color) or delete embed (red ERROR color) sent to context.channel.
  • Cache invalidated — same as stage 01: invalidateTomoriStateCache or invalidateUserCache immediately after DB success.

After a successful update:

  • The row with memory_id contains newContent as its content column.
  • The TomoriState or user cache for the affected scope has been invalidated.

After a successful delete:

  • No row with memory_id exists in the relevant table for this (server_id / user_id, persona_lineage_id) scope.
  • The embed shows the deleted content (fetched from the deletedMemory return value before deletion) for user confirmation.
ConditionPath taken
target_user absentServer memory path — update/delete from server_memories scoped to (server_id, persona_lineage_id)
target_user present and resolvedPersonal memory path — update/delete from personal_memories scoped to (user_id, persona_lineage_id)
target_user is a bridge userError — bridge users only support server-wide memories
target_user resolves to the botError — personal memories about the bot are not supported
SurfacePlugin-relevance
serverMemoryRepository.updateByIdWithLineage() / removeByIdWithLineage()Internal — scope is fixed by (server_id, persona_lineage_id); no plugin seam for custom scoping within this method.
personalMemoryRepository.updateByIdForUserAndLineage() / removeByIdForUserAndLineage()Internal — same as above for personal scope.
Embed color (ColorCode.MEMORY_UPDATE vs ColorCode.ERROR)Internal — color codes are defined in src/utils/misc/logger.ts; not a plugin seam.
  • Stage that creates the memories updated here: → ltm/01-ltm-create.md
  • Context-build stages that read these memories: → server / personal
  • Privacy level schema: → src/types/db/schema.ts (PrivacyLevel enum)
  • Bridge user detection: → src/utils/bridges/index.ts