Typed LLM settings, LangChain-first factories, LiteLLM metadata enrichment, and callback helpers.
Project description
ooai-llm
Typed LLM settings, provider-aware model-string parsing, LangChain-first chat model creation, live provider model discovery, LiteLLM pricing enrichment, and usage/cost callback helpers for Python applications.
What This Is
ooai-llm is a small integration layer for application code that already wants
to use LangChain model classes directly, but does not want to repeat the same
provider configuration, model defaults, env-var handling, cache setup, metadata
lookup, and usage accounting in every project.
It is not a router, proxy, agent framework, or hosted model catalog.
Features
- Typed
ModelStringparsing for bare, LangChain-style, and LiteLLM-style model names. - Provider inference for OpenAI, Anthropic, Google GenAI, xAI, DeepSeek, and Mistral.
AppSettingswith provider credentials, default aliases, provider presets, cache settings, catalog settings, and LiteLLM settings.- Native and app-prefixed credential env vars, such as
OPENAI_API_KEYandOOAI_OPENAI_API_KEY. - LangChain global cache bootstrap for SQLite, memory, SQLAlchemy, Redis, and Upstash Redis.
create_llm(...), a thin wrapper around LangChaininit_chat_model(...).create_llm_bundle(...), which returns the model, resolved metadata, and reasoning resolution together.- Live model listing through provider SDKs or REST fallbacks.
- Provider-generic default refresh from live model catalogs or LiteLLM metadata.
- Opt-in automatic factory refresh so aliases such as
latestcan update at runtime. - LangChain profile + LiteLLM pricing metadata in one
ModelInfoobject. - Provider-aware reasoning kwargs for OpenAI, Anthropic, Gemini, xAI, DeepSeek, and Mistral.
- Usage and cost helpers for LangChain metadata and LiteLLM callbacks.
- Unit, integration, e2e, live-provider tests, coverage reports, docs builds, package builds, and PyPI release workflow.
Installation
Base package:
pip install ooai-llm
With PDM:
pdm add ooai-llm
Install only the provider extras you use:
pdm add ooai-llm[openai]
pdm add ooai-llm[anthropic]
pdm add ooai-llm[deepseek]
pdm add ooai-llm[mistral]
pdm add ooai-llm[litellm]
pdm add ooai-llm[redis]
pdm add ooai-llm[upstash]
pdm add ooai-llm[caches]
Gemini and xAI are available as ooai-llm[google] and ooai-llm[xai], but you
can skip those extras entirely if you do not have those keys.
Factory Quick Start
from ooai_llm import AppSettings, configure_global_llm_cache, create_llm
settings = AppSettings()
configure_global_llm_cache(settings)
llm = create_llm(
alias="testing",
settings=settings,
temperature=0,
reasoning="fast",
)
print(type(llm).__name__)
Most applications only need the factory plus settings:
from ooai_llm import AppSettings, create_llm
settings = AppSettings()
testing_llm = create_llm(alias="testing", settings=settings, temperature=0)
reasoning_llm = create_llm(provider="anthropic", preset="reasoning", settings=settings)
explicit_llm = create_llm("openai:gpt-5.4-mini", settings=settings)
Use create_llm_bundle(...) when you want the created model and resolved
metadata together:
from ooai_llm import create_llm_bundle
bundle = create_llm_bundle(
alias="testing",
reasoning="fast",
temperature=0,
)
print(bundle.model.as_langchain())
print(bundle.metadata.identity.litellm_model)
print(bundle.reasoning.constructor_kwargs if bundle.reasoning else None)
Environment
The package accepts both native provider variables and OOAI_ aliases:
export OPENAI_API_KEY="..."
export ANTHROPIC_API_KEY="..."
export DEEPSEEK_API_KEY="..."
export MISTRAL_API_KEY="..."
export OOAI_OPENAI_API_KEY="..."
export OOAI_ANTHROPIC_API_KEY="..."
export OOAI_DEEPSEEK_API_KEY="..."
export OOAI_MISTRAL_API_KEY="..."
Google/Gemini and xAI variables are supported too, but are optional:
export GOOGLE_API_KEY="..."
export GEMINI_API_KEY="..."
export XAI_API_KEY="..."
Model Strings
from ooai_llm import ModelString
model = ModelString.parse("gpt-5.4-mini")
print(model.provider) # Provider.OPENAI
print(model.model_name) # gpt-5.4-mini
print(model.canonical()) # openai:gpt-5.4-mini
print(model.as_litellm()) # openai/gpt-5.4-mini
Settings And Defaults
from ooai_llm import AppSettings
settings = AppSettings()
print(settings.resolve_model(alias="cheap"))
print(settings.resolve_model(provider="anthropic", preset="reasoning"))
print(settings.default_llm_cache_path)
Default aliases and provider presets include:
defaultlatestcheaptestingfastbalancedreasoningcodingvision
Live Model Discovery
from ooai_llm import AppSettings, ListModelsConfig, list_available_models
settings = AppSettings()
result = list_available_models(
"openai",
settings=settings,
config=ListModelsConfig(limit=5),
)
for model in result.models:
print(model.model_string, model.display_name)
Provider SDKs are preferred when installed. Supported REST fallbacks are used
when SDK listing is unavailable or when you pass ListModelsConfig(prefer_sdk=False).
Refresh convenience factory defaults once at startup when you want aliases and provider presets to follow newer models:
from ooai_llm import AppSettings, refresh_model_defaults
settings = AppSettings()
refresh = refresh_model_defaults(
settings,
providers=["openai", "anthropic", "mistral"],
source="auto",
)
settings = refresh.settings
print(settings.resolve_model(alias="latest"))
print(settings.resolve_model(provider="anthropic", preset="reasoning"))
Use update_model_defaults(...) when you want the refreshed settings plus a
reusable override payload:
from ooai_llm import AppSettings, create_llm, update_model_defaults
update = update_model_defaults(
AppSettings(),
providers=["openai", "anthropic", "mistral"],
source="litellm",
output_format="env",
)
settings = update.settings
llm = create_llm(alias="latest", settings=settings)
print(update.output_text)
Or use the CLI to print or write those overrides:
ooai-llm models update --source litellm --providers openai,anthropic,mistral --format json
ooai-llm models update --source auto --provider openai --format env --output .env.models
Use source="litellm" to derive defaults from LiteLLM's local model registry
without provider-listing credentials. Use source="provider" for live provider
catalogs only.
Automatic refresh is opt-in for factory calls. Use this when you want
create_llm(...) to refresh convenience defaults before resolving aliases:
from ooai_llm import AppSettings, create_llm
settings = AppSettings(
llm={
"auto_refresh_models": {
"enabled": True,
"source": "litellm",
"providers": ["openai", "anthropic", "mistral"],
}
}
)
llm = create_llm(alias="latest", settings=settings)
The same setting can be enabled from .env:
OOAI_LLM__AUTO_REFRESH_MODELS__ENABLED=true
OOAI_LLM__AUTO_REFRESH_MODELS__SOURCE=litellm
OOAI_LLM__AUTO_REFRESH_MODELS__PROVIDERS='["openai","anthropic","mistral"]'
Automatic refresh uses a one-hour process-local cache by default. Set
OOAI_LLM__AUTO_REFRESH_MODELS__CACHE_SECONDS=0 to refresh on every factory
call, or pass force_model_refresh=True for one call.
Reasoning
from ooai_llm import ReasoningConfig, build_reasoning_resolution, create_llm
resolution = build_reasoning_resolution(
model="openai:gpt-5.4-mini",
reasoning="deep",
)
print(resolution.constructor_kwargs)
llm = create_llm(
"anthropic:claude-sonnet-4-20250514",
reasoning=ReasoningConfig(effort="medium", summary="auto"),
)
Metadata And Usage
from ooai_llm import BudgetPolicy, UsageRecorder, create_llm_bundle, make_litellm_cost_callback
bundle = create_llm_bundle(
"openai:gpt-5.4-mini",
reasoning="fast",
)
print(bundle.metadata.identity.litellm_model)
print(bundle.metadata.capabilities.raw_profile)
print(bundle.metadata.pricing.input_cost_per_token)
recorder = UsageRecorder()
callback = make_litellm_cost_callback(
recorder,
budget=BudgetPolicy(warn_total_tokens=5000),
)
Cache Bootstrap
from ooai_llm import AppSettings, configure_global_llm_cache
settings = AppSettings()
cache = configure_global_llm_cache(settings)
print(cache)
By default the SQLite cache is placed under:
{app_root}/.ooai/cache/llm/langchain_llm_cache.sqlite3
Override it with OOAI_LLM__CACHE__PATH or AppSettings(llm={"cache": {"path": ...}}).
Use Redis or Upstash Redis for a shared application cache:
settings = AppSettings(
llm={
"cache": {
"backend": "redis",
"redis_url": "redis://localhost:6379/0",
"ttl": 3600,
}
}
)
configure_global_llm_cache(settings)
settings = AppSettings(
llm={
"cache": {
"backend": "upstash_redis",
"upstash_url": "...",
"upstash_token": "...",
"ttl": 3600,
}
}
)
configure_global_llm_cache(settings)
Development
Install the development dependencies:
pdm install -G test -G docs -G dev
Run the full checked suite with coverage:
pdm run pytest
Live provider tests are skipped by the default suite so local keys in .env
do not trigger network calls accidentally.
Run tiers directly without the global coverage gate:
pdm run pytest -m unit --no-cov
pdm run pytest -m integration --no-cov
pdm run pytest -m "e2e and not live" --no-cov
Run live provider tests for your configured providers. This skips Gemini and xAI:
OOAI_LIVE_PROVIDERS=openai,anthropic,deepseek,mistral pdm run pytest -m live --no-cov
To make live e2e fail instead of skip when a selected provider is missing a key or SDK package:
OOAI_REQUIRE_LIVE=true OOAI_LIVE_PROVIDERS=openai,anthropic,deepseek,mistral pdm run pytest -m live --no-cov
AppSettings loads a local .env file. Keep real keys in .env, not
.env.example.
Build docs and distributions:
pdm run sphinx-build -E -W --keep-going -b html docs docs/_build/html
pdm build
pdm run twine check dist/*
Project Layout
src/ooai_llm/
cache.py LangChain cache setup
callbacks.py usage and cost events
catalog.py live provider model listing
factory.py LangChain chat-model creation
messages.py message normalization
metadata.py LangChain + LiteLLM metadata
providers.py provider normalization
reasoning.py provider reasoning kwargs
settings.py Pydantic settings
types.py ModelString
docs/ Sphinx + MyST docs
examples/ runnable examples
tests/ unit, integration, e2e, and live tests
Publishing
The repository includes:
.github/workflows/ci.ymlfor tests, coverage, docs build, and package build.github/workflows/docs.ymlfor standalone docs validation.github/workflows/release.ymlfor tagged PyPI releases with trusted publishing.readthedocs.yamlfor Read the Docs builds
Before publishing, configure the PyPI trusted publisher for release.yml and
environment pypi, import the repo in Read the Docs, and update
docs/changelog.md.
License
MIT
Project details
Release history Release notifications | RSS feed
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 ooai_llm-0.3.1.tar.gz.
File metadata
- Download URL: ooai_llm-0.3.1.tar.gz
- Upload date:
- Size: 64.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54c911fdffbbb04af2d973a7c94162122ab6d075ff0131409406a93da423af00
|
|
| MD5 |
3c0b56067502f4282bd4e925a4c5d76c
|
|
| BLAKE2b-256 |
cbf7150f7e9e48eeb4456e938fd75b197e465ffaae3394b60874ab7704812be4
|
Provenance
The following attestation bundles were made for ooai_llm-0.3.1.tar.gz:
Publisher:
release.yml on pr1m8/ooai-llm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ooai_llm-0.3.1.tar.gz -
Subject digest:
54c911fdffbbb04af2d973a7c94162122ab6d075ff0131409406a93da423af00 - Sigstore transparency entry: 1398177824
- Sigstore integration time:
-
Permalink:
pr1m8/ooai-llm@d8b74fbb5c739bafc86f70927252b51a488ff01b -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/pr1m8
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d8b74fbb5c739bafc86f70927252b51a488ff01b -
Trigger Event:
push
-
Statement type:
File details
Details for the file ooai_llm-0.3.1-py3-none-any.whl.
File metadata
- Download URL: ooai_llm-0.3.1-py3-none-any.whl
- Upload date:
- Size: 52.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60391fa009fd29041f8ec71fe1db0b39fd5c9f8d3017abb37565ad93638991fb
|
|
| MD5 |
e1e05144f082fb87e2e093b53edc624a
|
|
| BLAKE2b-256 |
7bcdce69a8d5cc6f552785b54fd60f39897706b3854016641462ffd3556e528a
|
Provenance
The following attestation bundles were made for ooai_llm-0.3.1-py3-none-any.whl:
Publisher:
release.yml on pr1m8/ooai-llm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ooai_llm-0.3.1-py3-none-any.whl -
Subject digest:
60391fa009fd29041f8ec71fe1db0b39fd5c9f8d3017abb37565ad93638991fb - Sigstore transparency entry: 1398177834
- Sigstore integration time:
-
Permalink:
pr1m8/ooai-llm@d8b74fbb5c739bafc86f70927252b51a488ff01b -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/pr1m8
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d8b74fbb5c739bafc86f70927252b51a488ff01b -
Trigger Event:
push
-
Statement type: