mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-06 06:52:20 +02:00
fix(memory): reject blank memory_id on edit and delete (#6342)
In src/ai_interaction.py, when parsing text-format edit or delete actions, an empty line 2 caused memory_id to resolve to empty string. Because startswith("") is always True, the first stored memory was inadvertently edited or deleted.
This change validates that memory_id is non-empty before searching the memory list, restoring parity with the MCP memory tool.
Fixes #6342.
This commit is contained in:
@@ -420,6 +420,8 @@ async def do_manage_memory(content: str, session_id: Optional[str] = None, owner
|
||||
return {"error": "Edit needs line 2: memory_id, line 3: new text"}
|
||||
memory_id = lines[1].strip()
|
||||
new_text = lines[2].strip()
|
||||
if not memory_id:
|
||||
return {"error": "Edit needs line 2: memory_id"}
|
||||
if not new_text:
|
||||
return {"error": "New text cannot be empty"}
|
||||
|
||||
@@ -453,6 +455,8 @@ async def do_manage_memory(content: str, session_id: Optional[str] = None, owner
|
||||
if len(lines) < 2:
|
||||
return {"error": "Delete needs line 2: memory_id"}
|
||||
memory_id = lines[1].strip()
|
||||
if not memory_id:
|
||||
return {"error": "Delete needs line 2: memory_id"}
|
||||
|
||||
memories = _memory_manager.load_all()
|
||||
original_len = len(memories)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import asyncio
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from src import ai_interaction
|
||||
from src.memory import MemoryManager
|
||||
|
||||
|
||||
def test_manage_memory_delete_blank_id_rejected(tmp_path, monkeypatch):
|
||||
"""Calling delete with a blank memory_id should return an error and not delete the first memory."""
|
||||
memory_file = tmp_path / "memory.json"
|
||||
initial_memories = [
|
||||
{"id": "first-mem-1111", "text": "First memory that must not be deleted", "category": "fact", "timestamp": 1000},
|
||||
{"id": "second-mem-2222", "text": "Second memory", "category": "fact", "timestamp": 2000},
|
||||
]
|
||||
memory_file.write_text(json.dumps(initial_memories), encoding="utf-8")
|
||||
|
||||
manager = MemoryManager(str(tmp_path))
|
||||
monkeypatch.setattr(ai_interaction, "_memory_manager", manager)
|
||||
monkeypatch.setattr(ai_interaction, "_memory_vector", None)
|
||||
|
||||
# Calling delete with a blank line before the ID
|
||||
result = asyncio.run(ai_interaction.do_manage_memory("delete\n\nsecond-mem-2222"))
|
||||
|
||||
# Must reject the call
|
||||
assert "error" in result
|
||||
assert "memory_id" in result["error"].lower()
|
||||
|
||||
# Verify that the first memory was NOT deleted
|
||||
remaining = manager.load_all()
|
||||
assert len(remaining) == 2
|
||||
assert remaining[0]["id"] == "first-mem-1111"
|
||||
|
||||
|
||||
def test_manage_memory_edit_blank_id_rejected(tmp_path, monkeypatch):
|
||||
"""Calling edit with a blank memory_id should return an error and not overwrite the first memory."""
|
||||
memory_file = tmp_path / "memory.json"
|
||||
initial_memories = [
|
||||
{"id": "first-mem-1111", "text": "First memory original content", "category": "fact", "timestamp": 1000},
|
||||
{"id": "second-mem-2222", "text": "Second memory", "category": "fact", "timestamp": 2000},
|
||||
]
|
||||
memory_file.write_text(json.dumps(initial_memories), encoding="utf-8")
|
||||
|
||||
manager = MemoryManager(str(tmp_path))
|
||||
monkeypatch.setattr(ai_interaction, "_memory_manager", manager)
|
||||
monkeypatch.setattr(ai_interaction, "_memory_vector", None)
|
||||
|
||||
# Calling edit with a blank line before the ID
|
||||
result = asyncio.run(ai_interaction.do_manage_memory("edit\n\nnew content for second"))
|
||||
|
||||
# Must reject the call
|
||||
assert "error" in result
|
||||
assert "memory_id" in result["error"].lower()
|
||||
|
||||
# Verify that the first memory was NOT overwritten
|
||||
remaining = manager.load_all()
|
||||
assert len(remaining) == 2
|
||||
assert remaining[0]["text"] == "First memory original content"
|
||||
Reference in New Issue
Block a user