Astro Intelligence

LLM API Reference

LLM API Reference

The anchor.llm module provides a unified interface for multiple LLM providers. It defines the LLMProvider protocol, a BaseLLMProvider base class with retry logic, a provider registry with automatic routing, and structured data models for messages, responses, and errors.

All classes are importable from anchor.llm:

from anchor.llm import (
    LLMProvider, BaseLLMProvider,
    create_provider, register_provider,
    FallbackProvider,
    Message, Role, LLMResponse, StreamChunk, Usage, StopReason,
    ContentBlock, ToolCall, ToolCallDelta, ToolResult, ToolSchema,
    ProviderError, AuthenticationError, RateLimitError, ServerError,
    TimeoutError, ModelNotFoundError, ContentFilterError,
    ProviderNotInstalledError,
    MODEL_PRICING, calculate_cost,
)

LLMProvider (Protocol)

A runtime-checkable protocol that all LLM providers must satisfy. Use this as the type hint when accepting any provider.

@runtime_checkable
class LLMProvider(Protocol):
    @property
    def model_id(self) -> str: ...
    @property
    def provider_name(self) -> str: ...
    def invoke(self, messages, *, tools=None, max_tokens=None, temperature=None, stop=None, **kwargs) -> LLMResponse: ...
    def stream(self, messages, *, tools=None, max_tokens=None, temperature=None, stop=None, **kwargs) -> Iterator[StreamChunk]: ...
    async def ainvoke(self, messages, *, tools=None, max_tokens=None, temperature=None, stop=None, **kwargs) -> LLMResponse: ...
    def astream(self, messages, *, tools=None, max_tokens=None, temperature=None, stop=None, **kwargs) -> AsyncIterator[StreamChunk]: ...

Properties

PropertyTypeDescription
model_idstrFully qualified model identifier (e.g. "openai/gpt-4o")
provider_namestrProvider name (e.g. "anthropic", "openai")

Methods

invoke

def invoke(
    self,
    messages: list[Message],
    *,
    tools: list[ToolSchema] | None = None,
    max_tokens: int | None = None,
    temperature: float | None = None,
    stop: list[str] | None = None,
    **kwargs: Any,
) -> LLMResponse

Send messages and return a complete response synchronously.

stream

def stream(
    self,
    messages: list[Message],
    *,
    tools: list[ToolSchema] | None = None,
    max_tokens: int | None = None,
    temperature: float | None = None,
    stop: list[str] | None = None,
    **kwargs: Any,
) -> Iterator[StreamChunk]

Send messages and yield response chunks as they arrive.

ainvoke

async def ainvoke(
    self,
    messages: list[Message],
    *,
    tools: list[ToolSchema] | None = None,
    max_tokens: int | None = None,
    temperature: float | None = None,
    stop: list[str] | None = None,
    **kwargs: Any,
) -> LLMResponse

Async variant of invoke().

astream

def astream(
    self,
    messages: list[Message],
    *,
    tools: list[ToolSchema] | None = None,
    max_tokens: int | None = None,
    temperature: float | None = None,
    stop: list[str] | None = None,
    **kwargs: Any,
) -> AsyncIterator[StreamChunk]

Async variant of stream().

Common Parameters

ParameterTypeDefaultDescription
messageslist[Message]requiredConversation messages
toolslist[ToolSchema] | NoneNoneTool definitions available to the model
max_tokensint | NoneNoneMaximum tokens in the response
temperaturefloat | NoneNoneSampling temperature
stoplist[str] | NoneNoneStop sequences

BaseLLMProvider

Abstract base class that implements retry logic, error mapping, and the LLMProvider protocol. Subclass this to add a new provider.

Constructor

class BaseLLMProvider(ABC):
    def __init__(
        self,
        model: str,
        *,
        api_key: str | None = None,
        base_url: str | None = None,
        max_retries: int = 2,
        timeout: float = 60.0,
        **kwargs: Any,
    ) -> None

Parameters

ParameterTypeDefaultDescription
modelstrrequiredModel name within the provider
api_keystr | NoneNoneAPI key (resolved by _resolve_api_key if not set)
base_urlstr | NoneNoneOverride the provider's default base URL
max_retriesint2Number of retries on transient errors
timeoutfloat60.0Request timeout in seconds

Properties

PropertyTypeDescription
model_idstrReturns "{provider_name}/{model}"
provider_namestrSet by each subclass (e.g. "anthropic")

Public Methods

The public methods invoke, stream, ainvoke, and astream wrap the abstract _do_* methods with retry logic for transient errors.

Abstract Methods (for subclasses)

MethodDescription
_resolve_api_key() -> strResolve the API key from environment or config
_do_invoke(messages, **kwargs) -> LLMResponseProvider-specific invoke
_do_stream(messages, **kwargs) -> Iterator[StreamChunk]Provider-specific stream
_do_ainvoke(messages, **kwargs) -> LLMResponseProvider-specific async invoke
_do_astream(messages, **kwargs) -> AsyncIterator[StreamChunk]Provider-specific async stream

create_provider

Factory function that creates a provider from a "provider/model" string.

Signature

def create_provider(
    model: str,
    *,
    api_key: str | None = None,
    fallbacks: list[str] | None = None,
    **kwargs: Any,
) -> LLMProvider

Parameters

ParameterTypeDefaultDescription
modelstrrequiredProvider-prefixed model string (e.g. "openai/gpt-4o")
api_keystr | NoneNoneAPI key passed to the provider
fallbackslist[str] | NoneNoneFallback model strings; wraps result in FallbackProvider

