From 6902ef7e28784e251f6af8666a3524bdd998e98a Mon Sep 17 00:00:00 2001 From: serply Date: Sat, 17 Oct 2026 09:30:40 -0400 Subject: [PATCH 1/2] web search: Serply as an API key service Moves third_party/mcp-cpp to the commit that adds serply-api to its catalogue, lists the id where the registry and the docs list the others, and notes it in the changelog. --- CHANGELOG.md | 5 +++++ docs/website/configuration.md | 8 ++++---- include/agentty/domain/web_search_config.hpp | 11 +++++++---- third_party/mcp-cpp | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 089668ae..ccbe64e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ All notable changes to agentty. Versions follow [SemVer](https://semver.org/). keys, [[Home]]/[[End]], [[Backspace]] and [[Delete]] edit it, [[Enter]] saves and [[Esc]] cancels. A title is one line of up to 60 bytes, and the thread keeps its place in the list. +- **Serply as a web search service.** `serply-api` joins the API key + services in Settings > Web Search: Google results from + [Serply](https://serply.io) ([docs](https://serply.io/docs)), with + Country and Freshness, up to 10 results a search. The key comes from the + key store or `AGENTTY_WEB_SEARCH_KEY_SERPLY_API`. ## [0.9.27] - 2026-10-17 ### Fixed diff --git a/docs/website/configuration.md b/docs/website/configuration.md index a69b7187..1e7874db 100644 --- a/docs/website/configuration.md +++ b/docs/website/configuration.md @@ -86,11 +86,11 @@ The Smart Mode *feature* toggles (which layers run) live in the `Ctrl+S` overlay |----------|---------| | `AGENTTY_WEB_SEARCH` | `auto` (default), `on`, or `off`. `auto` advertises `web_search` and leaves the result count to the model, as agentty did before the Web Search pane. `on` applies your `AGENTTY_WEB_SEARCH_COUNT` and `_MAX`. `off` removes `web_search` from every request, from the tool list `agentty mcp-serve` offers to other MCP clients, and refuses any call to it (a replayed thread, a call injected by an ACP client). `0`/`false`/`no` mean `off`; `1`/`true`/`yes` mean `auto` (search available, the model picks the count). | | `AGENTTY_WEB_SEARCH_COUNT` | Results when the model does not say how many. Applies only in `on`. Default `10`; range 1–20. | -| `AGENTTY_WEB_SEARCH_MAX` | Most results the model may ask for in one search; a larger request is clamped, and `0` or a negative count becomes `1`. Applies only in `on`. Default `20`; range 1–50. A search returns at most one result page from the service that answers, and each service caps it: 20 on Brave, Tavily, Serper and Perplexity, 30 on DuckDuckGo, 100 on Firecrawl and Exa. A larger request is cut to that cap. | -| `AGENTTY_WEB_SEARCH_EXCLUDE` | Domains never to return, space- or comma-separated (`pinterest.com w3schools.com`). Pasted URLs and `www.` are reduced to the host. Sent as `-site:` operators to Brave, DuckDuckGo and Serper, and as the service's own domain filter to Tavily, Firecrawl, Exa and Perplexity, so an excluded site never comes back and its slot goes to another result. Up to 20 sites go in the filter; any beyond that are added to the query as `-site:`. | -| `AGENTTY_WEB_SEARCH_PRIMARY`, `_SECONDARY`, `_FALLBACK` | Which service answers first, second and last; the first to succeed wins. A service id: `brave-free`, `ddg-free`, `tavily-free`, `firecrawl-free` (no account, card or key) or `brave-api`, `tavily-api`, `firecrawl-api`, `exa-api`, `serper-api`, `perplexity-api` (need an API key). `_SECONDARY` and `_FALLBACK` also take `none`. Defaults: `brave-free`, `ddg-free`, `tavily-free`. | +| `AGENTTY_WEB_SEARCH_MAX` | Most results the model may ask for in one search; a larger request is clamped, and `0` or a negative count becomes `1`. Applies only in `on`. Default `20`; range 1–50. A search returns at most one result page from the service that answers, and each service caps it: 10 on Serply, 20 on Brave, Tavily, Serper and Perplexity, 30 on DuckDuckGo, 100 on Firecrawl and Exa. A larger request is cut to that cap. | +| `AGENTTY_WEB_SEARCH_EXCLUDE` | Domains never to return, space- or comma-separated (`pinterest.com w3schools.com`). Pasted URLs and `www.` are reduced to the host. Sent as `-site:` operators to Brave, DuckDuckGo, Serper and Serply, and as the service's own domain filter to Tavily, Firecrawl, Exa and Perplexity, so an excluded site never comes back and its slot goes to another result. Up to 20 sites go in the filter; any beyond that are added to the query as `-site:`. | +| `AGENTTY_WEB_SEARCH_PRIMARY`, `_SECONDARY`, `_FALLBACK` | Which service answers first, second and last; the first to succeed wins. A service id: `brave-free`, `ddg-free`, `tavily-free`, `firecrawl-free` (no account, card or key) or `brave-api`, `tavily-api`, `firecrawl-api`, `exa-api`, `serper-api`, `serply-api`, `perplexity-api` (need an API key). `_SECONDARY` and `_FALLBACK` also take `none`. Defaults: `brave-free`, `ddg-free`, `tavily-free`. | | `AGENTTY_WEB_SEARCH_LANGUAGE` | `auto` (default) or a two-letter code (`en`, `de`, `ja`, ...) sent to the services that take one: Tavily, Brave API, Serper, Perplexity. The others ignore it. | -| `AGENTTY_WEB_SEARCH_KEY_` | An API key, taken from the environment instead of the key store: `AGENTTY_WEB_SEARCH_KEY_EXA_API`, `_BRAVE_API`, `_TAVILY_API`, `_FIRECRAWL_API`, `_SERPER_API`, `_PERPLEXITY_API`. Wins over a stored key and locks that row in the pane. Never written to disk. | +| `AGENTTY_WEB_SEARCH_KEY_` | An API key, taken from the environment instead of the key store: `AGENTTY_WEB_SEARCH_KEY_EXA_API`, `_BRAVE_API`, `_TAVILY_API`, `_FIRECRAWL_API`, `_SERPER_API`, `_SERPLY_API`, `_PERPLEXITY_API`. Wins over a stored key and locks that row in the pane. Never written to disk. | #### Choosing the services diff --git a/include/agentty/domain/web_search_config.hpp b/include/agentty/domain/web_search_config.hpp index 425cabe9..6304c325 100644 --- a/include/agentty/domain/web_search_config.hpp +++ b/include/agentty/domain/web_search_config.hpp @@ -54,8 +54,9 @@ namespace agentty::web_search_cfg { // // What a search can actually RETURN is capped per service: mcp-cpp asks the // service that answers for one result page and clamps the count to that -// service's documented maximum (WebSearchService::max_count: 20 for Brave, Tavily, -// Serper and Perplexity, 30 for DuckDuckGo, 100 for Firecrawl and Exa). So a +// service's documented maximum (WebSearchService::max_count: 10 for Serply, 20 +// for Brave, Tavily, Serper and Perplexity, 30 for DuckDuckGo, 100 for Firecrawl +// and Exa). So a // ceiling above a service's cap is accepted and clamped correctly, but yields // no more than that service gives. The ceiling is a limit, not a promise. inline constexpr int kCountMin = 1; @@ -71,10 +72,12 @@ inline constexpr int kMaxCountDefault = 20; // the two ever disagree. Primary cannot be empty; the other two can. inline constexpr std::string_view kServiceIds = "brave-free|ddg-free|tavily-free|firecrawl-free|" - "brave-api|tavily-api|firecrawl-api|exa-api|serper-api|perplexity-api"; + "brave-api|tavily-api|firecrawl-api|exa-api|serper-api|serply-api|" + "perplexity-api"; inline constexpr std::string_view kOptionalServiceIds = "none|brave-free|ddg-free|tavily-free|firecrawl-free|" - "brave-api|tavily-api|firecrawl-api|exa-api|serper-api|perplexity-api"; + "brave-api|tavily-api|firecrawl-api|exa-api|serper-api|serply-api|" + "perplexity-api"; // ISO 639-1, the languages the keyed services document support for. inline constexpr std::string_view kLanguages = "auto|en|de|fr|es|it|pt|nl|sv|da|fi|pl|cs|ru|uk|tr|ja|ko|zh|ar|he|hi"; diff --git a/third_party/mcp-cpp b/third_party/mcp-cpp index 3e1a57f5..3690988a 160000 --- a/third_party/mcp-cpp +++ b/third_party/mcp-cpp @@ -1 +1 @@ -Subproject commit 3e1a57f58898638d05b85770b563ac44aaa2029f +Subproject commit 3690988a937825210faa198472726befb52ebef5 From 2c1257de930629c963e2da209128995bc6439da2 Mon Sep 17 00:00:00 2001 From: serply Date: Sat, 17 Oct 2026 18:15:29 -0400 Subject: [PATCH 2/2] web search: Serply's country defaults to United States Moves third_party/mcp-cpp to 8663d3c, where serply-api sends gl=us when no country is chosen, and says so in the CHANGELOG entry and configuration.md. --- CHANGELOG.md | 5 +++-- docs/website/configuration.md | 2 +- third_party/mcp-cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccbe64e7..0c6eb740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,8 +20,9 @@ All notable changes to agentty. Versions follow [SemVer](https://semver.org/). - **Serply as a web search service.** `serply-api` joins the API key services in Settings > Web Search: Google results from [Serply](https://serply.io) ([docs](https://serply.io/docs)), with - Country and Freshness, up to 10 results a search. The key comes from the - key store or `AGENTTY_WEB_SEARCH_KEY_SERPLY_API`. + Country and Freshness, up to 10 results a search. Country defaults to + United States. The key comes from the key store or + `AGENTTY_WEB_SEARCH_KEY_SERPLY_API`. ## [0.9.27] - 2026-10-17 ### Fixed diff --git a/docs/website/configuration.md b/docs/website/configuration.md index 1e7874db..32afc848 100644 --- a/docs/website/configuration.md +++ b/docs/website/configuration.md @@ -98,7 +98,7 @@ The **Free** services need no account, card or key, but they are best effort: Br The **API key** services are the vendors' documented interfaces and do not depend on a page layout. Paste a key into the row under the slot that uses it and press Enter. It is stored encrypted (the OS keystore when `AGENTTY_USE_KEYSTORE` is set, otherwise a machine-bound sealed file) and is never written to `settings.json`; the row then reads `✓ key saved` and stays locked until *Remove key* forgets it. A key from `AGENTTY_WEB_SEARCH_KEY_` reads `● key from` the variable and is locked for as long as it is set. A keyed service chosen with no key is reported as such in the search result and the next slot is tried. -Each service offers up to seven extra settings which appear under its slot, and none for a service that has none. Most are a list to pick from: freshness, region, safe search, spell correction, exact phrases, sort order, and so on. Two are typed: Brave API's *Goggle* takes the `https://` URL of a hosted Goggle (a rules file on GitHub, GitLab or a Gist, registered at [search.brave.com/goggles/create](https://search.brave.com/goggles/create)) that re-ranks Brave's results, and Firecrawl's *Location* takes a place such as `San Francisco,California,United States`. A typed value is saved when you leave the row, and only if it is one the service accepts; otherwise the row goes back to what was saved. Empty the row to clear it. Settings are saved per service in `settings.json` under `web_search.dials`, so a choice survives moving the service between slots. Some only take effect together with another: Tavily's *Country* applies with the General topic, its *Safe search* not with the fast depths, and *Language match* only when a language is set. +Each service offers up to seven extra settings which appear under its slot, and none for a service that has none. Most are a list to pick from: freshness, region, safe search, spell correction, exact phrases, sort order, and so on. Two are typed: Brave API's *Goggle* takes the `https://` URL of a hosted Goggle (a rules file on GitHub, GitLab or a Gist, registered at [search.brave.com/goggles/create](https://search.brave.com/goggles/create)) that re-ranks Brave's results, and Firecrawl's *Location* takes a place such as `San Francisco,California,United States`. A typed value is saved when you leave the row, and only if it is one the service accepts; otherwise the row goes back to what was saved. Empty the row to clear it. Settings are saved per service in `settings.json` under `web_search.dials`, so a choice survives moving the service between slots. Some only take effect together with another: Tavily's *Country* applies with the General topic, its *Safe search* not with the fast depths, and *Language match* only when a language is set. Serply's *Country* defaults to United States: with no country, Serply answers from whichever region is free, and the results can change country from one search to the next. Kagi, Mojeek and Linkup are not offered yet: their request and response formats could not be verified against documentation or a real reply. diff --git a/third_party/mcp-cpp b/third_party/mcp-cpp index 3690988a..8663d3c8 160000 --- a/third_party/mcp-cpp +++ b/third_party/mcp-cpp @@ -1 +1 @@ -Subproject commit 3690988a937825210faa198472726befb52ebef5 +Subproject commit 8663d3c8bd5b25a8302db7d404e1a75fa25a46d1