Skip to content

feat: add Exa AI-powered search tool#5

Open
tgonzalezc5 wants to merge 1 commit into
tarun7r:mainfrom
tgonzalezc5:feat/add-exa-search
Open

feat: add Exa AI-powered search tool#5
tgonzalezc5 wants to merge 1 commit into
tarun7r:mainfrom
tgonzalezc5:feat/add-exa-search

Conversation

@tgonzalezc5
Copy link
Copy Markdown

Summary

  • Adds ExaProvider implementing the existing SearchProvider ABC, alongside DuckDuckGoProvider and TavilyProvider.
  • Exa is a neural/semantic web search API that returns relevance-ranked results along with rich content (text, highlights, summary) in a single search_and_contents call, so the provider can populate SearchResult.snippet without a separate content-extraction round-trip.
  • Selection is config-driven via SEARCH_PROVIDER=exa, with EXA_API_KEY, EXA_SEARCH_TYPE, and EXA_CATEGORY for tuning. Everything else (domain/text filters, date ranges, content sizes) is exposed via ExaProvider constructor kwargs for programmatic use.

Usage

# .env
SEARCH_PROVIDER=exa
EXA_API_KEY=your-exa-api-key
EXA_SEARCH_TYPE=auto        # optional: auto | neural | fast | deep
EXA_CATEGORY=research paper # optional
from src.utils.web_utils import ExaProvider, WebSearchTool

provider = ExaProvider(
    api_key="...",
    max_results=5,
    search_type="neural",
    category="research paper",
    include_domains=["arxiv.org"],
    start_published_date="2025-01-01",
)
results = await WebSearchTool(providers=[provider]).search_async("llm reasoning benchmarks")

Implementation notes

  • Follows the existing TavilyProvider pattern for circuit breaker, rate-limit detection, and error mapping (RateLimitError / SearchError).
  • exa-py's default client is synchronous, so the call is offloaded with asyncio.to_thread (same approach as DuckDuckGoProvider._execute_search).
  • Snippet extraction cascades summary → joined highlights → trimmed text → empty string, so any combination of returned content fields works.

Files changed

  • src/utils/web_utils.py — new ExaProvider class
  • src/utils/tools.py — register Exa in _build_search_providers
  • src/config.pyEXA_API_KEY, EXA_SEARCH_TYPE, EXA_CATEGORY fields
  • requirements.txt, pyproject.toml — add exa-py>=2.0.0
  • tests/test_exa_provider.py — 12 unit tests (parsing, request kwargs, snippet fallback, error mapping, provider registration); no live API calls

Test plan

  • pytest tests/test_exa_provider.py — 12/12 passing locally
  • ruff check introduces no new warnings on touched files
  • Smoke test with a real EXA_API_KEY in the running agent

Adds ExaProvider implementing the SearchProvider ABC alongside
DuckDuckGo and Tavily. Exa returns neural/semantic results with
rich content (text, highlights, summary) in a single call, so the
provider issues search_and_contents and cascades through the
available content fields when populating SearchResult.snippet.

- New ExaProvider with circuit breaker, rate-limit mapping, and
  support for search type, category, domain/text/date filters
- SEARCH_PROVIDER=exa selects it; EXA_API_KEY, EXA_SEARCH_TYPE,
  EXA_CATEGORY configure it
- Tests for parsing, kwargs, snippet fallback, error mapping, and
  provider registration

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant