diff --git a/src/brain/gemini_client.py b/src/brain/gemini_client.py index 2a11803..d6a3f2b 100644 --- a/src/brain/gemini_client.py +++ b/src/brain/gemini_client.py @@ -346,8 +346,10 @@ class GeminiClient: # Validate required fields if not all(k in data for k in ("action", "confidence", "rationale")): logger.warning("Missing fields in Gemini response — defaulting to HOLD") + # Preserve raw text in rationale so prompt_override callers (e.g. pre_market_planner) + # can extract their own JSON format from decision.rationale (#245) return TradeDecision( - action="HOLD", confidence=0, rationale="Missing required fields" + action="HOLD", confidence=0, rationale=raw ) action = str(data["action"]).upper() diff --git a/tests/test_brain.py b/tests/test_brain.py index 42eb49a..1103d6e 100644 --- a/tests/test_brain.py +++ b/tests/test_brain.py @@ -93,9 +93,21 @@ class TestMalformedJsonHandling: def test_json_with_missing_fields_returns_hold(self, settings): client = GeminiClient(settings) - decision = client.parse_response('{"action": "BUY"}') + raw = '{"action": "BUY"}' + decision = client.parse_response(raw) assert decision.action == "HOLD" assert decision.confidence == 0 + # rationale preserves raw so prompt_override callers (e.g. pre_market_planner) + # can extract non-TradeDecision JSON from decision.rationale (#245) + assert decision.rationale == raw + + def test_non_trade_decision_json_preserves_raw_in_rationale(self, settings): + """Playbook JSON (no action/confidence/rationale) must be preserved for planner.""" + client = GeminiClient(settings) + playbook_json = '{"market_outlook": "neutral", "stocks": []}' + decision = client.parse_response(playbook_json) + assert decision.action == "HOLD" + assert decision.rationale == playbook_json def test_json_with_invalid_action_returns_hold(self, settings): client = GeminiClient(settings)