BREAKING CHANGE: remove Tavily, Firecrawl, provider fallback, and web-search-config. web_search and web_fetch now use Exa-shaped inputs and return raw Exa-style details.
4.0 KiB
4.0 KiB
Exa-only rewrite for pi-web-search
- Status: approved design
- Date: 2026-04-12
- Project:
pi-web-search - Supersedes:
2026-04-12-firecrawl-design.md
Summary
Rewrite pi-web-search as an Exa-only package. Remove Tavily, Firecrawl, provider failover, and the interactive config command. Keep the two public tools, but make them Exa-shaped instead of provider-generic.
Approved product decisions
- Keep only
web_searchandweb_fetch. - Support Exa’s non-streaming
searchandgetContentsfunctionality. - Use a single Exa config instead of a provider list.
- Remove
web-search-config. - Return tool
detailsclose to raw Exa responses. - Delete Tavily and Firecrawl code, tests, docs, and config paths completely.
Goals
- Make the package Exa-only.
- Expose Exa-native request shapes for both tools.
- Keep human-readable output compact while preserving raw Exa details.
- Support config through
~/.pi/agent/web-search.jsonandEXA_API_KEY. - Remove stale multi-provider abstractions and tests.
Non-goals
- Expose Exa streaming APIs in this change.
- Expose Exa
answer,findSimilar, research, monitors, websets, imports, or webhook APIs. - Preserve the old provider-generic request contract.
- Preserve the interactive config command.
Public tool contract
web_search
Map directly to exa.search(query, options).
Supported top-level fields include:
querytypenumResultsincludeDomainsexcludeDomainsstartCrawlDateendCrawlDatestartPublishedDateendPublishedDatecategoryincludeTextexcludeTextflagsuserLocationmoderationuseAutopromptsystemPromptoutputSchemaadditionalQueriescontents
Behavior notes:
- Exa search returns text contents by default when
contentsis omitted. contents: falseis the metadata-only mode.additionalQueriesis allowed only for deep search types.includeTextandexcludeTextaccept at most one phrase of up to 5 words.
web_fetch
Map directly to exa.getContents(urls, options).
Supported fields include:
urlstexthighlightssummarycontextlivecrawllivecrawlTimeoutmaxAgeHoursfilterEmptyResultssubpagessubpageTargetextras
Behavior notes:
- No provider selection.
- No generic fallback behavior.
- No package-invented
textMaxCharacters; use Exatext.maxCharacters.
Config model
Use a single config object:
{
"apiKey": "exa_...",
"baseUrl": "https://api.exa.ai"
}
Rules:
apiKeyis required unlessEXA_API_KEYis set.baseUrlis optional.- Legacy multi-provider configs should fail with a migration hint.
- Missing config file is allowed when
EXA_API_KEYis present.
Runtime design
Keep runtime small:
- load Exa config
- create Exa client
- delegate to
searchorgetContents - return raw Exa response
Remove:
- provider registry
- provider capabilities
- fallback graph execution
- execution attempt metadata
Formatting
- Human-readable output should say
via Exa. - Tool
detailsshould stay close to raw Exa responses. - Search output should show
output.contentwhen present. - Fetch/search text should still be truncated in package formatting for readability.
Files expected to change
index.tssrc/config.tssrc/schema.tssrc/runtime.tssrc/providers/exa.tssrc/tools/web-search.tssrc/tools/web-fetch.tssrc/format.tsREADME.md- tests under
src/ - package metadata and agent docs
Testing strategy
- Config tests for single Exa config, env fallback, invalid
baseUrl, and legacy-config rejection. - Exa adapter tests for option pass-through and client construction.
- Runtime tests for raw Exa delegation.
- Tool tests for Exa-shaped normalization and validation.
- Formatting tests for compact Exa output.
- Manifest/README tests for Exa-only packaging.
Acceptance criteria
- No Tavily or Firecrawl runtime/config/tool paths remain.
web_searchandweb_fetchare Exa-shaped.web-search-configis removed.- Config supports file or
EXA_API_KEY. - Tests pass.