Skip to content

feat: add Brave and TinyFish web search providers#252

Open
JithendraNara wants to merge 5 commits into
NVIDIA-AI-Blueprints:developfrom
JithendraNara:feat/brave-tinyfish-web-search
Open

feat: add Brave and TinyFish web search providers#252
JithendraNara wants to merge 5 commits into
NVIDIA-AI-Blueprints:developfrom
JithendraNara:feat/brave-tinyfish-web-search

Conversation

@JithendraNara
Copy link
Copy Markdown

Summary

  • add brave_web_search source package for Brave Search API web results
  • add tinyfish_web_search source package for TinyFish Search API web results
  • wire both packages into uv workspace, Docker build, env example, and docs

Testing

  • uv run ruff check sources/brave_web_search sources/tinyfish_web_search
  • uv run pytest sources/brave_web_search/tests sources/tinyfish_web_search/tests
  • uv run pytest sources/exa_web_search/tests sources/brave_web_search/tests sources/tinyfish_web_search/tests
  • uv lock --check
  • uv run python -m py_compile sources/brave_web_search/src/register.py sources/tinyfish_web_search/src/register.py
  • git diff --check

Notes

  • Live provider calls are not run in tests; API interactions are mocked to avoid requiring provider credentials in CI or local review.

Signed-off-by: Jithendra Nara <jnara01@indianatech.net>
Copilot AI review requested due to automatic review settings May 23, 2026 21:33
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds two new NAT data source plugins for web search providers (Brave Search API and TinyFish Search API), including registration logic, packaging, tests, and docs updates.

Changes:

  • Introduces brave_web_search and tinyfish_web_search source packages with NAT registration functions and configs.
  • Adds unit tests covering default config behavior, formatting, retries, truncation, and missing-key stubs.
  • Updates workspace/dev dependencies, Docker build, env examples, and documentation to include both new providers.

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sources/tinyfish_web_search/src/register.py Implements TinyFish NAT tool config + registration and request/formatting logic
sources/tinyfish_web_search/tests/test_tinyfish_register.py Adds tests for TinyFish config + tool behavior
sources/tinyfish_web_search/src/init.py Exposes TinyFish tool entrypoint
sources/tinyfish_web_search/pyproject.toml Packages TinyFish plugin and registers NAT entry point
sources/tinyfish_web_search/README.md Documents TinyFish configuration
sources/brave_web_search/src/register.py Implements Brave NAT tool config + registration and request/formatting logic
sources/brave_web_search/tests/test_brave_register.py Adds tests for Brave config + tool behavior
sources/brave_web_search/src/init.py Exposes Brave tool entrypoint
sources/brave_web_search/pyproject.toml Packages Brave plugin and registers NAT entry point
sources/brave_web_search/README.md Documents Brave configuration
pyproject.toml Adds Brave/TinyFish packages to workspace/dev deps
docs/source/resources/troubleshooting.md Adds troubleshooting rows for Brave/TinyFish keys
docs/source/resources/faq.md Lists Brave/TinyFish as available web search tools
docs/source/get-started/quick-start.md Adds env var hints for Brave/TinyFish
docs/source/get-started/installation.md Adds install/key docs for Brave/TinyFish
docs/source/extending/adding-a-tool.md Adds Brave/TinyFish to tool list table
docs/source/extending/adding-a-data-source.md Adds Brave/TinyFish to data source list table
docs/source/deployment/kubernetes.md Documents Brave/TinyFish env vars
docs/source/deployment/docker-compose.md Documents Brave/TinyFish env vars
docs/source/deployment/docker-build.md Adds Brave/TinyFish to Docker build install list
docs/source/customization/tools-and-sources.md Updates backend-API-key examples to include Brave/TinyFish
docs/source/customization/configuration-reference.md Adds config reference sections for Brave/TinyFish
deploy/Dockerfile Installs Brave/TinyFish source packages in the image
deploy/.env.example Adds optional env vars for Brave/TinyFish
README.md Updates install instructions and API key table for new providers

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +86 to +93
def _render_document(result: dict, max_content_length: int | None) -> str:
url = result.get("url", "") or ""
title = result.get("title", "") or ""
site_name = result.get("site_name") or ""
snippet = result.get("snippet") or result.get("description") or ""
body_parts = [str(part) for part in (site_name, snippet) if part]
body = _truncate_content("\n".join(body_parts), max_content_length)
return f'<Document href="{url}">\n<title>\n{title}\n</title>\n{body}\n</Document>'
Comment on lines +94 to +105
def _render_document(result: dict, max_content_length: int | None) -> str:
url = result.get("url", "") or ""
title = result.get("title", "") or ""
snippets: list[str] = []
description = result.get("description") or result.get("snippet") or ""
if description:
snippets.append(str(description))
extra_snippets = result.get("extra_snippets") or []
if isinstance(extra_snippets, list):
snippets.extend(str(snippet) for snippet in extra_snippets if snippet)
body = _truncate_content("\n".join(snippets), max_content_length)
return f'<Document href="{url}">\n<title>\n{title}\n</title>\n{body}\n</Document>'
Comment on lines +81 to +83
if max_content_length and len(content) > max_content_length:
return content[: max_content_length - 3] + "..."
return content
Comment on lines +88 to +91
def _truncate_content(content: str, max_content_length: int | None) -> str:
if max_content_length and len(content) > max_content_length:
return content[: max_content_length - 3] + "..."
return content
Comment on lines +197 to +204
if "401" in error_msg or "Unauthorized" in error_msg:
return (
"Error: Brave web search failed due to invalid API key (401 Unauthorized).\n"
"Please check your BRAVE_API_KEY and ensure it is valid.\n"
)
if "429" in error_msg:
return "Error: Brave web search failed because the Brave Search API rate limit was exceeded.\n"
return f"Error: Brave web search failed - {error_msg}"
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR adds two new web search source packages — brave_web_search and tinyfish_web_search — following the same NAT plugin pattern as the existing exa_web_search. Both are wired into the uv workspace, Dockerfile, .env.example, and docs.

  • New packages: Each exposes a FunctionBaseConfig subclass with validated fields (ge=1, le=20, ge=1 on max_content_length), an async generator that registers a live or stub tool function, and shared helpers for HTTP, truncation, and HTML escaping.
  • Tests: Both packages include comprehensive mocked test suites covering document formatting, content truncation, HTML escaping, retry/backoff, stub-on-missing-key, and error-message formatting; async tests run via the root asyncio_mode = \"auto\" setting.
  • Infrastructure: Dockerfile, workspace members, and .env.example are updated consistently with existing patterns.

