Skip to content

fix(cli): keep every result in entity delete, not just the last#5936

Merged
kartik-mem0 merged 1 commit into
mem0ai:mainfrom
abhay-codes07:fix/cli-delete-entities-partial-result
Jun 29, 2026
Merged

fix(cli): keep every result in entity delete, not just the last#5936
kartik-mem0 merged 1 commit into
mem0ai:mainfrom
abhay-codes07:fix/cli-delete-entities-partial-result

Conversation

@abhay-codes07

Copy link
Copy Markdown
Contributor

Linked Issue

Closes #5935

Description

delete_entities() walks every entity it's asked to delete, but it writes each API response into one result variable that gets overwritten on the next pass — so only the last entity's response makes it back to the caller:

result: dict = {}
for entity_type, entity_id in entities.items():
    result = self._request("DELETE", f"/v2/entities/{entity_type}/{entity_id}/", ...)
return result

That matters because mem0 entity delete lets you pass --user-id, --agent-id, --app-id, and --run-id together, and cmd_entities_delete prints this value straight out under --output json. Delete two entities and the JSON only shows one — anything scripting against that output silently loses the rest.

The fix collects each response into a dict keyed by entity type ({"user": {...}, "agent": {...}}). Nothing is dropped, the deletes themselves were always happening (one request each), and the -> dict return type stays intact. Single-entity deletes just return a one-key dict.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactor (no functional changes)
  • Documentation update

Breaking Changes

The JSON shape of mem0 entity delete --output json changes from a single raw API response to a map keyed by entity type. This only affects the multi-entity case (which was lossy before) and the human/agent output modes are unaffected, so I've treated it as a bug fix rather than a breaking change — happy to adjust if you'd prefer to preserve the single-entity raw shape.

Test Coverage

  • I added/updated unit tests
  • I added/updated integration tests
  • I tested manually (describe below)
  • No tests needed

Added tests/test_platform_backend.py covering multi-entity (fails without the fix), single-entity, and the no-entity ValueError. _request is patched, so no network calls. Full CLI suite passes and ruff check is clean.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have added tests that prove my fix works
  • New and existing tests pass locally
  • I have updated documentation if needed (no user-facing docs affected)

