claude-proxy / src /free_claude_code /api /model_catalog.py
dheraingoud's picture
feat: sync upstream commits up to f17c92bc
a1bab2d
Raw
History Blame Contribute Delete
4.34 kB
"""Model-list response construction for Claude-compatible clients."""
from __future__ import annotations
from typing import Literal
from pydantic import BaseModel
from free_claude_code.application.ports import RequestRuntimePort
from free_claude_code.config.model_refs import configured_chat_model_refs
from free_claude_code.config.settings import Settings
from free_claude_code.core.gateway_model_ids import (
gateway_model_id,
no_thinking_gateway_model_id,
)
DISCOVERED_MODEL_CREATED_AT = "1970-01-01T00:00:00Z"
class ModelResponse(BaseModel):
object: Literal["model"] = "model"
created: int = 0
owned_by: str = "free-claude-code"
created_at: str
display_name: str
id: str
type: Literal["model"] = "model"
class ModelsListResponse(BaseModel):
object: Literal["list"] = "list"
data: list[ModelResponse]
first_id: str | None
has_more: bool
last_id: str | None
SUPPORTED_CLAUDE_MODELS = [
ModelResponse(
id="claude-fable-5",
display_name="Claude Fable 5",
created_at="2026-06-09T00:00:00Z",
),
ModelResponse(
id="claude-opus-4-20250514",
display_name="Claude Opus 4",
created_at="2025-05-14T00:00:00Z",
),
ModelResponse(
id="claude-sonnet-4-20250514",
display_name="Claude Sonnet 4",
created_at="2025-05-14T00:00:00Z",
),
ModelResponse(
id="claude-haiku-4-20250514",
display_name="Claude Haiku 4",
created_at="2025-05-14T00:00:00Z",
),
ModelResponse(
id="claude-3-opus-20240229",
display_name="Claude 3 Opus",
created_at="2024-02-29T00:00:00Z",
),
ModelResponse(
id="claude-3-5-sonnet-20241022",
display_name="Claude 3.5 Sonnet",
created_at="2024-10-22T00:00:00Z",
),
ModelResponse(
id="claude-3-haiku-20240307",
display_name="Claude 3 Haiku",
created_at="2024-03-07T00:00:00Z",
),
ModelResponse(
id="claude-3-5-haiku-20241022",
display_name="Claude 3.5 Haiku",
created_at="2024-10-22T00:00:00Z",
),
]
def build_models_list_response(
settings: Settings, runtime: RequestRuntimePort
) -> ModelsListResponse:
"""Return configured, cached, and compatibility model ids."""
models: list[ModelResponse] = []
seen: set[str] = set()
for ref in configured_chat_model_refs(settings):
supports_thinking = runtime.cached_model_supports_thinking(
ref.provider_id, ref.model_id
)
_append_provider_model_variants(
models,
seen,
ref.model_ref,
supports_thinking=supports_thinking,
)
for model_info in runtime.cached_prefixed_model_infos():
_append_provider_model_variants(
models,
seen,
model_info.model_id,
supports_thinking=model_info.supports_thinking,
)
for model in SUPPORTED_CLAUDE_MODELS:
_append_unique_model(models, seen, model)
return ModelsListResponse(
data=models,
first_id=models[0].id if models else None,
has_more=False,
last_id=models[-1].id if models else None,
)
def _discovered_model_response(model_id: str, *, display_name: str) -> ModelResponse:
return ModelResponse(
id=model_id,
display_name=display_name,
created_at=DISCOVERED_MODEL_CREATED_AT,
)
def _append_unique_model(
models: list[ModelResponse], seen: set[str], model: ModelResponse
) -> None:
if model.id in seen:
return
seen.add(model.id)
models.append(model)
def _append_provider_model_variants(
models: list[ModelResponse],
seen: set[str],
provider_model_ref: str,
*,
supports_thinking: bool | None = None,
) -> None:
if supports_thinking is not False:
_append_unique_model(
models,
seen,
_discovered_model_response(
gateway_model_id(provider_model_ref),
display_name=provider_model_ref,
),
)
_append_unique_model(
models,
seen,
_discovered_model_response(
no_thinking_gateway_model_id(provider_model_ref),
display_name=f"{provider_model_ref} (no thinking)",
),
)