diff --git a/letta/interfaces/anthropic_streaming_interface.py b/letta/interfaces/anthropic_streaming_interface.py index 56def5e6..0c394287 100644 --- a/letta/interfaces/anthropic_streaming_interface.py +++ b/letta/interfaces/anthropic_streaming_interface.py @@ -106,15 +106,19 @@ class AnthropicStreamingInterface: try: tool_input = json.loads(self.accumulated_tool_call_args) except json.JSONDecodeError as e: - logger.warning( - f"Failed to decode tool call arguments for tool_call_id={self.tool_call_id}, " - f"name={self.tool_call_name}. Raw input: {self.accumulated_tool_call_args!r}. Error: {e}" - ) - raise + # Attempt to use OptimisticJSONParser to handle incomplete/malformed JSON + try: + tool_input = self.json_parser.parse(self.accumulated_tool_call_args) + except: + logger.warning( + f"Failed to decode tool call arguments for tool_call_id={self.tool_call_id}, " + f"name={self.tool_call_name}. Raw input: {self.accumulated_tool_call_args!r}. Error: {e}" + ) + raise e if "id" in tool_input and tool_input["id"].startswith("toolu_") and "function" in tool_input: arguments = str(json.dumps(tool_input["function"]["arguments"], indent=2)) else: - arguments = self.accumulated_tool_call_args + arguments = str(json.dumps(tool_input, indent=2)) return ToolCall(id=self.tool_call_id, function=FunctionCall(arguments=arguments, name=self.tool_call_name)) def _check_inner_thoughts_complete(self, combined_args: str) -> bool: diff --git a/letta/server/rest_api/json_parser.py b/letta/server/rest_api/json_parser.py index 0a05bba4..610b9fa4 100644 --- a/letta/server/rest_api/json_parser.py +++ b/letta/server/rest_api/json_parser.py @@ -63,6 +63,8 @@ class OptimisticJSONParser(JSONParser): '"': self._parse_string, "t": self._parse_true, "f": self._parse_false, + "T": self._parse_true, + "F": self._parse_false, "n": self._parse_null, } # Register number parser for digits and signs