delete_entities looped over each entity but reassigned a single `result`
variable, so a multi-entity delete (e.g. --user-id and --agent-id together)
returned only the last entity's API response. Under `mem0 entity delete
--output json` the other deletions were silently dropped from the output.

Collect responses into a dict keyed by entity type. No data is lost and the
`-> dict` return type is preserved.

Adds a backend test module covering multi-entity, single-entity, and the
no-entity ValueError; the multi-entity case fails without the fix.

Closes mem0ai#5935
Copilot AI review requested due to automatic review settings June 27, 2026 19:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@abhay-codes07

Copy link
Copy Markdown
Contributor Author

@kartik-mem0 small CLI fix with tests. Noted a minor JSON-shape question in the description. Quick review when you can, thanks.

@kartik-mem0
kartik-mem0 merged commit ad57cbb into mem0ai:main Jun 29, 2026
15 of 16 checks passed
@kartik-mem0

Copy link
Copy Markdown
Contributor

hey @abhay-codes07 thank you for contribution can you confirm if this issues are also in the ts cli and raise the issue for them?

#5933, #5931 and the above one!

thanks!

@abhay-codes07

Copy link
Copy Markdown
Contributor Author

@kartik-mem0 thanks! Checked the Node/TS CLI for all three:

So only the entity delete one needed a fix on the TS side.

RudrenduPaul added a commit to RudrenduPaul/memtrust that referenced this pull request Jul 12, 2026
No adapter method exists for deleting a memory or entity, so no eval
can exercise the real, merged multi-entity-delete truncation bug class
(mem0ai/mem0#5936, #5970: client-side aggregation silently keeping only
the last response instead of all N). Add an abstract delete() to
MemoryBackendAdapter plus a concrete default delete_many() that loops
over delete() and aggregates one DeleteResult per input id, in order,
even when some deletes fail -- this is the primitive an eval needs to
construct that reproduction and prove the aggregation itself doesn't
truncate.

Implement delete() for real against Mem0 (DELETE /v1/memories/{id}/),
Zep/Graphiti, and OpenViking following each adapter's existing
store/query/update HTTP conventions and documented confidence level.
MemPalace has no confirmed delete/forget primitive in its vendor
surface, so its delete() raises a clearly-documented BackendAPIError
instead of guessing an unverified method name.

Built by Rudrendu Paul and Sourav Nandy, developed with Claude Code
RudrenduPaul added a commit to RudrenduPaul/memtrust that referenced this pull request Jul 16, 2026
No adapter method exists for deleting a memory or entity, so no eval
can exercise the real, merged multi-entity-delete truncation bug class
(mem0ai/mem0#5936, #5970: client-side aggregation silently keeping only
the last response instead of all N). Add an abstract delete() to
MemoryBackendAdapter plus a concrete default delete_many() that loops
over delete() and aggregates one DeleteResult per input id, in order,
even when some deletes fail -- this is the primitive an eval needs to
construct that reproduction and prove the aggregation itself doesn't
truncate.

Implement delete() for real against Mem0 (DELETE /v1/memories/{id}/),
Zep/Graphiti, and OpenViking following each adapter's existing
store/query/update HTTP conventions and documented confidence level.
MemPalace has no confirmed delete/forget primitive in its vendor
surface, so its delete() raises a clearly-documented BackendAPIError
instead of guessing an unverified method name.

Built by Rudrendu Paul and Sourav Nandy, developed with Claude Code
RudrenduPaul added a commit to RudrenduPaul/memtrust that referenced this pull request Jul 16, 2026
No adapter method exists for deleting a memory or entity, so no eval
can exercise the real, merged multi-entity-delete truncation bug class
(mem0ai/mem0#5936, #5970: client-side aggregation silently keeping only
the last response instead of all N). Add an abstract delete() to
MemoryBackendAdapter plus a concrete default delete_many() that loops
over delete() and aggregates one DeleteResult per input id, in order,
even when some deletes fail -- this is the primitive an eval needs to
construct that reproduction and prove the aggregation itself doesn't
truncate.

Implement delete() for real against Mem0 (DELETE /v1/memories/{id}/),
Zep/Graphiti, and OpenViking following each adapter's existing
store/query/update HTTP conventions and documented confidence level.
MemPalace has no confirmed delete/forget primitive in its vendor
surface, so its delete() raises a clearly-documented BackendAPIError
instead of guessing an unverified method name.

Built by Rudrendu Paul and Sourav Nandy, developed with Claude Code
RudrenduPaul added a commit to RudrenduPaul/memtrust that referenced this pull request Jul 16, 2026
No adapter method exists for deleting a memory or entity, so no eval
can exercise the real, merged multi-entity-delete truncation bug class
(mem0ai/mem0#5936, #5970: client-side aggregation silently keeping only
the last response instead of all N). Add an abstract delete() to
MemoryBackendAdapter plus a concrete default delete_many() that loops
over delete() and aggregates one DeleteResult per input id, in order,
even when some deletes fail -- this is the primitive an eval needs to
construct that reproduction and prove the aggregation itself doesn't
truncate.

Implement delete() for real against Mem0 (DELETE /v1/memories/{id}/),
Zep/Graphiti, and OpenViking following each adapter's existing
store/query/update HTTP conventions and documented confidence level.
MemPalace has no confirmed delete/forget primitive in its vendor
surface, so its delete() raises a clearly-documented BackendAPIError
instead of guessing an unverified method name.

Built by Rudrendu Paul and Sourav Nandy, developed with Claude Code
RudrenduPaul added a commit to RudrenduPaul/memtrust that referenced this pull request Jul 18, 2026
No adapter method exists for deleting a memory or entity, so no eval
can exercise the real, merged multi-entity-delete truncation bug class
(mem0ai/mem0#5936, #5970: client-side aggregation silently keeping only
the last response instead of all N). Add an abstract delete() to
MemoryBackendAdapter plus a concrete default delete_many() that loops
over delete() and aggregates one DeleteResult per input id, in order,
even when some deletes fail -- this is the primitive an eval needs to
construct that reproduction and prove the aggregation itself doesn't
truncate.

Implement delete() for real against Mem0 (DELETE /v1/memories/{id}/),
Zep/Graphiti, and OpenViking following each adapter's existing
store/query/update HTTP conventions and documented confidence level.
MemPalace has no confirmed delete/forget primitive in its vendor
surface, so its delete() raises a clearly-documented BackendAPIError
instead of guessing an unverified method name.

Built by Rudrendu Paul and Sourav Nandy, developed with Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(cli): entity delete returns only the last entity's response for multi-entity deletes

3 participants