fix: handle chatty LLM responses in JSON parsing#4525
Merged
kartik-mem0 merged 4 commits intomainfrom Mar 26, 2026
Merged
Conversation
Local LLMs (LM Studio, Ollama) often wrap JSON output in conversational
text. The fact retrieval path already has a JSONDecodeError fallback
using extract_json(), but the memory action path did not, causing empty
results. Apply the same fallback pattern to both sync and async paths,
and enhance extract_json() to locate JSON by first '{' / last '}'
boundaries when no code block is found.
Closes #3788
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Local LLMs (LM Studio, Ollama) often wrap JSON output in conversational
text. The fact retrieval path already has a JSONDecodeError fallback
using extract_json(), but the memory action path did not, causing empty
results. Apply the same fallback pattern to both sync and async paths,
and enhance extract_json() to locate JSON by first '{' / last '}'
boundaries when no code block is found.
Closes #3788
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce extract_json_from_chatty_response() instead of modifying the
existing extract_json() which is used by 15+ LLM providers and vector
stores. The new function adds {/} boundary detection for responses
without code blocks, while extract_json remains unchanged to avoid
regressions in unrelated code paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Local LLMs (LM Studio, Ollama) often wrap JSON output in conversational
text. This caused empty results because json.loads failed on the chatty
text and the error was silently swallowed.
Changes:
- Enhanced extract_json() to locate JSON by first '{' / last '}'
boundaries when no code block is found
- Added JSONDecodeError fallback to memory action parsing in both
sync and async paths (was completely missing)
- Fixed fact retrieval paths to pass original response to extract_json
instead of the already-processed output of remove_code_blocks
Closes #3788
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14 tasks
kartik-mem0
approved these changes
Mar 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked Issue
Closes #3788
Description
Local LLMs (LM Studio, Ollama) often wrap JSON output in conversational text (e.g., "Here is the memory extraction: {...} I hope this helps!"). This caused empty results because
json.loadsfailed on the chatty text and the error was silently swallowed.Three changes:
Enhanced
extract_json()to locate JSON by first{/ last}boundaries when no code block is found. This is safe for all existing callers — clean JSON, code-block-wrapped JSON, and arrays all produce identical results since the heuristic only activates when there's no code block AND the text contains{/}.Added
JSONDecodeErrorfallback to memory action parsing in both sync and async_add_to_vector_storepaths. This was completely missing — when the LLM returned chatty text,json.loads(remove_code_blocks(response))failed and the outerexcept Exceptionsilently setnew_memories_with_actions = {}.Fixed fact retrieval paths to pass the original
responsetoextract_json()instead of the already-processed output ofremove_code_blocks(). Previouslyresponse = remove_code_blocks(response)mutated the variable, so the fallback received degraded input.Type of Change
Breaking Changes
N/A
Test Coverage
Tests Added
New test file
tests/test_chatty_llm_parsing.pywith 21 tests across three test classes:TestExtractJson(9 tests) — validatesextract_json()handles:{/}heuristic)TestRemoveCodeBlocks(4 tests) — regression tests confirming:<think>tag handling edge casesTestFallbackChain(8 tests) — validates the fullremove_code_blocks → extract_jsonpattern as used inmain.py:<think>tags with JSON, LM Studio-style responsesAll 58 tests pass (21 new + 25 existing memory + 12 LLM provider tests).
Checklist