fix: prompt_override 경로 _total_decisions 미카운트, 완료 로그 추가, 테스트 보완
Some checks failed
CI / test (pull_request) Has been cancelled
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:
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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."""
|
||||||
|
|||||||
Reference in New Issue
Block a user