fed8b2eed7
Backend release / release (push) Waiting to run
Bandit Security Scan / bandit_scan (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / manifest (push) Blocked by required conditions
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / manifest (push) Blocked by required conditions
Python linting / ruff (push) Waiting to run
Run python tests with pytest / Run tests and count coverage (3.12) (push) Waiting to run
React Widget Build / build (push) Waiting to run
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
import logging
|
|
from dataclasses import dataclass, field
|
|
from enum import Enum
|
|
from typing import Dict, List, Optional
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Re-exported here so existing call sites (and tests) that do
|
|
# ``from application.core.model_settings import ModelRegistry`` keep
|
|
# working. The implementation lives in ``application/core/model_registry.py``.
|
|
# Imported lazily inside ``__getattr__`` to avoid an import cycle with
|
|
# ``model_yaml`` → ``model_settings`` (this file).
|
|
|
|
|
|
class ModelProvider(str, Enum):
|
|
OPENAI = "openai"
|
|
OPENAI_COMPATIBLE = "openai_compatible"
|
|
OPENROUTER = "openrouter"
|
|
ANTHROPIC = "anthropic"
|
|
GROQ = "groq"
|
|
GOOGLE = "google"
|
|
HUGGINGFACE = "huggingface"
|
|
LLAMA_CPP = "llama.cpp"
|
|
DOCSGPT = "docsgpt"
|
|
PREMAI = "premai"
|
|
SAGEMAKER = "sagemaker"
|
|
NOVITA = "novita"
|
|
|
|
|
|
@dataclass
|
|
class ModelCapabilities:
|
|
supports_tools: bool = False
|
|
supports_structured_output: bool = False
|
|
supports_streaming: bool = True
|
|
supported_attachment_types: List[str] = field(default_factory=list)
|
|
context_window: int = 128000
|
|
input_cost_per_token: Optional[float] = None
|
|
output_cost_per_token: Optional[float] = None
|
|
# OpenAI reasoning-model effort hint (none/minimal/low/medium/high/xhigh;
|
|
# the accepted subset is model-dependent). Consumed by OpenAILLM — sent
|
|
# top-level on Chat Completions and nested under ``reasoning`` on the
|
|
# Responses path; ignored by providers that don't accept it.
|
|
reasoning_effort: Optional[str] = None
|
|
# Which OpenAI wire protocol the model speaks: "chat_completions"
|
|
# (the default) or "responses" (the /v1/responses endpoint). Set per
|
|
# model so only models that actually support the Responses API opt in.
|
|
api_flavor: str = "chat_completions"
|
|
|
|
|
|
@dataclass
|
|
class AvailableModel:
|
|
id: str
|
|
provider: ModelProvider
|
|
display_name: str
|
|
description: str = ""
|
|
capabilities: ModelCapabilities = field(default_factory=ModelCapabilities)
|
|
enabled: bool = True
|
|
base_url: Optional[str] = None
|
|
# User-facing label distinct from dispatch provider (e.g. mistral
|
|
# routed through openai_compatible).
|
|
display_provider: Optional[str] = None
|
|
# Sent in the API call's ``model`` field; falls back to ``self.id``
|
|
# for built-ins where id IS the upstream name.
|
|
upstream_model_id: Optional[str] = None
|
|
# "builtin" for catalog YAMLs, "user" for BYOM records.
|
|
source: str = "builtin"
|
|
# Decrypted/resolved at registry-merge time. Never serialized.
|
|
api_key: Optional[str] = field(default=None, repr=False, compare=False)
|
|
|
|
def to_dict(self) -> Dict:
|
|
result = {
|
|
"id": self.id,
|
|
"provider": self.display_provider or self.provider.value,
|
|
"display_name": self.display_name,
|
|
"description": self.description,
|
|
"supported_attachment_types": self.capabilities.supported_attachment_types,
|
|
"supports_tools": self.capabilities.supports_tools,
|
|
"supports_structured_output": self.capabilities.supports_structured_output,
|
|
"supports_streaming": self.capabilities.supports_streaming,
|
|
"context_window": self.capabilities.context_window,
|
|
"enabled": self.enabled,
|
|
"source": self.source,
|
|
}
|
|
if self.base_url:
|
|
result["base_url"] = self.base_url
|
|
return result
|
|
|
|
|
|
def __getattr__(name):
|
|
"""Lazy re-export of ``ModelRegistry`` from ``model_registry.py``.
|
|
|
|
Done lazily to avoid an import cycle: ``model_registry`` imports
|
|
``model_yaml`` which imports the dataclasses from this file.
|
|
"""
|
|
if name == "ModelRegistry":
|
|
from application.core.model_registry import ModelRegistry as _MR
|
|
|
|
return _MR
|
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|