# NousResearch/hermes-agent · Expose limit parameter in web_search tool

## Open now

- Nothing open on GitHub.

These items concern adding and exposing a limit parameter for the web_search tool, along with documenting query operators. The request appears across a feature issue and two related pull requests.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #16934. Verify it addresses your case.
- **Recommended:** read PR #16934 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-16934`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #16696: \[Feature\]: Expose limit parameter and document query operators in web_search tool

## Prior & competing PRs

- **#16934: feat(web): expose limit for web_search**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `tests/tools/test_web_tools_config.py`, `tools/web_tools.py`, `website/docs/reference/tools-reference.md`
  - fix hunks:
  - `tests/tools/test_web_tools_config.py`

    ```diff
    @@ -448,6 +448,54 @@ def test_singleton_returns_same_instance(self):
                 assert client1 is client2
     
     
    +class TestWebSearchSchema:
    +    """Test suite for web_search tool schema and handler wiring."""
    +
    +    def test_schema_exposes_optional_limit(self):
    +        import tools.web_tools
    +
    +        limit_schema = tools.web_tools.WEB_SEARCH_SCHEMA["parameters"]["properties"]["limit"]
    +
    +        assert limit_schema["type"] == "integer"
    +        assert limit_schema["minimum"] == 1
    +        assert limit_schema["maximum"] == 100
    +        assert limit_schema["default"] == 5
    +        assert "limit" not in tools.web_tools.WEB_SEARCH_SCHEMA["parameters"]["required"]
    +
    +    def test_registered_handler_passes_limit(self):
    +        import tools.web_tools
    +
    +        entry = tools.web_tools.registry.get_entry("web_search")
    +        with patch("tools.web_tools.web_search_tool", return_value='{"success": true}') as mock_search:
    +            result = entry.handler({"query": "site:example.com docs", "limit": 12})
    +
    +        assert result == '{"success": true}'
    +        mock_search.assert_called_once_with("site:example.com docs", limit=12)
    +
    +    def test_registered_handler_defaults_limit_to_five(self):
    +        import tools.web_tools
    +
    +        entry = tools.web_tools.registry.get_entry("web_search")
    +        with patch("tools.web_tools.web_search_tool", return_value='{"success": true}') as mock_search:
    +            result = entry.handler({"query": "docs"})
    +
    +        assert result == '{"success": true}'
    +        mock_search.assert_called_once_with("docs", limit=5)
    +
    +    def test_web_search_clamps_limit_before_backend_call(self):
    +        import tools.web_tools
    +
    +        with patch("tools.web_tools._get_backend", return_value="parallel"), \
    +             patch("tools.web_tools._parallel_search", return_value={"success": True, "data": {"web": []}}) as mock_search, \
    +             patch("tools.interrupt.is_interrupted", return_value=False), \
    +             patch.object(tools.web_tools._debug, "log_call"), \
    +             patch.object(tools.web_tools._debug, "save"):
    +            result = json.loads(tools.web_tools.web_search_tool("docs", limit=500))
    +
    +        assert result == {"success": True, "data": {"web": []}}
    +        mock_search.assert_called_once_with("docs", 100)
    +
    +
     class TestWebSearchErrorHandling:
         """Test suite for web_search_tool() error responses."""
     
    ```
  - `tools/web_tools.py`

    ```diff
    @@ -1066,6 +1066,12 @@ def web_search_tool(query: str, limit: int = 5) -> str:
         Raises:
             Exception: If search fails or API key is not set
         """
    +    try:
    +        limit = int(limit)
    +    except (TypeError, ValueError):
    +        limit = 5
    +    limit = min(max(limit, 1), 100)
    +
         debug_call_data = {
             "parameters": {
                 "query": query,
    ```

    ```diff
    @@ -2047,13 +2053,20 @@ def check_auxiliary_model() -> bool:
     
     WEB_SEARCH_SCHEMA = {
         "name": "web_search",
    -    "description": "Search the web for information on any topic. Returns up to 5 relevant results with titles, URLs, and descriptions.",
    +    "description": "Search the web for information. Returns up to 5 results by default with titles, URLs, and descriptions. The query is passed through to the configured backend, so operators such as site:domain, filetype:pdf, intitle:word, -term, and \"exact phrase\" may work when the backend supports them.",
         "parameters": {
             "type": "object",
             "properties": {
                 "query": {
                     "type": "string",
    -                "description": "The search query to look up on the web"
    +                "description": "The search query to look up on the web. You may include backend-supported operators such as site:example.com, filetype:pdf, intitle:word, -term, or \"exact phrase\"."
    +            },
    +            "limit": {
    +                "type": "integer",
    +                "description": "Maximum number of results to return. Defaults to 5.",
    +                "minimum": 1,
    +                "maximum": 100,
    +                "default": 5
                 }
             },
             "required": ["query"]
    ```

    ```diff
    @@ -2081,7 +2094,7 @@ def check_auxiliary_model() -> bool:
         name="web_search",
         toolset="web",
         schema=WEB_SEARCH_SCHEMA,
    -    handler=lambda args, **kw: web_search_tool(args.get("query", ""), limit=5),
    +    handler=lambda args, **kw: web_search_tool(args.get("query", ""), limit=args.get("limit", 5)),
         check_fn=check_web_api_key,
         requires_env=_web_requires_env(),
         emoji="🔍",
    ```
  - `website/docs/reference/tools-reference.md`

    ```diff
    @@ -179,7 +179,7 @@ Scoped to the Feishu document-comment handler. Drives comment read/write operati
     
     | Tool | Description | Requires environment |
     |------|-------------|----------------------|
    -| `web_search` | Search the web for information on any topic. Returns up to 5 relevant results with titles, URLs, and descriptions. | EXA_API_KEY or PARALLEL_API_KEY or FIRECRAWL_API_KEY or TAVILY_API_KEY |
    +| `web_search` | Search the web for information. Returns up to 5 results by default with titles, URLs, and descriptions. Accepts an optional `limit` (1-100, default 5). The query is passed through to the configured backend, so operators such as `site:domain`, `filetype:pdf`, `intitle:word`, `-term`, and `"exact phrase"` may work when the backend supports them. | EXA_API_KEY or PARALLEL_API_KEY or FIRECRAWL_API_KEY or TAVILY_API_KEY |
     | `web_extract` | Extract content from web page URLs. Returns page content in markdown format. Also works with PDF URLs — pass the PDF link directly and it converts to markdown text. Pages under 5000 chars return full markdown; larger pages are LLM-summarized. | EXA_API_KEY or PARALLEL_API_KEY or FIRECRAWL_API_KEY or TAVILY_API_KEY |
     
     ## `tts` toolset
    ```
- **#16808: feat(web): expose limit for web_search**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#16934`, `#16696`

## Fix status

- Merged to main in PR #16934 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-04-28`. This confirmation is old and may be out of date (a revert/reopen would not have invalidated it here); re-verify.
