Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions hindsight-api-slim/hindsight_api/api/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,50 @@ async def api_get_memory(
logger.error(f"Error in /v1/default/banks/{bank_id}/memories/{memory_id}: {error_detail}")
raise HTTPException(status_code=500, detail=str(e))


@app.delete(
"/v1/default/banks/{bank_id}/memories/{memory_id}",
response_model=DeleteResponse,
summary="Delete a memory unit",
description="Delete a single memory unit and all its associated links, entity associations, "
"and derived observations.\n\n"
"Due to CASCADE DELETE constraints, this will automatically delete:\n"
"- All links from/to this memory unit\n"
"- All entity associations\n"
"- All derived observations (remaining source memories are reset for re-consolidation)\n\n"
"This operation cannot be undone.",
operation_id="delete_memory",
tags=["Memory"],
)
@audited("delete_memory", request_param=None)
async def api_delete_memory(
bank_id: str,
memory_id: str,
request_context: RequestContext = Depends(get_request_context),
):
"""Delete a single memory unit and all its associated data."""
try:
result = await app.state.memory.delete_memory_unit(
memory_id,
request_context=request_context,
)
if not result.get("success"):
raise HTTPException(status_code=404, detail=f"Memory unit '{memory_id}' not found")
return DeleteResponse(
success=True,
message=result.get("message", "Memory unit deleted successfully"),
)
except OperationValidationError as e:
raise HTTPException(status_code=e.status_code, detail=e.reason)
except (AuthenticationError, HTTPException):
raise
except Exception as e:
import traceback

error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
logger.error(f"Error in DELETE /v1/default/banks/{bank_id}/memories/{memory_id}: {error_detail}")
raise HTTPException(status_code=500, detail=str(e))

@app.get(
"/v1/default/banks/{bank_id}/memories/{memory_id}/history",
summary="Get observation history",
Expand Down
75 changes: 75 additions & 0 deletions hindsight-api-slim/tests/test_http_api_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,81 @@ async def test_document_deletion_with_slashes_in_id(api_client):
await api_client.delete(f"/v1/default/banks/{test_bank_id}")



@pytest.mark.asyncio
async def test_delete_memory_unit(api_client):
"""Test deleting a single memory unit via DELETE endpoint.

Workflow:
1. Create a bank by storing memories
2. List memories and pick one
3. Delete that single memory unit
4. Verify it returns 404 on GET
5. Verify other memories still exist
6. Delete again returns 404
"""
test_bank_id = f"delete_memory_test_{datetime.now().timestamp()}"

# 1. Store two memories
response = await api_client.post(
f"/v1/default/banks/{test_bank_id}/memories",
json={
"items": [
{
"content": "Alice is a software engineer who loves hiking.",
"context": "team info",
},
{
"content": "Bob is a data scientist who enjoys painting.",
"context": "team info",
},
]
},
)
assert response.status_code == 200
assert response.json()["success"] is True

# 2. List memories and pick one to delete
response = await api_client.post(
f"/v1/default/banks/{test_bank_id}/memories/list",
json={},
)
assert response.status_code == 200
memories = response.json()["items"]
assert len(memories) >= 2
memory_to_delete = memories[0]["id"]
other_memory = memories[1]["id"]

# 3. Delete the memory unit
response = await api_client.delete(
f"/v1/default/banks/{test_bank_id}/memories/{memory_to_delete}"
)
assert response.status_code == 200
delete_result = response.json()
assert delete_result["success"] is True

# 4. Verify deleted memory returns 404
response = await api_client.get(
f"/v1/default/banks/{test_bank_id}/memories/{memory_to_delete}"
)
assert response.status_code == 404

# 5. Verify other memory still exists
response = await api_client.get(
f"/v1/default/banks/{test_bank_id}/memories/{other_memory}"
)
assert response.status_code == 200

# 6. Try to delete again (should return 404)
response = await api_client.delete(
f"/v1/default/banks/{test_bank_id}/memories/{memory_to_delete}"
)
assert response.status_code == 404

# Cleanup
await api_client.delete(f"/v1/default/banks/{test_bank_id}")


@pytest.mark.asyncio
async def test_delete_bank(api_client):
"""Test delete bank endpoint.
Expand Down
Loading