import json import httpx import pytest from ai_platform.infrastructure.aihub import AiHubClient, AiHubError from ai_platform.infrastructure.scoring import _scoring_system_prompt, _scoring_user_prompt VKEY = "request-only-vkey-test-secret" def completion(content: str) -> httpx.Response: return httpx.Response( 200, json={"choices": [{"message": {"content": content}}]}, ) @pytest.mark.asyncio async def test_two_pass_adapter_uses_same_model_timeout_and_vkey_without_putting_key_in_prompts(): requests: list[httpx.Request] = [] def handler(request: httpx.Request) -> httpx.Response: requests.append(request) body = json.loads(request.content) assert body["model"] == "openai/gpt-4o-mini" assert body["stream"] is False assert body["response_format"] == {"type": "json_object"} assert request.headers["authorization"] == f"Bearer {VKEY}" assert request.extensions["timeout"]["read"] == 7 return completion( '{"items":[{"signal":"ý định","detail":"Hỏi điều kiện đăng ký","source":"message-1"}]}' if len(requests) == 1 else '{"score":81,"confidence":0.91,"reasoning":"Quan tâm rõ ràng"}' ) http_client = httpx.AsyncClient(transport=httpx.MockTransport(handler)) client = AiHubClient("https://aihub.test", http_client) snapshot = { "lead_profile": {"name": "Example", "custom_fields": {"region": "north"}}, "conversations": [ { "messages": [ { "message_id": "message-1", "sender_type": "contact", "content": "Please send me requirements.", } ] } ], } try: evidence = await client.extract_evidence( model="openai/gpt-4o-mini", snapshot=snapshot, vkey=VKEY, timeout=7 ) score = await client.score( model="openai/gpt-4o-mini", system_prompt=_scoring_system_prompt("Đánh giá theo hồ sơ AI đã cấu hình."), user_prompt=_scoring_user_prompt(snapshot, evidence.model_dump(mode="json")), vkey=VKEY, timeout=7, ) finally: await client.aclose() assert score.score == 81 assert score.confidence == 0.91 assert len(requests) == 2 for request in requests: body = json.loads(request.content) prompt = " ".join(message["content"] for message in body["messages"]) assert VKEY not in prompt assert '"points"' not in prompt assert '"rule_weight"' not in prompt assert '"ai_weight"' not in prompt assert "message-1" in json.loads(requests[0].content)["messages"][1]["content"] assert "EVIDENCE" in json.loads(requests[1].content)["messages"][1]["content"] @pytest.mark.asyncio async def test_aihub_errors_have_stable_codes_and_do_not_expose_response_or_request_secret(): def handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(429, text=f"private response mentions {VKEY}") client = AiHubClient( "https://aihub.test", httpx.AsyncClient(transport=httpx.MockTransport(handler)) ) try: with pytest.raises(AiHubError) as error: await client.extract_evidence(model="openai/gpt-4o-mini", snapshot={}, vkey=VKEY) finally: await client.aclose() assert error.value.error_code == "aihub_http_error" assert VKEY not in str(error.value) assert "private response" not in str(error.value) @pytest.mark.asyncio async def test_aihub_rejects_response_that_echoes_request_vkey(): client = AiHubClient( "https://aihub.test", httpx.AsyncClient( transport=httpx.MockTransport( lambda _request: completion( json.dumps({"items": [{"signal": "s", "detail": VKEY, "source": "m"}]}) ) ) ), ) try: with pytest.raises(AiHubError) as error: await client.extract_evidence(model="openai/gpt-4o-mini", snapshot={}, vkey=VKEY) finally: await client.aclose() assert error.value.error_code == "aihub_invalid_response" assert VKEY not in str(error.value)