Python API Reference

Complete reference for using llm-discovery as a Python library.

Package Version

Get the installed version of llm-discovery:

from llm_discovery import __version__

print(__version__)  # Example: "0.1.0"

The version is dynamically retrieved from package metadata using importlib.metadata.

Note

The version attribute uses Pydantic v2 for data validation throughout the library. All model classes inherit from pydantic.BaseModel for automatic validation and serialization.

DiscoveryClient Class

The main interface for fetching and managing LLM model information.

Import

from llm_discovery import DiscoveryClient

Constructor

class DiscoveryClient:
    def __init__(
        self,
        *,
        config: Config | None = None
    ):
        """
        Initialize DiscoveryClient.

        Args:
            config: Configuration object (auto-generated from environment variables if None)

        Raises:
            ConfigurationError: Required environment variables not set
            RuntimeError: Configuration validation failed
        """

Example:

from llm_discovery import DiscoveryClient

# Auto-configuration from environment variables
client = DiscoveryClient()

# Custom configuration
from llm_discovery.models import Config
custom_config = Config.from_env()
client = DiscoveryClient(config=custom_config)

fetch_models()

Fetch model list from all providers concurrently.

async def fetch_models(self) -> list[Model]:
    """
    Fetch model list from all providers.

    Returns:
        List of Model objects

    Raises:
        ProviderFetchError: API fetch failed (fail-fast behavior)
        PartialFetchError: Partial fetch failure
        AuthenticationError: Invalid credentials
        ConfigurationError: Environment variables not set
    """

Example:

import asyncio
from llm_discovery import DiscoveryClient
from llm_discovery.exceptions import ProviderFetchError, PartialFetchError

async def main():
    client = DiscoveryClient()

    try:
        models = await client.fetch_models()
        print(f"Fetched {len(models)} models")

        for model in models:
            print(f"{model.provider_name}/{model.model_id}: {model.model_name}")

    except ProviderFetchError as e:
        print(f"API fetch failed: {e}")
        # External retry management (cron, CI/CD, etc.)

    except PartialFetchError as e:
        print(f"Partial failure: {e}")
        print(f"Successful providers: {e.successful_providers}")
        print(f"Failed providers: {e.failed_providers}")

asyncio.run(main())

Tip

Use asyncio.run() for async best practices. The library is fully async-native using modern Python async/await patterns.

get_cached_models()

Retrieve models from local cache without API calls.

def get_cached_models(self) -> list[Model]:
    """
    Retrieve models from local cache.

    Returns:
        List of cached Model objects

    Raises:
        CacheNotFoundError: Cache file does not exist
        CacheCorruptedError: Cache file is corrupted or invalid
    """

Example:

from llm_discovery import DiscoveryClient
from llm_discovery.exceptions import CacheNotFoundError

client = DiscoveryClient()

try:
    models = client.get_cached_models()
    print(f"Loaded {len(models)} models from cache")
except CacheNotFoundError:
    print("No cache found. Run 'update' command first.")

Config Class

Configuration management for llm-discovery.

Import

from llm_discovery.models.config import Config

from_env()

Create configuration from environment variables.

@classmethod
def from_env(cls) -> Config:
    """
    Create Config from environment variables.

    Returns:
        Config object

    Raises:
        ConfigurationError: Required environment variables not set
        ValueError: Invalid environment variable values
    """

Example:

from llm_discovery.models.config import Config

# Load from environment variables
config = Config.from_env()

print(config.openai_api_key)  # Masked: "sk-...***"
print(config.cache_dir)       # Path to cache directory

Environment Variables:

  • OPENAI_API_KEY: OpenAI API key (optional)

  • GOOGLE_API_KEY: Google AI Studio API key (optional)

  • GOOGLE_GENAI_USE_VERTEXAI: Use Vertex AI instead of AI Studio (optional, default: false)

  • GOOGLE_APPLICATION_CREDENTIALS: Path to GCP credentials JSON (required if using Vertex AI)

  • LLM_DISCOVERY_CACHE_DIR: Custom cache directory (optional, default: ~/.cache/llm-discovery)

ProviderSnapshot Class

Represents a snapshot of models from a single provider.

Import

from llm_discovery.models.provider import ProviderSnapshot

Attributes

class ProviderSnapshot(BaseModel):
    provider_name: str          # Provider identifier (e.g., "openai", "google")
    models: list[Model]         # List of models from this provider
    fetched_at: datetime        # Timestamp when models were fetched (UTC)
    source: ModelSource         # Data source (API or CACHE)

Example:

from llm_discovery import DiscoveryClient

async def main():
    client = DiscoveryClient()
    snapshots = await client.fetch_all_models()

    for snapshot in snapshots:
        print(f"Provider: {snapshot.provider_name}")
        print(f"Fetched at: {snapshot.fetched_at}")
        print(f"Models: {len(snapshot.models)}")

Model Class

Represents a single LLM model.

Import

from llm_discovery.models.provider import Model

Attributes

class Model(BaseModel):
    model_id: str              # Unique model identifier
    model_name: str            # Human-readable model name
    provider_name: str         # Provider name
    source: ModelSource        # Data source (API or CACHE)
    fetched_at: datetime       # Timestamp (UTC)
    capabilities: list[str]    # Model capabilities (optional)

Example:

from llm_discovery import DiscoveryClient

async def main():
    client = DiscoveryClient()
    models = await client.fetch_models()

    # Filter models by capability
    chat_models = [m for m in models if "chat" in m.capabilities]

    for model in chat_models:
        print(f"{model.provider_name}/{model.model_id}")
        print(f"  Name: {model.model_name}")
        print(f"  Capabilities: {', '.join(model.capabilities)}")

