fix: prompt_override 경로 _total_decisions 미카운트, 완료 로그 추가, 테스트 보완
Some checks failed
CI / test (pull_request) Has been cancelled

리뷰 지적 사항 반영:
- _total_decisions 카운트 제거 (플레이북 생성은 거래 결정이 아님 → 메트릭 왜곡 방지)
- "Gemini raw response received" INFO 로그 추가 (완료 추적 가능)
- test_prompt_override_takes_priority_over_optimization 신규 추가
  (enable_optimization=True 상태에서도 prompt_override 우선됨을 검증)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
agentson
2026-02-25 01:54:55 +09:00
parent 1c7a17320c
commit d31a61cd0b
2 changed files with 34 additions and 1 deletions

View File

@@ -445,7 +445,10 @@ class GeminiClient:
# not a parsed TradeDecision. Skip parse_response to avoid spurious # not a parsed TradeDecision. Skip parse_response to avoid spurious
# "Missing fields" warnings and return the raw response directly. (#247) # "Missing fields" warnings and return the raw response directly. (#247)
if "prompt_override" in market_data: if "prompt_override" in market_data:
self._total_decisions += 1 logger.info(
"Gemini raw response received (prompt_override, tokens=%d)", token_count
)
# Not a trade decision — don't inflate _total_decisions metrics
return TradeDecision( return TradeDecision(
action="HOLD", confidence=0, rationale=raw, token_count=token_count action="HOLD", confidence=0, rationale=raw, token_count=token_count
) )

View File

@@ -360,6 +360,36 @@ class TestPromptOverride:
# Raw playbook JSON preserved in rationale # Raw playbook JSON preserved in rationale
assert decision.rationale == playbook_json assert decision.rationale == playbook_json
@pytest.mark.asyncio
async def test_prompt_override_takes_priority_over_optimization(self, settings):
"""prompt_override must win over enable_optimization=True."""
client = GeminiClient(settings)
client._enable_optimization = True
custom_prompt = "Explicit playbook prompt"
mock_response = MagicMock()
mock_response.text = '{"market_outlook": "neutral", "stocks": []}'
with patch.object(
client._client.aio.models,
"generate_content",
new_callable=AsyncMock,
return_value=mock_response,
) as mock_generate:
market_data = {
"stock_code": "PLANNER",
"current_price": 0,
"prompt_override": custom_prompt,
}
await client.decide(market_data)
actual_prompt = mock_generate.call_args[1].get(
"contents", mock_generate.call_args[0][1] if len(mock_generate.call_args[0]) > 1 else None
)
# The custom prompt must be used, not the compressed prompt
assert actual_prompt == custom_prompt
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_without_prompt_override_uses_build_prompt(self, settings): async def test_without_prompt_override_uses_build_prompt(self, settings):
"""Without prompt_override, decide() should use build_prompt as before.""" """Without prompt_override, decide() should use build_prompt as before."""