Compare commits

...

1 Commits

Author SHA1 Message Date
f1f76b9a99 fix: extract position dict from CallToolResult.structuredContent
Fix negative cash bug where ContextInjector._current_position never updated.

Root cause: MCP tools return mcp.types.CallToolResult objects, not plain
dicts. The isinstance(result, dict) check always failed, preventing
_current_position from accumulating trades within a session.

This caused all trades to calculate from initial $10,000 position instead
of previous trade's ending position, resulting in negative cash balances
when total purchases exceeded $10,000.

Solution: Extract position dict from CallToolResult.structuredContent field
before validating. Maintains backward compatibility by handling both
CallToolResult objects (production) and plain dicts (unit tests).

Impact:
- Fixes negative cash positions (e.g., -$8,768.68 after 11 trades)
- Enables proper intra-day position tracking
- Validates sufficient cash before each trade based on cumulative position
- Trade tool responses now properly accumulate all holdings

Testing:
- All existing unit tests pass (handle plain dict results)
- Production logs confirm structuredContent extraction works
- Debug logging shows _current_position now updates after each trade
2025-11-07 14:24:48 -05:00

View File

@@ -91,15 +91,25 @@ class ContextInjector:
# Debug: Log result type and structure
print(f"[DEBUG ContextInjector] Trade result type: {type(result)}")
print(f"[DEBUG ContextInjector] Trade result: {result}")
print(f"[DEBUG ContextInjector] isinstance(result, dict): {isinstance(result, dict)}")
# Check if result is a valid position dict (not an error)
if isinstance(result, dict) and "error" not in result and "CASH" in result:
# Extract position dict from MCP result
# MCP tools return CallToolResult objects with structuredContent field
position_dict = None
if hasattr(result, 'structuredContent') and result.structuredContent:
position_dict = result.structuredContent
print(f"[DEBUG ContextInjector] Extracted from structuredContent: {position_dict}")
elif isinstance(result, dict):
position_dict = result
print(f"[DEBUG ContextInjector] Using result as dict: {position_dict}")
# Check if position dict is valid (not an error) and update state
if position_dict and "error" not in position_dict and "CASH" in position_dict:
# Update our tracked position with the new state
self._current_position = result.copy()
self._current_position = position_dict.copy()
print(f"[DEBUG ContextInjector] Updated _current_position: {self._current_position}")
else:
print(f"[DEBUG ContextInjector] Did NOT update _current_position - check failed")
print(f"[DEBUG ContextInjector] position_dict: {position_dict}")
print(f"[DEBUG ContextInjector] _current_position remains: {self._current_position}")
return result