import os from typing import Any, cast from ...config.logfire_config import get_logger logger = get_logger(__name__) async def get_active_provider(manager: Any, service_type: str = "llm") -> dict[str, Any]: """ Get the currently active provider configuration. Searches across critical categories with deep fallback to OS environment. """ try: ai_settings = await manager.get_credentials_by_category("ai") marketing_settings = await manager.get_credentials_by_category("marketing") rag_settings = await manager.get_credentials_by_category("rag_strategy") all_settings = {**ai_settings, **marketing_settings, **rag_settings} provider_key = "LLM_PROVIDER" if service_type == "llm" else "EMBEDDING_PROVIDER" provider = all_settings.get(provider_key) if not provider: provider = os.getenv(provider_key, "openai").lower() api_key = await _get_provider_api_key(manager, provider) base_url = _get_provider_base_url(provider, all_settings) chat_model = all_settings.get("MODEL_CHOICE") or all_settings.get("MARKETING_MODEL") or "" embedding_model = all_settings.get("EMBEDDING_MODEL", "") return { "provider": provider, "api_key": api_key, "base_url": base_url, "chat_model": chat_model, "embedding_model": embedding_model, } except Exception as e: logger.error(f"Error getting active provider for {service_type}: {e}") provider = os.getenv("LLM_PROVIDER", "openai") return { "provider": provider, "api_key": os.getenv("OPENAI_API_KEY"), "base_url": None, "chat_model": "", "embedding_model": "", } async def get_embedding_provider_configs(manager: Any) -> list[dict[str, Any]]: """ Get the currently active primary and fallback embedding provider configurations. Designed for failover and separate from the main LLM provider logic. """ configs = [] try: ai_settings = await manager.get_credentials_by_category("ai") marketing_settings = await manager.get_credentials_by_category("marketing") rag_settings = await manager.get_credentials_by_category("rag_strategy") all_settings = {**ai_settings, **marketing_settings, **rag_settings} provider_types = [ {"type": "primary", "suffix": ""}, {"type": "fallback", "suffix": "_FALLBACK"}, ] for pt in provider_types: provider_key = f"EMBEDDING_PROVIDER{pt['suffix']}" model_key = f"EMBEDDING_MODEL{pt['suffix']}" api_key_override_key = f"EMBEDDING_API_KEY{pt['suffix']}" provider = all_settings.get(provider_key) if not provider: if pt["type"] == "primary": provider = all_settings.get("LLM_PROVIDER") or os.getenv("LLM_PROVIDER", "openai").lower() else: continue embedding_model = all_settings.get(model_key) if not embedding_model and pt["type"] == "primary": embedding_model = all_settings.get("EMBEDDING_MODEL") or os.getenv("EMBEDDING_MODEL", "") if not embedding_model: if provider == "google": embedding_model = "gemini-embedding-001" elif provider == "openai": embedding_model = "text-embedding-3-small" else: embedding_model = "default-embedding" api_key = await manager.get_credential(api_key_override_key) if not api_key: api_key = await _get_provider_api_key(manager, provider) base_url = _get_provider_base_url(provider, all_settings) if api_key: configs.append( { "provider": provider, "api_key": api_key, "base_url": base_url, "embedding_model": embedding_model, } ) return configs except Exception as e: logger.error(f"Error getting embedding provider configs: {e}") return [] async def _get_provider_api_key(manager: Any, provider: str) -> str | None: """Get API key for a specific provider.""" key_mapping = { "openai": "OPENAI_API_KEY", "google": "GOOGLE_API_KEY", "ollama": None, } key_name = key_mapping.get(provider) if key_name: return cast(str | None, await manager.get_credential(key_name)) return "ollama" if provider == "ollama" else None def _get_provider_base_url(provider: str, rag_settings: dict) -> str | None: """Get base URL for provider.""" if provider == "ollama": return cast(str | None, rag_settings.get("LLM_BASE_URL", "http://localhost:11434/v1")) elif provider == "google": return "https://generativelanguage.googleapis.com/v1beta/openai/" return None async def set_active_provider(manager: Any, provider: str, service_type: str = "llm") -> bool: """Set the active provider for a service type.""" try: return bool( await manager.set_credential( "llm_provider", provider, category="rag_strategy", description=f"Active {service_type} provider", ) ) except Exception as e: logger.error(f"Error setting active provider {provider} for {service_type}: {e}") return False