| """One closable generation of lazily constructed provider clients.""" |
|
|
| import asyncio |
| from collections.abc import Callable, MutableMapping |
|
|
| from free_claude_code.config.settings import Settings |
| from free_claude_code.providers.base import BaseProvider |
|
|
| from .factory import create_provider |
|
|
| ProviderConstructor = Callable[[str, Settings], BaseProvider] |
|
|
|
|
| class ProviderRuntime: |
| """Own provider instances for one immutable settings snapshot.""" |
|
|
| def __init__( |
| self, |
| settings: Settings, |
| providers: MutableMapping[str, BaseProvider] | None = None, |
| *, |
| provider_constructor: ProviderConstructor = create_provider, |
| ) -> None: |
| self.settings = settings |
| self._providers = providers if providers is not None else {} |
| self._provider_constructor = provider_constructor |
|
|
| def is_cached(self, provider_id: str) -> bool: |
| """Return whether a provider for this id is already cached.""" |
| return provider_id in self._providers |
|
|
| def resolve_provider(self, provider_id: str) -> BaseProvider: |
| """Return an existing provider or create it lazily.""" |
| if provider_id not in self._providers: |
| self._providers[provider_id] = self._provider_constructor( |
| provider_id, self.settings |
| ) |
| return self._providers[provider_id] |
|
|
| async def cleanup(self) -> None: |
| """Release every provider client constructed by this generation.""" |
| errors: list[Exception] = [] |
| for provider_id, provider in list(self._providers.items()): |
| try: |
| await provider.cleanup() |
| except asyncio.CancelledError: |
| raise |
| except Exception as exc: |
| errors.append(exc) |
| else: |
| self._providers.pop(provider_id, None) |
| if len(errors) == 1: |
| raise errors[0] |
| if len(errors) > 1: |
| raise ExceptionGroup("One or more provider cleanups failed", errors) |
|
|