feat: add Exa AI-powered search tool#264
Open
Teo (tgonzalezc5) wants to merge 1 commit into
Open
Conversation
Adds Exa as a selectable search provider alongside Tavily and the native OpenAI/Anthropic web search tools. - Wire up SearchAPI.EXA in configuration with a UI option - Implement exa_search tool and async wrapper, mirroring the Tavily shape so the existing summarization and dedup pipeline applies unchanged - Expose key Exa features: search type, category, domain include/exclude, and published-date range filters - Use the exa_py SDK via asyncio.to_thread to keep the event loop free - Read EXA_API_KEY from env or apiKeys config (matching the existing Tavily pattern) - Bump exa-py floor to >=2.0.0 and document EXA_API_KEY in .env.example - Add unit tests for response parsing, content fallbacks, API key resolution, async wrapper validation, and tool registration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Exa as a selectable search provider alongside Tavily and the native OpenAI/Anthropic web-search tools.
SearchAPI.EXAenum value plus a UI option inConfiguration.search_api.exa_searchtool andexa_search_asyncwrapper inutils.py, mirroring the Tavily shape so the existing dedup-and-summarize pipeline applies unchanged.search_type(auto/neural/fast),category,include_domains/exclude_domains, andstart_published_date/end_published_date.exa-pySDK; sync calls are dispatched viaasyncio.to_threadso the event loop stays free, and queries run in parallel viaasyncio.gather.EXA_API_KEYfrom the environment or fromconfigurable.apiKeyswhenGET_API_KEYS_FROM_CONFIG=true, matching the existing Tavily pattern.exa-pyfloor to>=2.0.0and addsEXA_API_KEY=to.env.example.Usage
The agent will then call
exa_searchwith a list of queries; the helper retrieves results with text + AI summary + highlights and feeds them into the same summarization step the Tavily path uses.Files changed
src/open_deep_research/configuration.py— registerSearchAPI.EXA+ UI option.src/open_deep_research/utils.py—exa_searchtool,exa_search_async,_format_exa_response,get_exa_api_key, dispatch inget_search_tool.pyproject.toml—exa-py>=2.0.0..env.example— addEXA_API_KEY=.tests/test_exa_search.py— 15 unit tests.Test plan
python -m ruff check src/open_deep_research/utils.py tests/test_exa_search.py— no new findings.python -m pytest tests/test_exa_search.py -v --asyncio-mode=auto— 15 passed:get_exa_api_keyenv vs.apiKeysconfig lookupexa_search_asyncraises when key is missing or domain filters conflictx-exa-integrationtracking headerget_search_tool(SearchAPI.EXA)returns the wired Exa toolsearch_api=exa(requires a liveEXA_API_KEY; not exercised here).