| """Provider model-list metadata cache.""" |
|
|
| from collections.abc import Iterable |
|
|
| from free_claude_code.application.model_metadata import ProviderModelInfo |
| from free_claude_code.config.provider_catalog import SUPPORTED_PROVIDER_IDS |
|
|
|
|
| class ProviderModelCache: |
| """Store provider model metadata for instant model-list responses.""" |
|
|
| def __init__( |
| self, |
| available_provider_ids: Iterable[str] = SUPPORTED_PROVIDER_IDS, |
| ) -> None: |
| self._available_provider_ids = frozenset(available_provider_ids) |
| self._model_infos_by_provider: dict[str, dict[str, ProviderModelInfo]] = {} |
|
|
| def cache_model_infos( |
| self, provider_id: str, model_infos: Iterable[ProviderModelInfo] |
| ) -> None: |
| """Store provider model metadata by raw provider model id.""" |
| if provider_id not in self._available_provider_ids: |
| return |
| clean_infos = { |
| info.model_id: info for info in model_infos if info.model_id.strip() |
| } |
| self._model_infos_by_provider[provider_id] = clean_infos |
|
|
| def set_available_providers(self, provider_ids: Iterable[str]) -> None: |
| """Replace the provider scope and discard entries outside it.""" |
| self._available_provider_ids = frozenset(provider_ids) |
| self._model_infos_by_provider = { |
| provider_id: infos |
| for provider_id, infos in self._model_infos_by_provider.items() |
| if provider_id in self._available_provider_ids |
| } |
|
|
| def add_provider(self, provider_id: str) -> None: |
| """Make one dynamically authenticated provider cacheable.""" |
|
|
| self._available_provider_ids = self._available_provider_ids | {provider_id} |
|
|
| def remove_provider(self, provider_id: str) -> None: |
| """Evict one provider and stop accepting its discovered metadata.""" |
|
|
| self._available_provider_ids = self._available_provider_ids - {provider_id} |
| self._model_infos_by_provider.pop(provider_id, None) |
|
|
| def cached_model_ids(self) -> dict[str, frozenset[str]]: |
| """Return cached raw provider model ids by provider.""" |
| return { |
| provider_id: frozenset(infos) |
| for provider_id, infos in self._model_infos_by_provider.items() |
| } |
|
|
| def has_provider(self, provider_id: str) -> bool: |
| """Return whether this provider has any cached model-list result.""" |
| return provider_id in self._model_infos_by_provider |
|
|
| def cached_model_supports_thinking( |
| self, provider_id: str, model_id: str |
| ) -> bool | None: |
| """Return cached thinking support when a provider exposes it.""" |
| info = self._model_infos_by_provider.get(provider_id, {}).get(model_id) |
| if info is None: |
| return None |
| return info.supports_thinking |
|
|
| def cached_prefixed_model_infos(self) -> tuple[ProviderModelInfo, ...]: |
| """Return cached provider models with user-selectable prefixed ids.""" |
| infos: list[ProviderModelInfo] = [] |
| for provider_id in SUPPORTED_PROVIDER_IDS: |
| provider_infos = self._model_infos_by_provider.get(provider_id, {}) |
| infos.extend( |
| ProviderModelInfo( |
| model_id=f"{provider_id}/{info.model_id}", |
| supports_thinking=info.supports_thinking, |
| ) |
| for info in sorted( |
| provider_infos.values(), key=lambda item: item.model_id |
| ) |
| ) |
| return tuple(infos) |
|
|
| def clear(self) -> None: |
| """Clear all cached model metadata.""" |
| self._model_infos_by_provider.clear() |
|
|