Skip to content

feat(common_tools): add BraveSearchTool with web, news, image, video, and local search#5689

Open
LaurMost wants to merge 5 commits into
pydantic:mainfrom
LaurMost:feat/brave-search-tool
Open

feat(common_tools): add BraveSearchTool with web, news, image, video, and local search#5689
LaurMost wants to merge 5 commits into
pydantic:mainfrom
LaurMost:feat/brave-search-tool

Conversation

@LaurMost
Copy link
Copy Markdown

@LaurMost LaurMost commented May 27, 2026

Summary

Add BraveSearchTool: common tool providing access to the Brave Search API from Pydantic AI agents. Uses the existing httpx dependency and covers web, news, images, videos, LLM context, place search, local POIs, local descriptions, and rich search callbacks.

Changes

  • New pydantic_ai.common_tools.brave module with BraveSearchTool and typed response models
  • Tests in tests/test_brave.py
  • Documentation in docs/common-tools.md and API reference in docs/api/common_tools.md

Checklist

  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • No breaking changes in accordance with the version policy.
  • PR title is fit for the release changelog.

@github-actions github-actions Bot added size: XL Extra large PR (>1500 weighted lines) feature New feature request, or PR implementing a feature (enhancement) labels May 27, 2026
@Quantum0uasar
Copy link
Copy Markdown

Great addition to common_tools! I reviewed the implementation at pydantic_ai/common_tools/brave.py (1532 lines, 48.9 KB) and have some observations that might help before merge:

Strengths

  • Clean dual-mode design: individual tool factories (brave_web_search_tool, brave_llm_context_tool, etc.) vs. BraveSearchToolset for shared HTTP client — mirrors the existing Tavily pattern nicely.
  • Smart use of KW_ONLY + dataclass for typed response models.
  • Developer-controlled vs. LLM-controlled parameter separation via construction-time vs. call-time arguments is elegant.

Concerns / Suggestions

1. No timeout on httpx.AsyncClient

The _BraveAPIClient creates/uses an httpx.AsyncClient without an explicit timeout. Brave's Search API can be slow under load, and a hung request will block the agent indefinitely.

# Suggested default
client: httpx.AsyncClient = field(default_factory=lambda: httpx.AsyncClient(timeout=30.0))

2. No handling of HTTP 429 (rate limit) responses

response.raise_for_status() will raise an httpx.HTTPStatusError on 429, but the error message surfaced to the LLM will be a raw HTTP exception. Consider catching 429 specifically and raising a more descriptive RuntimeError:

if response.status_code == 429:
    raise RuntimeError("Brave Search API rate limit exceeded. Retry after a moment.")
response.raise_for_status()

3. TypeAdapter instantiated at module level (minor perf note)

If each response type has a module-level TypeAdapter, that's fine. But if they're re-instantiated per call, it's worth caching them as module-level singletons since TypeAdapter construction is not free.

4. No __init__.py export check

Make sure BraveSearchToolset and the individual tool factories are properly exported from pydantic_ai.common_tools (i.e., added to __init__.py or __all__ in the package), so users can do from pydantic_ai.common_tools import BraveSearchToolset consistently with the Tavily pattern.

5. Test coverage for error paths

The test file at tests/test_brave.py likely covers happy paths. It would strengthen confidence to add tests for:

  • Missing/invalid API key (expect a clear error message)
  • Simulated 429 response
  • Simulated network timeout

Using httpx.MockTransport or respx makes this straightforward without real API calls.

6. Docs mention gpt-5.2 in usage example

The usage snippet in the PR description references openai:gpt-5.2 — presumably a typo for gpt-4o or gpt-4.1. Worth fixing before merge to avoid confusion.

Overall this is a solid, well-structured contribution. The concerns above are mostly about production robustness (timeouts, rate limits) rather than correctness. Happy to see Brave Search land as a first-class common tool alongside Tavily!

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

Labels

feature New feature request, or PR implementing a feature (enhancement) size: XL Extra large PR (>1500 weighted lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants