v2.25.0 — structured outputs + multi-modality profiles
Esperanto v2.25.0 — structured outputs everywhere, and OpenAI-compatible profiles that span every modality. Validated with the mocked canonical suite (1468 tests) and a clean-room build + install gate.
✨ New features
- Schema-driven structured outputs across all LLM providers. Set
config={"structured": {"type": "json_schema", "schema": MyPydanticModel}}(or a
JSON Schema dict) and read the parsed, validated result fromresponse.structured.
Works consistently across OpenAI, Azure, OpenAI-compatible, Google (Gemini), Vertex,
Anthropic, Groq, Mistral, Ollama, OpenRouter, Perplexity, and Cohere. Each choice
carries its own parsed value (choices[i].message.structured), son>1works.
Schema mode is non-streaming in v1, and providers that can't honor ajson_schema
request fail fast with a clear error. (#95) - Multi-modality OpenAI-compatible profiles. A registered
OpenAICompatibleProfilecan now serveembedding,speech_to_text, and
text_to_speechin addition tolanguage, via an opt-incapabilitiesfield and
per-modalitydefault_models. All four factories resolve profiles through one shared
precedence chain. Requesting an undeclared modality raises the new typed
ProviderCapabilityError(unless a first-class class of the same name covers it —
hybrid providers keep working). New base exceptionEsperantoError. (#230) requires_api_keyflag for local/no-auth endpoints. A profile can now tolerate a
missing API key (falls back to"not-required"instead of raising) — for local
servers that need no auth. (#228)
🔌 New providers
- PayPerQ (PPQ) — a pay-as-you-go gateway across LLM + embedding + STT + TTS through
one OpenAI-compatible endpoint.AIFactory.create_language("ppq", ...)(and the other
three factories) withPPQ_API_KEY. (#238) - Novita AI — pay-as-you-go gateway to many open-source models.
AIFactory.create_language("novita", "moonshotai/kimi-k2.5")withNOVITA_API_KEY. (#120) - OpenRouter text-to-speech and speech-to-text — rounds out OpenRouter to LLM + TTS +
STT. (#224) - oMLX — built-in profile for the local oMLX MLX
server on Apple Silicon (language + embedding, no API key). (#228)
⚠️ Deprecations (back-compat kept)
OpenAICompatibleProfile(default_model=...)→ use
default_models={"language": ...}. The old field still works as a language alias and
now emits aDeprecationWarning. No action required to keep current code working.
🙏 Thanks
- @JTCorrin — schema-driven structured outputs across all providers (#95)
- @kumar-shivang — OpenRouter TTS + STT providers (#224)
- @Alex-yang00 — Novita AI provider (#120)
- @mattius459 — PayPerQ provider (#238)
- @ukalia — pre-commit config with ruff + mypy hooks (#213)
And thanks to everyone who opened issues and drove the profile-mechanism design.
Full details in the CHANGELOG.
Install: pip install esperanto==2.25.0 (extras: esperanto[openai,anthropic,...]).