diff --git a/rdagent/core/utils.py b/rdagent/core/utils.py index dd6b8e751..ab61b68e9 100644 --- a/rdagent/core/utils.py +++ b/rdagent/core/utils.py @@ -56,6 +56,14 @@ def __reduce__(self) -> NoReturn: def parse_json(response: str) -> Any: + import re + + # Some LLM providers (e.g. Volcengine) return Python-style booleans + # (True/False) instead of JSON-standard (true/false). Normalize them + # before parsing to avoid JSONDecodeError. + response = re.sub(r"\bTrue\b", "true", response) + response = re.sub(r"\bFalse\b", "false", response) + response = re.sub(r"\bNone\b", "null", response) try: return json.loads(response) except json.decoder.JSONDecodeError: diff --git a/rdagent/log/ui/app.py b/rdagent/log/ui/app.py index 881b32fb6..fe4c2fa1a 100644 --- a/rdagent/log/ui/app.py +++ b/rdagent/log/ui/app.py @@ -229,6 +229,9 @@ def get_msgs_until(end_func: Callable[[Message], bool] = lambda _: True): state.hypotheses[state.lround] = msg.content elif "evolving code" in tags: msg.content = [i for i in msg.content if i] + # Also store under the short key so downstream consumers + # that read state.msgs[round]["evolving code"] can find it. + state.msgs[state.lround]["evolving code"].append(msg) elif "evolving feedback" in tags: total_len = len(msg.content) none_num = total_len - len(msg.content) diff --git a/rdagent/log/utils/__init__.py b/rdagent/log/utils/__init__.py index 44edb67e6..89518ba85 100644 --- a/rdagent/log/utils/__init__.py +++ b/rdagent/log/utils/__init__.py @@ -99,7 +99,12 @@ def extract_evoid(tag: str) -> str | None: def extract_json(log_content: str) -> dict | None: match = re.search(r"\{.*\}", log_content, re.DOTALL) if match: - return cast(dict, json.loads(match.group(0))) + raw = match.group(0) + # Normalize Python-style booleans/null that some LLM providers return + raw = re.sub(r"\bTrue\b", "true", raw) + raw = re.sub(r"\bFalse\b", "false", raw) + raw = re.sub(r"\bNone\b", "null", raw) + return cast(dict, json.loads(raw)) return None