Skip to content

feat(web_search): add Serply search provider - #6100

Open
googio wants to merge 2 commits into
Hmbown:mainfrom
googio:feat/serply-search
Open

feat(web_search): add Serply search provider#6100
googio wants to merge 2 commits into
Hmbown:mainfrom
googio:feat/serply-search

Conversation

@googio

@googio googio commented Sep 11, 2026

Copy link
Copy Markdown

Summary

Adds Serply (https://serply.io) as a [search] provider for the Web tool, following the shape of the Sofya adapter in #2790.

  • provider = "serply" calls GET https://api.serply.io/v1/search?q=...&num=... with the key in an X-Api-Key header and maps results[].title/link/description onto WebSearchEntry. Ads, knowledge graph and related questions in the response are ignored.
  • Key comes from [search] api_key or the SERPLY_API_KEY env var; preflight fails closed with a clear message when neither is set, and SERPLY_API_KEY joins the workspace .env credential allowlist.
  • BackendId::Serply for receipts, api.serply.io for network policy and default_backend_host, search_probe_target for doctor.
  • Docs: config.example.toml, docs/CONFIGURATION.md, docs/zh_hans/CONFIGURATION.md.

Opt-in only: Firecrawl stays the default and nothing changes for existing configs. No new dependencies. CHANGELOG files untouched per CONTRIBUTING.

Disclosure: I work with Serply.

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features --locked (warning-free under the CI allow list)
  • cargo test --workspace --all-features --locked: every other crate green (40 suites, 2339 tests); codewhale-tui 12224 unit tests plus the cucumber and integration targets green. The runtime_api::tests module is order-sensitive in my WSL environment (a different handful of its tests fail on every run of the module, on untouched main as well); each of those tests passes when run alone on this branch.

New tests: serply_search_url_encodes_query_and_result_count, parse_serply_results_reads_link_and_description_and_skips_malformed_rows, serply_provider_without_api_key_surfaces_clear_error_not_silent_fallback, the Serply rows in doctor_search_probe_targets_cover_every_builtin_provider and every_configured_provider_maps_to_one_explicit_backend_adapter, and two config parse/round-trip tests.

Live check with a real key (SERPLY_API_KEY, provider = "serply"): a query through web_search returned ranked Google results with titles, URLs and snippets and source: "serply" in the receipt; with the key removed the tool fails closed with the Serply message instead of falling back.

Checklist

  • This PR adds a new layer/module/abstraction: it names or deletes the layer it replaces (not applicable, one more arm in the existing provider enum)
  • Updated docs or comments as needed
  • Added or updated tests where relevant
  • Verified TUI behavior manually if UI changes (no UI changes)
  • Harvested/co-authored credit uses a GitHub numeric noreply address (Signed-off-by uses the numeric noreply address)

Devin Review

Add Serply (https://serply.io) as an opt-in `[search]` provider alongside
Sofya and the other keyed backends. `provider = "serply"` sends
`GET https://api.serply.io/v1/search?q=...&num=...` with the key in an
`X-Api-Key` header and maps `results[].title/link/description` onto
`WebSearchEntry`; ads, knowledge graph and related questions are ignored.

The key comes from `[search] api_key` or the `SERPLY_API_KEY` env var.
Preflight fails closed with a clear message when neither is set, and
`SERPLY_API_KEY` joins the workspace `.env` credential allowlist.
`BackendId::Serply` records receipts, `api.serply.io` is the network-policy
and `default_backend_host` host, and `search_probe_target` covers it for
`doctor`. Firecrawl stays the default; existing configs are unchanged.

Docs: config.example.toml, docs/CONFIGURATION.md and the zh_hans copy.

Signed-off-by: googio <59339358+googio@users.noreply.github.com>
@googio
googio requested a review from Hmbown as a code owner September 11, 2026 21:06
@github-actions

Copy link
Copy Markdown
Contributor

Thanks @googio for taking the time to contribute.

This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant recurring PR access by commenting /lgtm on a pull request.

devin-ai-integration[bot]

This comment was marked as resolved.

…nd chain

run_serply_search classified a missing API key as ExecutionFailed, which
run_backend_chain treats as recoverable, so a configured Serply route that
reached the adapter after a failed provider-native attempt degraded to
DuckDuckGo instead of stopping. Classify it as InvalidInput, matching the
preflight not_configured path, and pin the classification with a test that
fails without the change.

Signed-off-by: googio <59339358+googio@users.noreply.github.com>
@Hmbown
Hmbown enabled auto-merge (squash) September 12, 2026 05:32

@Hmbown Hmbown left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you so much for this!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants