dr-providers
Typed LLM provider-call kernel for OpenRouter, OpenAI, Gemini, and Anthropic: one Provider Call Config, Request, Transport Policy, and no-throw Transport Outcome vocabulary across providers. Requires Python 3.12+.
Ecosystem
dr-providers is the typed LLM-provider HTTP transport kernel, with an
optional [serve] FastAPI facade for localhost HTTP callers. It builds
Provider Call Definition, Config, and Request Identity Documents — each
carrying its own full 64-char SHA-256 Identity Hash — through
dr-serialize. Its neighboring repos are dr-serialize, dr-graph,
dr-platform, dr-code, whetstone-ai, and unitbench. Whetstone-ai /
dr-platform, dr-graph's graph runner, and unitbench playgrounds are
consumers.
The vocabulary sheet
(source: .defs/vocab.html) is the authoritative statement of the
provider-call transport contract this repo implements: the terms, the
guarantees, what is in and out of scope, and the mapping from each term
to the exported names.
Install
pip install dr-providers
Or with uv:
uv add dr-providers
Authentication
Set the API key env var for whichever provider(s) you call:
export OPENROUTER_API_KEY="sk-or-..."
export OPENAI_API_KEY="sk-..."
export GEMINI_API_KEY="..."
export ANTHROPIC_API_KEY="sk-ant-..."
Quickstart
from dr_providers import (
ApiKeyEnv,
GenerationControls,
HttpProvider,
MessageRole,
ProviderBaseUrl,
ProviderCallRequest,
ProviderTransportPolicy,
ProviderTransportResponse,
PromptMessage,
ReasoningEffort,
Transcript,
openrouter_chat_config,
)
# A Provider Call Config is a complete validated assignment of one
# Provider Call Definition; it carries a full SHA-256 Identity Hash.
config = openrouter_chat_config(
model="openai/gpt-4o-mini",
controls=GenerationControls(reasoning=ReasoningEffort.LOW),
)
# A Provider Call Request is one Config reference + one Transcript.
request = ProviderCallRequest(
config=config,
transcript=Transcript(
messages=(
PromptMessage(
role=MessageRole.USER, content="Say hello in one word."
),
)
),
)
# Transport policy (credentials, base URL, timeout, native retry) is
# separate and excluded from identity. Native retry defaults to zero.
policy = ProviderTransportPolicy(
api_key_env=str(ApiKeyEnv.OPENROUTER),
base_url=str(ProviderBaseUrl.OPENROUTER),
)
with HttpProvider(policy=policy) as provider:
outcome = provider.complete(request) # no-throw typed outcome
if isinstance(outcome, ProviderTransportResponse):
print(outcome.text)
complete returns a closed no-throw Provider Transport Outcome
(ProviderTransportResponse | ProviderTransportFailure); expected
outcomes never raise. invoke instead returns a stable
ProviderInvocationEvidence artifact binding the request + policy
identities to the outcome and the complete least-processed raw request
and success/failure bodies (authorization headers and credentials are
never persisted).
HttpProvider is a context manager. In the default (owned) mode each
wire call runs on its own short-lived httpx.Client and daemon thread
under a per-invocation wall-clock deadline, so one call's deadline breach
tears down only that call's connection pool and never disturbs another.
If you inject your own client it is shared and left open for you to
manage; the transport cannot forcibly cancel a wedged call on a
caller-owned sync client (see the HttpProvider docstring).
Provider matrix
Presets in dr_providers.config build a Provider Call Definition and
materialize its Config, fixing each provider's Model Route
(provider, protocol, model), the token-limit parameter, and the
reasoning wire shape. Base URL and API key env var live on the separate
ProviderTransportPolicy; policy_for(kind, ...) derives them from the
DEFAULT_BASE_URLS / DEFAULT_API_KEY_ENVS per-provider maps (both in
dr_providers.policy), each overridable:
| Preset | Provider | Protocol | Reasoning wire shape |
|---|---|---|---|
openrouter_chat_config |
openrouter |
chat_completions |
reasoning: {"effort": ...} object |
openai_chat_config |
openai |
chat_completions |
reasoning_effort: ... field |
openai_responses_config |
openai |
responses |
reasoning: {"effort": ...} object |
gemini_chat_config |
gemini |
chat_completions |
reasoning_effort: ... field (OpenAI-compat endpoint) |
anthropic_messages_config |
anthropic |
anthropic_messages |
output_config: {"effort": ...} object |
Both the OpenAI-compatible / OpenRouter chat_completions path and the
Anthropic anthropic_messages path are first-class, each usable with a
custom base URL via the transport policy.
ReasoningEffort is a shared enum (NONE, MINIMAL, LOW, MEDIUM,
HIGH, XHIGH); each Definition's reasoning_shape constraint
determines how build_payload() serializes it on the wire. Anthropic
Messages accepts only low/medium/high, so NONE, MINIMAL, and
XHIGH are rejected with a ControlValidationError rather than silently
coerced. Anthropic also requires max_tokens, so anthropic_messages_config
marks TOKEN_LIMIT a required control (the CLI and serve facade default it
to 4096 when unset).
OpenAI Responses bodies are normalized from wire output[] parts into
text, typed no-text failures, and content-free diagnostics
(ResponsesDiagnostics). See the vocabulary sheet
for the authoritative per-name mapping of the parse/diagnostic surface.
Testing with ScriptedProvider
ScriptedProvider implements the same Provider interface as
HttpProvider but scripts outcomes with no network:
from dr_providers import ScriptedOutcome, ScriptedProvider
provider = ScriptedProvider([ScriptedOutcome(text="scripted reply")])
outcome = provider.complete(request)
assert outcome.text == "scripted reply"
Public API
Import stable symbols from the top-level package:
from dr_providers import (
ProviderCallConfig,
ProviderCallRequest,
ProviderTransportPolicy,
HttpProvider,
ReasoningEffort,
)
dr_providers.__all__ is the authoritative export list; the
vocabulary sheet
maps every one of those names to the contract term it implements, so
this README does not repeat the per-name detail. HttpProvider loads
lazily so importing the pure modules (route, controls, config, request,
response, outcome, policy, evidence) never pulls in httpx.
CLI
The [cli] extra installs a typer CLI, exposed as the dr-providers
console script, for one-shot provider calls:
pip install 'dr-providers[cli]'
dr-providers --provider openrouter --model openai/gpt-4o-mini -m "Say hello."
The console script is always installed, but the CLI itself requires the
[cli] extra; running it without that extra prints an install hint and
exits nonzero.
Serve facade
An optional FastAPI facade (the [serve] extra) exposes the kernel
over HTTP for non-Python callers:
uv run python -m dr_providers.serve serve
Release notes live in the changelog; note that 0.2.0 is a complete rewrite with no API compatibility with the 0.1.x query client.
Development
uv sync --frozen
uv run pre-commit install
uv run pre-commit run --all-files
Live verification matrix
The default uv run pytest run is fully offline (addopts = "-m 'not live'"). A live-marked matrix in tests/live/test_live_matrix.py
exercises the five presets against real provider endpoints:
uv run pytest -m live
Each case skips (not fails) when its API key env var
(OPENROUTER_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY,
ANTHROPIC_API_KEY) is unset, so this is safe to run without every
provider configured. Successful calls overwrite
data/wire-corpus/<provider>_<protocol>.json with the raw response
body; tests/test_wire_corpus.py re-parses those bodies offline on
every normal run.
Audit corpus ground truth
This repo includes a small audit-output corpus and curated ground-truth
normalization artifacts under data/audit-corpus/. Regenerate the parsed audit
and analysis files with:
uv run python scripts/generate_audit_ground_truth.py \
--corpus-dir data/audit-corpus \
--output-dir data/audit-corpus/ground-truth
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dr_providers-0.2.1.tar.gz.
File metadata
- Download URL: dr_providers-0.2.1.tar.gz
- Upload date:
- Size: 39.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75c467cb2a55c3c08f898210b0e850ab38e8e106ebd2f71def7e837534ac2f78
|
|
| MD5 |
087d792a6d08f0458c86923ae829c965
|
|
| BLAKE2b-256 |
ccd7135cdac222dbe6832f1c3db0c3bd5223f0505dc90542db3602f672813c32
|
Provenance
The following attestation bundles were made for dr_providers-0.2.1.tar.gz:
Publisher:
release.yaml on danielle-rothermel/dr-providers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dr_providers-0.2.1.tar.gz -
Subject digest:
75c467cb2a55c3c08f898210b0e850ab38e8e106ebd2f71def7e837534ac2f78 - Sigstore transparency entry: 2342944781
- Sigstore integration time:
-
Permalink:
danielle-rothermel/dr-providers@58382ce919d90b6ea2582cc620092c5d30270953 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/danielle-rothermel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
self-hosted -
Publication workflow:
release.yaml@58382ce919d90b6ea2582cc620092c5d30270953 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dr_providers-0.2.1-py3-none-any.whl.
File metadata
- Download URL: dr_providers-0.2.1-py3-none-any.whl
- Upload date:
- Size: 52.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16cb17eff0aa59583a08e483560b1419626e99b0366c838f01e061b3a474db60
|
|
| MD5 |
0945adca2f22d5e6f3eef5505a9e951d
|
|
| BLAKE2b-256 |
78b51eced6614663d125d1c6a1854e7b068d1b23136da5647746f12319945171
|
Provenance
The following attestation bundles were made for dr_providers-0.2.1-py3-none-any.whl:
Publisher:
release.yaml on danielle-rothermel/dr-providers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dr_providers-0.2.1-py3-none-any.whl -
Subject digest:
16cb17eff0aa59583a08e483560b1419626e99b0366c838f01e061b3a474db60 - Sigstore transparency entry: 2342944801
- Sigstore integration time:
-
Permalink:
danielle-rothermel/dr-providers@58382ce919d90b6ea2582cc620092c5d30270953 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/danielle-rothermel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
self-hosted -
Publication workflow:
release.yaml@58382ce919d90b6ea2582cc620092c5d30270953 -
Trigger Event:
push
-
Statement type: