"""Provider credential records — API keys and endpoints for AI providers. Each row stores one named account for a single provider (Anthropic, OpenAI, Ollama, etc.). An organization can have multiple rows per provider, enabling separate cost tracking for e.g. "work" and "personal" OpenAI accounts. Token storage follows the same pattern as ForgejoConnection and Gateway: plaintext in the trusted DB, last-four chars available for verification without exposing the full key. """ from __future__ import annotations from datetime import datetime from uuid import UUID, uuid4 from sqlmodel import Field from app.core.time import utcnow from app.models.base import QueryModel RUNTIME_ANNOTATION_TYPES = (datetime,) SUPPORTED_PROVIDERS = frozenset({"anthropic", "openai", "ollama", "google", "other"}) class ProviderCredential(QueryModel, table=True): """One named AI-provider account for an organisation.""" __tablename__ = "provider_credentials" # pyright: ignore[reportAssignmentType] id: UUID = Field(default_factory=uuid4, primary_key=True) organization_id: UUID = Field(foreign_key="organizations.id", index=True) # Provider identity provider: str = Field(index=True) # "anthropic", "openai", "ollama", … account_key: str = Field(index=True) # user label: "work", "personal", "local" display_name: str = Field(default="") # human-readable name shown in the UI # Credentials (not all providers need both) api_key: str | None = Field(default=None) # full key — never returned in API api_key_last_four: str | None = Field(default=None) # shown in UI for verification base_url: str | None = Field(default=None) # Ollama, Azure, custom endpoints active: bool = Field(default=True, index=True) created_at: datetime = Field(default_factory=utcnow) updated_at: datetime = Field(default_factory=utcnow)