feat: improve Exa search integration with tracking header and updated API#900
feat: improve Exa search integration with tracking header and updated API#900tgonzalezc5 wants to merge 2 commits intomodelscope:mainfrom
Conversation
… API support - Add x-exa-integration tracking header for API usage attribution - Remove deprecated 'keyword' search type; add 'fast', 'deep-lite', 'deep', 'deep-reasoning', and 'instant' types per current API - Add highlights and summary content retrieval options - Add domain filtering (include_domains, exclude_domains), category filter, and user_location support - Fix to_list() to include text/highlights/summary content fields with graceful fallback when fields are absent - Add comprehensive unit tests for schema, search engine, and response parsing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request enhances the Exa search tool by integrating advanced features such as highlights, summaries, domain filtering, and expanded search modes. The changes include updates to the request schema, tool definitions, and result processing logic to support these new parameters, along with the addition of comprehensive unit tests. Review feedback identifies opportunities to improve the consistency of optional field handling in the to_dict method and to refine type hints for better type safety in result lists.
| def to_dict(self) -> Dict[str, Any]: | ||
| """ | ||
| Convert the request parameters to a dictionary. | ||
| Convert the request parameters to a dictionary suitable for | ||
| exa-py's search_and_contents() call. | ||
| """ | ||
| return { | ||
| d: Dict[str, Any] = { | ||
| 'query': self.query, | ||
| 'text': self.text, | ||
| 'highlights': self.highlights, | ||
| 'summary': self.summary, | ||
| 'type': self.type, | ||
| 'num_results': self.num_results, | ||
| 'start_published_date': self.start_published_date, | ||
| 'end_published_date': self.end_published_date, | ||
| 'start_crawl_date': self.start_crawl_date, | ||
| 'end_crawl_date': self.end_crawl_date | ||
| 'end_crawl_date': self.end_crawl_date, | ||
| } | ||
| if self.include_domains: | ||
| d['include_domains'] = self.include_domains | ||
| if self.exclude_domains: | ||
| d['exclude_domains'] = self.exclude_domains | ||
| if self.category: | ||
| d['category'] = self.category | ||
| if self.user_location: | ||
| d['user_location'] = self.user_location | ||
| return d |
There was a problem hiding this comment.
The to_dict method handles optional parameters inconsistently. Date-related fields (lines 65-68) are included in the dictionary even when they are None, while domain and category filters (lines 70-77) are conditionally added. It is cleaner and more robust for API compatibility to omit all optional fields when they do not have a value.
def to_dict(self) -> Dict[str, Any]:
"""
Convert the request parameters to a dictionary suitable for
exa-py's search_and_contents() call.
"""
d: Dict[str, Any] = {
'query': self.query,
'text': self.text,
'highlights': self.highlights,
'summary': self.summary,
'type': self.type,
'num_results': self.num_results,
}
# Add optional filters only if they have values
for field_name in [
'start_published_date', 'end_published_date',
'start_crawl_date', 'end_crawl_date', 'include_domains',
'exclude_domains', 'category', 'user_location'
]:
value = getattr(self, field_name)
if value:
d[field_name] = value
return d
ms_agent/tools/search/exa/schema.py
Outdated
| @@ -81,57 +110,35 @@ def to_list(self): | |||
|
|
|||
| res_list: List[Any] = [] | |||
There was a problem hiding this comment.
…pe hint Address review feedback: - Omit all optional fields from to_dict() when None, not just domain/category filters; avoids sending null values to the API - Narrow to_list() return type from List[Any] to List[Dict[str, Any]] - Add date field assertions to test_to_dict_basic Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
x-exa-integrationtracking header for API usage attribution (ms-agent)keywordsearch type; add current types:fast,deep-lite,deep,deep-reasoning,instanthighlightsandsummaryalongside existingtextinclude_domains,exclude_domains,category,user_locationto_list()result formatting to include text/highlights/summary content fields with graceful fallback when fields are absentUsage Example
Files Changed
ms_agent/tools/search/exa/search.py-- integration header, updated tool definition and request builderms_agent/tools/search/exa/schema.py-- new fields (highlights, summary, domain filters, category, user_location), improvedto_list()with content fallbacktests/search/test_exa_search.py-- new test file with comprehensive coverageTest Plan
ExaSearchRequestdefault values andto_dict()serializationExaSearchRequestwith domain/category/location filtersExaSearchResult.to_list()with text-only, highlights-only, summary-only, and all-content responsesExaSearchResult.to_list()graceful fallback when content fields are absentExaSearchResult.to_list()with empty responseExaSearchsetsx-exa-integration: ms-agentheader on initializationExaSearchraisesAssertionErrorwhenEXA_API_KEYis not setExaSearch.get_tool_definition()does not includekeywordtypeExaSearch.get_tool_definition()exposes all filter parametersExaSearch.build_request_from_args()correctly maps all parameters