|
|
@ -2253,17 +2253,31 @@ class BaseTool(BaseModel):
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
# Convert string to dict if needed
|
|
|
|
# Convert string to dict if needed
|
|
|
|
if isinstance(api_response, str):
|
|
|
|
if isinstance(api_response, str):
|
|
|
|
|
|
|
|
# Handle empty or whitespace-only strings
|
|
|
|
|
|
|
|
api_response = api_response.strip()
|
|
|
|
|
|
|
|
if not api_response:
|
|
|
|
|
|
|
|
self._log_if_verbose(
|
|
|
|
|
|
|
|
"warning",
|
|
|
|
|
|
|
|
"Empty API response string received, returning empty list"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
api_response = json.loads(api_response)
|
|
|
|
api_response = json.loads(api_response)
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
raise ToolValidationError(
|
|
|
|
self._log_if_verbose(
|
|
|
|
f"Invalid JSON in API response: {e}"
|
|
|
|
"error",
|
|
|
|
) from e
|
|
|
|
f"Failed to parse JSON from API response: {e}. Response: '{api_response[:100]}...'"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
# If JSON parsing fails, try to continue without function calls
|
|
|
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
if not isinstance(api_response, dict):
|
|
|
|
if not isinstance(api_response, dict):
|
|
|
|
raise ToolValidationError(
|
|
|
|
self._log_if_verbose(
|
|
|
|
"API response must be a dictionary, JSON string, BaseModel, or list of tool calls"
|
|
|
|
"warning",
|
|
|
|
|
|
|
|
f"API response is not a dictionary (type: {type(api_response)}), returning empty list"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
# Extract function calls from dictionary response
|
|
|
|
# Extract function calls from dictionary response
|
|
|
|
function_calls = (
|
|
|
|
function_calls = (
|
|
|
@ -2387,11 +2401,15 @@ class BaseTool(BaseModel):
|
|
|
|
if name:
|
|
|
|
if name:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
# Parse arguments JSON string
|
|
|
|
# Parse arguments JSON string
|
|
|
|
arguments = (
|
|
|
|
if isinstance(arguments_str, str):
|
|
|
|
json.loads(arguments_str)
|
|
|
|
# Handle empty or whitespace-only arguments
|
|
|
|
if isinstance(arguments_str, str)
|
|
|
|
arguments_str = arguments_str.strip()
|
|
|
|
else arguments_str
|
|
|
|
if not arguments_str:
|
|
|
|
)
|
|
|
|
arguments = {}
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
arguments = json.loads(arguments_str)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
arguments = arguments_str if arguments_str is not None else {}
|
|
|
|
|
|
|
|
|
|
|
|
function_calls.append(
|
|
|
|
function_calls.append(
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -2404,7 +2422,16 @@ class BaseTool(BaseModel):
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
self._log_if_verbose(
|
|
|
|
self._log_if_verbose(
|
|
|
|
"error",
|
|
|
|
"error",
|
|
|
|
f"Failed to parse arguments for {name}: {e}",
|
|
|
|
f"Failed to parse arguments for {name}: {e}. Using empty dict instead.",
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
# Use empty dict as fallback
|
|
|
|
|
|
|
|
function_calls.append(
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"name": name,
|
|
|
|
|
|
|
|
"arguments": {},
|
|
|
|
|
|
|
|
"id": response.get("id"),
|
|
|
|
|
|
|
|
"type": "openai",
|
|
|
|
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Check for choices[].message.tool_calls format
|
|
|
|
# Check for choices[].message.tool_calls format
|
|
|
@ -2885,12 +2912,15 @@ class BaseTool(BaseModel):
|
|
|
|
|
|
|
|
|
|
|
|
if name:
|
|
|
|
if name:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
# Parse arguments JSON string
|
|
|
|
# Parse arguments JSON string with better error handling
|
|
|
|
arguments = (
|
|
|
|
if isinstance(arguments_str, str):
|
|
|
|
json.loads(arguments_str)
|
|
|
|
arguments_str = arguments_str.strip()
|
|
|
|
if isinstance(arguments_str, str)
|
|
|
|
if not arguments_str:
|
|
|
|
else arguments_str
|
|
|
|
arguments = {}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
|
|
|
|
arguments = json.loads(arguments_str)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
arguments = arguments_str if arguments_str is not None else {}
|
|
|
|
|
|
|
|
|
|
|
|
function_calls.append(
|
|
|
|
function_calls.append(
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -2905,7 +2935,18 @@ class BaseTool(BaseModel):
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
self._log_if_verbose(
|
|
|
|
self._log_if_verbose(
|
|
|
|
"error",
|
|
|
|
"error",
|
|
|
|
f"Failed to parse arguments for {name}: {e}",
|
|
|
|
f"Failed to parse arguments for {name}: {e}. Using empty dict instead.",
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
# Use empty dict as fallback
|
|
|
|
|
|
|
|
function_calls.append(
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"name": name,
|
|
|
|
|
|
|
|
"arguments": {},
|
|
|
|
|
|
|
|
"id": getattr(
|
|
|
|
|
|
|
|
tool_call, "id", None
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
"type": "openai",
|
|
|
|
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Handle dictionary representations of tool calls
|
|
|
|
# Handle dictionary representations of tool calls
|
|
|
|