Conversation
…ject#326) Add a keyless, self-hosted SearXNG backend for the gateway-owned web_search tool with a mandatory base URL validated at startup, typed request/response mapping (categories split, time_range, language normalization, numeric safesearch), client-side domain filtering and count truncation, actionable 403/429 diagnostics for the JSON format and bot-detection limiter, hermetic Axum mock coverage, and documentation. Signed-off-by: Zheng Lu <Lz429671594@gmail.com>
…review Signed-off-by: Zheng Lu <Lz429671594@gmail.com>
Zheng-Lu
force-pushed
the
feat/326-searxng-provider
branch
from
September 18, 2026 00:23
58223f2 to
7155f09
Compare
Zheng-Lu
marked this pull request as ready for review
September 18, 2026 01:04
Zheng-Lu
requested review from
bbrowning,
franciscojavierarceo,
haoshan98,
jiahuei,
leseb,
maralbahari,
noobHappylife,
qandrew and
tjtanaa
as code owners
September 18, 2026 01:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #326 (Part of #291).
Summary
Adds a self-hosted, keyless SearXNG backend for the gateway-owned
web_searchtool so air-gapped and privacy-sensitive deployments can run web search without any direct client queries leaving the local network.Key Changes
Provider Implementation (
crates/agentic-server-core/src/tool/web_search/searxng.rs):GET {base_url}/searchwithformat=json&categories=general,news,Accept: application/json, and optionalAuthorization: BearerfromSEARXNG_API_KEY.http(s)without a query or fragment; validated at startup and again by the provider, with/searchbuilt from the parsed path so sub-path mounts (e.g.http://host/searxng/) work.Accept-Encoding: gzipis never sent (corereqwestlacks gzip support).webandnewssections based on each result item'scategory.Input & Output Adaptations (verified against SearXNG
master):freshness: Maps named variants totime_range=day|week|month|year(date ranges are ignored with a debug log).language: Normalized to SearXNG's accepted^[a-z]{2,3}(-[A-Z]{2})?$format so complex BCP 47 subtags (e.g.zh-Hans) do not trigger a400error.safesearch: Mapped to numeric strings0|1|2.DomainFilter.count: Applied client-side after domain filtering (falling back tosearch_context_size), as SearXNG only has pagination (pageno).country,boost_domains, You.com crawl args) are safely ignored with debug logging.Actionable Diagnostics (Credential-Free):
403→ Points to JSON format disabled in SearXNG (search.formats: [html, json]).429→ Addresses SearXNG's bot-detection limiter (which blocks requests without gzip), guiding operators to configurebotdetection.ip_lists.pass_ipwith the gateway's source Pod IP / Pod CIDR, or setserver.limiter: false, and echoesRetry-After.401→ MentionsSEARXNG_API_KEYwithout echoing secrets.400→ Parameter error with upstream body.Configuration & Fail-Fast Validation:
WebSearchProviderKind::Searxng("searxng") and conventionalSEARXNG_API_KEY.resolve_web_search_configvalidates and rejects missing, non-HTTP(S), or query/fragment-bearing URLs at startup. Direct provider construction falls back to the sameSEARXNG_BASE_URL_HINT.Architecture, File Sizes & Non-Breaking API:
WebSearchProviderConfigbuilders andfrom_configare reused as-is).null_as_default,read_response_limited) frommod.rstoprovider.rswith re-exports, keepingmod.rswell within the 500-line limit (473 lines, chore: enforce Rust production file size limits #319) without modifying baseline policies."SearXNG"toclippy.tomldoc-valid-idents.Documentation:
README.md(quick start, provider table, SearXNG privacy boundary & limiter caveats),docs/deploying/README.md,docs/deploying/kubernetes.md(correct Pod CIDR guidance),CHANGELOG.md, andARCHITECTURE.md.Test Plan
Local Verification & Lints:
cargo fmt -- --check— passes.cargo clippy --all-targets -- -D warnings— passes with 0 warnings.cargo test --workspace— all workspace unit and integration tests pass (0 failures).pre-commit run --all-files(includingscripts/check_rust_file_sizes.py:mod.rs473,searxng.rs409,config.rs396 prod lines) — all hooks pass.Hermetic Integration Suite (
crates/agentic-server-core/tests/web_search_searxng_test.rs):127.0.0.1:0:"provider": "searxng"inmetadata[].format=json,categories,time_range,language, numericsafesearch, noAccept-Encoding, noAuthorizationwhen keyless).http://host/searxng/search).SEARXNG_API_KEYis configured.countbehavior and context size defaulting.403,401,429(asserts single request withRetry-After),400,502, and HTML responses without leaking secrets.Unit Tests:
searxng.rstesting pure mapping helpers (language normalization, category splitting, param rendering, URL validation).searxngprovider kind.Zero Regressions:
web_search_tool_test.rs,web_search_brave_test.rs) pass without regression.