Skip to content

feat(search): add Exa Search API as a search provider#547

Open
lmorchard wants to merge 1 commit into
mainfrom
worktree-exa-search-provider
Open

feat(search): add Exa Search API as a search provider#547
lmorchard wants to merge 1 commit into
mainfrom
worktree-exa-search-provider

Conversation

@lmorchard

Copy link
Copy Markdown
Collaborator

Summary

Adds Exa (exa-api) as a search provider alongside the existing parallel-api / google / bing / duckduckgo providers. It slots into the existing provider abstraction — no changes to the webSearch tool, SearchService, or the agent loop.

ExaSearchProvider POSTs to https://api.exa.ai/search, opting into contents.highlights so results include snippets (Exa returns metadata only by default), and maps url/title/highlights through the same markdown + security-wrapper path as the Parallel provider.

Changes

  • config (config/defaults.ts): "exa-api" added to SEARCH_PROVIDERS; new exa_api_key field (env EXA_API_KEY, CLI --exa-api-key).
  • factory + webAgent: exa-api case in createSearchProvider; key-required validation guard mirroring parallel-api.
  • key selection (run.ts, taskRunner.ts): the agent exposes a single provider-agnostic searchApiKey, so call sites now pick exa_api_key vs parallel_api_key by provider. The server also gained exa-api in its inline provider union and a key-required validation branch.
  • debug logging for both API providers (gated on --debug, via the [X:debug] console.warn convention):
    • request: the exact outbound body (query + options, API key omitted)
    • response: result count plus an abbreviated sample of the first result so all returned fields are visible, with long strings truncated (shared abbreviateForDebug helper)

Note: highlights-only, text/summary intentionally not enabled

Exa can also return text (full page markdown) and summary (an LLM-generated abstract) via contents.text / contents.summary. This PR intentionally requests only highlights to keep parity with the Parallel provider's excerpts and avoid the extra token/cost overhead (Exa bills for summary generation). The debug response sample confirms Exa otherwise returns id / image / favicon beyond what we map; Parallel returns only url / title / excerpts. Enabling text/summary later is a one-line change in the request body, ideally behind a config knob.

Testing

  • Unit tests cover both providers: factory creation/validation, markdown formatting, empty/missing-title results, API error, the Exa highlights opt-in, and debug request/response logging on and off.
  • Verified live against the real Exa and Parallel APIs through the full agent loop (pilo run ... --search-provider exa-api --debug), confirming the search step, key wiring, and debug output.
  • Full suite green: core 913, cli 229, server 103, extension 273. Typecheck, prettier, and gitleaks all clean.

🤖 Generated with Claude Code

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants