Skip to content

v2.26.0 — Provider swaps that actually swap

Latest

Choose a tag to compare

@lfnovo lfnovo released this 30 Jul 01:34
81cb450

Embeddings stop breaking when you swap providers — and three first-class providers stop shipping a default model that no longer exists. Validated with the canonical suite (1633 tests) plus the real-API release tests across OpenAI, Anthropic, Google, Groq, Mistral, Cohere, Azure, Jina, Voyage, OpenRouter and ElevenLabs.

✨ New features

Automatic embedding batching across all providers (#108, #203)

embed() / aembed() now transparently split large inputs into requests that respect each provider's per-request limit, then concatenate the results in input order. A list of 500 texts that worked on OpenAI no longer fails after switching to Vertex — the same code just works, which is the whole point of the library.

Ceilings applied automatically:

Provider Ceiling
OpenAI · Azure · OpenAI-compatible · Jina 2048
Voyage 1000
Cohere · OpenRouter 96
Mistral 64
Google 250
Vertex 25 (conservative — :predict also caps at 20k tokens)
Ollama unbatched (single request)
transformers keeps its own internal batching

Lower it per model with config={"embed_batch_size": N} — values above the provider maximum are clamped, N <= 0 raises ValueError. embed([]) makes zero API calls.

⚡ Performance

Google and Vertex batch natively (#203). Both previously issued one HTTP call per text. They now use the native :batchEmbedContents (Google) and multi-instance :predict (Vertex) endpoints — a large speedup on big inputs.

🐛 Notable fixes

Three providers were defaulting to withdrawn models (#272, #274)

Google withdrew gemini-2.0-flash and Anthropic withdrew the entire claude-3 family. Those were the default models for google, vertex and anthropic, so this failed outright:

AIFactory.create_language("google")      # This model is no longer available
AIFactory.create_language("anthropic")   # model: claude-3-7-sonnet-20250219

Model discovery was recommending them too. Defaults are now gemini-2.5-flash and claude-sonnet-5, the hardcoded lists carry the current families, and the docs stop pointing at ghosts. Tests now pin the defaults and assert no withdrawn family appears in any list — so the next withdrawal fails a test instead of reaching users.

Schema-driven structured output was broken on OpenAI and Anthropic (#273)

structured={"type": "json_schema", "schema": MyModel} was rejected before the request ran. OpenAI's strict mode requires additionalProperties: false on every object; Anthropic's output_config requires the same; Pydantic emits neither. Schemas are now normalized recursively (nested models under $defs included) on a copy, so your own dict is never mutated.

Where a schema has optional fields — which strict mode forbids outright, since it also demands every property be required — the request is sent with strict: false rather than silently promoting your optional fields to required. The response is still validated against the schema locally.

Every non-Whisper OpenAI and Azure transcription model now works (#269, #263)

Both providers requested response_format=verbose_json for anything that didn't match a narrow gpt-4o-*-transcribe name shape — Azure hardcoded it. But verbose_json is Whisper-only, so gpt-transcribe, gpt-4o-transcribe-diarize and every Azure gpt-4o-*-transcribe deployment failed before transcription started. In practice whisper-1 was the only OpenAI STT model that worked.

The check is now an allowlist: Whisper gets verbose_json, anything unrecognized degrades to jsonsegments and duration come back None instead of the call hard-failing, so a new model arrives working rather than broken. On Azure, where deployment names are user-chosen and may not reveal the model, config={"response_format": "verbose_json"} forces it.

to_langchain() forwards a custom base URL for Google (#248). Converting a Gemini model configured with GEMINI_API_BASE_URL previously reconnected to the official endpoint. Completes the audit started in #229.

⚠️ Breaking changes & deprecations

No API breaks. Three behavior changes worth knowing when you upgrade:

  1. gemini-2.5-flash is a thinking model. Its reasoning tokens come from the same budget as the answer, so a tight max_tokens (under a few hundred) can now truncate output where gemini-2.0-flash fit comfortably. Raise the budget, or pass an explicit model_name.

  2. claude-sonnet-5 is an undated alias. It tracks Anthropic's current Sonnet 5 release rather than staying fixed, so the default's behavior can shift without Esperanto publishing anything. Pass a dated id (e.g. claude-sonnet-4-5-20250929) when you need it pinned.

  3. Non-Whisper STT models return segments=None and duration=None instead of raising. If your code assumed segments were always present, that path was previously only reachable via Whisper — but it's worth a null check.

🔍 Not verified in this cycle

Stated plainly rather than implied: Vertex could not be exercised against the live API — no Google Cloud project was configured in the release environment, so Vertex LLM calls error on VERTEX_PROJECT before reaching Google. Its default moved alongside Google's by inference (the withdrawal is model-side, not endpoint-side), not by observed pass. Likewise the Azure non-Whisper deployment path, which needs a gpt-4o-*-transcribe deployment to point at. Both are covered by mocked tests.

🙏 Thanks

  • @HariHaranDFX — reported #263, the Azure half of the verbose_json bug, with a reproduction against a live Azure resource, the exact offending line, and the observation that Azure deployment names are user-chosen. That last point directly shaped the config escape hatch in the fix. Also flagged the related #262.
  • Thanks to everyone filing issues and reproductions. Several fixes here started as a downstream report rather than something we caught ourselves — #263 among them, and the whole withdrawn-model sweep came out of running the real-API suite that those reports prompted us to take more seriously.

Full details in the CHANGELOG.
Install: pip install esperanto==2.26.0 (extras: esperanto[openai,anthropic,...])