Skip to content

Commit d07a62c

Browse files
vinnymellerKludex
andauthored
feat: support Google's url_context builtin tool (#2604)
Co-authored-by: Marcelo Trylesinski <[email protected]>
1 parent 7d6cef3 commit d07a62c

File tree

7 files changed

+136
-4
lines changed

7 files changed

+136
-4
lines changed

docs/builtin-tools.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ Builtin tools are native tools provided by LLM providers that can be used to enh
44

55
## Overview
66

7-
PydanticAI supports two types of builtin tools:
7+
PydanticAI supports the following builtin tools:
88

99
- **[`WebSearchTool`][pydantic_ai.builtin_tools.WebSearchTool]**: Allows agents to search the web
1010
- **[`CodeExecutionTool`][pydantic_ai.builtin_tools.CodeExecutionTool]**: Enables agents to execute code in a secure environment
11+
- **[`UrlContextTool`][pydantic_ai.builtin_tools.UrlContextTool]**: Enables agents to pull URL contents into their context
1112

1213
These tools are passed to the agent via the `builtin_tools` parameter and are executed by the model provider's infrastructure.
1314

@@ -118,6 +119,35 @@ result = agent.run_sync('Calculate the factorial of 15 and show your work')
118119
# > The factorial of 15 is **1,307,674,368,000**.
119120
```
120121

122+
## URL Context Tool
123+
124+
The [`UrlContextTool`][pydantic_ai.builtin_tools.UrlContextTool] enables your agent to pull URL contents into its context,
125+
allowing it to pull up-to-date information from the web.
126+
127+
### Provider Support
128+
129+
| Provider | Supported |
130+
|----------|-----------|
131+
| Google ||
132+
| OpenAI ||
133+
| Anthropic ||
134+
| Groq ||
135+
| Bedrock ||
136+
| Mistral ||
137+
| Cohere ||
138+
| HuggingFace ||
139+
140+
### Usage
141+
142+
```py title="url_context_basic.py"
143+
from pydantic_ai import Agent, UrlContextTool
144+
145+
agent = Agent('google-gla:gemini-2.5-flash', builtin_tools=[UrlContextTool()])
146+
147+
result = agent.run_sync('What is this? https://ai.pydantic.dev')
148+
# > A Python agent framework for building Generative AI applications.
149+
```
150+
121151
## API Reference
122152

123153
For complete API documentation, see the [API Reference](api/builtin_tools.md).

pydantic_ai_slim/pydantic_ai/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from importlib.metadata import version as _metadata_version
22

33
from .agent import Agent, CallToolsNode, EndStrategy, ModelRequestNode, UserPromptNode, capture_run_messages
4-
from .builtin_tools import CodeExecutionTool, WebSearchTool, WebSearchUserLocation
4+
from .builtin_tools import CodeExecutionTool, UrlContextTool, WebSearchTool, WebSearchUserLocation
55
from .exceptions import (
66
AgentRunError,
77
FallbackExceptionGroup,
@@ -45,6 +45,7 @@
4545
# builtin_tools
4646
'WebSearchTool',
4747
'WebSearchUserLocation',
48+
'UrlContextTool',
4849
'CodeExecutionTool',
4950
# output
5051
'ToolOutput',

pydantic_ai_slim/pydantic_ai/builtin_tools.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,11 @@ class CodeExecutionTool(AbstractBuiltinTool):
103103
* OpenAI
104104
* Google
105105
"""
106+
107+
108+
class UrlContextTool(AbstractBuiltinTool):
109+
"""Allows your agent to access contents from URLs.
110+
111+
Supported by:
112+
* Google
113+
"""

pydantic_ai_slim/pydantic_ai/models/google.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from .. import UnexpectedModelBehavior, _utils, usage
1414
from .._output import OutputObjectDefinition
1515
from .._run_context import RunContext
16-
from ..builtin_tools import CodeExecutionTool, WebSearchTool
16+
from ..builtin_tools import CodeExecutionTool, UrlContextTool, WebSearchTool
1717
from ..exceptions import UserError
1818
from ..messages import (
1919
BinaryContent,
@@ -72,6 +72,7 @@
7272
ToolConfigDict,
7373
ToolDict,
7474
ToolListUnionDict,
75+
UrlContextDict,
7576
)
7677

7778
from ..providers.google import GoogleProvider
@@ -270,6 +271,8 @@ def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[T
270271
for tool in model_request_parameters.builtin_tools:
271272
if isinstance(tool, WebSearchTool):
272273
tools.append(ToolDict(google_search=GoogleSearchDict()))
274+
elif isinstance(tool, UrlContextTool):
275+
tools.append(ToolDict(url_context=UrlContextDict()))
273276
elif isinstance(tool, CodeExecutionTool): # pragma: no branch
274277
tools.append(ToolDict(code_execution=ToolCodeExecutionDict()))
275278
else: # pragma: no cover
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
interactions:
2+
- request:
3+
body: '{"contents": [{"parts": [{"text": "What is the first sentence on the page
4+
https://ai.pydantic.dev? Reply with only the sentence."}], "role": "user"}],
5+
"systemInstruction": {"parts": [{"text": "You are a helpful chatbot."}], "role":
6+
"user"}, "tools": [{"urlContext": {}}], "generationConfig": {}}'
7+
headers:
8+
accept:
9+
- '*/*'
10+
accept-encoding:
11+
- gzip, deflate
12+
connection:
13+
- keep-alive
14+
content-length:
15+
- '295'
16+
content-type:
17+
- application/json
18+
host:
19+
- generativelanguage.googleapis.com
20+
method: POST
21+
uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
22+
response:
23+
body:
24+
string: "{\n \"candidates\": [\n {\n \"content\": {\n \"parts\"\
25+
: [\n {\n \"text\": \"Pydantic AI is a Python agent framework\
26+
\ designed to make it less painful to build production grade applications\
27+
\ with Generative AI.\"\n }\n ],\n \"role\": \"model\"\
28+
\n },\n \"finishReason\": \"STOP\",\n \"index\": 0,\n \
29+
\ \"groundingMetadata\": {\n \"groundingChunks\": [\n {\n\
30+
\ \"web\": {\n \"uri\": \"https://ai.pydantic.dev\"\
31+
,\n \"title\": \"Pydantic AI\"\n }\n }\n\
32+
\ ],\n \"groundingSupports\": [\n {\n \"\
33+
segment\": {\n \"endIndex\": 131,\n \"text\": \"\
34+
Pydantic AI is a Python agent framework designed to make it less painful to\
35+
\ build production grade applications with Generative AI.\"\n },\n\
36+
\ \"groundingChunkIndices\": [\n 0\n ]\n\
37+
\ }\n ]\n },\n \"urlContextMetadata\": {\n \
38+
\ \"urlMetadata\": [\n {\n \"retrievedUrl\": \"https://ai.pydantic.dev\"\
39+
,\n \"urlRetrievalStatus\": \"URL_RETRIEVAL_STATUS_SUCCESS\"\n\
40+
\ }\n ]\n }\n }\n ],\n \"usageMetadata\": {\n \
41+
\ \"promptTokenCount\": 32,\n \"candidatesTokenCount\": 41,\n \"totalTokenCount\"\
42+
: 2515,\n \"promptTokensDetails\": [\n {\n \"modality\": \"\
43+
TEXT\",\n \"tokenCount\": 32\n }\n ],\n \"toolUsePromptTokenCount\"\
44+
: 2395,\n \"toolUsePromptTokensDetails\": [\n {\n \"modality\"\
45+
: \"TEXT\",\n \"tokenCount\": 2395\n }\n ],\n \"thoughtsTokenCount\"\
46+
: 47\n },\n \"modelVersion\": \"gemini-2.5-flash\",\n \"responseId\": \"\
47+
qgqkaI-iDLrTjMcP0bP24A4\"\n}\n"
48+
headers:
49+
Alt-Svc:
50+
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
51+
Content-Type:
52+
- application/json; charset=UTF-8
53+
Date:
54+
- Tue, 19 Aug 2025 05:24:58 GMT
55+
Server:
56+
- scaffolding on HTTPServer2
57+
Server-Timing:
58+
- gfet4t7; dur=9182
59+
Transfer-Encoding:
60+
- chunked
61+
Vary:
62+
- Origin
63+
- X-Origin
64+
- Referer
65+
X-Content-Type-Options:
66+
- nosniff
67+
X-Frame-Options:
68+
- SAMEORIGIN
69+
X-XSS-Protection:
70+
- '0'
71+
content-length:
72+
- '1627'
73+
status:
74+
code: 200
75+
message: OK
76+
version: 1

tests/models/test_google.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from pydantic_ai import UsageLimitExceeded
1414
from pydantic_ai.agent import Agent
15-
from pydantic_ai.builtin_tools import CodeExecutionTool, WebSearchTool
15+
from pydantic_ai.builtin_tools import CodeExecutionTool, UrlContextTool, WebSearchTool
1616
from pydantic_ai.exceptions import ModelRetry, UnexpectedModelBehavior, UserError
1717
from pydantic_ai.messages import (
1818
AudioUrl,
@@ -600,6 +600,19 @@ async def test_google_model_web_search_tool(allow_model_requests: None, google_p
600600
assert result.output == snapshot('Today is Wednesday, May 28, 2025, in Utrecht.\n')
601601

602602

603+
async def test_google_model_url_context_tool(allow_model_requests: None, google_provider: GoogleProvider):
604+
m = GoogleModel('gemini-2.5-flash', provider=google_provider)
605+
agent = Agent(m, system_prompt='You are a helpful chatbot.', builtin_tools=[UrlContextTool()])
606+
607+
result = await agent.run(
608+
'What is the first sentence on the page https://ai.pydantic.dev? Reply with only the sentence.'
609+
)
610+
611+
assert result.output == snapshot(
612+
'Pydantic AI is a Python agent framework designed to make it less painful to build production grade applications with Generative AI.'
613+
)
614+
615+
603616
async def test_google_model_code_execution_tool(allow_model_requests: None, google_provider: GoogleProvider):
604617
m = GoogleModel('gemini-2.0-flash', provider=google_provider)
605618
agent = Agent(m, system_prompt='You are a helpful chatbot.', builtin_tools=[CodeExecutionTool()])

tests/test_examples.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ async def call_tool(
304304
'Who was Albert Einstein?': 'Albert Einstein was a German-born theoretical physicist.',
305305
'What was his most famous equation?': "Albert Einstein's most famous equation is (E = mc^2).",
306306
'What is the date?': 'Hello Frank, the date today is 2032-01-02.',
307+
'What is this? https://ai.pydantic.dev': 'A Python agent framework for building Generative AI applications.',
307308
'Put my money on square eighteen': ToolCallPart(
308309
tool_name='roulette_wheel', args={'square': 18}, tool_call_id='pyd_ai_tool_call_id'
309310
),

0 commit comments

Comments
 (0)