Providers¶
Stability: files, batches, standalone generation endpoints, stored-cache resources and live sessions are provisional in 1.0. They ship, but may change incompatibly in 1.x with a contract change entry; their presence on a provider class does not make them part of the frozen chat API. See release scope.
AnthropicLM
dataclass
¶
Bases: BaseProviderLM
Anthropic Messages dialect, bound to an access policy.
access defaults to the API-key policy (lm15.access.ANTHROPIC_API);
lm15.access.CLAUDE_CODE binds the same dialect to a local Claude
Code login (ClaudeCodeLM is that binding under a name). The policy
is consulted at exactly these points: the auth header, static headers
(anthropic-beta is joined with the dialect's own betas), the system
prefix, the login hint on errors, and the endpoint surfaces.
AsyncBaseProviderLM
¶
Shared asynchronous provider LM implementation.
Mirrors :class:BaseProviderLM faithfully: build (delegated, pure) ->
await async transport -> parse (delegated, pure); status>=400 raises the
delegated normalize_error; transport errors are wrapped in
lm15.TransportError. Streaming applies MAP-3 via
:func:lm15.result.acoalesce_stream.
access: ProviderManifest
property
¶
The bound access policy — the inner sync adapter's.
plan(request: Request)
¶
What a call WOULD adapt (MAP-13), no network, no credential; pure, so sync.
list_models()
async
¶
Async mirror of BaseProviderLM.list_models (canonical ModelInfo).
batch(requests, *, model: str | None = None, label: str | None = None, extensions=None)
async
¶
Third execution mode, async twin: returns an AsyncBatchJob.
AsyncOpenAIChatLM
dataclass
¶
Bases: AsyncBaseProviderLM
request_from_openai_chat(body: 'Mapping[str, Any]') -> Request
¶
Pure; the sync sibling's, under this adapter's compat (MAP-12).
response_from_openai_chat(body: 'Mapping[str, Any]', *, model: str | None = None, choice: int | None = None) -> Response
¶
Pure; the sync sibling's reader under this adapter's provider name.
complete(request: Request) -> Response
async
¶
Mirror of OpenAIChatLM.complete: the judgment trie driver (MAP-14 §4) over the inner adapter's pure hooks, else the ordinary path.
AsyncTransport
¶
Bases: Protocol
Minimal async transport surface used by async provider LMs.
stream returns an async context manager producing an
:class:AsyncTransportResponse (StdlibAsyncTransport's shape).
AsyncTypeSafeLM
dataclass
¶
Bases: AsyncBaseProviderLM
Async mirror of :class:TypeSafeLM (composition; the inner adapter
cannot reach the network).
AsyncXaiLM
dataclass
¶
BaseProviderLM
¶
Shared synchronous provider LM implementation.
An adapter is a dialect (the class) bound to an access policy (a value,
lm15.access): the policy says which credential travels in which
header, which static headers ride along, which endpoint surfaces this
access path carries, and which backend variant the dialect must switch
on. manifest is the class's default policy; access is the bound
one. Dialect code reads self.access at a small set of stated points
and never carries a subclass per access path.
supports: EndpointSupport
property
¶
The endpoint surfaces this bound access path carries.
has_stored_credential() -> bool
classmethod
¶
Offline probe for the router's oauth-unless-explicit chain
(spec/auth.md AUTH-1): is a usable login stored locally?
credential_origin() -> str
¶
Where this adapter's credential comes from, as a sentence fragment with no secret in it (AUTH-1 provenance). For a cloud chain provider this is the rung that last won, or what will be walked when no request has been sent yet.
plan(request: Request, *, policy: 'AdaptationPolicy | None' = None) -> 'tuple[Adaptation, ...]'
¶
What a call with this request WOULD adapt, with no network and no
credential invoked (like resolve(), offline). Raises what the
call would raise (a refusal under any policy, or every deviation
under adaptations="refuse"). Returns the full record under
every policy, "silent" included: a preview that hid what it saw
would be no preview.
image_generate(request: ImageGenerationRequest) -> ImageGenerationResponse
¶
Generate (or, with request.images, edit) images.
Input images are ordinary ImageParts; adapters route them to the
provider's real edit door (OpenAI: /images/edits; Gemini: the
same chat call; xAI: /images/edits) and raise where the wire
has none — never silently ignore them.
speech_generate(request: SpeechGenerationRequest) -> SpeechGenerationResponse
¶
Text-to-speech. Omitted voice/format mean the server's
defaults, honestly reported in the returned part's media_type —
lm15 injects no defaults of its own.
video_submit(request: VideoGenerationRequest) -> VideoJobInfo
¶
Submit a video job; returns the ticket snapshot.
video_result(video_id: str) -> VideoPart
¶
The finished video as a VideoPart, in the provider's own
delivery mode (URL or bytes) — no silent re-hosting, no silent
gigabyte download; part.bytes fetches URL results on demand.
Raises ValueError while the job runs.
video_list(limit: int = 20, model: str | None = None) -> 'tuple[VideoJobInfo, ...]'
¶
One page of this credential's video jobs. model is required
on Gemini (operations list per model), ignored on OpenAI; xAI has
no list endpoint at all and raises.
video_generate(request: VideoGenerationRequest) -> 'VideoJob'
¶
Submit and wrap the ticket in a VideoJob handle.
video_job(video_id: str) -> 'VideoJob'
¶
Re-attach to an existing job by id alone.
video_jobs(limit: int = 20, model: str | None = None) -> 'tuple[VideoJob, ...]'
¶
Enumerate this credential's video jobs, where the wire lists
them (OpenAI: account-wide; Gemini: per model, pass model).
xAI has no list endpoint and raises: the ticket you stored is
the only copy.
list_models() -> 'tuple[ModelInfo, ...]'
¶
Fetch the models this credential can use, as canonical ModelInfo.
batch_submit(request: BatchRequest) -> BatchJobInfo
¶
Submit to the provider's batch queue; returns the ticket snapshot.
batch_results(batch_id: str) -> 'tuple[BatchEntry, ...]'
¶
Entries in submission order; raises ValueError while the job runs.
batch_cancel(batch_id: str) -> BatchJobInfo
¶
Request cancellation — a request, not a guarantee.
batch_list(limit: int = 20) -> 'tuple[BatchJobInfo, ...]'
¶
Enumerate this credential's batch jobs, newest first.
The provider is the system of record; recovery from a lost id must never depend on the user having been careful.
batch(requests: 'BatchRequest | Sequence[Request]', *, model: str | None = None, label: str | None = None, extensions: 'dict[str, Any] | None' = None) -> 'BatchJob'
¶
Third execution mode: many requests, later, ~half price.
batch_job(batch_id: str) -> 'BatchJob'
¶
Re-attach to a submitted batch from its id (one status round trip).
batches(limit: int = 20) -> 'tuple[BatchJob, ...]'
¶
Lost the ticket? The queue remembers.
cache_create(prefix: Request, *, ttl_seconds: int | None = None, label: str | None = None) -> CacheInfo
¶
Store the prefix (model, system, tools, messages) as a cache object.
cache_delete(cache_id: str) -> None
¶
Returning without an exception IS the confirmation (the files precedent).
cache(prefix: Request, *, ttl_seconds: int | None = None, label: str | None = None) -> CachedPrefix
¶
Make a prompt beginning reusable with the best tier this provider has.
Resource tier: creates the stored object (one network call, billed
per hour while it lives) and returns it inside the CachedPrefix.
Marks and automatic tiers: pure — the CachedPrefix only records the
boundary; cached + messages places the mark or sends nothing.
file_upload(request: FileUploadRequest) -> FileInfo
¶
Store a file with the provider; returns its canonical snapshot.
FileInfo.id is the reference to place in a media Part's
file_id. On Gemini the file may come back pending
(processing); file_wait_ready covers that.
file_list(limit: int = 20, cursor: str | None = None) -> FilePage
¶
One page of this credential's stored files.
The provider is the system of record: a lost file id is recovered
by listing, never by client-side bookkeeping. cursor is the
opaque next_cursor of the previous page.
file_delete(file_id: str) -> None
¶
Delete a stored file. Returning without an exception IS the confirmation; provider acknowledgement bodies differ and carry no canonical information.
file_download(file_id: str) -> bytes
¶
Download a file's content, when THIS file supports download.
Every provider restricts which files are downloadable (Anthropic: tool-generated only; OpenAI: by purpose; Gemini: generated only) and refuses the rest with a typed error — forwarded, not masked.
file_wait_ready(file_id: str, poll_every: float = 2.0, timeout: float | None = None) -> FileInfo
¶
Poll until the file leaves pending; returns the terminal
snapshot (ready or failed) — check readiness, mirroring
BatchJob.wait's return-don't-raise convention. Gemini uploads and
Azure OpenAI v1 uploads can be pending; the first poll usually returns.
HttpResponse
dataclass
¶
Buffered provider-level HTTP response.
The stdlib transport is streaming-first. LMs that implement ordinary request/response endpoints buffer the body into this small value object so their parsing code can stay pure and easy to test.
json()
¶
The body as JSON. A body that is not JSON — a gateway's HTML
error page behind a 200, a truncated reply, a captive portal — is
a provider reply that cannot become a Response without inventing
one, so it raises :class:ProviderError (ErrorCode provider)
carrying the status and the first bytes of what arrived. A raw
JSONDecodeError would escape every except LM15Error and
say nothing about who sent what.
SyncTransport
¶
Bases: Protocol
Minimal sync transport surface used by provider LMs.
ClaudeCodeLM
¶
GeminiLM
dataclass
¶
Bases: BaseProviderLM
OpenAILM
dataclass
¶
Bases: BaseProviderLM
OpenAI Responses dialect, bound to an access policy.
access defaults to the API-key policy (lm15.access.OPENAI_API);
lm15.access.OPENAI_CODEX binds the same dialect to the ChatGPT Codex
backend on a local Codex CLI login (OpenAICodexLM is that binding
under a name). Policy consult points: the auth header and static
headers, the chatgpt-account-id header when the credential carries
an account, the login hint on errors, the endpoint surfaces, and the
backend switch at four stated places — payload defaults
(instructions prefix, store: false, streaming-only, no max-token
knob), streaming-first complete, the {"detail": ...} error
envelope, and the /models endpoint shape.
from_profile(*, api_key: Credential, profile: ProviderProfile, transport: SyncTransport | None = None) -> 'OpenAILM'
classmethod
¶
DEPRECATED (1.0.0rc2; removed in 1.0.0): OpenAILM(api_key=..., compat=..., base_url=...).
normalize_error(status: int, body: str) -> ProviderError
¶
Extract message from OpenAI error shape.
OpenAIChatLM
dataclass
¶
Bases: BaseProviderLM
Adapter for the OpenAI Chat Completions wire dialect.
compat may be an :class:OpenAIChatCompat, a preset name
("ollama", "groq", "openrouter", "vllm", "sglang",
"openai", …), or None (plain OpenAI policy). A preset name also
supplies that server's default base_url; an explicit non-default
base_url argument always wins.
request_from_openai_chat(body: Mapping[str, Any]) -> Request
¶
The inverse of :meth:build_request's body under this adapter's
compat (MAP-12): a Chat Completions request body → canonical
:class:Request. See :func:request_from_openai_chat.
response_from_openai_chat(body: Mapping[str, Any], *, model: str | None = None, choice: int | None = None, response_format: Mapping[str, Any] | None = None) -> Response
¶
A Chat Completions response body → canonical :class:Response
under this adapter's provider name and error mapping; see
:func:response_from_openai_chat. response_format (the
request's) folds a judgment answer into a DataPart (MAP-14).
TypeSafeLM
dataclass
¶
XaiLM
¶
Bases: OpenAIChatLM
Chat Completions adapter for xAI, with subscription OAuth fallback.
xAI is a provider, not an access path: its image and video wire, and
its refusals (reasoning off, logprobs, the MAP-8 cells), are provider
facts and live here. Only the credential path is composed: the
lm15.access.XAI policy carries the oauth-unless-explicit chain,
the login hint, and the endpoint surfaces.
resolve_credential(credential: Credential) -> str
¶
The bearer/key STRING of a credential — the pre-2026-09-03 shape the
dialects' header code reads. AWS credentials have no single string;
they travel as a SigV4 signature (_emit), never through here.