Skip to content

pydantic_ai.common_tools

DuckDuckGoResult

Bases: TypedDict

A DuckDuckGo search result.

Attributes

title

The title of the search result.

Type: str

href

The URL of the search result.

Type: str

body

The body of the search result.

Type: str

DuckDuckGoSearchTool

The DuckDuckGo search tool.

Attributes

client

The DuckDuckGo search client.

Type: DDGS

max_results

The maximum number of results. If None, returns results only from the first response.

Type: int | None

Methods

__call__

@async

def __call__(query: str) -> list[DuckDuckGoResult]

Searches DuckDuckGo for the given query and returns the results.

Returns

list[DuckDuckGoResult] — The search results.

Parameters

query : str

The query to search for.

duckduckgo_search_tool

def duckduckgo_search_tool(
    duckduckgo_client: DDGS | None = None,
    max_results: int | None = None,
)

Creates a DuckDuckGo search tool.

Parameters

duckduckgo_client : DDGS | None Default: None

The DuckDuckGo search client.

max_results : int | None Default: None

The maximum number of results. If None, returns results only from the first response.

Exa tools for Pydantic AI agents.

Provides web search, content retrieval, and AI-powered answer capabilities using the Exa API, a neural search engine that finds high-quality, relevant results across billions of web pages.

These tools are deprecated and will be removed in v3. Use the ExaSearch capability from the Pydantic AI Harness instead.

ExaSearchResult

Bases: TypedDict

An Exa search result with content.

See Exa Search API documentation for more information.

Attributes

title

The title of the search result.

Type: str

url

The URL of the search result.

Type: str

published_date

The published date of the content, if available.

Type: str | None

author

The author of the content, if available.

Type: str | None

text

The text content of the search result.

Type: str

ExaAnswerResult

Bases: TypedDict

An Exa answer result with citations.

See Exa Answer API documentation for more information.

Attributes

answer

The AI-generated answer to the query.

Type: str

citations

Citations supporting the answer.

Type: list[dict[str, Any]]

ExaContentResult

Bases: TypedDict

Content retrieved from a URL.

See Exa Contents API documentation for more information.

Attributes

url

The URL of the content.

Type: str

title

The title of the page.

Type: str

text

The text content of the page.

Type: str

author

The author of the content, if available.

Type: str | None

published_date

The published date of the content, if available.

Type: str | None

ExaSearchTool

The Exa search tool.

Attributes

client

The Exa async client.

Type: AsyncExa

num_results

The number of results to return.

Type: int

max_characters

Maximum characters of text content per result, or None for no limit.

Type: int | None

Methods

__call__

@async

def __call__(
    query: str,
    search_type: Literal['auto', 'keyword', 'neural', 'fast', 'deep'] = 'auto',
) -> list[ExaSearchResult]

Searches Exa for the given query and returns the results with content.

Returns

list[ExaSearchResult] — The search results with text content.

Parameters

query : str

The search query to execute with Exa.

search_type : Literal[‘auto’, ‘keyword’, ‘neural’, ‘fast’, ‘deep’] Default: 'auto'

The type of search to perform. ‘auto’ automatically chooses the best search type, ‘keyword’ for exact matches, ‘neural’ for semantic search, ‘fast’ for speed-optimized search, ‘deep’ for comprehensive multi-query search.

ExaFindSimilarTool

The Exa find similar tool.

Attributes

client

The Exa async client.

Type: AsyncExa

num_results

The number of results to return.

Type: int

Methods

__call__

@async

def __call__(url: str, exclude_source_domain: bool = True) -> list[ExaSearchResult]

Finds pages similar to the given URL and returns them with content.

Returns

list[ExaSearchResult] — Similar pages with text content.

Parameters

url : str

The URL to find similar pages for.

exclude_source_domain : bool Default: True

Whether to exclude results from the same domain as the input URL. Defaults to True.

ExaGetContentsTool

The Exa get contents tool.

Attributes

client

The Exa async client.

Type: AsyncExa

