fix: Fix parsing bug where Anthropic returns nested JSON (#3096)

This commit is contained in:
Matthew Zhou
2025-06-29 11:41:33 -07:00
committed by GitHub
parent 0f5bc65aa2
commit 4848e53530
2 changed files with 15 additions and 11 deletions

View File

@@ -210,17 +210,21 @@ def generate_step_id():
return f"step-{uuid.uuid4()}"
def _safe_load_dict(raw: str) -> dict:
def _safe_load_tool_call_str(tool_call_args_str: str) -> dict:
"""Lenient JSON → dict with fallback to eval on assertion failure."""
if "}{" in raw: # strip accidental parallel calls
raw = raw.split("}{", 1)[0] + "}"
# Temp hack to gracefully handle parallel tool calling attempt, only take first one
if "}{" in tool_call_args_str:
tool_call_args_str = tool_call_args_str.split("}{", 1)[0] + "}"
try:
data = json.loads(raw)
if not isinstance(data, dict):
raise AssertionError
return data
except (json.JSONDecodeError, AssertionError):
return json.loads(raw) if raw else {}
tool_args = json.loads(tool_call_args_str)
if not isinstance(tool_args, dict):
# Load it again - this is due to sometimes Anthropic returning weird json @caren
tool_args = json.loads(tool_args)
except json.JSONDecodeError:
tool_args = {}
return tool_args
def _pop_heartbeat(tool_args: dict) -> bool:

View File

@@ -15,7 +15,7 @@ from letta.agents.helpers import (
_create_letta_response,
_pop_heartbeat,
_prepare_in_context_messages_no_persist_async,
_safe_load_dict,
_safe_load_tool_call_str,
generate_step_id,
)
from letta.constants import DEFAULT_MAX_STEPS, NON_USER_MSG_PREFIX
@@ -944,7 +944,7 @@ class LettaAgent(BaseAgent):
# 1. Parse and validate the tool-call envelope
tool_call_name: str = tool_call.function.name
tool_call_id: str = tool_call.id or f"call_{uuid.uuid4().hex[:8]}"
tool_args = _safe_load_dict(tool_call.function.arguments)
tool_args = _safe_load_tool_call_str(tool_call.function.arguments)
request_heartbeat: bool = _pop_heartbeat(tool_args)
tool_args.pop(INNER_THOUGHTS_KWARG, None)