155 lines
5.3 KiB
Markdown
155 lines
5.3 KiB
Markdown
# Tool Call Fix Summary
|
|
|
|
## Problem Description
|
|
|
|
The TradingAgents system was experiencing a critical error during execution:
|
|
|
|
```
|
|
Error code: 400 - {'error': {'message': "An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id'. The following tool_call_ids did not have response messages: call_Ai2XeBuqwYn44GC5ogLZxzsG", 'type': 'invalid_request_error', 'param': 'messages', 'code': None}}
|
|
```
|
|
|
|
## Root Cause Analysis
|
|
|
|
The error occurred in the Market Analyst when it made multiple tool calls, but one of them failed:
|
|
|
|
1. **Market Analyst** made 8 tool calls including `get_stockstats_indicators_report_online` with `macd_signal` indicator
|
|
2. **Tool execution failed** because `macd_signal` is not supported (only `macds` is available)
|
|
3. **No ToolMessage created** for the failed tool call
|
|
4. **OpenAI API rejected** the conversation because tool call `call_Ai2XeBuqwYn44GC5ogLZxzsG` had no response
|
|
|
|
From the logs:
|
|
```
|
|
ERROR:tradingagents.graph.setup:❌ market tools: Error executing get_stockstats_indicators_report_online: Indicator macd_signal is not supported. Please choose from: ['close_50_sma', 'close_200_sma', 'close_10_ema', 'macd', 'macds', 'macdh', 'rsi', 'boll', 'boll_ub', 'boll_lb', 'atr', 'vwma', 'mfi']
|
|
```
|
|
|
|
## Solution Implemented
|
|
|
|
Modified `backend/tradingagents/graph/setup.py` in the `_wrap_tool_node_for_channel` method to ensure **every tool call gets a ToolMessage response**, even when errors occur.
|
|
|
|
### Changes Made
|
|
|
|
1. **Failed Tool Execution**: Create error ToolMessage
|
|
```python
|
|
except Exception as e:
|
|
logger.error(f"❌ {analyst_type} tools: Error executing {tool_name}: {str(e)}")
|
|
# Create an error ToolMessage to maintain conversation flow
|
|
error_message = ToolMessage(
|
|
content=f"Error executing {tool_name}: {str(e)}",
|
|
tool_call_id=tool_call_id
|
|
)
|
|
updated_messages.append(error_message)
|
|
logger.info(f"🔧 {analyst_type} tools: ✅ Added error ToolMessage for {tool_name}")
|
|
tools_executed += 1
|
|
```
|
|
|
|
2. **Skipped Tool Calls**: Create skip ToolMessage
|
|
```python
|
|
if not can_call:
|
|
logger.warning(f"🔧 {analyst_type} tools: SKIPPING - {reason}")
|
|
# Create a skip ToolMessage to maintain conversation flow
|
|
skip_message = ToolMessage(
|
|
content=f"Tool call skipped: {reason}",
|
|
tool_call_id=tool_call_id
|
|
)
|
|
updated_messages.append(skip_message)
|
|
logger.info(f"🔧 {analyst_type} tools: ✅ Added skip ToolMessage for {tool_name}")
|
|
tools_executed += 1
|
|
continue
|
|
```
|
|
|
|
3. **Unknown Tool Call Format**: Create error ToolMessage
|
|
```python
|
|
else:
|
|
logger.error(f"❌ {analyst_type} tools: Unknown tool call format")
|
|
# Create an error ToolMessage even for unknown format
|
|
unknown_tool_call_id = f'unknown_format_{i}'
|
|
error_message = ToolMessage(
|
|
content=f"Error: Unknown tool call format at index {i}",
|
|
tool_call_id=unknown_tool_call_id
|
|
)
|
|
updated_messages.append(error_message)
|
|
logger.info(f"🔧 {analyst_type} tools: ✅ Added error ToolMessage for unknown format")
|
|
tools_executed += 1
|
|
continue
|
|
```
|
|
|
|
4. **Empty Tool Name**: Create error ToolMessage
|
|
```python
|
|
if not tool_name:
|
|
logger.error(f"❌ {analyst_type} tools: Empty tool name")
|
|
# Create an error ToolMessage for empty tool name
|
|
error_message = ToolMessage(
|
|
content=f"Error: Empty tool name at index {i}",
|
|
tool_call_id=tool_call_id
|
|
)
|
|
updated_messages.append(error_message)
|
|
logger.info(f"🔧 {analyst_type} tools: ✅ Added error ToolMessage for empty tool name")
|
|
tools_executed += 1
|
|
continue
|
|
```
|
|
|
|
5. **Improved Tool Call ID Handling**: Ensure unique IDs
|
|
```python
|
|
tool_call_id = tool_call.get('id', f'unknown_{i}') # For dict format
|
|
tool_call_id = tool_call.id if hasattr(tool_call, 'id') else f'unknown_{i}' # For object format
|
|
```
|
|
|
|
## Testing Results
|
|
|
|
### Test 1: Simple Fix Verification
|
|
```bash
|
|
python test_simple_fix.py
|
|
```
|
|
**Result**: ✅ PASS - No tool call errors detected in first 15 chunks
|
|
|
|
### Test 2: Extended Analysis Test
|
|
```bash
|
|
python test_extended_fix.py
|
|
```
|
|
**Result**: ✅ PASS - No tool call errors detected during 90-second execution
|
|
|
|
### Test 3: API Health Check
|
|
```bash
|
|
curl http://localhost:8000/health
|
|
```
|
|
**Result**: ✅ {"status":"healthy"}
|
|
|
|
## Impact
|
|
|
|
- **✅ Fixed**: Critical OpenAI API error that was breaking the analysis flow
|
|
- **✅ Improved**: Error handling and logging for tool execution
|
|
- **✅ Enhanced**: Robustness of the conversation flow with OpenAI API
|
|
- **✅ Maintained**: All existing functionality while adding error resilience
|
|
|
|
## Verification Commands
|
|
|
|
To verify the fix is working:
|
|
|
|
1. Start the API server:
|
|
```bash
|
|
cd backend
|
|
uvicorn api:app --host 0.0.0.0 --port 8000
|
|
```
|
|
|
|
2. Run the verification test:
|
|
```bash
|
|
python test_simple_fix.py
|
|
```
|
|
|
|
3. Test with real endpoint:
|
|
```bash
|
|
curl -X GET "http://localhost:8000/analyze/stream?ticker=AAPL"
|
|
```
|
|
|
|
The system should now run without the tool call error and handle failed tool executions gracefully.
|
|
|
|
## Files Modified
|
|
|
|
- `backend/tradingagents/graph/setup.py` - Main fix implementation
|
|
- `backend/test_simple_fix.py` - Simple verification test (created)
|
|
- `backend/test_extended_fix.py` - Extended verification test (created)
|
|
- `backend/test_tool_call_fix.py` - Comprehensive test script (created)
|
|
|
|
## Status
|
|
|
|
🎉 **RESOLVED** - Tool call error fix successfully implemented and tested. |