Data Export Formats

Export model data in multiple formats.

JSON Export

from llm_discovery.services.exporters import JSONExporter

exporter = JSONExporter()
models = client.get_cached_models()
json_data = exporter.export(models)

# Save to file
with open("models.json", "w") as f:
    f.write(json_data)

Output Format:

{
  "models": [
    {
      "model_id": "gpt-4",
      "model_name": "GPT-4",
      "provider_name": "openai",
      "source": "API",
      "fetched_at": "2025-10-19T12:00:00Z",
      "capabilities": ["chat", "completion"]
    }
  ],
  "metadata": {
    "total_count": 1,
    "fetched_at": "2025-10-19T12:00:00Z"
  }
}

CSV Export

from llm_discovery.services.exporters import CSVExporter

exporter = CSVExporter()
csv_data = exporter.export(models)

with open("models.csv", "w") as f:
    f.write(csv_data)

Output Format:

provider_name,model_id,model_name,source,fetched_at,capabilities
openai,gpt-4,GPT-4,API,2025-10-19T12:00:00Z,"chat,completion"

YAML Export

from llm_discovery.services.exporters import YAMLExporter

exporter = YAMLExporter()
yaml_data = exporter.export(models)

with open("models.yaml", "w") as f:
    f.write(yaml_data)

Output Format:

models:
  - model_id: gpt-4
    model_name: GPT-4
    provider_name: openai
    source: API
    fetched_at: '2025-10-19T12:00:00Z'
    capabilities:
      - chat
      - completion

Markdown Export

from llm_discovery.services.exporters import MarkdownExporter

exporter = MarkdownExporter()
markdown_data = exporter.export(models)

with open("models.md", "w") as f:
    f.write(markdown_data)

Output Format:

# LLM Models

| Provider | Model ID | Model Name | Source | Fetched At |
|----------|----------|------------|--------|------------|
| openai   | gpt-4    | GPT-4      | API    | 2025-10-19T12:00:00Z |

TOML Export

from llm_discovery.services.exporters import TOMLExporter

exporter = TOMLExporter()
toml_data = exporter.export(models)

with open("models.toml", "w") as f:
    f.write(toml_data)

Output Format:

[[models]]
model_id = "gpt-4"
model_name = "GPT-4"
provider_name = "openai"
source = "API"
fetched_at = "2025-10-19T12:00:00Z"
capabilities = ["chat", "completion"]

Exception Handling

All exceptions inherit from LLMDiscoveryError.

Exception Hierarchy

LLMDiscoveryError
├── ConfigurationError          # Configuration issues
├── ProviderFetchError          # API fetch failures
│   ├── AuthenticationError     # Invalid credentials
│   └── NetworkError            # Network connectivity issues
├── PartialFetchError           # Partial fetch failures
├── CacheError                  # Cache-related errors
│   ├── CacheNotFoundError      # Cache file not found
│   └── CacheCorruptedError     # Cache file corrupted
└── ExportError                 # Export format errors

Example Error Handling

from llm_discovery import DiscoveryClient
from llm_discovery.exceptions import (
    ConfigurationError,
    AuthenticationError,
    ProviderFetchError,
    CacheNotFoundError
)

async def fetch_with_error_handling():
    try:
        client = DiscoveryClient()
        models = await client.fetch_models()
        return models

    except ConfigurationError as e:
        print(f"Configuration error: {e}")
        print("Please check environment variables")

    except AuthenticationError as e:
        print(f"Authentication failed: {e}")
        print("Please verify API keys")

    except ProviderFetchError as e:
        print(f"Failed to fetch models: {e}")
        # Fallback to cache
        try:
            return client.get_cached_models()
        except CacheNotFoundError:
            print("No cache available")
            raise

    except Exception as e:
        print(f"Unexpected error: {e}")
        raise

Complete Usage Example

import asyncio
from datetime import UTC, datetime
from llm_discovery import DiscoveryClient
from llm_discovery.models.config import Config
from llm_discovery.services.exporters import JSONExporter
from llm_discovery.exceptions import (
    ProviderFetchError,
    CacheNotFoundError
)

async def main():
    # Load configuration
    config = Config.from_env()
    client = DiscoveryClient(config=config)

    # Fetch models from all providers
    try:
        models = await client.fetch_models()
        print(f"✓ Fetched {len(models)} models from APIs")
    except ProviderFetchError as e:
        print(f"✗ API fetch failed: {e}")
        # Fallback to cache
        try:
            models = client.get_cached_models()
            print(f"✓ Loaded {len(models)} models from cache")
        except CacheNotFoundError:
            print("✗ No cache available")
            return

    # Filter models by provider
    openai_models = [m for m in models if m.provider_name == "openai"]
    google_models = [m for m in models if m.provider_name == "google"]

    print(f"\nOpenAI models: {len(openai_models)}")
    print(f"Google models: {len(google_models)}")

    # Export to JSON
    exporter = JSONExporter()
    json_data = exporter.export(models)

    with open("models.json", "w") as f:
        f.write(json_data)
    print(f"\n✓ Exported to models.json")

    # Display recent models
    recent_models = sorted(
        models,
        key=lambda m: m.fetched_at,
        reverse=True
    )[:10]

    print("\nRecent models:")
    for model in recent_models:
        print(f"  {model.provider_name}/{model.model_id}: {model.model_name}")

if __name__ == "__main__":
    asyncio.run(main())

Next Steps

  • CLI Reference: See technical contract at specs/001-llm-model-discovery/contracts/cli-interface.md

  • Error Handling: See specs/001-llm-model-discovery/contracts/error-handling.md

  • Contributing: See CONTRIBUTING.md in the repository root