mirror of
https://github.com/Xe138/AI-Trader.git
synced 2026-04-15 14:27:25 -04:00
fix: handle invalid_tool_calls args normalization for DeepSeek
Extended ToolCallArgsParsingWrapper to handle both tool_calls and invalid_tool_calls args formatting inconsistencies from DeepSeek: - tool_calls.args: string -> dict (for successful calls) - invalid_tool_calls.args: dict -> string (for failed calls) The wrapper now normalizes both types before AIMessage construction, preventing Pydantic validation errors in both success and error cases. Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [0.4.1] - 2025-11-05
|
## [0.4.1] - 2025-11-05
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed Pydantic validation error for tool_calls when using DeepSeek and other AI providers that return `args` as JSON strings instead of dictionaries. Added `ToolCallArgsParsingWrapper` that monkey-patches ChatOpenAI's `_create_chat_result` method to parse string arguments before AIMessage construction.
|
- Fixed Pydantic validation errors for both `tool_calls` and `invalid_tool_calls` when using DeepSeek and other AI providers:
|
||||||
|
- `tool_calls.args`: Converts JSON strings to dictionaries (for successful tool calls)
|
||||||
|
- `invalid_tool_calls.args`: Converts dictionaries to JSON strings (for failed tool calls)
|
||||||
|
- Added `ToolCallArgsParsingWrapper` that monkey-patches ChatOpenAI's `_create_chat_result` method to normalize arguments before AIMessage construction.
|
||||||
|
|
||||||
## [0.4.0] - 2025-11-05
|
## [0.4.0] - 2025-11-05
|
||||||
|
|
||||||
|
|||||||
@@ -50,19 +50,36 @@ class ToolCallArgsParsingWrapper:
|
|||||||
|
|
||||||
if 'choices' in response_dict:
|
if 'choices' in response_dict:
|
||||||
for choice in response_dict['choices']:
|
for choice in response_dict['choices']:
|
||||||
if 'message' in choice and 'tool_calls' in choice['message']:
|
if 'message' not in choice:
|
||||||
tool_calls = choice['message']['tool_calls']
|
continue
|
||||||
if tool_calls:
|
|
||||||
for tool_call in tool_calls:
|
message = choice['message']
|
||||||
if 'function' in tool_call and 'arguments' in tool_call['function']:
|
|
||||||
args = tool_call['function']['arguments']
|
# Fix regular tool_calls: string args -> dict
|
||||||
# Parse string arguments to dict
|
if 'tool_calls' in message and message['tool_calls']:
|
||||||
if isinstance(args, str):
|
for tool_call in message['tool_calls']:
|
||||||
try:
|
if 'function' in tool_call and 'arguments' in tool_call['function']:
|
||||||
tool_call['function']['arguments'] = json.loads(args)
|
args = tool_call['function']['arguments']
|
||||||
except json.JSONDecodeError:
|
# Parse string arguments to dict
|
||||||
# Keep as string if parsing fails
|
if isinstance(args, str):
|
||||||
pass
|
try:
|
||||||
|
tool_call['function']['arguments'] = json.loads(args)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
# Keep as string if parsing fails
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fix invalid_tool_calls: dict args -> string
|
||||||
|
if 'invalid_tool_calls' in message and message['invalid_tool_calls']:
|
||||||
|
for invalid_call in message['invalid_tool_calls']:
|
||||||
|
if 'args' in invalid_call:
|
||||||
|
args = invalid_call['args']
|
||||||
|
# Convert dict arguments to JSON string
|
||||||
|
if isinstance(args, dict):
|
||||||
|
try:
|
||||||
|
invalid_call['args'] = json.dumps(args)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
# Keep as-is if serialization fails
|
||||||
|
pass
|
||||||
|
|
||||||
# Call original method with fixed response
|
# Call original method with fixed response
|
||||||
return original_create_chat_result(response_dict, generation_info)
|
return original_create_chat_result(response_dict, generation_info)
|
||||||
|
|||||||
Reference in New Issue
Block a user