Methods

__call__

@async

def __call__(urls: list[str]) -> list[ExaContentResult]

Gets the content of the specified URLs.

Returns

list[ExaContentResult] — The content of each URL.

Parameters

urls : list[str]

A list of URLs to get content for.

ExaAnswerTool

The Exa answer tool.

Attributes

client

The Exa async client.

Type: AsyncExa

Methods

__call__

@async

def __call__(query: str) -> ExaAnswerResult

Generates an AI-powered answer to the query with citations.

Returns

ExaAnswerResult — An answer with supporting citations from web sources.

Parameters

query : str

The question to answer.

ExaToolset

Bases: FunctionToolset

A toolset that provides Exa search tools with a shared client.

Deprecated in favor of the ExaSearch capability in the Pydantic AI Harness:

from pydantic_ai_harness.exa import ExaSearch

from pydantic_ai import Agent

agent = Agent('openai:gpt-5.2', capabilities=[ExaSearch()])

Methods

__init__
def __init__(
    api_key: str,
    *,
    num_results: int = 5,
    max_characters: int | None = None,
    include_search: bool = True,
    include_find_similar: bool = True,
    include_get_contents: bool = True,
    include_answer: bool = True,
    id: str | None = None,
)

Creates an Exa toolset with a shared client.

Parameters

api_key : str

The Exa API key.

You can get one by signing up at https://dashboard.exa.ai.

num_results : int Default: 5

The number of results to return for search and find_similar. Defaults to 5.

max_characters : int | None Default: None

Maximum characters of text content per result. Use this to limit token usage. Defaults to None (no limit).

include_search : bool Default: True

Whether to include the search tool. Defaults to True.

include_find_similar : bool Default: True

Whether to include the find_similar tool. Defaults to True.

include_get_contents : bool Default: True

Whether to include the get_contents tool. Defaults to True.

include_answer : bool Default: True

Whether to include the answer tool. Defaults to True.

id : str | None Default: None

Optional ID for the toolset, used for durable execution environments.

exa_search_tool

@deprecated

def exa_search_tool(
    api_key: str,
    *,
    num_results: int = 5,
    max_characters: int | None = None,
) -> Tool[Any]
def exa_search_tool(
    *,
    client: AsyncExa,
    num_results: int = 5,
    max_characters: int | None = None,
) -> Tool[Any]

Creates an Exa search tool.

Returns

Tool[Any]

Parameters

api_key : str | None Default: None

The Exa API key. Required if client is not provided.

You can get one by signing up at https://dashboard.exa.ai.

client : AsyncExa | None Default: None

An existing AsyncExa client. If provided, api_key is ignored. This is useful for sharing a client across multiple tools.

num_results : int Default: 5

The number of results to return. Defaults to 5.

max_characters : int | None Default: None

Maximum characters of text content per result. Use this to limit token usage. Defaults to None (no limit).

exa_find_similar_tool

@deprecated

def exa_find_similar_tool(api_key: str, *, num_results: int = 5) -> Tool[Any]
def exa_find_similar_tool(*, client: AsyncExa, num_results: int = 5) -> Tool[Any]

Creates an Exa find similar tool.

Returns

Tool[Any]

Parameters

api_key : str | None Default: None

The Exa API key. Required if client is not provided.

You can get one by signing up at https://dashboard.exa.ai.

client : AsyncExa | None Default: None

An existing AsyncExa client. If provided, api_key is ignored. This is useful for sharing a client across multiple tools.

num_results : int Default: 5

The number of similar results to return. Defaults to 5.

exa_get_contents_tool

@deprecated

def exa_get_contents_tool(api_key: str) -> Tool[Any]
def exa_get_contents_tool(*, client: AsyncExa) -> Tool[Any]

Creates an Exa get contents tool.

Returns

Tool[Any]

Parameters

api_key : str | None Default: None

The Exa API key. Required if client is not provided.

You can get one by signing up at https://dashboard.exa.ai.

client : AsyncExa | None Default: None