A model string without a prefix defaults to "anthropic" for backward compatibility.

Example

from anchor.llm import create_provider

# Single provider
provider = create_provider("openai/gpt-4o")
response = provider.invoke(messages)

# With fallbacks
provider = create_provider(
    "anthropic/claude-sonnet-4-20250514",
    fallbacks=["openai/gpt-4o"],
)

register_provider

Register a custom provider class in the global registry.

Signature

def register_provider(name: str, cls: type[BaseLLMProvider]) -> None

Parameters

ParameterTypeDescription
namestrPrefix used in model strings (e.g. "mycloud")
clstype[BaseLLMProvider]Provider class to instantiate

Example

from anchor.llm import register_provider, BaseLLMProvider

class MyProvider(BaseLLMProvider):
    provider_name = "mycloud"
    ...

register_provider("mycloud", MyProvider)
provider = create_provider("mycloud/my-model")

FallbackProvider

Wraps a primary provider with one or more fallback providers. On transient errors, automatically retries with the next provider in the chain.

Constructor

class FallbackProvider:
    def __init__(
        self,
        primary: LLMProvider,
        fallbacks: list[LLMProvider],
    ) -> None

Parameters

ParameterTypeDescription
primaryLLMProviderThe preferred provider tried first
fallbackslist[LLMProvider]Providers tried in order on transient failure

Properties

PropertyTypeDescription
model_idstrDelegates to the primary provider
provider_namestrDelegates to the primary provider

Fallback Behavior

  • invoke / ainvoke: On a transient ProviderError, tries each fallback in order until one succeeds.
  • stream / astream: Fallback is attempted only before the first chunk is yielded. Mid-stream errors propagate to the caller.

Supported Providers

ProviderModel PrefixSDK PackageInstall Extra
Anthropicanthropic/anthropicpip install astro-anchor[anthropic]
OpenAIopenai/openaipip install astro-anchor[openai]
Google Geminigemini/google-genaipip install astro-anchor[gemini]
Grok (xAI)grok/openaipip install astro-anchor[openai]
Ollamaollama/ollamapip install astro-anchor[ollama]
OpenRouteropenrouter/openaipip install astro-anchor[openai]
LiteLLMlitellm/litellmpip install astro-anchor[litellm]

Data Models

All models are frozen Pydantic BaseModel instances unless otherwise noted.

Role

class Role(StrEnum):
    SYSTEM = "system"
    USER = "user"
    ASSISTANT = "assistant"
    TOOL = "tool"

Message

class Message(BaseModel):
    role: Role
    content: str | list[ContentBlock] | None = None
    tool_calls: list[ToolCall] | None = None
    tool_result: ToolResult | None = None
    name: str | None = None
FieldTypeDefaultDescription
roleRolerequiredMessage role
contentstr | list[ContentBlock] | NoneNoneText or multimodal content
tool_callslist[ToolCall] | NoneNoneTool calls requested by the assistant
tool_resultToolResult | NoneNoneResult of a tool invocation
namestr | NoneNoneOptional participant name

ContentBlock

class ContentBlock(BaseModel):
    type: str
    text: str | None = None
    image_url: str | None = None
    image_base64: str | None = None
    media_type: str | None = None

ToolCall

class ToolCall(BaseModel):
    id: str
    name: str
    arguments: dict

ToolCallDelta

class ToolCallDelta(BaseModel):
    index: int
    id: str | None = None
    name: str | None = None
    arguments_fragment: str | None = None

ToolResult

class ToolResult(BaseModel):
    tool_call_id: str
    content: str
    is_error: bool = False

ToolSchema

class ToolSchema(BaseModel):
    name: str
    description: str
    input_schema: dict

Usage

class Usage(BaseModel):
    prompt_tokens: int
    completion_tokens: int
    total_tokens: int
    total_cost: float | None = None

StopReason

class StopReason(StrEnum):
    STOP = "stop"
    MAX_TOKENS = "max_tokens"
    TOOL_USE = "tool_use"

LLMResponse

class LLMResponse(BaseModel):
    content: str | None = None
    tool_calls: list[ToolCall] | None = None
    usage: Usage | None = None
    model: str | None = None
    provider: str | None = None
    stop_reason: StopReason | None = None

StreamChunk

class StreamChunk(BaseModel):
    content: str | None = None
    tool_call_delta: ToolCallDelta | None = None
    usage: Usage | None = None
    stop_reason: StopReason | None = None

Pricing

MODEL_PRICING

A dictionary mapping model name patterns to per-token costs. Used by calculate_cost to estimate request costs.

calculate_cost

def calculate_cost(
    model: str,
    usage: Usage,
) -> float | None

Returns the estimated cost in USD for the given model and token usage, or None if the model is not in MODEL_PRICING.


Errors

All runtime provider errors inherit from ProviderError. Each error carries a provider string and an is_transient flag that controls retry behavior.

ProviderError

class ProviderError(Exception):
    provider: str
    is_transient: bool

Base class for all provider errors.

Error Subclasses

Erroris_transientDescription
AuthenticationErrorFalseInvalid or missing API key
RateLimitErrorTrueRate limit exceeded; has optional retry_after: float | None
ServerErrorTrueProvider returned a 5xx error
TimeoutErrorTrueRequest timed out
ModelNotFoundErrorFalseRequested model does not exist
ContentFilterErrorFalseContent blocked by the provider's safety filter

ProviderNotInstalledError

class ProviderNotInstalledError(Exception)

Raised at setup time when a required SDK package is not installed. This is not a subclass of ProviderError since it is a configuration issue, not a runtime error.


See Also

On this page