refactor(memory): streamline memory extraction#1335
Conversation
…ext_content utility
|
@AnishSarkar22 is attempting to deploy a commit to the Rohan Verma's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
surfsense_backend/tests/unit/agents/new_chat/test_memory_response_content.py (1)
1-10: ⚡ Quick winConsider adding a test for the
_forced_rewriteempty-text scenario.The test suite covers
_save_memory's type guard but has no coverage for the case where_forced_rewritereturns an empty string (thinking-only model response) and_save_memoryconsequently setscontent = "". A targeted test would both document the expected behavior and confirm the fix suggested forupdate_memory.py.💡 Suggested test skeleton
`@pytest.mark.asyncio` async def test_save_memory_skips_empty_forced_rewrite() -> None: """Memory must not be wiped when forced-rewrite LLM returns no text.""" large_content = "- (2026-01-01) [fact] x\n" * 1200 # > MEMORY_HARD_LIMIT class _EmptyRewriteLLM: async def ainvoke(self, *args, **kwargs): # Simulates a thinking-only response → extract_text_content returns "" class _Resp: content = [{"type": "thinking", "thinking": "..."}] return _Resp() recorder = _Recorder() result = await _save_memory( updated_memory=large_content, old_memory=None, llm=_EmptyRewriteLLM(), apply_fn=recorder.apply, commit_fn=recorder.commit, rollback_fn=recorder.rollback, label="memory", scope="user", ) # With the fix, _forced_rewrite returns None → content stays large → hard-limit error assert result["status"] == "error" assert recorder.applied_content is None🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@surfsense_backend/tests/unit/agents/new_chat/test_memory_response_content.py` around lines 1 - 10, Add an async unit test to verify _save_memory does not wipe memory when _forced_rewrite yields empty text: create a large_content string > MEMORY_HARD_LIMIT, mock an LLM class (_EmptyRewriteLLM) whose ainvoke returns a response whose content is [{"type":"thinking", ...}] so extract_text_content would produce "" (simulating thinking-only output), implement a recorder stub with apply/commit/rollback that records applied_content, call _save_memory(updated_memory=large_content, old_memory=None, llm=_EmptyRewriteLLM(), apply_fn=recorder.apply, commit_fn=recorder.commit, rollback_fn=recorder.rollback, label="memory", scope="user") and assert the returned result["status"] == "error" and recorder.applied_content is None to confirm that when _forced_rewrite yields empty text, content remains unchanged (not set to ""), exercising the update_memory._forced_rewrite path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@surfsense_backend/app/agents/new_chat/tools/update_memory.py`:
- Around line 192-193: The issue is that the `_forced_rewrite` function can
return an empty string, which leads to silent data loss because it replaces
existing memory with an empty string. To fix this, modify `_forced_rewrite` so
that if `extract_text_content(response.content)` returns an empty string,
`_forced_rewrite` should return None instead, indicating a failed rewrite. This
ensures the caller in `_save_memory` treats empty results as failures and avoids
overwriting memory with empty content.
---
Nitpick comments:
In
`@surfsense_backend/tests/unit/agents/new_chat/test_memory_response_content.py`:
- Around line 1-10: Add an async unit test to verify _save_memory does not wipe
memory when _forced_rewrite yields empty text: create a large_content string >
MEMORY_HARD_LIMIT, mock an LLM class (_EmptyRewriteLLM) whose ainvoke returns a
response whose content is [{"type":"thinking", ...}] so extract_text_content
would produce "" (simulating thinking-only output), implement a recorder stub
with apply/commit/rollback that records applied_content, call
_save_memory(updated_memory=large_content, old_memory=None,
llm=_EmptyRewriteLLM(), apply_fn=recorder.apply, commit_fn=recorder.commit,
rollback_fn=recorder.rollback, label="memory", scope="user") and assert the
returned result["status"] == "error" and recorder.applied_content is None to
confirm that when _forced_rewrite yields empty text, content remains unchanged
(not set to ""), exercising the update_memory._forced_rewrite path.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a2a01eb3-9b14-4327-bb05-13592992e184
📒 Files selected for processing (5)
surfsense_backend/app/agents/new_chat/memory_extraction.pysurfsense_backend/app/agents/new_chat/tools/update_memory.pysurfsense_backend/app/routes/memory_routes.pysurfsense_backend/app/routes/search_spaces_routes.pysurfsense_backend/tests/unit/agents/new_chat/test_memory_response_content.py
- Updated the `_forced_rewrite` function to strip whitespace from the extracted text and added a warning log if the response is empty, preventing potential issues with empty rewrites.
Description
Motivation and Context
FIX #
Screenshots
API Changes
Change Type
Testing Performed
Checklist
High-level PR Summary
This PR refactors memory extraction code by consolidating duplicate text extraction logic into a centralized
extract_text_contentutility function. The changes replace multiple instances of inline conditional logic for handling LLM response content (checking if content is a string or needs conversion) across memory extraction, memory update, and memory editing endpoints with a single reusable utility. Additionally, a validation guard was added to_save_memoryto reject non-string memory payloads early, and comprehensive unit tests were included to verify the text extraction behavior handles various response formats including thinking blocks, markdown text, and plain strings.⏱️ Estimated Review Time: 5-15 minutes
💡 Review Order Suggestion
surfsense_backend/tests/unit/agents/new_chat/test_memory_response_content.pysurfsense_backend/app/agents/new_chat/tools/update_memory.pysurfsense_backend/app/agents/new_chat/memory_extraction.pysurfsense_backend/app/routes/memory_routes.pysurfsense_backend/app/routes/search_spaces_routes.pySummary by CodeRabbit
Bug Fixes
Tests