An existing AsyncExa client. If provided, api_key is ignored. This is useful for sharing a client across multiple tools.

exa_answer_tool

@deprecated

def exa_answer_tool(api_key: str) -> Tool[Any]
def exa_answer_tool(*, client: AsyncExa) -> Tool[Any]

Creates an Exa answer tool.

Returns

Tool[Any]

Parameters

api_key : str | None Default: None

The Exa API key. Required if client is not provided.

You can get one by signing up at https://dashboard.exa.ai.

client : AsyncExa | None Default: None

An existing AsyncExa client. If provided, api_key is ignored. This is useful for sharing a client across multiple tools.

TavilySearchResult

Bases: TypedDict

A Tavily search result.

See Tavily Search Endpoint documentation for more information.

Attributes

title

The title of the search result.

Type: str

url

The URL of the search result..

Type: str

content

A short description of the search result.

Type: str

score

The relevance score of the search result.

Type: float

TavilySearchTool

The Tavily search tool.

Attributes

client

The Tavily search client.

Type: AsyncTavilyClient

max_results

The maximum number of results. If None, the Tavily default is used.

Type: int | None Default: None

Methods

__call__

@async

def __call__(
    query: str,
    search_depth: Literal['basic', 'advanced', 'fast', 'ultra-fast'] = 'basic',
    topic: Literal['general', 'news', 'finance'] = 'general',
    time_range: Literal['day', 'week', 'month', 'year'] | None = None,
    include_domains: list[str] | None = None,
    exclude_domains: list[str] | None = None,
) -> list[TavilySearchResult]

Searches Tavily for the given query and returns the results.

Returns

list[TavilySearchResult] — A list of search results from Tavily.

Parameters

query : str

The search query to execute with Tavily.

search_depth : Literal[‘basic’, ‘advanced’, ‘fast’, ‘ultra-fast’] Default: 'basic'

The depth of the search.

topic : Literal[‘general’, ‘news’, ‘finance’] Default: 'general'

The category of the search.

time_range : Literal[‘day’, ‘week’, ‘month’, ‘year’] | None Default: None

The time range back from the current date to filter results.

include_domains : list[str] | None Default: None

List of domains to specifically include in the search results.

exclude_domains : list[str] | None Default: None

List of domains to specifically exclude from the search results.

tavily_search_tool

def tavily_search_tool(
    api_key: str,
    *,
    max_results: int | None = None,
    search_depth: Literal['basic', 'advanced', 'fast', 'ultra-fast'] = _UNSET,
    topic: Literal['general', 'news', 'finance'] = _UNSET,
    time_range: Literal['day', 'week', 'month', 'year'] | None = _UNSET,
    include_domains: list[str] | None = _UNSET,
    exclude_domains: list[str] | None = _UNSET,
) -> Tool[Any]
def tavily_search_tool(
    *,
    client: AsyncTavilyClient,
    max_results: int | None = None,
    search_depth: Literal['basic', 'advanced', 'fast', 'ultra-fast'] = _UNSET,
    topic: Literal['general', 'news', 'finance'] = _UNSET,
    time_range: Literal['day', 'week', 'month', 'year'] | None = _UNSET,
    include_domains: list[str] | None = _UNSET,
    exclude_domains: list[str] | None = _UNSET,
) -> Tool[Any]

Creates a Tavily search tool.

max_results is always developer-controlled and does not appear in the LLM tool schema. Other parameters, when provided, are fixed for all searches and hidden from the LLM’s tool schema. Parameters left unset remain available for the LLM to set per-call.

Returns

Tool[Any]

Parameters

api_key : str | None Default: None

The Tavily API key. Required if client is not provided.

You can get one by signing up at https://app.tavily.com/home.

client : AsyncTavilyClient | None Default: None

An existing AsyncTavilyClient. If provided, api_key is ignored. This is useful for sharing a client across multiple tool instances.

max_results : int | None Default: None

The maximum number of results. If None, the Tavily default is used.

