Jev 기반 내담자 감정 상태와 응답 일관성 개선
This commit is contained in:
parent
77f8421818
commit
8344bc2ad2
23 changed files with 3384 additions and 25 deletions
104
apps/api/app/test_jev_config.py
Normal file
104
apps/api/app/test_jev_config.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
"""Jev 감정 공급자 설정 계약."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import unittest
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from pydantic import SecretStr, ValidationError
|
||||
|
||||
from .config import Settings
|
||||
from . import main
|
||||
|
||||
|
||||
class JevSettingsTest(unittest.TestCase):
|
||||
def test_defaults_keep_legacy_provider(self) -> None:
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"VIGNETTE_CLIENT_AFFECT_PROVIDER": "legacy",
|
||||
"TYPESAFE_API_KEY": "",
|
||||
"OPENROUTER_API_KEY": "",
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
configured = Settings(_env_file=None)
|
||||
|
||||
self.assertEqual("legacy", configured.client_affect_provider)
|
||||
self.assertEqual("openrouter", configured.jev_provider)
|
||||
self.assertEqual("~typesafe/jev-latest", configured.jev_model)
|
||||
self.assertEqual(1.2, configured.jev_timeout_seconds)
|
||||
self.assertEqual(0.65, configured.jev_min_confidence)
|
||||
|
||||
def test_default_openrouter_jev_requires_its_own_key(self) -> None:
|
||||
with self.assertRaisesRegex(ValidationError, "OPENROUTER_API_KEY"):
|
||||
Settings(
|
||||
_env_file=None,
|
||||
client_affect_provider="jev",
|
||||
typesafe_api_key=SecretStr("typesafe-only-key"),
|
||||
openrouter_api_key=SecretStr(""),
|
||||
)
|
||||
|
||||
def test_explicit_typesafe_jev_requires_typesafe_key(self) -> None:
|
||||
with self.assertRaisesRegex(ValidationError, "TYPESAFE_API_KEY"):
|
||||
Settings(
|
||||
_env_file=None,
|
||||
client_affect_provider="jev",
|
||||
jev_provider="typesafe",
|
||||
openrouter_api_key=SecretStr("openrouter-only-key"),
|
||||
typesafe_api_key=SecretStr(""),
|
||||
)
|
||||
|
||||
def test_jev_environment_aliases_and_limits_apply(self) -> None:
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"VIGNETTE_CLIENT_AFFECT_PROVIDER": "jev",
|
||||
"VIGNETTE_JEV_PROVIDER": "openrouter",
|
||||
"OPENROUTER_API_KEY": "unit-test-openrouter-key",
|
||||
"VIGNETTE_JEV_MODEL": "~typesafe/jev-latest",
|
||||
"VIGNETTE_JEV_TIMEOUT_SECONDS": "0.4",
|
||||
"VIGNETTE_JEV_MIN_CONFIDENCE": "0.8",
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
configured = Settings(_env_file=None)
|
||||
|
||||
self.assertEqual("jev", configured.client_affect_provider)
|
||||
self.assertEqual("openrouter", configured.jev_provider)
|
||||
self.assertEqual(
|
||||
"unit-test-openrouter-key",
|
||||
configured.openrouter_api_key.get_secret_value(),
|
||||
)
|
||||
self.assertEqual(0.4, configured.jev_timeout_seconds)
|
||||
self.assertEqual(0.8, configured.jev_min_confidence)
|
||||
|
||||
def test_timeout_bounds_are_enforced(self) -> None:
|
||||
with self.assertRaises(ValidationError):
|
||||
Settings(_env_file=None, jev_timeout_seconds=0.09)
|
||||
with self.assertRaises(ValidationError):
|
||||
Settings(_env_file=None, jev_timeout_seconds=10.1)
|
||||
|
||||
|
||||
class JevHealthStatusTest(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_health_exposes_configuration_without_claiming_live_readiness(self) -> None:
|
||||
with (
|
||||
patch.object(main, "healthcheck", AsyncMock(return_value=True)),
|
||||
patch.object(
|
||||
main.engine_client,
|
||||
"health_detail",
|
||||
AsyncMock(return_value={"ok": True}),
|
||||
),
|
||||
):
|
||||
response = await main.health()
|
||||
|
||||
self.assertEqual(main.settings.client_affect_provider, response["client_affect_provider"])
|
||||
self.assertEqual(main.settings.jev_model, response["jev"]["model"])
|
||||
self.assertEqual(main.settings.jev_provider, response["jev"]["provider"])
|
||||
self.assertIn("configured", response["jev"])
|
||||
self.assertFalse(response["jev"]["live_verified"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue