Migrating to 0.8
No rewrites needed. 0.8 is purely additive: a new WebSearch
capability in @effect-uai/core, a ready-made webSearchTool for
grounding an LLM, and three search providers (@effect-uai/perplexity,
@effect-uai/exa, @effect-uai/tavily). Nothing in the existing surface
changed. Bump your dependencies, run typecheck, done.
If you see a 0.8-version compile error that looks like a rename
(durationSeconds, GeminiTranscriber, prompts, etc.), you are
actually upgrading across an earlier breaking release. Apply the
0.6 → 0.7 rules (and the earlier pages) first.
What’s new (additive, no migration needed)
@effect-uai/core/WebSearch
A generic WebSearch service for searching the live web, in the same
shape as every other capability: a portable request floor, a free helper,
and provider layers that register both the generic tag and their own
typed tag.
import { search } from "@effect-uai/core/WebSearch"
const { results } = yield * search({ query: "effect-ts v4 release notes" })// results: ReadonlyArray<SearchResult>, portable across providersCommonSearchRequest carries only the fields most backends honor
(query, maxResults, recency, startDate / endDate as DateTime,
includeDomains / excludeDomains, country, language). There is no
model: pure search has nothing to pick. Where a backend cannot honor a
common field, the adapter warnDroppeds rather than silently changing
your query.
@effect-uai/core/WebSearchTool
webSearchTool(options?) is a ready-made tool for the agent loop whose
only requirement is WebSearch. The model controls the query (and an
optional recency); app policy (maxResults, includeDomains /
excludeDomains, result rendering) is pinned on the tool, not left to the
model.
import { webSearchTool } from "@effect-uai/core/WebSearchTool"
const tools = [webSearchTool({ maxResults: 5 })]Because the tool sits on the generic tag, the contract the model sees is identical no matter which backend answers.
Three search providers
Provide one provider layer (plus an HttpClient) and your
WebSearch-yielding code resolves.
| Provider | Package | Layer import |
|---|---|---|
| Perplexity | @effect-uai/perplexity | @effect-uai/perplexity/PerplexitySearch |
| Exa | @effect-uai/exa | @effect-uai/exa/ExaSearch |
| Tavily | @effect-uai/tavily | @effect-uai/tavily/TavilySearch |
import { layer as perplexity } from "@effect-uai/perplexity/PerplexitySearch"
const app = program.pipe( Effect.provide( perplexity({ apiKey: Redacted.make(process.env.PERPLEXITY_API_KEY!) }).pipe( Layer.provide(FetchHttpClient.layer), ), ),)Swap PerplexitySearch for ExaSearch or TavilySearch and neither your
program nor the model’s tool changes.
Two recipes
- Grounded answer: the model searches, reads, and writes a cited answer; LLM and search backend swap independently.
- Deep research: plan a broad question into sub-questions, research each with a parallel sub-agent, and synthesize a cited report you can watch assemble.
See the Web search overview for the full capability tour.