Add Exa as a search engine option in WebSearchTool#2139
Add Exa as a search engine option in WebSearchTool#213910ishq wants to merge 3 commits intohuggingface:mainfrom
Conversation
Add 'exa' as a new engine parameter value for WebSearchTool, following the same pattern as the existing 'bing' engine. Uses the Exa REST API directly with requests (no extra dependencies beyond what's already required). Returns search results with highlights as descriptions. Requires EXA_API_KEY environment variable. Includes x-exa-integration header for usage tracking. Co-Authored-By: Tanishq Jaiswal <tanishq.jaiswal97@gmail.com>
|
Hey @albertvillanova — would love your review on this when you get a chance! This follows the same pattern as the Bing engine addition in #1313 (which @aymeric-roucher reviewed). Happy to address any feedback. |
VANDRANKI
left a comment
There was a problem hiding this comment.
Clean implementation that follows the existing engine pattern correctly. Two issues worth fixing before merge.
Blocker: missing timeout on requests.post
Every other search method in this file was just updated to add timeout=30 in PR #2140 (currently open). search_exa has the same missing timeout. Without it, a hanging Exa endpoint will block the agent indefinitely with no way to recover. The fix is one line:
response = requests.post(
"https://api.exa.ai/search",
headers={...},
json={...},
timeout=30,
)Bug: highlights can be None, not just absent
The result description is built with:
"description": " ".join(result.get("highlights", []))The Exa API returns "highlights": null for results where highlight generation fails or was not requested, rather than omitting the key entirely. result.get("highlights", []) returns None in that case, and " ".join(None) raises TypeError. The safe form is:
"description": " ".join(result.get("highlights") or [])The or [] coerces both a missing key and an explicit null to an empty list.
Note on test coverage
The test suite covers the three main paths cleanly (missing key, successful results, empty results). One edge case worth adding: a result where highlights is null in the response to confirm the or [] fix holds. This would prevent the bug from regressing silently.
Aside from the two issues above, the implementation is straightforward and the x-exa-integration: smolagents header is a nice touch for API attribution.
- Add timeout=30 to requests.post in search_exa() to prevent hanging - Use 'or []' to safely handle highlights being null vs absent - Add test_exa_null_highlights to cover the null highlights edge case Co-Authored-By: Tanishq Jaiswal <tanishq.jaiswal97@gmail.com>
|
Thanks for the thorough review @VANDRANKI! All three points addressed in the latest commit — added |
|
All three points addressed:
LGTM. |
|
Hey @VANDRANKI, thanks so much for the review! Can you please approve and merge? That'd be great. Thanks again for your time. |
|
Approved. I'm not a maintainer on this repo so I can't merge directly — a maintainer will need to do that. You can tag @aymeric-roucher or another maintainer to get eyes on it. |
|
Hey @aymeric-roucher I would really appreciate it if you could help merge the PR. Thanks. |
|
Gentle bump — this has been reviewed and approved, just needs a maintainer merge. @julien-c @merveenoyan would either of you be able to take a look? It's a small addition (~35 lines) following the existing Bing engine pattern from #1313. Thanks! |
|
Adding a note as the reviewer: the implementation is clean and all feedback was addressed promptly. Follows the Bing engine pattern closely, includes proper timeout handling, null-safe highlights, and 5 tests covering the edge cases. Ready to merge from a code standpoint. |
Use getattr(self, 'timeout', 30) instead of hardcoded timeout=30 so search_exa respects self.timeout when the configurable timeout parameter is added to WebSearchTool (see huggingface#2198). Co-Authored-By: Tanishq Jaiswal <tanishq.jaiswal97@gmail.com>
|
Updated the timeout handling based on feedback from #2198 — @albertvillanova would really appreciate a quick look when you have a moment — it's a small, self-contained addition with tests and an approval already in place. Happy to address any concerns. Thanks! |
|
Hey @julien-c thanks so much for your review! Would be amazing if you or @VANDRANKI were able to merge this. |
Summary
Adds
"exa"as a newengineparameter value forWebSearchTool, following the same pattern as the existing"bing"engine added in #1313.Changes
search_exa()method toWebSearchToolclass (~35 lines, 1 file)requests— no new dependenciesEXA_API_KEYenvironment variableUsage
Tests
Added 4 unit tests with mocked API calls:
test_exa_missing_api_key— raisesValueErrorwhenEXA_API_KEYis not settest_exa_search_results— verifies correct parsing and markdown outputtest_exa_no_results— raises exception on empty resultstest_exa_empty_highlights— gracefully handles missing highlightsAll existing tests continue to pass.