You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Here's the implementation plan, following the existing Parallel provider as the template (packages/trueforge-core/src/core/web-search/ParallelWebSearchProvider.ts, schemas/webSearchProvider.ts, catalog/web-search-catalog.yaml, websearch/providers.ts):
Add WebSearchProviders.Exa and an ExaWebSearchProvider implements IWebSearchProvider in trueforge-core, calling Exa's search API with an injected ssrfFetch (matching Parallel's SSRF guard usage), mapped into the existing normalized WebSearchHits/WebFetchPages shapes.
Extend WebSearchProviderManifestSchema's discriminated union with an exa variant (type: 'exa' plus auth.api_key), using the same redact-on-read and rotate-or-keep-on-PUT semantics as Parallel. No changes to the singleton settings model.
Add exa to web-search-catalog.yaml so it's discoverable via the catalog endpoint.
Wire resolveWebSearchProvider() to construct ExaWebSearchProvider when manifest.type === 'exa', so it's picked up in agent turns and gates capabilities the same way Parallel does today.
Add provider-level tests (search/fetch mapping, missing/invalid-key failure) and route-level tests (PUT/GET redaction and rotation, catalog listing) mirroring the Parallel test coverage.
Regenerate the OpenAPI-derived SDK types affected by the manifest union change.
One open question I'll resolve during implementation: Exa's content-extraction endpoint doesn't map 1:1 to Parallel's extract API, so I'll either adapt it to the fetch() contract or return a clear per-URL "unsupported" error if it doesn't fit, following whatever's closest to existing provider-parity expectations. Not touching the TrueFoundry-managed env-var synthesis path (TrueFoundryWebSearchProviderStore) since that's enterprise-only and outside this issue's stated scope.
Hi @thesujai, I'd like to work on this issue. Is it still available, and would you approve me taking it?
I've reviewed the current Parallel integration and propose to:
add Exa to the catalog and settings manifest;
resolve the configured provider at runtime;
implement Exa search and, if expected by the current interface, Exa-backed web_fetch;
preserve secret redaction/rotation and require a fresh key when switching provider types;
add focused provider, settings, resolver, and catalog tests, with no UI changes.
Before implementation, could you confirm three scope details?
Should this issue include web_fetch through Exa Contents? IWebSearchProvider currently requires both search() and fetch(), and the capability exposes both tools.
For multiple search_queries, is one Exa request per query followed by URL deduplication and a global result cap acceptable? Exa's additionalQueries is limited to deep-search variants.
Should invalid credentials fail clearly on first use, or should settings PUT validate them remotely?
I'll wait for approval and scope confirmation before starting implementation.
@thesujai, Implementation is ready locally and tested. I'll open the PR if you're okay with the following implementation details:
What's implemented
ExaWebSearchProvider calls Exa /search and /contents through ssrfFetch, with no new dependency.
exa is added to the manifest union and to web-search-catalog.yaml, and resolveWebSearchProvider() is wired for it.
A changeset is included. I did not touch the generated SDK, since CI regenerates it.
Bug fix beyond the original plan: a PUT that switched provider type with a redacted key reused the previous provider's stored key. It now returns 400 and requires a fresh key.
Scope decisions
fetch(): implemented via Exa /contents, because IWebSearchProvider requires both methods. Per-URL failures come from statuses, and successful pages are kept.
Multiple search_queries: one /search request per query, results interleaved, duplicate URLs dropped, and a total cap of 5 hits with 500-character snippets.
Invalid credentials: they fail clearly on first use (401 and 402 have dedicated messages). PUT does not validate remotely.
Testing
Unit tests cover the provider, the settings API (upsert, redaction, rotation, type switch), the resolver, and the catalog.
Typecheck, lint, format, and the full core and server suites pass.
Live run against Exa with a real key: search, contents, a bad URL, and the invalid-key error all behaved as expected.
Not covered: an end-to-end agent turn using Exa.
Notes
trueforge-ui's catalog adapter still only handles parallel. I left it alone as UI work is out of scope.
Hi @Aman-goel-04, I have assigned the issue to you. Could you check the current web search prompt -
Operators such as site:domain, filetype:pdf, intitle:word, -term, and "exact phrase" may work. And add details in the implementation, on which of the following are supported and hence tested for Exa?
Also, for the contract differences, please note the exact differences, and the finalised approach before raising the PR. Thanks!
@heerambavi1998, Thanks for assigning it to me. I checked the search prompt operators against Exa and pinned down the contract differences.
Operator support (tested live against Exa /search)
Constraint-satisfying hits out of 10 to 30 per operator. "Operator" means the operator written in the query text.
Operator
Without operator
With operator
Result
site:domain
2/10
10/10
Supported
-site:domain
6 hits from the excluded domain
0
Supported
-term
2/10
10/10
Supported
"exact phrase"
23/30
30/30
Supported
filetype:pdf
13/30
16/30
Weak, not reliable
intitle:word
19/30
18/30
Not supported
Exa's docs describe no operator syntax, but it honors most of these from the query text. I also tried the native parameters. includeDomains and excludeDomains match the query-text results, while excludeText and includeText are deprecated and approximate (excludeText matched 7/10 versus 10/10 for -term in the query).
Finalised approach
Queries are sent to Exa verbatim. The provider does not parse operators into API parameters, since the query text performs as well as or better than the native parameters.
The shared tool prompt is unchanged. It already says operators "may work when the backend supports them".
The supported and unsupported operators are documented on ExaWebSearchProvider, and a unit test asserts that operator syntax reaches Exa unmodified.
Contract differences vs Parallel
Objective: Parallel has an objective field. Exa has none, so it is passed as the highlights query. This focuses snippets but does not affect ranking.
Multiple queries: Parallel accepts them in one call. Exa needs one request per query (up to 5), merged with interleaving, URL dedupe, and a 5-hit cap.
Snippets: Exa highlights, capped at 500 characters each to match Parallel.
published_at: often null on Exa, since publishedDate is missing for many pages.
fetch(): Exa /contents returns full text and ignores objective. Per-URL errors come from statuses[].error (tag plus HTTP code) instead of Parallel's errors[].
Auth:x-api-key header over REST, no SDK, still routed through ssrfFetch.
Credential failures: raised on first use with a clear message (401 and 402 have their own messages). PUT does not validate the key remotely.
Activity
thesujai commentedon Sep 23, 2026
For the folks picking this up let us know the implementation plan before we can assign you and you can begin the work
Aman-goel-04 commentedon Sep 23, 2026
Would like to pick this up! Letting you know about the implementation plan in a bit.
Aman-goel-04 commentedon Sep 23, 2026
Here's the implementation plan, following the existing Parallel provider as the template (packages/trueforge-core/src/core/web-search/ParallelWebSearchProvider.ts, schemas/webSearchProvider.ts, catalog/web-search-catalog.yaml, websearch/providers.ts):
One open question I'll resolve during implementation: Exa's content-extraction endpoint doesn't map 1:1 to Parallel's extract API, so I'll either adapt it to the fetch() contract or return a clear per-URL "unsupported" error if it doesn't fit, following whatever's closest to existing provider-parity expectations. Not touching the TrueFoundry-managed env-var synthesis path (TrueFoundryWebSearchProviderStore) since that's enterprise-only and outside this issue's stated scope.
Happy to adjust based on feedback.
Aman-goel-04 commentedon Sep 23, 2026
@thesujai, Let me know if I can start working on it!
xinpingzh commentedon Sep 23, 2026
Hi @thesujai, I'd like to work on this issue. Is it still available, and would you approve me taking it?
I've reviewed the current Parallel integration and propose to:
web_fetch;Before implementation, could you confirm three scope details?
web_fetchthrough Exa Contents?IWebSearchProvidercurrently requires bothsearch()andfetch(), and the capability exposes both tools.search_queries, is one Exa request per query followed by URL deduplication and a global result cap acceptable? Exa'sadditionalQueriesis limited to deep-search variants.I'll wait for approval and scope confirmation before starting implementation.
Aman-goel-04 commentedon Sep 25, 2026
@thesujai, Implementation is ready locally and tested. I'll open the PR if you're okay with the following implementation details:
What's implemented
ExaWebSearchProvidercalls Exa/searchand/contentsthroughssrfFetch, with no new dependency.exais added to the manifest union and toweb-search-catalog.yaml, andresolveWebSearchProvider()is wired for it.Scope decisions
fetch(): implemented via Exa/contents, becauseIWebSearchProviderrequires both methods. Per-URL failures come fromstatuses, and successful pages are kept.search_queries: one/searchrequest per query, results interleaved, duplicate URLs dropped, and a total cap of 5 hits with 500-character snippets.Testing
Notes
trueforge-ui's catalog adapter still only handlesparallel. I left it alone as UI work is out of scope.heerambavi1998 commentedon Sep 26, 2026
Hi @Aman-goel-04, I have assigned the issue to you. Could you check the current web search prompt -
Operators such as site:domain, filetype:pdf, intitle:word, -term, and "exact phrase" may work. And add details in the implementation, on which of the following are supported and hence tested for Exa?
Also, for the contract differences, please note the exact differences, and the finalised approach before raising the PR. Thanks!
Aman-goel-04 commentedon Sep 26, 2026
@heerambavi1998, Thanks for assigning it to me. I checked the search prompt operators against Exa and pinned down the contract differences.
Operator support (tested live against Exa
/search)Constraint-satisfying hits out of 10 to 30 per operator. "Operator" means the operator written in the query text.
site:domain-site:domain-term"exact phrase"filetype:pdfintitle:wordExa's docs describe no operator syntax, but it honors most of these from the query text. I also tried the native parameters.
includeDomainsandexcludeDomainsmatch the query-text results, whileexcludeTextandincludeTextare deprecated and approximate (excludeTextmatched 7/10 versus 10/10 for-termin the query).Finalised approach
ExaWebSearchProvider, and a unit test asserts that operator syntax reaches Exa unmodified.Contract differences vs Parallel
objectivefield. Exa has none, so it is passed as the highlightsquery. This focuses snippets but does not affect ranking.published_at: oftennullon Exa, sincepublishedDateis missing for many pages.fetch(): Exa/contentsreturns full text and ignoresobjective. Per-URL errors come fromstatuses[].error(tag plus HTTP code) instead of Parallel'serrors[].x-api-keyheader over REST, no SDK, still routed throughssrfFetch.Happy to adjust anything before I raise the PR.
thesujai commentedon Sep 28, 2026
@zhangxinping666 since this is already being worked on, you can look at #853 if you are interested. It is similar
thesujai commentedon Sep 28, 2026
@Aman-goel-04 Please open a PR
Aman-goel-04 commentedon Sep 28, 2026
@thesujai, done! Please review it when you get the time.
thesujai commentedon Sep 29, 2026
We will review it next week
Aman-goel-04 commentedon Oct 6, 2026
@thesujai @heerambavi1998, Could you please review it now?
Aman-goel-04 commentedon Oct 21, 2026
@thesujai @heerambavi1998 hey?