feat: add Tavily as a search provider alongside Serper, Brave, Google#95
Conversation
|
|
|
Someone is attempting to deploy a commit to the developersdigest's Team Team on Vercel. A member of the Team first needs to authorize it. |
| const final = response.results.map((result: any): SearchResult => ({ | ||
| title: result.title, | ||
| link: result.url, | ||
| favicon: `https://www.google.com/s2/favicons?domain=${new URL(result.url).hostname}&sz=128` |
There was a problem hiding this comment.
🟡 A single malformed search result URL crashes the entire search instead of gracefully skipping it
A URL is parsed with a throwing constructor (new URL(result.url) at app/tools/searchProviders.tsx:113) inside a .map() over all results, so one malformed URL from the search API causes every valid result to be discarded and the search to fail entirely.
Impact: Users see a complete search failure instead of results whenever the upstream API returns even one result with an unusual or malformed URL.
Mechanism: new URL() throws inside .map(), aborting the entire transformation
The tavilySearch function at app/tools/searchProviders.tsx:106-120 maps over response.results and calls new URL(result.url).hostname to construct a favicon URL. The new URL() constructor throws a TypeError for malformed URLs. Because this is inside .map(), a single bad URL aborts the entire mapping. The error propagates to the catch block at line 116-118, which re-throws, causing the whole search operation to fail.
Other search providers (brave, google, serper) don't have this risk because they don't parse URLs with new URL(). A safer approach would be to wrap the new URL() call in a try/catch or use a fallback for the favicon.
| favicon: `https://www.google.com/s2/favicons?domain=${new URL(result.url).hostname}&sz=128` | |
| favicon: (() => { try { return `https://www.google.com/s2/favicons?domain=${new URL(result.url).hostname}&sz=128`; } catch { return ''; } })() |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Adds Tavily as a fourth selectable search provider in the LLM answer engine, configured via
config.searchProvider = 'tavily'.What changed
app/tools/searchProviders.tsx: AddedtavilySearch()function using@tavily/coreSDK, mapping Tavily results to the existingSearchResultshape. Addedcase 'tavily'to thegetSearchResults()switch. Favicons are derived from Google's favicon service using the result URL hostname.app/config.tsx: Updated thesearchProvidercomment to list'tavily'as a valid option..env.example: AddedTAVILY_API_KEY=APIKEYGOESHEREentry.package.json: Added@tavily/core(^0.6.1) to dependencies.Files changed
app/tools/searchProviders.tsxapp/config.tsx.env.examplepackage.jsonDependency changes
@tavily/core(^0.6.1) topackage.jsondependenciesEnvironment variable changes
TAVILY_API_KEY(required whensearchProvideris set to'tavily')Notes for reviewers
searchProvider: 'tavily'inapp/config.tsxand provideTAVILY_API_KEYin your environment.npm installhas a pre-existing issue with"latest"version specs in package.json unrelated to this PR.Automated Review
tavily({ apiKey })client construction,.search(query, { maxResults }), andresponse.results[].url/titlefield mapping are all valid. The implementation is consistent in style and error handling with the existing Brave, Google, and Serper providers. No regressions introduced. Three minor issues noted but none are blocking.