Skip to content

feat: add TavilySearchTool and related functionality for web search#2701

Merged
Lancetnik merged 5 commits intoag2ai:mainfrom
vvlrff:tavily-search
Apr 21, 2026
Merged

feat: add TavilySearchTool and related functionality for web search#2701
Lancetnik merged 5 commits intoag2ai:mainfrom
vvlrff:tavily-search

Conversation

@vvlrff
Copy link
Copy Markdown
Collaborator

@vvlrff vvlrff commented Apr 18, 2026

TavilySearchTool

API

from autogen.beta.tools import TavilySearchTool

Constructor

TavilySearchTool(
    api_key: str | None = None,
    max_results: int | Variable | None = None,
    search_depth: Literal["basic", "advanced", "fast", "ultra-fast"] | Variable | None = None,
    topic: Literal["general", "news", "finance"] | Variable | None = None,
    include_answer: bool | Literal["basic", "advanced"] | Variable | None = None,
    include_raw_content: bool | Literal["markdown", "text"] | Variable | None = None,
    include_images: bool | Variable | None = None,
    time_range: Literal["day", "week", "month", "year"] | Variable | None = None,
    start_date: str | Variable | None = None,
    end_date: str | Variable | None = None,
    days: int | Variable | None = None,
    include_domains: Sequence[str] | Variable | None = None,
    exclude_domains: Sequence[str] | Variable | None = None,
    country: str | Variable | None = None,
    auto_parameters: bool | Variable | None = None,
    include_favicon: bool | Variable | None = None,
    client: TavilyClient | None = None,
    name: str = "tavily_search",
    *,
    description: str = "Search the web using Tavily. Returns titles, URLs, snippets, relevance scores, and optional LLM-generated answer, raw content, and images.",
    middleware: Iterable[ToolMiddleware] = (),
)

All search parameters accept Variable for deferred resolution from context.variables at call time. None values are not forwarded to the Tavily API, so Tavily's server-side defaults apply.

Parameter Type Default Description
api_key str | None None Tavily API key. If None, TavilyClient falls back to TAVILY_API_KEY env var.
max_results int | Variable | None None Max results per search
search_depth "basic" | "advanced" | "fast" | "ultra-fast" | Variable | None None Quality / cost trade-off
topic "general" | "news" | "finance" | Variable | None None Topical filter
include_answer bool | "basic" | "advanced" | Variable | None None Attach an LLM-generated answer to the response
include_raw_content bool | "markdown" | "text" | Variable | None None Include full page content per result
include_images bool | Variable | None None Include image URLs
time_range "day" | "week" | "month" | "year" | Variable | None None Relative time window
start_date / end_date str | Variable | None None Absolute date range (ISO 8601)
days int | Variable | None None Look-back window in days
include_domains / exclude_domains Sequence[str] | Variable | None None Allow-list / block-list of domains
country str | Variable | None None Country code for locale-biased results
auto_parameters bool | Variable | None None Let Tavily auto-tune search parameters
include_favicon bool | Variable | None None Attach favicon URL to each result
client TavilyClient | None None Custom TavilyClient instance (for proxy, custom base URL, etc.)
name str "tavily_search" Tool name exposed to the LLM
description str auto Tool description exposed to the LLM
middleware Iterable[ToolMiddleware] () Tool-level middleware

Tool schema (what the LLM sees)

{
  "name": "tavily_search",
  "parameters": {
    "properties": {
      "query": { "type": "string", "description": "The search query string." }
    },
    "required": ["query"]
  }
}

Return type

The tool returns a SearchResponse dataclass. The framework serialises it to JSON automatically when forwarding the result back to the LLM.

@dataclass(slots=True)
class SearchResult:
    title: str
    url: str
    snippet: str
    score: float | None = None
    raw_content: str | None = None
    favicon: str | None = None

@dataclass(slots=True)
class SearchResponse:
    query: str
    results: list[SearchResult]        # empty list when nothing was found
    answer: str | None = None          # populated when include_answer is set
    images: list[str] = []             # populated when include_images=True

Example (serialised form seen by the LLM):

{
  "query": "ag2 framework",
  "results": [
    {
      "title": "AG2 Framework",
      "url": "https://ag2.ai",
      "snippet": "AG2 is an open-source agent framework.",
      "score": 0.95,
      "raw_content": null,
      "favicon": "https://ag2.ai/favicon.ico"
    },
    {
      "title": "GitHub - AG2",
      "url": "https://github.com/ag2ai/ag2",
      "snippet": "Open source repo for AG2.",
      "score": 0.82,
      "raw_content": null,
      "favicon": null
    }
  ],
  "answer": "AG2 is an open-source multi-agent framework.",
  "images": []
}

Empty result: {"query": "...", "results": [], "answer": null, "images": []}.

Usage examples

Basic

import asyncio
from autogen.beta import Agent
from autogen.beta.config import OpenAIConfig
from autogen.beta.tools import TavilySearchTool

config = OpenAIConfig(model="gpt-4o", api_key="...")
tavily = TavilySearchTool()  # reads TAVILY_API_KEY from env

agent = Agent("researcher", "You are a research assistant.", config=config, tools=[tavily])

async def main():
    reply = await agent.ask("What is the AG2 framework? Search the web.")
    print(await reply.content())

asyncio.run(main())

Tuned for quality

tavily = TavilySearchTool(
    api_key="tvly-...",
    max_results=10,
    search_depth="advanced",
    include_answer=True,
    include_raw_content="markdown",
    include_domains=["arxiv.org", "github.com"],
)

@vvlrff vvlrff requested a review from Lancetnik as a code owner April 18, 2026 20:05
@github-actions github-actions Bot added the beta label Apr 18, 2026
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Apr 18, 2026
@priyansh4320
Copy link
Copy Markdown
Collaborator

@claude add a review

@claude
Copy link
Copy Markdown

claude Bot commented Apr 21, 2026

Claude Code is working…

I'll analyze this and get back to you.

View job run

Comment thread test/beta/tools/search/test_resolve.py
@Lancetnik Lancetnik added this pull request to the merge queue Apr 21, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Apr 21, 2026
@Lancetnik Lancetnik merged commit 26919b2 into ag2ai:main Apr 21, 2026
19 of 21 checks passed
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 24.07407% with 41 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
autogen/beta/tools/search/tavily.py 12.76% 41 Missing ⚠️
Files with missing lines Coverage Δ
autogen/beta/tools/__init__.py 100.00% <100.00%> (ø)
autogen/beta/tools/search/__init__.py 100.00% <100.00%> (ø)
autogen/beta/tools/search/tavily.py 12.76% <12.76%> (ø)

... and 351 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

beta dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants