Migrating to 0.12
0.12 has two breaking changes, both narrow: providerData is namespaced per
provider, and @effect-uai/exa/ExaDeepResearch is removed. Neither touches the
core loop, tools, or streaming. Everything else is additive.
No effect bump this release; the peer range stays >=4.0.0-beta.94 <5.0.0.
If you hit a compile error that looks like an older rename, you are crossing an earlier breaking release. Apply the 0.11 page and the ones before it first.
Breaking: providerData is namespaced per provider
providerData is a shared slot on a HistoryItem. Providers used to write to
its root and re-emit whatever they found, so an item that had passed through
another provider first (dynamic fallback) went back on the wire as that
provider’s data. Now each provider writes under its own key and reads only that
key, so several can coexist and unknown data is left untouched. Where the slot
is meant to be read, it now carries a domain value with an exported accessor,
not the raw wire shape.
Google deep research. The step-by-step research trace moved to
providerData.gemini as a typed GeminiResearchData. Read it with the accessor
instead of reaching into providerData:
// beforeconst steps = (item.providerData as any)?.steps
// afterimport * as GoogleDeepResearch from "@effect-uai/google/GoogleDeepResearch"const data = GoogleDeepResearch.researchDataOf(item) // Option<GeminiResearchData>The Turn still carries the final report and the deduped union of sources; only
the per-step trace lives under the namespaced slot.
Perplexity. No longer writes providerData at all: its text is on the
Turn, usage on Turn.usage, and search results are annotations with their
[n] markers. Drop any code reading providerData off a Perplexity result.
Responses. Keeps its wire item internally under providerData.responses,
purely to round-trip encrypted_content and item ids; it was never public. One
upgrade caveat: items persisted by an older version keep their data at the root,
so a conversation that spans the upgrade loses encrypted_content and item ids
on those items (they fall back to a normal encode). Only turns straddling the
upgrade are affected.
Breaking: ExaDeepResearch removed
@effect-uai/exa/ExaDeepResearch is gone. Exa retired the Research API
(POST /research/v0/tasks now returns RESEARCH_RETIRED), so the capability
could no longer succeed. @effect-uai/exa/ExaSearch and
@effect-uai/exa/ExaContents are unaffected.
For provider-hosted deep research, swap the layer for another DeepResearch
provider; the capability tag and call sites are identical:
@effect-uai/responses/OpenAIDeepResearch@effect-uai/perplexity/PerplexityDeepResearch@effect-uai/google/GoogleDeepResearch
Behavior change: throughput counts all output deltas
Metrics.throughput now measures every delta that carries generated output, not
just TextDelta: ReasoningDelta, RefusalDelta, and ToolCallArgsDelta count
too. A tool-heavy agent that used to chart a rate near zero (its output is mostly
tool-call arguments) will now show a real rate. ThroughputOptions.tokenizer is
called with the new OutputDelta type rather than TurnEvent; a tokenizer that
accepts a full TurnEvent stays assignable. timeToFirstToken is unchanged.
What’s new (additive)
@effect-uai/chat-completions: a reusable OpenAI Chat Completions (POST /chat/completions)LanguageModelbase for any compatible endpoint (OpenRouter, Requesty, Groq, Together, self-hosted). Prefer Responses where the endpoint supports it; this is the legacy dialect for endpoints that do not. See Chat Completions and gateways.@effect-uai/openaiis now the single OpenAI install. It re-exports the Responses language model, embeddings, and deep research from@effect-uai/responsesalongside its speech surface, under new subpaths (@effect-uai/openai/Responses,/OpenAIEmbedding,/OpenAIDeepResearch,/ResponsesTools).@effect-uai/responsesstill installs standalone for protocol-only use (e.g. against a gateway). No code change required.- Anthropic prompt caching.
anthropicLayer({ apiKey, promptCaching: true })(or{ ttl: "1h" }) pays for a long system prompt and toolkit once instead of per turn. Off by default. Cache-creation (write) tokens are now reported:Items.Usage.input_tokens_detailsgainscache_write_tokens, andMetricsemits aneffect_uai_cache_write_tokenscounter.
Internally, the Mistral language model was rebuilt on
@effect-uai/chat-completions (it speaks that dialect); no public API change.
Migration order
- Bump dependencies to 0.12 and run
pnpm typecheck. - If you read
providerDataon a deep-research result, switch toGoogleDeepResearch.researchDataOf(item)(and drop any PerplexityproviderDatareads). - If you used
@effect-uai/exa/ExaDeepResearch, swap to anotherDeepResearchprovider layer.