From 91ac460799d586cbe7b4855f557220ad5b99dd0a Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Jun 2026 16:30:03 +0530 Subject: [PATCH] chore: finish renaming UserConfiguration --- api/db/organization_usage_client.py | 4 ++-- api/db/user_client.py | 20 +++++++++++-------- api/schemas/user_configuration.py | 4 ---- api/services/auth/depends.py | 8 ++++---- api/services/configuration/check_validity.py | 4 ++-- api/services/configuration/masking.py | 8 ++++---- api/services/configuration/merge.py | 10 +++++----- api/services/configuration/resolve.py | 10 +++++----- api/services/workflow/qa/llm_config.py | 2 +- .../integrations/_run_pipeline_helpers.py | 4 ++-- api/tests/test_ai_model_configuration_v2.py | 12 +++++------ api/tests/test_grok_realtime_wrapper.py | 4 ++-- api/tests/test_masked_key_rejection.py | 8 ++++---- api/tests/test_resolve_effective_config.py | 16 +++++++-------- api/tests/test_ultravox_realtime_wrapper.py | 4 ++-- api/tests/test_workflow_text_chat.py | 6 +++--- 16 files changed, 62 insertions(+), 62 deletions(-) diff --git a/api/db/organization_usage_client.py b/api/db/organization_usage_client.py index f69f195..f845fc7 100644 --- a/api/db/organization_usage_client.py +++ b/api/db/organization_usage_client.py @@ -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": diff --git a/api/db/user_client.py b/api/db/user_client.py index 0983a38..9c4476f 100644 --- a/api/db/user_client.py +++ b/api/db/user_client.py @@ -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: diff --git a/api/schemas/user_configuration.py b/api/schemas/user_configuration.py index 1f8d8ff..fc958a5 100644 --- a/api/schemas/user_configuration.py +++ b/api/schemas/user_configuration.py @@ -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 diff --git a/api/services/auth/depends.py b/api/services/auth/depends.py index 7a28492..d9e2468 100644 --- a/api/services/auth/depends.py +++ b/api/services/auth/depends.py @@ -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( diff --git a/api/services/configuration/check_validity.py b/api/services/configuration/check_validity.py index 0e4da86..e8f5bfa 100644 --- a/api/services/configuration/check_validity.py +++ b/api/services/configuration/check_validity.py @@ -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: diff --git a/api/services/configuration/masking.py b/api/services/configuration/masking.py index adbc621..c3fa4bf 100644 --- a/api/services/configuration/masking.py +++ b/api/services/configuration/masking.py @@ -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 { diff --git a/api/services/configuration/merge.py b/api/services/configuration/merge.py index f421648..1b174ee 100644 --- a/api/services/configuration/merge.py +++ b/api/services/configuration/merge.py @@ -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( diff --git a/api/services/configuration/resolve.py b/api/services/configuration/resolve.py index 742e46b..a33f5c0 100644 --- a/api/services/configuration/resolve.py +++ b/api/services/configuration/resolve.py @@ -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. diff --git a/api/services/workflow/qa/llm_config.py b/api/services/workflow/qa/llm_config.py index ec3ae41..9f4d06f 100644 --- a/api/services/workflow/qa/llm_config.py +++ b/api/services/workflow/qa/llm_config.py @@ -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 diff --git a/api/tests/integrations/_run_pipeline_helpers.py b/api/tests/integrations/_run_pipeline_helpers.py index a1e19b0..1a3251a 100644 --- a/api/tests/integrations/_run_pipeline_helpers.py +++ b/api/tests/integrations/_run_pipeline_helpers.py @@ -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( diff --git a/api/tests/test_ai_model_configuration_v2.py b/api/tests/test_ai_model_configuration_v2.py index 023a330..98f431e 100644 --- a/api/tests/test_ai_model_configuration_v2.py +++ b/api/tests/test_ai_model_configuration_v2.py @@ -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, diff --git a/api/tests/test_grok_realtime_wrapper.py b/api/tests/test_grok_realtime_wrapper.py index f3cfa1a..7f7359d 100644 --- a/api/tests/test_grok_realtime_wrapper.py +++ b/api/tests/test_grok_realtime_wrapper.py @@ -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", diff --git a/api/tests/test_masked_key_rejection.py b/api/tests/test_masked_key_rejection.py index 9bf1f54..2012c60 100644 --- a/api/tests/test_masked_key_rejection.py +++ b/api/tests/test_masked_key_rejection.py @@ -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, diff --git a/api/tests/test_resolve_effective_config.py b/api/tests/test_resolve_effective_config.py index c539c7c..85afe30 100644 --- a/api/tests/test_resolve_effective_config.py +++ b/api/tests/test_resolve_effective_config.py @@ -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, diff --git a/api/tests/test_ultravox_realtime_wrapper.py b/api/tests/test_ultravox_realtime_wrapper.py index 1034b8d..65b062b 100644 --- a/api/tests/test_ultravox_realtime_wrapper.py +++ b/api/tests/test_ultravox_realtime_wrapper.py @@ -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", diff --git a/api/tests/test_workflow_text_chat.py b/api/tests/test_workflow_text_chat.py index 219f333..e69e7c0 100644 --- a/api/tests/test_workflow_text_chat.py +++ b/api/tests/test_workflow_text_chat.py @@ -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(