diff --git a/letta/agents/helpers.py b/letta/agents/helpers.py index 96011147..b49303e6 100644 --- a/letta/agents/helpers.py +++ b/letta/agents/helpers.py @@ -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: diff --git a/letta/agents/letta_agent.py b/letta/agents/letta_agent.py index 8a310747..cdf2c52a 100644 --- a/letta/agents/letta_agent.py +++ b/letta/agents/letta_agent.py @@ -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)