Confidence Score: 5/5

Both new packages are self-contained additions that follow established patterns in the codebase; no existing code paths are modified.

The changes add two independent source packages. Config validation is properly constrained, the truncation and escaping helpers are correct, and both packages have well-exercised mock-based test suites. The only findings are a post-loop dead-code return and a cosmetic retry-latency issue on empty results — neither affects correctness for users who receive valid API responses.

No files require special attention; the two register.py files contain the noted minor issues but are otherwise safe.

Important Files Changed

Filename Overview
sources/brave_web_search/src/register.py New Brave Search API integration; config is well-constrained (ge=1/le=20), truncation logic is correct, error handling covers 401/429; minor dead-code and retry-delay issues noted.
sources/tinyfish_web_search/src/register.py New TinyFish Search API integration; mirrors Brave implementation with correct le=20 bound and ge=1 on max_content_length; same unreachable-return and retry-delay patterns as brave.
sources/brave_web_search/tests/test_brave_register.py Comprehensive unit tests covering stub, document formatting, truncation, escaping, retries, 401/429, and empty-results; async tests run correctly via root asyncio_mode=auto.
sources/tinyfish_web_search/tests/test_tinyfish_register.py Comprehensive unit tests matching the Brave test suite structure; covers max_results client-side slicing, stub path, escaping, retries, and error responses.
deploy/Dockerfile Adds uv pip install steps for brave-web-search and tinyfish-web-search; consistent with existing source package install pattern.
deploy/.env.example Documents BRAVE_API_KEY and TINYFISH_API_KEY as commented-out optional keys alongside EXA_API_KEY; clear and correctly optional.

Sequence Diagram

sequenceDiagram
    participant App
    participant Register as brave/tinyfish_web_search (register)
    participant Env as os.environ
    participant API as Brave / TinyFish API

    App->>Register: tool_config (api_key, max_results, ...)
    Register->>Env: get API key (env var or config fallback)
    alt API key missing
        Register-->>App: yield stub FunctionInfo (error message)
    else API key present
        Register-->>App: yield live FunctionInfo
        App->>Register: call _search(question)
        loop up to max_retries
            Register->>API: "GET /search?q=...&count=..."
            alt HTTP error
                API-->>Register: HTTPError (401 / 429 / other)
            else Success
                API-->>Register: JSON payload
                Register->>Register: slice results[:max_results]
                Register->>Register: _truncate_content + html.escape
                Register-->>App: formatted Document XML
            end
        end
    end
Loading

Reviews (4): Last reviewed commit: "chore: merge upstream develop" | Re-trigger Greptile

Comment thread sources/tinyfish_web_search/src/register.py Outdated
Comment thread sources/brave_web_search/src/register.py
Signed-off-by: Jithendra Nara <jnara01@indianatech.net>
Signed-off-by: Jithendra Nara <jnara01@indianatech.net>
@JithendraNara
Copy link
Copy Markdown
Author

Addressed the bot review feedback in 2ffb696:

  • escaped provider response fields before rendering <Document> output
  • made max_content_length validation/truncation robust for tiny values
  • capped TinyFish max_results at 20 and documented the cap
  • added mocked 429 rate-limit tests for both providers

Re-ran:

  • uv run ruff check sources/brave_web_search sources/tinyfish_web_search
  • uv run pytest sources/brave_web_search/tests sources/tinyfish_web_search/tests
  • uv lock --check
  • uv run python -m py_compile sources/brave_web_search/src/register.py sources/tinyfish_web_search/src/register.py
  • git diff --check

Signed-off-by: Jithendra Nara <jnara01@indianatech.net>
Signed-off-by: Jithendra Nara <jnara01@indianatech.net>

# Conflicts:
#	.secrets.baseline
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants