Migrating to 0.4
0.4 is purely additive on top of 0.3. No imports break, no signatures
change, no behavior changes. The release introduces three new
modality services (STT, TTS, music generation), the shared Audio /
Transcript / Music domain that backs them, and three new provider
packages (@effect-uai/openai for OpenAI speech,
@effect-uai/elevenlabs, @effect-uai/inworld). Skip this page if
you’re only using language models.
At a glance
| What’s new | Where it lives |
|---|---|
Transcriber service (STT) | @effect-uai/core/Transcriber |
SpeechSynthesizer service (TTS) | @effect-uai/core/SpeechSynthesizer |
MusicGenerator service | @effect-uai/core/MusicGenerator |
| Audio / transcript / music domain | @effect-uai/core/Audio, /Transcript, /Music |
SttStreaming / TtsIncrementalText | provider-fit markers |
| OpenAI speech provider | @effect-uai/openai (new package) |
| ElevenLabs speech provider | @effect-uai/elevenlabs (new package) |
| Inworld speech provider | @effect-uai/inworld (new package) |
| Gemini speech + Lyria music | @effect-uai/google/Gemini{Synthesizer,Transcriber} + LyriaGenerator |
Speech services (STT + TTS)
Transcriber and SpeechSynthesizer are siblings of LanguageModel
and EmbeddingModel. Both expose a sync shape (transcribe /
synthesize) and a stream shape (streamTranscriptionFrom /
streamSynthesisFrom).
- Streaming STT takes
Stream<Uint8Array>(mic frames) and returns aStream<TranscriptEvent>(partial/final/speech-started/speech-stopped/usage). - Streaming TTS takes
Stream<string>(incremental text) and returns aStream<AudioChunk>.
Live audio composes with the rest of Effect (Stream.run*,
Stream.merge, scoped resources) — no special audio runtime needed.
import { Transcriber } from "@effect-uai/core/Transcriber"import { OpenAIRealtimeTranscriber } from "@effect-uai/openai/OpenAIRealtimeTranscriber"
const program = Effect.gen(function* () { const transcripts = yield* Transcriber.streamTranscriptionFrom(micFrames) yield* transcripts.pipe(Stream.runForEach((ev) => Effect.sync(() => console.log(ev))))})program.pipe(Effect.provide(OpenAIRealtimeTranscriber.layer({ apiKey })))Provider-fit markers
SttStreaming and TtsIncrementalText are tags providers register
alongside the base Transcriber / SpeechSynthesizer service. Recipes
that demand live audio (e.g. Voice loop) require the marker at the
type level — a sync-only provider fails to compile rather than blowing
up at runtime.
// Demands a streaming STT provider; rejects sync-only at compile time.const recipe: Effect.Effect<void, never, Transcriber | SttStreaming> = ...Music generation
MusicGenerator is a third sibling for prompt-to-audio music models.
Today: Google’s Lyria via @effect-uai/google/LyriaGenerator. Same
sync generate shape as the speech services.
New provider packages
Three new npm packages ship in 0.4:
@effect-uai/openai— OpenAI speech only (TTS viaOpenAISynthesizer, STT viaOpenAITranscriberandOpenAIRealtimeTranscriber). The OpenAI Responses API stays in@effect-uai/responses; these are intentionally separate packages because the API surfaces are unrelated.@effect-uai/elevenlabs— TTS (incremental text-in via WebSocket) and Scribe v2 Realtime STT. RegistersTtsIncrementalTextandSttStreaming.@effect-uai/inworld— sync + realtime TTS / STT. Registers both markers on the realtime layers.
The existing @effect-uai/google package gains
GeminiSynthesizer (TTS), GeminiTranscriber (STT), and
LyriaGenerator (music) sub-paths.
Recommended order
If you’re not adopting speech / music in this upgrade:
- Bump every
@effect-uai/*dependency in yourpackage.jsonto^0.4.0. - Run typecheck. Nothing should break.
- Done.
If you are adopting speech / music:
- Bump dependencies as above.
- Install the new provider package(s) you need
(
@effect-uai/openai,@effect-uai/elevenlabs,@effect-uai/inworld, or use the new@effect-uai/googleexports). - See the speech overview and music generation overview for the service shape and the per-provider docs for setup.
What about renames / removals?
There aren’t any. The renames listed in some 0.4 changelog entries
(Loop.streamUntilComplete → Loop.onTurnComplete,
Toolkit.nextStateFrom → Toolkit.continueWith, Match module
removal, ToolResult / ToolEvent / Image* → Data.TaggedEnum,
Loop.loopWithState, embeddings) actually landed in 0.3 and are
covered by Migrating to 0.3. If you’re upgrading
straight from 0.2, apply the 0.3 guide first, then this one.
Using Claude to migrate
Nothing to migrate here, but the effect-uai-migrate skill flags 0.4
as a no-op release so it won’t try to invent rewrites:
/skill effect-uai-migrate