search_depth : Literal[‘basic’, ‘advanced’, ‘fast’, ‘ultra-fast’] Default: _UNSET

The depth of the search.

topic : Literal[‘general’, ‘news’, ‘finance’] Default: _UNSET

The category of the search.

time_range : Literal[‘day’, ‘week’, ‘month’, ‘year’] | None Default: _UNSET

The time range back from the current date to filter results.

include_domains : list[str] | None Default: _UNSET

List of domains to specifically include in the search results.

exclude_domains : list[str] | None Default: _UNSET

List of domains to specifically exclude from the search results.

Web fetch tool for Pydantic AI agents.

Fetches web pages and converts their content to markdown using SSRF-protected HTTP requests and the markdownify library for HTML-to-markdown conversion.

WebFetchResult

Bases: TypedDict

Result of fetching a web page.

Attributes

url

The URL that was fetched.

Type: str

title

The page title, or empty string if not found.

Type: str

content

The page content converted to markdown.

Type: str

WebFetchLocalTool

Fetches a URL and converts the response to markdown.

Attributes

max_content_length

Maximum character length of returned content. None for no limit.

Type: int | None

allow_local_urls

Whether to allow fetching from private/local IP addresses.

Type: bool

timeout

Request timeout in seconds.

Type: int

allowed_domains

Only fetch from these domains (exact hostname match). Raises ModelRetry on violation.

Type: list[str] | None Default: field(default=None)

blocked_domains

Never fetch from these domains (exact hostname match). Raises ModelRetry on violation.

Type: list[str] | None Default: field(default=None)

headers

Additional HTTP headers to include in the request.

The model controls the URL, so use allowed_domains when these include credentials.

Type: dict[str, str] | None Default: field(default=None)

Methods

__call__

@async

def __call__(url: str) -> WebFetchResult | BinaryContent

Fetches the content of a web page at the given URL and returns it as markdown.

For textual content (HTML, JSON, plain text), returns a WebFetchResult. For binary content (PDF, images, etc.), returns a BinaryContent so the model can process it natively.

Returns

WebFetchResult | BinaryContent — The fetched page content.

Parameters

url : str

The URL to fetch.

web_fetch_tool

def web_fetch_tool(
    *,
    max_content_length: int | None = 50000,
    allow_local_urls: bool = False,
    timeout: int = 30,
    allowed_domains: list[str] | None = None,
    blocked_domains: list[str] | None = None,
    headers: dict[str, str] | None = None,
) -> Tool[Any]

Creates a web fetch tool that fetches URLs and converts content to markdown.

This tool uses SSRF protection via pydantic_ai._ssrf.safe_download.

By default, sends Accept: text/markdown to request markdown directly from servers that support it (e.g. Cloudflare, Vercel, Mintlify). This reduces token usage and improves content quality. Falls back to HTML-to-markdown conversion when the server doesn’t support markdown responses.

Returns

Tool[Any]

Parameters

max_content_length : int | None Default: 50000

Maximum character length of returned content. Defaults to 50,000 (~12,500 tokens). Use None for no limit.

allow_local_urls : bool Default: False

Whether to allow fetching from private/local IP addresses. Defaults to False.

timeout : int Default: 30

Request timeout in seconds. Defaults to 30.

allowed_domains : list[str] | None Default: None

Only fetch from these domains (exact hostname match). Raises ModelRetry on violation.

blocked_domains : list[str] | None Default: None

Never fetch from these domains (exact hostname match). Raises ModelRetry on violation.

headers : dict[str, str] | None Default: None

Additional HTTP headers to include in requests. Overrides the default Accept: text/markdown header if Accept is provided. The URL is controlled by the model, so a credential configured here (e.g. Authorization) can be sent to any URL the model requests that passes the domain filters, which match the hostname only, not scheme or port. On redirects, configured sensitive headers (Authorization, Cookie, Proxy-Authorization) are only forwarded to the same origin (scheme, host, and port) or a same-host http→https upgrade on the default ports.