Merge pull request #1404 from MemPalace/fix/1155-call-llm-retry-on-json-decode

fix(closet_llm): retry _call_llm on JSONDecodeError (#1155)
This commit is contained in:
Igor Lins e Silva
2026-05-07 17:38:04 -03:00
committed by GitHub
2 changed files with 29 additions and 2 deletions
+3
View File
@@ -169,6 +169,9 @@ def _call_llm(cfg: LLMConfig, source_file: str, wing: str, room: str, content: s
parsed = json.loads(text)
return parsed, payload.get("usage")
except json.JSONDecodeError:
if attempt < 2:
time.sleep(2**attempt)
continue
return None, None
except urllib.error.HTTPError as e:
# 429 / 503 = retry with backoff
+26 -2
View File
@@ -196,10 +196,34 @@ class TestCallLLM:
}
)
with patch("urllib.request.urlopen", side_effect=fake_urlopen):
parsed, usage = _call_llm(cfg, "/tmp/x", "w", "r", "c")
with (
patch("urllib.request.urlopen", side_effect=fake_urlopen),
patch("mempalace.closet_llm.time.sleep"),
):
parsed, _ = _call_llm(cfg, "/tmp/x", "w", "r", "c")
assert parsed is None
def test_retries_on_json_decode_error(self):
cfg = self._make_cfg()
call_count = {"n": 0}
def fake_urlopen(req, timeout=None):
call_count["n"] += 1
return _FakeResp(
{
"choices": [{"message": {"content": "not json at all"}}],
"usage": {"prompt_tokens": 1, "completion_tokens": 1},
}
)
with (
patch("urllib.request.urlopen", side_effect=fake_urlopen),
patch("mempalace.closet_llm.time.sleep"),
):
parsed, _ = _call_llm(cfg, "/tmp/x", "w", "r", "c")
assert parsed is None
assert call_count["n"] == 3
# ── regenerate_closets error paths ───────────────────────────────────────