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
{{ message }}
Repository navigation
[Feature]: Choose the web search provider, with Serply as a second option #459
Web research (#433, settings in #439) only works with a Tavily key. A user who already pays for a different search API, or whose organization has approved a different one, has to open a Tavily account before research slides can cite anything. WEB_SEARCH.md already says the tool contract is provider-independent. The only Tavily-specific parts are the key slot (secrets['tavily']), the request in web-research-network.ts, and the Settings copy.
Proposed solution
Add a provider choice to the existing Web Search settings, and ship Serply as the second adapter. Everything else would stay as it is:
Config: an optional webSearch.provider field, 'tavily' | 'serply', defaulting to 'tavily'. Existing configs and saved keys keep working with no migration.
Keys: each provider has its own slot (secrets['tavily'], secrets['serply']) in the same safe: / plain: store. Switching providers never moves or exposes a key.
Settings > Web Search: a provider selector above the key field. Get, save and test keep returning status codes only, now for the selected provider.
Adapter:GET https://api.serply.io/v1/search?q=...&num=... with an X-Api-Key header. results[].title/link/description map onto the current result shape, within the same 1 to 5 result and 2,000 character snippet limits. The network rules for search requests don't change.
Unchanged: the permission prompt, maxCalls, page fetching, and "no automatic fallback". Only one provider is active at a time.
Rest of the change: en and zh-CN strings, WEB_SEARCH.md, tests next to the existing Tavily ones, and a changeset.
I'd build and maintain the PR. If you'd rather review it in two steps, I can send the provider field (with Tavily as the only option) first and the Serply adapter second.
Disclosure: I work with Serply.
Alternatives considered
A generic "custom endpoint" provider: rejected. Search APIs differ in auth, request and response shape, so this would need a mapping DSL, which is more surface than one small adapter.
Replacing Tavily: not proposed. It stays the default.
Scope
Provider / model
Hard-constraints check
I have read the hard constraints in CLAUDE.md and this proposal does not conflict with any of them (BYOK only, no proxy, no new dependency, no new credential store).
Thanks for the thorough write-up, and for the Serply disclosure up front — that's genuinely helpful for review. A provider-selectable Web Search slot with Tavily as the default plus one additional adapter is a reasonable, well-bounded direction, and the scope you list matches how the current Tavily integration is already laid out. This reads as an extension of the earlier web-research work (#433, #439) rather than a duplicate.
What lines up with the current design:
The existing integration is already search-only and settings-driven. .changeset/tavily-settings-entry.md describes safe key save/replace/clear with bounded connection testing, applying settings to new runs "without restarting while retaining per-run networking consent and active-run snapshots", and keeping search-only credentials out of the model API service list. A second adapter reuses that same shape — consent, per-run snapshots, and the no-automatic-fallback behavior stay as they are.
.changeset/preserve-web-search-settings.md shows web-search opt-in and limits are already preserved across provider/model changes, config imports, image settings, and design-system saves, so an optional webSearch.provider field should ride that same persistence path instead of adding a second one.
The adapter is app code over the existing HTTP path — no new shipped dependency, so the permissive-dependency constraint isn't triggered.
Things worth pinning down before the PR:
On-disk config should carry the schemaVersion field (per CLAUDE.md: "Schema-version everything that lives on disk") with 'tavily' as the default, so existing installs migrate with no user action.
Repo guidance says to avoid config-driven dispatch "unless we have two real callers" (CLAUDE.md). Shipping both providers at once satisfies that; the two-step split (field with Tavily only first) would land a dispatcher with a single caller. Either ordering is workable — a maintainer may have a preference.
Keeping each provider's key strictly in its own slot, with no move or copy on switch, is the right call and matches your proposal.
Need more info:
Should maxCalls, the 1–5 result count, and the 2,000-character snippet cap stay shared across providers, or can they be provider-specific?
Will the Serply adapter stay under the same opt-in networking rules as the current search requests, with no new host beyond api.serply.io?
Do you want the first PR to include the provider selector and en / zh-CN strings for both providers, or land the selector with Tavily only and add Serply routing in the follow-up?
Activity
github-actions commentedon Oct 2, 2026
Thanks for the thorough write-up, and for the Serply disclosure up front — that's genuinely helpful for review. A provider-selectable Web Search slot with Tavily as the default plus one additional adapter is a reasonable, well-bounded direction, and the scope you list matches how the current Tavily integration is already laid out. This reads as an extension of the earlier web-research work (#433, #439) rather than a duplicate.
What lines up with the current design:
.changeset/tavily-settings-entry.mddescribes safe key save/replace/clear with bounded connection testing, applying settings to new runs "without restarting while retaining per-run networking consent and active-run snapshots", and keeping search-only credentials out of the model API service list. A second adapter reuses that same shape — consent, per-run snapshots, and the no-automatic-fallback behavior stay as they are..changeset/preserve-web-search-settings.mdshows web-search opt-in and limits are already preserved across provider/model changes, config imports, image settings, and design-system saves, so an optionalwebSearch.providerfield should ride that same persistence path instead of adding a second one.Things worth pinning down before the PR:
schemaVersionfield (perCLAUDE.md: "Schema-version everything that lives on disk") with'tavily'as the default, so existing installs migrate with no user action.CLAUDE.md). Shipping both providers at once satisfies that; the two-step split (field with Tavily only first) would land a dispatcher with a single caller. Either ordering is workable — a maintainer may have a preference.Need more info:
maxCalls, the 1–5 result count, and the 2,000-character snippet cap stay shared across providers, or can they be provider-specific?api.serply.io?Open-CoDesign Bot