chore: finish renaming UserConfiguration

This commit is contained in:
Abhishek Kumar 2026-06-09 16:30:03 +05:30
parent cdbd06c8d9
commit 91ac460799
16 changed files with 62 additions and 62 deletions

View file

@ -19,7 +19,7 @@ from api.db.models import (
WorkflowRunModel,
)
from api.enums import OrganizationConfigurationKey
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
class OrganizationUsageClient(BaseDBClient):
@ -473,7 +473,7 @@ class OrganizationUsageClient(BaseDBClient):
)
config_obj = config_result.scalar_one_or_none()
if config_obj and config_obj.configuration:
user_config = UserConfiguration.model_validate(
user_config = EffectiveAIModelConfiguration.model_validate(
config_obj.configuration
)
if user_config.timezone and user_timezone == "UTC":

View file

@ -8,7 +8,7 @@ from sqlalchemy.future import select
from api.db.base_client import BaseDBClient
from api.db.models import UserConfigurationModel, UserModel
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
class UserClient(BaseDBClient):
@ -65,7 +65,9 @@ class UserClient(BaseDBClient):
)
return result.scalars().first()
async def get_user_configurations(self, user_id: int) -> UserConfiguration:
async def get_user_configurations(
self, user_id: int
) -> EffectiveAIModelConfiguration:
async with self.async_session() as session:
result = await session.execute(
select(UserConfigurationModel).where(
@ -74,10 +76,10 @@ class UserClient(BaseDBClient):
)
configuration_obj = result.scalars().first()
if not configuration_obj:
return UserConfiguration()
return EffectiveAIModelConfiguration()
try:
return UserConfiguration.model_validate(
return EffectiveAIModelConfiguration.model_validate(
{
**configuration_obj.configuration,
"last_validated_at": configuration_obj.last_validated_at,
@ -90,11 +92,11 @@ class UserClient(BaseDBClient):
f"Failed to validate user configuration for user {user_id}: {e}. "
"Returning default configuration."
)
return UserConfiguration()
return EffectiveAIModelConfiguration()
async def update_user_configuration(
self, user_id: int, configuration: UserConfiguration
) -> UserConfiguration:
self, user_id: int, configuration: EffectiveAIModelConfiguration
) -> EffectiveAIModelConfiguration:
async with self.async_session() as session:
result = await session.execute(
select(UserConfigurationModel).where(
@ -115,7 +117,9 @@ class UserClient(BaseDBClient):
await session.rollback()
raise e
await session.refresh(configuration_obj)
return UserConfiguration.model_validate(configuration_obj.configuration)
return EffectiveAIModelConfiguration.model_validate(
configuration_obj.configuration
)
async def update_user_configuration_last_validated_at(self, user_id: int) -> None:
async with self.async_session() as session:

View file

@ -31,7 +31,3 @@ class EffectiveAIModelConfiguration(BaseModel):
if isinstance(realtime, dict) and not realtime.get("api_key"):
data.pop("realtime", None)
return data
# Backward-compatible alias for legacy persistence and existing call sites.
UserConfiguration = EffectiveAIModelConfiguration

View file

@ -9,7 +9,7 @@ from api.constants import AUTH_PROVIDER, DOGRAH_MPS_SECRET_KEY, MPS_API_URL
from api.db import db_client
from api.db.models import UserModel
from api.enums import PostHogEvent
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.auth.stack_auth import stackauth
from api.services.configuration.registry import ServiceProviders
from api.services.posthog_client import capture_event
@ -213,7 +213,7 @@ async def _handle_api_key_auth(api_key: str) -> UserModel:
async def create_user_configuration_with_mps_key(
user_id: int, organization_id: int, user_provider_id: str
) -> Optional[UserConfiguration]:
) -> Optional[EffectiveAIModelConfiguration]:
"""Create user configuration using MPS service key.
Args:
@ -222,7 +222,7 @@ async def create_user_configuration_with_mps_key(
user_provider_id: The user's provider ID (for created_by field)
Returns:
UserConfiguration with MPS-provided API keys or None if failed
EffectiveAIModelConfiguration with MPS-provided API keys or None if failed
"""
async with httpx.AsyncClient() as client:
@ -285,7 +285,7 @@ async def create_user_configuration_with_mps_key(
"model": "default",
},
}
user_config = UserConfiguration(**configuration)
user_config = EffectiveAIModelConfiguration(**configuration)
return user_config
else:
logger.warning(

View file

@ -9,7 +9,7 @@ from groq import Groq
# except ImportError:
# Neuphonic = None
from api.schemas.user_configuration import (
UserConfiguration,
EffectiveAIModelConfiguration,
)
from api.services.configuration.registry import ServiceConfig, ServiceProviders
from api.services.mps_service_key_client import mps_service_key_client
@ -64,7 +64,7 @@ class UserConfigurationValidator:
async def validate(
self,
configuration: UserConfiguration,
configuration: EffectiveAIModelConfiguration,
organization_id: Optional[int] = None,
created_by: Optional[str] = None,
) -> APIKeyStatusResponse:

View file

@ -12,7 +12,7 @@ The rules are simple:
import copy
from typing import Any, Dict, Optional
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.registry import ServiceConfig
from api.services.integrations import get_node_secret_fields
@ -31,7 +31,7 @@ def contains_masked_key(value: str | list[str] | None) -> bool:
return any(MASK_MARKER in k for k in keys)
def check_for_masked_keys(config: "UserConfiguration") -> None:
def check_for_masked_keys(config: "EffectiveAIModelConfiguration") -> None:
"""Raise ValueError if any service in *config* still has a masked secret."""
for field in ("llm", "tts", "stt", "embeddings", "realtime"):
service = getattr(config, field, None)
@ -111,7 +111,7 @@ def resolve_masked_api_keys(
# ---------------------------------------------------------------------------
# High-level helpers for UserConfiguration objects
# High-level helpers for EffectiveAIModelConfiguration objects
# ---------------------------------------------------------------------------
@ -129,7 +129,7 @@ def _mask_service(service_cfg: Optional[ServiceConfig]) -> Optional[Dict[str, An
return data
def mask_user_config(config: UserConfiguration) -> Dict[str, Any]:
def mask_user_config(config: EffectiveAIModelConfiguration) -> Dict[str, Any]:
"""Return a JSON-serialisable dict of *config* with every api_key masked."""
return {

View file

@ -7,7 +7,7 @@ stored, while honouring masked API keys.
import copy
from typing import Dict
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.masking import (
MODEL_OVERRIDE_FIELDS,
SERVICE_SECRET_FIELDS,
@ -66,9 +66,9 @@ def _merge_service_secret_fields(
def merge_user_configurations(
existing: UserConfiguration, incoming_partial: Dict[str, dict]
) -> UserConfiguration:
"""Merge *incoming_partial* onto *existing* and return a new UserConfiguration.
existing: EffectiveAIModelConfiguration, incoming_partial: Dict[str, dict]
) -> EffectiveAIModelConfiguration:
"""Merge *incoming_partial* onto *existing* and return a new EffectiveAIModelConfiguration.
*incoming_partial* is the body of the PUT request (already `model_dump()`ed or
extracted via Pydantic `model_dump`).
@ -113,7 +113,7 @@ def merge_user_configurations(
if "timezone" in incoming_partial:
merged["timezone"] = incoming_partial["timezone"]
return UserConfiguration.model_validate(merged)
return EffectiveAIModelConfiguration.model_validate(merged)
def merge_workflow_configuration_secrets(

View file

@ -4,13 +4,13 @@ from __future__ import annotations
import copy
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.registry import (
REGISTRY,
ServiceType,
)
# Maps override key → (UserConfiguration field, ServiceType for registry lookup)
# Maps override key → (EffectiveAIModelConfiguration field, ServiceType for registry lookup)
_SECTION_MAP: dict[str, ServiceType] = {
"llm": ServiceType.LLM,
"tts": ServiceType.TTS,
@ -36,7 +36,7 @@ _SECRET_FIELDS = ("api_key", "credentials", "aws_access_key", "aws_secret_key")
def enrich_overrides_with_api_keys(
model_overrides: dict,
user_config: UserConfiguration,
user_config: EffectiveAIModelConfiguration,
) -> dict:
"""Copy API keys from the global config into model_overrides where missing.
@ -74,9 +74,9 @@ def enrich_overrides_with_api_keys(
def resolve_effective_config(
user_config: UserConfiguration,
user_config: EffectiveAIModelConfiguration,
model_overrides: dict | None,
) -> UserConfiguration:
) -> EffectiveAIModelConfiguration:
"""Deep-merge workflow model_overrides onto global user config.
- If model_overrides is None or empty, returns a copy of user_config unchanged.

View file

@ -42,7 +42,7 @@ async def resolve_llm_config(
async def resolve_user_llm_config(
workflow_run: WorkflowRunModel,
) -> tuple[str, str, str, dict]:
"""Resolve the user's configured LLM (from UserConfiguration).
"""Resolve the user's configured LLM (from EffectiveAIModelConfiguration).
Returns:
(provider, model, api_key, service_kwargs) tuple

View file

@ -203,7 +203,7 @@ async def create_workflow_run_rows(
Returns:
Tuple of (workflow_run, user, workflow).
"""
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
org = OrganizationModel(provider_id=f"test-org-{provider_id_suffix}")
async_session.add(org)
@ -218,7 +218,7 @@ async def create_workflow_run_rows(
await db_session.update_user_configuration(
user_id=user.id,
configuration=UserConfiguration.model_validate(USER_CONFIGURATION),
configuration=EffectiveAIModelConfiguration.model_validate(USER_CONFIGURATION),
)
workflow = await db_session.create_workflow(

View file

@ -6,7 +6,7 @@ from api.schemas.ai_model_configuration import (
OrganizationAIModelConfigurationV2,
compile_ai_model_configuration_v2,
)
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.ai_model_configuration import (
WORKFLOW_MODEL_CONFIGURATION_V2_OVERRIDE_KEY,
check_for_masked_keys_in_ai_model_configuration_v2,
@ -142,7 +142,7 @@ def test_masked_v2_configuration_masks_nested_service_keys():
def test_legacy_all_dograh_pipeline_converts_to_dograh_v2():
legacy = UserConfiguration(
legacy = EffectiveAIModelConfiguration(
llm=DograhLLMService(
provider="dograh",
api_key=["mps-secret"],
@ -170,7 +170,7 @@ def test_legacy_all_dograh_pipeline_converts_to_dograh_v2():
def test_legacy_mixed_dograh_pipeline_converts_to_dograh_v2():
legacy = UserConfiguration(
legacy = EffectiveAIModelConfiguration(
llm=OpenAILLMService(
provider="openai",
api_key="sk-llm",
@ -202,7 +202,7 @@ def test_legacy_mixed_dograh_pipeline_converts_to_dograh_v2():
def test_legacy_byok_pipeline_converts_to_byok_v2():
legacy = UserConfiguration(
legacy = EffectiveAIModelConfiguration(
llm=OpenAILLMService(
provider="openai",
api_key="sk-llm",
@ -235,7 +235,7 @@ def test_legacy_byok_pipeline_converts_to_byok_v2():
def test_workflow_model_override_migration_removes_v1_override_and_sets_v2():
base = UserConfiguration(
base = EffectiveAIModelConfiguration(
llm=OpenAILLMService(
provider="openai",
api_key="sk-llm",
@ -279,7 +279,7 @@ def test_workflow_model_override_migration_removes_v1_override_and_sets_v2():
def test_workflow_model_override_migration_removes_invalid_v1_override_marker():
base = UserConfiguration()
base = EffectiveAIModelConfiguration()
workflow_configurations = {
"ambient_noise_configuration": {"enabled": False},
"model_overrides": None,

View file

@ -7,7 +7,7 @@ from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.frame_processor import FrameDirection
from pipecat.services.xai.realtime import events
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.registry import GrokRealtimeLLMConfiguration
from api.services.pipecat.realtime.grok_realtime import (
DograhGrokRealtimeLLMService,
@ -120,7 +120,7 @@ async def test_completed_input_transcription_is_broadcast_as_finalized():
def test_factory_creates_dograh_grok_realtime_service():
user_config = UserConfiguration(
user_config = EffectiveAIModelConfiguration(
is_realtime=True,
realtime=GrokRealtimeLLMConfiguration(
provider="grok_realtime",

View file

@ -5,7 +5,7 @@ from fastapi import FastAPI
from fastapi.testclient import TestClient
from api.routes.user import router
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.auth.depends import get_user
from api.services.configuration.masking import mask_key
from api.services.configuration.registry import (
@ -33,7 +33,7 @@ MASKED_KEY = mask_key(REAL_KEY) # "**************************cdef"
def _existing_openai_config():
return UserConfiguration(
return EffectiveAIModelConfiguration(
llm=OpenAILLMService(
provider="openai",
api_key=REAL_KEY,
@ -111,7 +111,7 @@ class TestMaskedKeyRejection:
client = TestClient(app)
new_key = "AIzaSyNewRealKey12345678"
updated = UserConfiguration(
updated = EffectiveAIModelConfiguration(
llm=GoogleLLMService(
provider="google",
api_key=new_key,
@ -178,7 +178,7 @@ class TestMaskedKeyRejection:
real_credentials = '{"type":"service_account","project_id":"demo-project"}'
masked_credentials = mask_key(real_credentials)
existing = UserConfiguration(
existing = EffectiveAIModelConfiguration(
llm=GoogleVertexLLMConfiguration(
provider="google_vertex",
api_key=None,

View file

@ -2,14 +2,14 @@
TDD tests for resolve_effective_config().
This function deep-merges workflow-level model_overrides onto the global
UserConfiguration. Fields not overridden inherit from global.
EffectiveAIModelConfiguration. Fields not overridden inherit from global.
Module under test: api.services.configuration.resolve
"""
import pytest
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.masking import (
contains_masked_key,
mask_workflow_configurations,
@ -35,9 +35,9 @@ from api.services.configuration.resolve import (
@pytest.fixture
def global_config() -> UserConfiguration:
def global_config() -> EffectiveAIModelConfiguration:
"""A realistic global user configuration."""
return UserConfiguration(
return EffectiveAIModelConfiguration(
llm=OpenAILLMService(
provider="openai", api_key="sk-global-llm", model="gpt-4.1"
),
@ -59,9 +59,9 @@ def global_config() -> UserConfiguration:
@pytest.fixture
def global_config_realtime() -> UserConfiguration:
def global_config_realtime() -> EffectiveAIModelConfiguration:
"""Global config with realtime enabled."""
return UserConfiguration(
return EffectiveAIModelConfiguration(
llm=OpenAILLMService(
provider="openai", api_key="sk-global-llm", model="gpt-4.1"
),
@ -302,7 +302,7 @@ class TestRealtimeOverride:
class TestOverrideOnNullGlobal:
def test_override_stt_when_global_is_none(self):
"""When global has no STT config, override creates one from scratch."""
config = UserConfiguration(
config = EffectiveAIModelConfiguration(
llm=OpenAILLMService(provider="openai", api_key="sk-key", model="gpt-4.1"),
stt=None,
tts=None,
@ -325,7 +325,7 @@ class TestOverrideOnNullGlobal:
def test_override_realtime_when_global_is_none(self):
"""Realtime section can be created from override even if global has none."""
config = UserConfiguration(
config = EffectiveAIModelConfiguration(
llm=OpenAILLMService(provider="openai", api_key="sk-key", model="gpt-4.1"),
is_realtime=False,
realtime=None,

View file

@ -10,7 +10,7 @@ from pipecat.processors.frame_processor import FrameDirection
from websockets.exceptions import ConnectionClosedError
from websockets.frames import Close
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.services.configuration.registry import UltravoxRealtimeLLMConfiguration
from api.services.pipecat.realtime.ultravox_realtime import (
_RESUMPTION_USER_MESSAGE,
@ -430,7 +430,7 @@ async def test_receive_messages_reports_unexpected_websocket_close():
def test_factory_creates_dograh_ultravox_realtime_service():
user_config = UserConfiguration(
user_config = EffectiveAIModelConfiguration(
is_realtime=True,
realtime=UltravoxRealtimeLLMConfiguration(
provider="ultravox_realtime",

View file

@ -4,7 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from api.db.models import OrganizationModel, UserModel
from api.schemas.user_configuration import UserConfiguration
from api.schemas.user_configuration import EffectiveAIModelConfiguration
from api.tests.integrations._run_pipeline_helpers import USER_CONFIGURATION
from pipecat.tests import MockLLMService
@ -38,7 +38,7 @@ async def _create_user_and_workflow(
await db_session.update_user_configuration(
user_id=user.id,
configuration=UserConfiguration.model_validate(USER_CONFIGURATION),
configuration=EffectiveAIModelConfiguration.model_validate(USER_CONFIGURATION),
)
workflow = await db_session.create_workflow(
@ -1041,7 +1041,7 @@ async def test_text_chat_session_creation_requires_selected_org_scope(
await db_session.update_user_configuration(
user_id=user.id,
configuration=UserConfiguration.model_validate(USER_CONFIGURATION),
configuration=EffectiveAIModelConfiguration.model_validate(USER_CONFIGURATION),
)
workflow = await db_session.create_workflow(