Repository navigation
[Bug]: add/flush returns 500 every time when an extraction reply quotes code with an unmatched } (everalgo brace-counting JSON extractor) #515
Description
Area
src/everos
What happened?
POST /memory/add (and /memory/flush) returns HTTP 500 INTERNAL_ERROR for some conversations every time it is retried. The episode extractor's LLM reply is valid JSON, but EverOS fails to parse it:
episode_extract_retry error='Unterminated string starting at: line 3 column 14 ...' (x2)
unhandled_exception exception_type=JSONDecodeError
The cause is _extract_json_object in the pinned everalgo packages. It finds the first balanced {...} by counting { and } characters, but it does not skip braces inside JSON string values. When the model writes code into a string (common for coding-agent conversations, e.g. "... closed the callback with `});` ..."), the extra } closes the object early. json.loads then gets a truncated string and raises JSONDecodeError. The failure is determined by the content, so retries never help and the conversation can never be stored.
Expected: a valid JSON reply is parsed regardless of what its string values contain.
Steps to reproduce
Minimal, no server or LLM needed (everalgo-user-memory 0.4.0, as pinned by EverOS 1.4.2):
import json
from everalgo.user_memory.episode import _extract_json_object
reply = '{"title": "Fix", "content": "Closed the handler with `});` and redeployed.", "summary": "Fix."}'
json.loads(reply) # OK, the reply is valid JSON
json.loads(_extract_json_object(reply)) # JSONDecodeError: Unterminated string starting at: line 1 column 29End to end: send /memory/add a conversation in which the assistant pastes JavaScript, so that the model's episode content quotes a snippet like }); with more } than {.
Affected code
The same helper is duplicated in 9 modules. In EverAlgo at the everalgo-user-memory/v0.4.0 tag (the version EverOS 1.4.2 pins):
everalgo-user-memory:user_memory/episode.py:111,atomic_fact.py:154,foresight.py:112,profile.py:233everalgo-agent-memory:agent_memory/case.py:742,profile.py:516,skill.py:325,skill_ops.py:193everalgo-rank:rank/rerank.py:105
The latest stable releases (everalgo-user-memory 0.7.0, everalgo-agent-memory 0.5.1) still have it. EverAlgo main no longer does: the strict LLM-contract rewrite (EverAlgo ae523ec, shipped only in the 0.9.0rc / 0.6.0rc pre-releases) replaced these helpers with model_validate_json. So EverOS stays affected until it moves to a stable everalgo release that includes that rewrite, or until the fix is backported to the pinned line.
Suggested fix for the stable line: read exactly one JSON value from the first { with json.JSONDecoder().raw_decode(text, start) and keep the existing error messages. A backport with tests is ready.
Related: the default LLM timeout is too short for slower endpoints
Separately, in the same incident, about a third of the extraction calls to a slower OpenAI-compatible endpoint (~50 output tokens/s) were cancelled at exactly 60 s. Any episode or atomic-fact reply over ~3,000 tokens could never finish, and the synchronous add/flush returned 500 (LLMError: Request timed out) after the client's retries. Setting EVEROS_LLM__TIMEOUT_SECONDS=180 fixed it. That setting exists (see #333) but is missing from .env.example and the configuration docs, next to the embedding and rerank timeouts that are listed. Suggestion: document it there, and mention that one add can take up to (retries + 1) x timeout, so that reverse-proxy and client timeouts can be sized to match.
Environment
EverOS 1.4.2 (PyPI), Python 3.12, Linux
everalgo-user-memory 0.4.0, everalgo-agent-memory 0.4.0, everalgo-rank 0.4.1, everalgo-core 0.3.0
LLM: OpenAI-compatible gateway
Logs or screenshots
episode_extract_retry error='Unterminated string starting at: line 3 column 14 (char 67)'
episode_extract_retry error='Unterminated string starting at: line 3 column 14 (char 82)'
unhandled_exception exception_type=JSONDecodeError -> HTTP 500 INTERNAL_ERRORA tested backport of the raw_decode fix for all 9 modules (with unit tests) is ready: which maintenance branch of EverAlgo would you like the backport PR against?
Activity