Migrations
effect-uai is pre-1.0; minor releases (0.x) can include breaking changes.
Each release that contains breaking changes ships a migration page on this
site with the full “old → new” picture: renames, removals, behavior
changes, and recommended migration order.
The CHANGELOG covers the why (one entry per PR). These pages cover the how (one page per release, written for a reader doing the upgrade in front of their editor).
Versions
- Migrating to 0.12: two narrow breaking changes.
providerDatais namespaced per provider (read Google deep-research traces viaGoogleDeepResearch.researchDataOf; Perplexity no longer writes the slot), and@effect-uai/exa/ExaDeepResearchis removed (Exa retired the API; use OpenAI / Perplexity / Gemini). Additive:@effect-uai/chat-completions(a reusable OpenAI-compatible Chat Completions base for gateways like OpenRouter and Requesty),@effect-uai/openaias a single install re-exporting the Responses stack, Anthropic prompt caching, and throughput metrics that count every output delta. - Migrating to 0.11: additive with one required action,
bump the
effectpeer dependency from the pin4.0.0-beta.57to the range>=4.0.0-beta.94 <5.0.0(most of the release’s internal diff is the mechanical ripple of that bump; effect-uai’s own API renamed nothing). New: aDeepResearchcapability (submit a question, a provider runs a background research job, collect one cited report) with four providers (@effect-uai/responses,@effect-uai/google,@effect-uai/perplexity,@effect-uai/exa) over the genericJob/Citationprimitives; native grounding via provider-hosted tools that render end to end on OpenAI (ResponsesTools), Gemini (GeminiTools), and Anthropic (AnthropicTools); and@effect-uai/ai-sdk, a Vercel AI SDK compatibility package (decodeMessages+toUIMessageStream). - Migrating to 0.10: mostly additive. One small
breaking change to the tool layer: a
Toolnow carries a typed errorE(added beforeR, so only hand-written fullTool<...>annotations need editing), andToolkit.runpropagates tool failures typed rather than silently showing them to the model (fail with astring/Tool.fail, or wrap the toolkit inToolkit.describeFailures, to keep a failure model-visible). Additive: aWebReadcapability (URL to clean markdown, providers@effect-uai/firecrawl,@effect-uai/exa,@effect-uai/tavily,@effect-uai/jina, pluswebReadTool) and aBrowsercapability (drive a real browser over CDP via@effect-uai/browser, withbrowserToolkitand the verb tools). - Migrating to 0.9: a tool-layer refactor (breaking
but mechanical) plus an additive Mistral provider. A
Toolkitis now a name-indexed record built withToolkit.makeand passed straight tostreamTurn/Toolkit.run(noTool.toDescriptorsat the call site); plain and streaming tools unify into oneTool.makewhoserun(input, emit)returns anEffect(Tool.streaming/finalizeremoved); control and provider tools get honest kinds (Tool.signal,Tool.interaction,Tool.provider); independent toolkits combine withToolkit.compose. Additive:@effect-uai/mistral(Mistral LLM plus Voxtral STT/TTS), enough to run an all-Mistral voice loop. - Migrating to 0.8: purely additive. A new
WebSearchcapability in@effect-uai/core(a generic search service plus a ready-madewebSearchToolfor grounding an LLM), three search providers (@effect-uai/perplexity,@effect-uai/exa,@effect-uai/tavily), and two recipes (grounded answer, deep research). No breaking changes; bump dependencies and run typecheck. - Migrating to 0.7: a capability-honesty pass
across audio and embeddings.
AudioBlob.durationSeconds: numberbecomesduration: Duration.Duration(flowing through STT, TTS, and music). STT:GeminiTranscriberremoved (use OpenAI / ElevenLabs / Inworld),promptsplits intoprompt+biasingTerms,TranscriptResult.durationSeconds → duration. TTS:PhoneticEncodingandCustomPronunciation.encodingremoved (IPA-only), pronunciations now failUnsupportedon providers without an IPA path,DialogueTurntrims to{ voiceId, text }. Embeddings:EmbedEncodingtrimmed tofloat32 | int8 | binary(sparse / multivector move toJinaEncoding), mismatched encoding / image / multi-part now failUnsupportedinstead of degrading silently. Music:prompts → prompt,bpm/scale/instrumentaldropped,MusicResultcomposesAudioBlob(result.bytes → result.audio.bytes),generatereturnsGenerateResult(primary+variants[]),streamGenerationFromyieldsMusicStreamEvent. LLM (no rewrites): GeminitoolChoicenow mapped, Gemini URL images nowUnsupported, Lyria clip reports mp3 honestly. Additive (no migration needed):@effect-uai/elevenlabs/ElevenLabsMusicGenerator,@effect-uai/core/Capabilitieswarn-and-drop helper, ElevenLabspronunciationDictionaryLocators, multi-provider recipe runner via--provider=. - Migrating to 0.6: the consistent-naming sweep
plus additive speech features. Breaking but mechanical: “function
call” → “tool call” terminology (
Item→HistoryItem,FunctionCall→ToolCall), modulesOutcome→ToolResultandResolvers→Approval,Toolkit.executeAll→run,Tool.AnyKindTool→AnyTool,ToolEvent.Intermediate→Progress, and a trimmedLoopsurface (loopFrom→loopOver,stop()/stop(state),nextAfter/stopAfterremoved); the wire format is unchanged. Additive (no migration needed): multi-speaker dialogue and custom pronunciations onSpeechSynthesizer. - Migrating to 0.5:
TurnEventmigrated toData.TaggedEnum(type→_tag, snake_case → PascalCase),Encoding→EmbedEncoding, genericEmbedResponse<E>,Toolkit.outputEvent/outputEventsremoved, Gemini tool calling, newLoop.stopWith/loopFrom,LanguageModel.turn/retry,Tool.fromStandardSchema. - Migrating to 0.4: purely additive. New speech
(
Transcriber,SpeechSynthesizer) and music (MusicGenerator) services, sharedAudio/Transcript/Musicdomain, and three new provider packages (@effect-uai/openai,@effect-uai/elevenlabs,@effect-uai/inworld). No breaking changes. - Migrating to 0.3:
streamUntilComplete→onTurnComplete,nextStateFrom→continueWith(now pipe-friendly),Matchmodule removed, tool requirements flow throughR, newloopWithState, new embedding subsystem.
Versioning policy
0.x.y: minor (x) bumps may break source compatibility; patch (y) bumps don’t. Migration pages live at this level.- Post-1.0: semver. Breaking changes only on majors; each major gets a migration page.
Using Claude to migrate
These migration pages are the source of truth. Point your AI coding agent (Claude Code, Cursor, …) at the page for your target version, or paste its “old → new” diffs: the pages are written in operator form (“if you see X, write Y”) so the agent can apply the rewrites across your codebase directly.
Release process
For maintainers: every release that contains a breaking change MUST ship:
- A new
docs/migrations/v{X.Y}.mdpage following the template of the most recent migration page. - A sidebar entry in
webpage/astro.config.mjslinking the new page. - CHANGELOG entries (via a changeset) cross-linked to the migration page.
Treat these like CHANGELOG bumps: required in the same PR, not “I’ll do it later.” Stale migration content actively misleads users (and Claude) into recommending APIs that no longer exist.