diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b2b440ec0..9c7927295 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -60,6 +60,6 @@ repos: rev: v2.3.0 hooks: - id: codespell - args: ['--skip', 'tests/models/cassettes/*,docs/a2a/fasta2a.md'] + args: ['--skip', 'tests/models/cassettes/*,docs/a2a/fasta2a.md,tests/models/test_groq.py'] additional_dependencies: - tomli diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index bf8397174..ecd72ec25 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -12,6 +12,7 @@ from opentelemetry.trace import Tracer from typing_extensions import TypeGuard, TypeVar, assert_never +from pydantic_ai.builtin_tools import AbstractBuiltinTool from pydantic_graph import BaseNode, Graph, GraphRunContext from pydantic_graph.nodes import End, NodeRunEndT @@ -94,6 +95,7 @@ class GraphAgentDeps(Generic[DepsT, OutputDataT]): output_validators: list[_output.OutputValidator[DepsT, OutputDataT]] function_tools: dict[str, Tool[DepsT]] = dataclasses.field(repr=False) + builtin_tools: list[AbstractBuiltinTool] = dataclasses.field(repr=False) mcp_servers: Sequence[MCPServer] = dataclasses.field(repr=False) default_retries: int @@ -266,6 +268,7 @@ async def add_mcp_server_tools(server: MCPServer) -> None: output_schema = ctx.deps.output_schema return models.ModelRequestParameters( function_tools=function_tool_defs, + builtin_tools=ctx.deps.builtin_tools, allow_text_output=_output.allow_text_output(output_schema), output_tools=output_schema.tool_defs() if output_schema is not None else [], ) @@ -418,7 +421,7 @@ async def stream( async for _event in stream: pass - async def _run_stream( + async def _run_stream( # noqa C901 self, ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, NodeRunEndT]] ) -> AsyncIterator[_messages.HandleResponseEvent]: if self._events_iterator is None: @@ -434,6 +437,10 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: texts.append(part.content) elif isinstance(part, _messages.ToolCallPart): tool_calls.append(part) + elif isinstance(part, _messages.ServerToolCallPart): + yield _messages.ServerToolCallEvent(part) + elif isinstance(part, _messages.ServerToolReturnPart): + yield _messages.ServerToolResultEvent(part) else: assert_never(part) diff --git a/pydantic_ai_slim/pydantic_ai/_utils.py b/pydantic_ai_slim/pydantic_ai/_utils.py index fe8501e6c..5b653129f 100644 --- a/pydantic_ai_slim/pydantic_ai/_utils.py +++ b/pydantic_ai_slim/pydantic_ai/_utils.py @@ -205,7 +205,13 @@ def now_utc() -> datetime: return datetime.now(tz=timezone.utc) -def guard_tool_call_id(t: _messages.ToolCallPart | _messages.ToolReturnPart | _messages.RetryPromptPart) -> str: +def guard_tool_call_id( + t: _messages.ToolCallPart + | _messages.ToolReturnPart + | _messages.RetryPromptPart + | _messages.ServerToolCallPart + | _messages.ServerToolReturnPart, +) -> str: """Type guard that either returns the tool call id or generates a new one if it's None.""" return t.tool_call_id or generate_tool_call_id() diff --git a/pydantic_ai_slim/pydantic_ai/agent.py b/pydantic_ai_slim/pydantic_ai/agent.py index 57010f5f8..c1a1eab38 100644 --- a/pydantic_ai_slim/pydantic_ai/agent.py +++ b/pydantic_ai_slim/pydantic_ai/agent.py @@ -14,6 +14,7 @@ from pydantic.json_schema import GenerateJsonSchema from typing_extensions import Literal, Never, Self, TypeIs, TypeVar, deprecated +from pydantic_ai.builtin_tools import AbstractBuiltinTool, WebSearchTool from pydantic_graph import End, Graph, GraphRun, GraphRunContext from pydantic_graph._utils import get_event_loop @@ -174,6 +175,7 @@ def __init__( retries: int = 1, output_retries: int | None = None, tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (), + builtin_tools: Sequence[Literal['web-search'] | AbstractBuiltinTool] = (), prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None, mcp_servers: Sequence[MCPServer] = (), defer_model_check: bool = False, @@ -203,6 +205,7 @@ def __init__( result_tool_description: str | None = None, result_retries: int | None = None, tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (), + builtin_tools: Sequence[Literal['web-search'] | AbstractBuiltinTool] = (), prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None, mcp_servers: Sequence[MCPServer] = (), defer_model_check: bool = False, @@ -227,6 +230,7 @@ def __init__( retries: int = 1, output_retries: int | None = None, tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (), + builtin_tools: Sequence[Literal['web-search'] | AbstractBuiltinTool] = (), prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None, mcp_servers: Sequence[MCPServer] = (), defer_model_check: bool = False, @@ -256,6 +260,8 @@ def __init__( output_retries: The maximum number of retries to allow for result validation, defaults to `retries`. tools: Tools to register with the agent, you can also register tools via the decorators [`@agent.tool`][pydantic_ai.Agent.tool] and [`@agent.tool_plain`][pydantic_ai.Agent.tool_plain]. + builtin_tools: The builtin tools that the agent will use. This depends on the model, as some models may not + support certain tools. On models that don't support certain tools, the tool will be ignored. prepare_tools: custom method to prepare the tool definition of all tools for each step. This is useful if you want to customize the definition of multiple tools or you want to register a subset of tools for a given step. See [`ToolsPrepareFunc`][pydantic_ai.tools.ToolsPrepareFunc] @@ -342,6 +348,14 @@ def __init__( self._default_retries = retries self._max_result_retries = output_retries if output_retries is not None else retries self._mcp_servers = mcp_servers + self._builtin_tools: list[AbstractBuiltinTool] = [] + + for tool in builtin_tools: + if tool == 'web-search': + self._builtin_tools.append(WebSearchTool()) + else: + self._builtin_tools.append(tool) + self._prepare_tools = prepare_tools for tool in tools: if isinstance(tool, Tool): @@ -691,6 +705,7 @@ async def get_instructions(run_context: RunContext[AgentDepsT]) -> str | None: output_schema=output_schema, output_validators=output_validators, function_tools=self._function_tools, + builtin_tools=self._builtin_tools, mcp_servers=self._mcp_servers, default_retries=self._default_retries, tracer=tracer, diff --git a/pydantic_ai_slim/pydantic_ai/builtin_tools.py b/pydantic_ai_slim/pydantic_ai/builtin_tools.py new file mode 100644 index 000000000..46cc7b628 --- /dev/null +++ b/pydantic_ai_slim/pydantic_ai/builtin_tools.py @@ -0,0 +1,95 @@ +from __future__ import annotations as _annotations + +from abc import ABC +from dataclasses import dataclass +from typing import Any, Literal + +from typing_extensions import TypedDict + +__all__ = ('AbstractBuiltinTool', 'WebSearchTool', 'UserLocation') + + +@dataclass +class AbstractBuiltinTool(ABC): + """A builtin tool that can be used by an agent. + + This class is abstract and cannot be instantiated directly. + + The builtin tools are passed to the model as part of the `ModelRequestParameters`. + """ + + def handle_custom_tool_definition(self, model: str) -> Any: ... + + +@dataclass +class WebSearchTool(AbstractBuiltinTool): + """A builtin tool that allows your agent to search the web for information. + + The parameters that PydanticAI passes depend on the model, as some parameters may not be supported by certain models. + """ + + search_context_size: Literal['low', 'medium', 'high'] = 'medium' + """The `search_context_size` parameter controls how much context is retrieved from the web to help the tool formulate a response. + + Supported by: + * OpenAI + """ + + user_location: UserLocation | None = None + """The `user_location` parameter allows you to localize search results based on a user's location. + + Supported by: + * Anthropic + * OpenAI + """ + + blocked_domains: list[str] | None = None + """If provided, these domains will never appear in results. + + With Anthropic, you can only use one of `blocked_domains` or `allowed_domains`, not both. + + Supported by: + * Anthropic (https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool#domain-filtering) + * Groq (https://console.groq.com/docs/agentic-tooling#search-settings) + * MistralAI + """ + + allowed_domains: list[str] | None = None + """If provided, only these domains will be included in results. + + With Anthropic, you can only use one of `blocked_domains` or `allowed_domains`, not both. + + Supported by: + * Anthropic (https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool#domain-filtering) + * Groq (https://console.groq.com/docs/agentic-tooling#search-settings) + """ + + max_uses: int | None = None + """If provided, the tool will stop searching the web after the given number of uses. + + Supported by: + * Anthropic + """ + + +class UserLocation(TypedDict, total=False): + """Allows you to localize search results based on a user's location. + + Supported by: + * Anthropic + * OpenAI + """ + + city: str + country: str + region: str + timezone: str + + +class CodeExecutionTool(AbstractBuiltinTool): + """A builtin tool that allows your agent to execute code. + + Supported by: + * Anthropic + * OpenAI + """ diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index f19afea8d..9b7d02cb6 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -349,8 +349,8 @@ def otel_event(self, settings: InstrumentationSettings) -> Event: @dataclass(repr=False) -class ToolReturnPart: - """A tool return message, this encodes the result of running a tool.""" +class BaseToolReturnPart: + """Base class for tool return parts.""" tool_name: str """The name of the "tool" was called.""" @@ -364,9 +364,6 @@ class ToolReturnPart: timestamp: datetime = field(default_factory=_now_utc) """The timestamp, when the tool returned.""" - part_kind: Literal['tool-return'] = 'tool-return' - """Part type identifier, this is available on all parts as a discriminator.""" - def model_response_str(self) -> str: """Return a string representation of the content for the model.""" if isinstance(self.content, str): @@ -388,9 +385,29 @@ def otel_event(self, _settings: InstrumentationSettings) -> Event: body={'content': self.content, 'role': 'tool', 'id': self.tool_call_id, 'name': self.tool_name}, ) + def has_content(self) -> bool: + """Return `True` if the tool return has content.""" + return self.content is not None + __repr__ = _utils.dataclasses_no_defaults_repr +@dataclass(repr=False) +class ToolReturnPart(BaseToolReturnPart): + """A tool return message, this encodes the result of running a tool.""" + + part_kind: Literal['tool-return'] = 'tool-return' + """Part type identifier, this is available on all parts as a discriminator.""" + + +@dataclass(repr=False) +class ServerToolReturnPart(BaseToolReturnPart): + """A tool return message from a server tool.""" + + part_kind: Literal['server-tool-return'] = 'server-tool-return' + """Part type identifier, this is available on all parts as a discriminator.""" + + error_details_ta = pydantic.TypeAdapter(list[pydantic_core.ErrorDetails], config=pydantic.ConfigDict(defer_build=True)) @@ -503,7 +520,7 @@ def has_content(self) -> bool: @dataclass(repr=False) -class ToolCallPart: +class BaseToolCallPart: """A tool call from a model.""" tool_name: str @@ -521,9 +538,6 @@ class ToolCallPart: In case the tool call id is not provided by the model, PydanticAI will generate a random one. """ - part_kind: Literal['tool-call'] = 'tool-call' - """Part type identifier, this is available on all parts as a discriminator.""" - def args_as_dict(self) -> dict[str, Any]: """Return the arguments as a Python dictionary. @@ -560,7 +574,28 @@ def has_content(self) -> bool: __repr__ = _utils.dataclasses_no_defaults_repr -ModelResponsePart = Annotated[Union[TextPart, ToolCallPart], pydantic.Discriminator('part_kind')] +@dataclass(repr=False) +class ToolCallPart(BaseToolCallPart): + """A tool call from a model.""" + + part_kind: Literal['tool-call'] = 'tool-call' + """Part type identifier, this is available on all parts as a discriminator.""" + + +@dataclass(repr=False) +class ServerToolCallPart(BaseToolCallPart): + """A tool call from a server tool.""" + + model_name: str | None = None + """The name of the model that generated the response.""" + + part_kind: Literal['server-tool-call'] = 'server-tool-call' + """Part type identifier, this is available on all parts as a discriminator.""" + + +ModelResponsePart = Annotated[ + Union[TextPart, ToolCallPart, ServerToolCallPart, ServerToolReturnPart], pydantic.Discriminator('part_kind') +] """A message part returned by a model.""" @@ -883,6 +918,29 @@ class FunctionToolResultEvent: __repr__ = _utils.dataclasses_no_defaults_repr +@dataclass(repr=False) +class ServerToolCallEvent: + """An event indicating the start to a call to a server tool.""" + + part: ServerToolCallPart + """The server tool call to make.""" + + event_kind: Literal['server_tool_call'] = 'server_tool_call' + """Event type identifier, used as a discriminator.""" + + +@dataclass(repr=False) +class ServerToolResultEvent: + """An event indicating the result of a server tool call.""" + + result: ServerToolReturnPart + """The result of the call to the server tool.""" + + event_kind: Literal['server_tool_result'] = 'server_tool_result' + """Event type identifier, used as a discriminator.""" + + HandleResponseEvent = Annotated[ - Union[FunctionToolCallEvent, FunctionToolResultEvent], pydantic.Discriminator('event_kind') + Union[FunctionToolCallEvent, FunctionToolResultEvent, ServerToolCallEvent, ServerToolResultEvent], + pydantic.Discriminator('event_kind'), ] diff --git a/pydantic_ai_slim/pydantic_ai/models/__init__.py b/pydantic_ai_slim/pydantic_ai/models/__init__.py index 714080305..b09045ff8 100644 --- a/pydantic_ai_slim/pydantic_ai/models/__init__.py +++ b/pydantic_ai_slim/pydantic_ai/models/__init__.py @@ -16,6 +16,7 @@ import httpx from typing_extensions import Literal, TypeAliasType +from pydantic_ai.builtin_tools import AbstractBuiltinTool from pydantic_ai.profiles import DEFAULT_PROFILE, ModelProfile, ModelProfileSpec from .._parts_manager import ModelResponsePartsManager @@ -292,6 +293,7 @@ class ModelRequestParameters: """Configuration for an agent's request to a model, specifically related to tools and output handling.""" function_tools: list[ToolDefinition] = field(default_factory=list) + builtin_tools: list[AbstractBuiltinTool] = field(default_factory=list) allow_text_output: bool = True output_tools: list[ToolDefinition] = field(default_factory=list) diff --git a/pydantic_ai_slim/pydantic_ai/models/anthropic.py b/pydantic_ai_slim/pydantic_ai/models/anthropic.py index 69808aa5f..f3b20185a 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -7,8 +7,16 @@ from datetime import datetime, timezone from typing import Any, Literal, Union, cast, overload +from anthropic.types.beta import ( + BetaCodeExecutionToolResultBlock, + BetaCodeExecutionToolResultBlockParam, + BetaServerToolUseBlockParam, + BetaWebSearchToolResultBlockParam, +) from typing_extensions import assert_never +from pydantic_ai.builtin_tools import CodeExecutionTool, WebSearchTool + from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage from .._utils import guard_tool_call_id as _guard_tool_call_id from ..messages import ( @@ -21,6 +29,8 @@ ModelResponsePart, ModelResponseStreamEvent, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, ToolCallPart, @@ -45,6 +55,7 @@ from anthropic.types.beta import ( BetaBase64PDFBlockParam, BetaBase64PDFSourceParam, + BetaCodeExecutionTool20250522Param, BetaContentBlock, BetaContentBlockParam, BetaImageBlockParam, @@ -59,15 +70,20 @@ BetaRawMessageStartEvent, BetaRawMessageStopEvent, BetaRawMessageStreamEvent, + BetaServerToolUseBlock, BetaTextBlock, BetaTextBlockParam, BetaTextDelta, BetaToolChoiceParam, BetaToolParam, BetaToolResultBlockParam, + BetaToolUnionParam, BetaToolUseBlock, BetaToolUseBlockParam, + BetaWebSearchTool20250305Param, + BetaWebSearchToolResultBlock, ) + from anthropic.types.beta.beta_web_search_tool_20250305_param import UserLocation from anthropic.types.model_param import ModelParam except ImportError as _import_error: @@ -208,6 +224,7 @@ async def _messages_create( ) -> BetaMessage | AsyncStream[BetaRawMessageStreamEvent]: # standalone function to make it easier to override tools = self._get_tools(model_request_parameters) + tools += self._get_builtin_tools(model_request_parameters) tool_choice: BetaToolChoiceParam | None if not tools: @@ -226,6 +243,7 @@ async def _messages_create( try: extra_headers = model_settings.get('extra_headers', {}) extra_headers.setdefault('User-Agent', get_user_agent()) + extra_headers.setdefault('anthropic-beta', 'code-execution-2025-05-22') return await self.client.beta.messages.create( max_tokens=model_settings.get('max_tokens', 1024), system=system_prompt or NOT_GIVEN, @@ -253,6 +271,31 @@ def _process_response(self, response: BetaMessage) -> ModelResponse: for item in response.content: if isinstance(item, BetaTextBlock): items.append(TextPart(content=item.text)) + elif isinstance(item, BetaWebSearchToolResultBlock): + items.append( + ServerToolReturnPart( + tool_name=item.type, + content=item.content, + tool_call_id=item.tool_use_id, + ) + ) + elif isinstance(item, BetaServerToolUseBlock): + items.append( + ServerToolCallPart( + model_name='anthropic', + tool_name=item.name, + args=cast(dict[str, Any], item.input), + tool_call_id=item.id, + ) + ) + elif isinstance(item, BetaCodeExecutionToolResultBlock): + items.append( + ServerToolReturnPart( + tool_name=item.type, + content=item.content, + tool_call_id=item.tool_use_id, + ) + ) else: assert isinstance(item, BetaToolUseBlock), f'unexpected item type {type(item)}' items.append( @@ -283,7 +326,25 @@ def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[B tools += [self._map_tool_definition(r) for r in model_request_parameters.output_tools] return tools - async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[BetaMessageParam]]: + def _get_builtin_tools(self, model_request_parameters: ModelRequestParameters) -> list[BetaToolUnionParam]: + tools: list[BetaToolUnionParam] = [] + for tool in model_request_parameters.builtin_tools: + if isinstance(tool, WebSearchTool): + user_location = UserLocation(type='approximate', **tool.user_location) if tool.user_location else None + tools.append( + BetaWebSearchTool20250305Param( + name='web_search', + type='web_search_20250305', + allowed_domains=tool.allowed_domains, + blocked_domains=tool.blocked_domains, + user_location=user_location, + ) + ) + elif isinstance(tool, CodeExecutionTool): + tools.append(BetaCodeExecutionTool20250522Param(name='code_execution', type='code_execution_20250522')) + return tools + + async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[BetaMessageParam]]: # noqa: C901 """Just maps a `pydantic_ai.Message` to a `anthropic.types.MessageParam`.""" system_prompt_parts: list[str] = [] anthropic_messages: list[BetaMessageParam] = [] @@ -319,11 +380,17 @@ async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[Be if len(user_content_params) > 0: anthropic_messages.append(BetaMessageParam(role='user', content=user_content_params)) elif isinstance(m, ModelResponse): - assistant_content_params: list[BetaTextBlockParam | BetaToolUseBlockParam] = [] + assistant_content_params: list[ + BetaTextBlockParam + | BetaToolUseBlockParam + | BetaServerToolUseBlockParam + | BetaWebSearchToolResultBlockParam + | BetaCodeExecutionToolResultBlockParam + ] = [] for response_part in m.parts: if isinstance(response_part, TextPart): assistant_content_params.append(BetaTextBlockParam(text=response_part.content, type='text')) - else: + elif isinstance(response_part, ToolCallPart): tool_use_block_param = BetaToolUseBlockParam( id=_guard_tool_call_id(t=response_part), type='tool_use', @@ -331,6 +398,29 @@ async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[Be input=response_part.args_as_dict(), ) assistant_content_params.append(tool_use_block_param) + elif isinstance(response_part, ServerToolCallPart): + server_tool_use_block_param = BetaServerToolUseBlockParam( + id=_guard_tool_call_id(t=response_part), + type='server_tool_use', + name=cast(Literal['web_search', 'code_execution'], response_part.tool_name), + input=response_part.args_as_dict(), + ) + assistant_content_params.append(server_tool_use_block_param) + elif isinstance(response_part, ServerToolReturnPart): + tool_use_id = _guard_tool_call_id(t=response_part) + if response_part.tool_name == 'web_search_tool_result': + server_tool_result_block_param = BetaWebSearchToolResultBlockParam( + tool_use_id=tool_use_id, type=response_part.tool_name, content=response_part.content + ) + elif response_part.tool_name == 'code_execution_tool_result': + server_tool_result_block_param = BetaCodeExecutionToolResultBlockParam( + tool_use_id=tool_use_id, type=response_part.tool_name, content=response_part.content + ) + else: + raise ValueError(f'Unsupported tool name: {response_part.tool_name}') + assistant_content_params.append(server_tool_result_block_param) + else: + assert_never(response_part) anthropic_messages.append(BetaMessageParam(role='assistant', content=assistant_content_params)) else: assert_never(m) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 99f9950f0..84631e00c 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -10,6 +10,8 @@ from typing_extensions import assert_never +from pydantic_ai.builtin_tools import CodeExecutionTool, WebSearchTool +from pydantic_ai.exceptions import UserError from pydantic_ai.providers import Provider from .. import UnexpectedModelBehavior, _utils, usage @@ -24,6 +26,8 @@ ModelResponsePart, ModelResponseStreamEvent, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, ToolCallPart, @@ -54,10 +58,12 @@ FunctionDeclarationDict, GenerateContentConfigDict, GenerateContentResponse, + GoogleSearchDict, Part, PartDict, SafetySettingDict, ThinkingConfigDict, + ToolCodeExecutionDict, ToolConfigDict, ToolDict, ToolListUnionDict, @@ -208,6 +214,13 @@ def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[T ToolDict(function_declarations=[_function_declaration_from_tool(t)]) for t in model_request_parameters.output_tools ] + for tool in model_request_parameters.builtin_tools: + if isinstance(tool, WebSearchTool): + tools.append(ToolDict(google_search=GoogleSearchDict())) + elif isinstance(tool, CodeExecutionTool): + tools.append(ToolDict(code_execution=ToolCodeExecutionDict())) + else: + raise UserError(f'Unsupported builtin tool: {tool}') return tools or None def _get_tool_config( @@ -447,7 +460,18 @@ def _process_response_from_parts( ) -> ModelResponse: items: list[ModelResponsePart] = [] for part in parts: - if part.text is not None: + if part.executable_code is not None: + items.append(ServerToolCallPart(args=part.executable_code.model_dump(), tool_name='code_execution')) + elif part.code_execution_result is not None: + # TODO(Marcelo): Is the idea to generate the tool_call_id on the `executable_code`, and then pass it here? + items.append( + ServerToolReturnPart( + tool_name='code_execution', + content=part.code_execution_result.output, + tool_call_id="It doesn't have.", + ) + ) + elif part.text is not None: items.append(TextPart(content=part.text)) elif part.function_call: assert part.function_call.name is not None diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index 067cfb516..e161e8e25 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -10,7 +10,7 @@ from typing_extensions import assert_never from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage -from .._utils import guard_tool_call_id as _guard_tool_call_id +from .._utils import generate_tool_call_id, guard_tool_call_id as _guard_tool_call_id from ..messages import ( BinaryContent, DocumentUrl, @@ -21,6 +21,8 @@ ModelResponsePart, ModelResponseStreamEvent, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, ToolCallPart, @@ -220,7 +222,7 @@ async def _completions_create( extra_headers = model_settings.get('extra_headers', {}) extra_headers.setdefault('User-Agent', get_user_agent()) return await self.client.chat.completions.create( - model=str(self._model_name), + model=self._model_name, messages=groq_messages, n=1, parallel_tool_calls=model_settings.get('parallel_tool_calls', NOT_GIVEN), @@ -249,6 +251,15 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: timestamp = datetime.fromtimestamp(response.created, tz=timezone.utc) choice = response.choices[0] items: list[ModelResponsePart] = [] + if choice.message.executed_tools: + for tool in choice.message.executed_tools: + tool_call_id = generate_tool_call_id() + items.append( + ServerToolCallPart( + tool_name=tool.type, args=tool.arguments, model_name='groq', tool_call_id=tool_call_id + ) + ) + items.append(ServerToolReturnPart(tool_name=tool.type, content=tool.output, tool_call_id=tool_call_id)) if choice.message.content is not None: items.append(TextPart(content=choice.message.content)) if choice.message.tool_calls is not None: diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 4e99fb574..e0693b601 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -10,6 +10,7 @@ from typing_extensions import assert_never +from pydantic_ai.builtin_tools import WebSearchTool from pydantic_ai.profiles.openai import OpenAIModelProfile from pydantic_ai.providers import Provider, infer_provider @@ -26,6 +27,8 @@ ModelResponsePart, ModelResponseStreamEvent, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, ToolCallPart, @@ -58,6 +61,11 @@ from openai.types.chat.chat_completion_content_part_image_param import ImageURL from openai.types.chat.chat_completion_content_part_input_audio_param import InputAudio from openai.types.chat.chat_completion_content_part_param import File, FileFile + from openai.types.chat.completion_create_params import ( + WebSearchOptions, + WebSearchOptionsUserLocation, + WebSearchOptionsUserLocationApproximate, + ) from openai.types.responses import ComputerToolParam, FileSearchToolParam, WebSearchToolParam from openai.types.responses.response_input_param import FunctionCallOutput, Message from openai.types.shared import ReasoningEffort @@ -263,6 +271,7 @@ async def _completions_create( model_request_parameters: ModelRequestParameters, ) -> chat.ChatCompletion | AsyncStream[ChatCompletionChunk]: tools = self._get_tools(model_request_parameters) + web_search_options = self._get_web_search_options(model_request_parameters) # standalone function to make it easier to override if not tools: @@ -298,6 +307,7 @@ async def _completions_create( logprobs=model_settings.get('openai_logprobs', NOT_GIVEN), top_logprobs=model_settings.get('openai_top_logprobs', NOT_GIVEN), user=model_settings.get('openai_user', NOT_GIVEN), + web_search_options=web_search_options or NOT_GIVEN, extra_headers=extra_headers, extra_body=model_settings.get('extra_body'), ) @@ -365,6 +375,19 @@ def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[c tools += [self._map_tool_definition(r) for r in model_request_parameters.output_tools] return tools + def _get_web_search_options(self, model_request_parameters: ModelRequestParameters) -> WebSearchOptions | None: + for tool in model_request_parameters.builtin_tools: + if isinstance(tool, WebSearchTool): + if tool.user_location: + return WebSearchOptions( + search_context_size=tool.search_context_size, + user_location=WebSearchOptionsUserLocation( + type='approximate', + approximate=WebSearchOptionsUserLocationApproximate(**tool.user_location), + ), + ) + return WebSearchOptions(search_context_size=tool.search_context_size) + async def _map_messages(self, messages: list[ModelMessage]) -> list[chat.ChatCompletionMessageParam]: """Just maps a `pydantic_ai.Message` to a `openai.types.ChatCompletionMessageParam`.""" openai_messages: list[chat.ChatCompletionMessageParam] = [] @@ -380,6 +403,9 @@ async def _map_messages(self, messages: list[ModelMessage]) -> list[chat.ChatCom texts.append(item.content) elif isinstance(item, ToolCallPart): tool_calls.append(self._map_tool_call(item)) + # OpenAI doesn't return server tools calls. + elif isinstance(item, (ServerToolCallPart, ServerToolReturnPart)): + continue else: assert_never(item) message_param = chat.ChatCompletionAssistantMessageParam(role='assistant') @@ -642,6 +668,7 @@ async def _responses_create( ) -> responses.Response | AsyncStream[responses.ResponseStreamEvent]: tools = self._get_tools(model_request_parameters) tools = list(model_settings.get('openai_builtin_tools', [])) + tools + tools = self._get_builtin_tools(model_request_parameters) + tools # standalone function to make it easier to override if not tools: @@ -694,6 +721,20 @@ def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[r tools += [self._map_tool_definition(r) for r in model_request_parameters.output_tools] return tools + def _get_builtin_tools(self, model_request_parameters: ModelRequestParameters) -> list[responses.ToolParam]: + tools: list[responses.ToolParam] = [] + for tool in model_request_parameters.builtin_tools: + if isinstance(tool, WebSearchTool): + web_search_tool = responses.WebSearchToolParam( + type='web_search_preview', search_context_size=tool.search_context_size + ) + if tool.user_location: + web_search_tool['user_location'] = responses.web_search_tool_param.UserLocation( + type='approximate', **tool.user_location + ) + tools.append(web_search_tool) + return tools + def _map_tool_definition(self, f: ToolDefinition) -> responses.FunctionToolParam: return { 'name': f.name, @@ -747,6 +788,9 @@ async def _map_messages( openai_messages.append(responses.EasyInputMessageParam(role='assistant', content=item.content)) elif isinstance(item, ToolCallPart): openai_messages.append(self._map_tool_call(item)) + # OpenAI doesn't return server tools calls. + elif isinstance(item, (ServerToolCallPart, ServerToolReturnPart)): + continue else: assert_never(item) else: diff --git a/pydantic_ai_slim/pyproject.toml b/pydantic_ai_slim/pyproject.toml index 631cc196d..3625c392d 100644 --- a/pydantic_ai_slim/pyproject.toml +++ b/pydantic_ai_slim/pyproject.toml @@ -66,7 +66,7 @@ cohere = ["cohere>=5.13.11; platform_system != 'Emscripten'"] vertexai = ["google-auth>=2.36.0", "requests>=2.32.2"] google = ["google-genai>=1.15.0"] anthropic = ["anthropic>=0.52.0"] -groq = ["groq>=0.15.0"] +groq = ["groq>=0.25.0"] mistral = ["mistralai>=1.2.5"] bedrock = ["boto3>=1.35.74"] # Tools diff --git a/tests/models/cassettes/test_anthropic/test_anthropic_code_execution_tool.yaml b/tests/models/cassettes/test_anthropic/test_anthropic_code_execution_tool.yaml new file mode 100644 index 000000000..76f19dc00 --- /dev/null +++ b/tests/models/cassettes/test_anthropic/test_anthropic_code_execution_tool.yaml @@ -0,0 +1,86 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '250' + content-type: + - application/json + host: + - api.anthropic.com + method: POST + parsed_body: + max_tokens: 1024 + messages: + - content: + - text: How much is 3 * 12390? + type: text + role: user + model: claude-sonnet-4-0 + stream: false + tool_choice: + type: auto + tools: + - name: code_execution + type: code_execution_20250522 + uri: https://api.anthropic.com/v1/messages?beta=true + response: + headers: + connection: + - keep-alive + content-length: + - '927' + content-type: + - application/json + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + container: + expires_at: '2025-05-26T13:30:45.703429+00:00' + id: container_011CPW9LpfbF8dmXMvVNCiQJ + content: + - text: I'll calculate 3 * 12390 for you. + type: text + - id: srvtoolu_01CPfaeVC7ju4VsdzxjSLDrY + input: + code: |- + result = 3 * 12390 + print(f"3 * 12390 = {result}") + name: code_execution + type: server_tool_use + - content: + content: [] + return_code: 0 + stderr: '' + stdout: | + 3 * 12390 = 37170 + type: code_execution_result + tool_use_id: srvtoolu_01CPfaeVC7ju4VsdzxjSLDrY + type: code_execution_tool_result + - text: The answer is **37,170**. + type: text + id: msg_015H6Emn2T8vZhE52mU2jF1U + model: claude-sonnet-4-20250514 + role: assistant + stop_reason: end_turn + stop_sequence: null + type: message + usage: + cache_creation_input_tokens: 0 + cache_read_input_tokens: 0 + input_tokens: 1630 + output_tokens: 105 + server_tool_use: + web_search_requests: 0 + service_tier: standard + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_anthropic/test_anthropic_server_tool_pass_history_to_another_provider.yaml b/tests/models/cassettes/test_anthropic/test_anthropic_server_tool_pass_history_to_another_provider.yaml new file mode 100644 index 000000000..a73ea3aa4 --- /dev/null +++ b/tests/models/cassettes/test_anthropic/test_anthropic_server_tool_pass_history_to_another_provider.yaml @@ -0,0 +1,280 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '312' + content-type: + - application/json + host: + - api.anthropic.com + method: POST + parsed_body: + max_tokens: 1024 + messages: + - content: + - text: What day is today? + type: text + role: user + model: claude-3-5-sonnet-latest + stream: false + tool_choice: + type: auto + tools: + - allowed_domains: null + blocked_domains: null + name: web_search + type: web_search_20250305 + user_location: null + uri: https://api.anthropic.com/v1/messages?beta=true + response: + headers: + connection: + - keep-alive + content-length: + - '15304' + content-type: + - application/json + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + content: + - text: Let me search for today's date. + type: text + - id: srvtoolu_01BJh8n7va96puUF3hhNnYnY + input: + query: current date today May 26 2025 + name: web_search + type: server_tool_use + - content: + - encrypted_content: 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 + page_age: null + title: May 2025 Calendar + type: web_search_result + url: https://www.calendar-365.com/calendar/2025/May.html + - encrypted_content: EuwCCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDNOs+T2nScTnsxVJZRoM3g9Mm5RlKN0sgiPBIjC1PJPZRfoUgRpmpfVZcF8sBTMUr6Lu9BK9xOxTQ8nMMBGjC7kFOrwJZ3ENgXLhRzcq7wF51cgLQ+Pb0MiXBGozKXa1r7DbogMoIacrDz92bvzbwXbo4mTQMipnow47//PYVelJXipxVAA6ISswEiYPGXyCjqSy6QEIde1TOc8nvMpaM0Y4u3DdOXez5EsgP+ZxIYly/I7JS35h/azV0nbpzEKsptZwNWwuBtNIYbkklPaluda13QbkE0KK1Cl6PnkNMVbO0Uo9XURcwLn5aDLJol0GJGVpuiApXVJoMk7e7L/Ib+p1BE77VW619KzDmQvuAjQXZR28Fb5KEbRxXkSaq7xAZnYZyQFtOlqg/07Tv+V4g0WYZhI3tn0phBe0w+95NhgD + page_age: null + title: May 26, 2025 Calendar with Holidays & Count Down - USA + type: web_search_result + url: https://www.wincalendar.com/Calendar/Date/May-26-2025 + - encrypted_content: Es0ICioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDE+yP8aOxk+46r0AERoMFOlAyJD/AGdtDxeVIjDDhlbQbqqMmuMK9bN7ZNTwHWQwahkAaZd/LltU3eIPifLnfk4Apnck+mUOM61zRiQq0Ac12DCFUzhrlxvkXqpK3gWjgosGbUyzt8WbmwSaEmCbXf9F4bNc7+LKvQUtEceYmCesYcQa0lOT+88IhhRTxYBMyXo0Ws3Pw1yrLJi9P1JqfpcnWebg8McOGY/pD/MFeJORQvH+0UvGjBoMD0uaPPY1U6cFC7EWL+IebMjjmpj80RqAi/xjOOnU2XO8N98dFCzW4GiI9IWut8OBv8u3kLpmyYOV6cVxr3WTEntDv3onveQvTIyJFiDG8bmOKK72ONWrevnrKGQ7JY2gPYp5CakS+SYahIKiJOOY3cWQfUEheIfEZeuGadI907uvREyb1bf4h/0KsFjnOBWrHXdl7LIDRSfz8OIwfJufTERGCfG0vzMiHzFJbFcezciz3K9m25QjxL676NcrYbgZGFhIXar9jNvPAjGcUecpaOLAEztHx7pd0nHMsW5KKUTS0yU5sMFNY1+RMSKk8kVoCcBtOuOsiegf+BJV/J997IvbQG5A7h/72VsVyUbiBDT1z77VjKTPcerZr4EReCobAoyGdMKt1mihwvYvsyvZepAkvrxOoKnb+2pkzhZQtxGt0ub23yhSZyLgi0frVSS04KeYncVWW7cQJJygzfDS37pdSPnU0wZmAgZLzQ3X1NVmR9AQVSQ+IcIoVSCuru/WiBcS7aJPC4uh6cn5sB9C6yThrD8i7T7DJGbR/uutIADP9IgGUzdoppStgQugx4TwnQI9SC6e36zjfsK6NeUkxLi2b4T1uuRDvjgUDc0OXGZdoGQgc8nHoe7rexoLJqeWat19KNwy4DqnM7oywivVJWDJ2ThV4863f3+hYRlXeuxnojBsmENJsSxZtF46ye1gfPSvBYlEpO/Uu9FzR3yy4bB3b/qOh2+JMTLkk3R5u4C6Ca/Nye0bpnsKG7xjW2cKguqfKhUuUFaSucCCJqg/hT21DlUiHXZQ6wq6Ywi9C9l+wJbzfJWWHczjkTJvWhFq8saXSAzfWDd8tTKH1zje7NN38jRQPUDxS0CWMM78/+BgWoqsB5+IjkEl5QHV55GSCg+05HQPLyHQWWjBdMLWr+Uu3T0kKI0B/QDJPHO1mSX5AsGot5HZzva5qEPzn3vGly1n1vs14JWE+RrtIJTBHi0ypFhaO6oCRGejMRDbZhotP4gWW1VW0gLNikgfW0Z5waOb8wmLcN4vQhsHRFfZiXsqUF0dTXsme8+kF8qcVZNnPtghyf1ACvFgZ8TAF4PaM1wzpa8kDeBFvyp14U39R8XDJ3T6lGWR2rpv0WjS8d5h0RCZ3XlFuqPUXWEQ89OpEH8vEiYXGAM= + page_age: null + title: Daily Calendar for Monday, May 26, 2025 | Almanac.com + type: web_search_result + url: https://www.almanac.com/calendar/date/2025-05-26 + - encrypted_content: EpoFCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDClGwxB0YzJdub7VGhoMASvr8D1KqeBCa4knIjAV1lHpDjDIw6nag+Y/ax/aq2LhfZ1/CXJoRyRFiUGLVQHpERodH6/Kg+l8aLy01gAqnQQR8cCm+MlfMM3pSSNah8dZ0m5wam3enQ+5A3VLu0P/CF/TlwL5yB21pfaiu0lad9Ee99YFvs7LInvXpyFcUgLuhankIzNNZZbUIeS4sZIK39RrN+pmifOl6KQqT1f2tpJE6x7erDlAscnMvbRIr9U8Pwf8Au709bI6zcHqCg4GNJk2CqDf6kAXRHRRhcWYFtm8b0wvg9HaWVYZFOunZMJ1gFD3D82dSm3m4awyDSZm54A/9hmzE/lcQyiSVBC73NOmJMBxbNec16qaeJdUTZp33JYk0Fdro1VnkUiJyq5Kb2W7VYvfeQ1a2dLXPTYIsXeQXLHesmVTe7m0X70w0BgCAC+yKZPp68bbsEbsbjwxaWOxQ50seu8kkXDiEgscUK5e4N5YnPXMNjyMNZmlbhmFtw3abOmOCVdpcDORXGOgJZBWBkEqQ4mE8b+aEzXMGRqLzYjDKZHx11wolF3MGu/V/+f4lWEyNwR2Kipp67teOx1ypvl4DiZiPVkZwx9lt08u+TJGEGbTYtdPMQRLVX1K2K4YOEcP5/abNrdT9KdYH7dNscRDqDY04gi+47JyyTSRObcCjQun9LUqh0q6/NfIIWQwjguZ6dbYL67ymiuRgHJDXsPnc/P58qP4kRsClz9lu/XPTFuAzCQwaXioK3XiBNW73nSKyRaxm6/OxbYetPGIG2JUTkQtrmGL5AYJTfFbI6XOB1AFDcsoSC7nGAM= + page_age: null + title: How long ago was May 26th 2025? | howlongagogo.com + type: web_search_result + url: https://howlongagogo.com/date/2025/may/26 + - encrypted_content: Eq0DCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDDT/5zRyvf5kzhhLgxoM5vWn/Zjmu43rvWgPIjCf4z9SIoZxgNKyiLOqk422DLmHbFXGX+mhy6FPo43NOogfLhu/a3F3EPkiMxfd0UMqsAKIhRJKuEhfoi2saPCA3LpNhJ3YPO2NZyYL75SJdCbkfACe2YJOcCXHmt4hkrbA98Mrvh9DmtP6HNA9iYdsotXkDi0BuTlmiIcspblXnkpXLIURVpNYqqZ2jbjBEmi/mVlTonm9NJwx1rZHzwciKhaIrz440Vk/uTIqpiMb22U00hWrQ563gNlMSXpvIpyayhJcCnNEjQybJjQUsKaMqb/3Xbp8NUoWtidUb4ARNeoNe4BlzMEEcIPc0QWi1CKoQJH3JazxAhMSqvc4SVWXRyspZZP6lSHhMcIYlf/yorVYVF3FmL1djZfxXbVnI/VbFbpoNejvnOh5QIdbDrHu6UN3u2iGZBUJLgs6i9OUwMWw8kpi2WUm+3JeRkdyThE0M9WAhK+4qYD3UHgFCcucX7ZeGAM= + page_age: null + title: How many days until 26th May 2025? + type: web_search_result + url: https://days.to/26-may/2025 + - encrypted_content: EpACCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDNXuvVNnWjvXgGql0RoMXwqBXk4fJbTzoM0pIjC1HFbYVJOlp39xpYzw/uJVUO6cC2L9ScOu9ceP2MDjyBWuE0X2LxBsyFjM3ZwzQtYqkwHukWybclFQu5CuM7gntDFNVYsSAVDbslXo5WwOlljEXnC7ohNjuB4lJfXS5HomdOmnUs0/thHHvR5mvCvHt5o+XrnTV8PSOXJvZonVctfjBeMe/3VWaQX2Pr8F71hiBVghYnc4lqnvA/nebBXcqdz2VTlG7V2/u+KCGVfR27l0+BX9s8vroR6dZ7flEBZBSDDzt3QYAw== + page_age: null + title: What day of the week will May 26th 2025 be on? | howlongagogo.com + type: web_search_result + url: https://howlongagogo.com/day-of-the-week/2025-05-26 + - encrypted_content: EtkGCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDNqnvrEdyAJMqZiouRoMl3zAD6YOqFa5Y+LGIjCFzjG2cb9Uv/fUGE2iFHKU3CP5i7yVrpvusD4UBOrARkME7qTDdfIczSbj1PvU7ygq3AUQ9yGVSgg9AB7qawws2Zx43sVi5sDW/thrC8owactbSzc2qE9IsmucxwknSZXemJFSMW3I2vWhlpJVcfipESwRyVSnVNoTivU7/aIbnI15/NOGATtd/TR0mkyO2MMMAFIHiEfq0iuvMUX/EmnEqlSzDngrlWdPvb0qDrZIkSVEYFE5FEPHXuXEFEWZ/yLs7rUK7M9kc161gTbQ/NMALrWDjKtFtgI20Wf2luvbfX8G8kivyPttdUk9aiBxStWetpJZqsBEGT1auj3hk7FaHU2FTNW0LGvIe++QZNL+w/nKa+YuNGpJCxAiLt3X+2hnZmz8Mskfyfl5I5EWt7eOQmoR0qStl7Fh9Myb3vZ0rpZ8gZeaLd1xn6pKKa+tBonm1Oq1zQvsoMkMwTcMRK3LA53dF3rtkgSFyBAWis/tenbdrRVUGlicecn/bSd9FVFoGM5RWYvXR9/3zr3SBf2qNTT2jmeLqcl07LYUk+WDGcas6vAVGDXxVoAh+uAC0WziUtKfv//V4IeleGEOLJNdX1jDC8uQMKyGuRCXNRJAoHRhgUr2F46Ax9xJOHWXKDheklfqTFff0wf93d5U/d4p52RaeM7jcBexjz0wMQRBL91ZOZVweRHbV2BVTBpPH79Y9W/UmBEycRnTmurJJspZre10EVH7MIX/4DRhxBipdZrQFgqTrCgbN6dRFLlQR9w1n+Y2pSEXnSeHdwOTPVHSKBKQO43XCKWmJPgNFELcRBZdVxGcE9xd2/dzs0C6Aa7vXZ/5ZPx9rgis1TY2UegdpiyWmKV0yw1K2LKpq8BOdH4t3OPDTPvJrymaZwldTb+w6rLGf0p1YAkZIBPpUX9tAstQ1HAz58zHnLhQfUzpm5ft4S3m2i+WkyjzIkh4F2Y1bIvbwQvqT2x3rGJRRWJGyg9PDEVCY4gjKObhjkQbanRG58uPuf7mBofFqKbUBJOngnAvSmGibWNn9uSftf8YAw== + page_age: null + title: Calendar 2025 + type: web_search_result + url: https://www.timeanddate.com/calendar/ + - encrypted_content: Eq0CCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDJI9LlFy1IIRylVnDxoMIXCLnspt86G8qxeIIjD0AiJH0r4ULSsSOXmrBj0ntQEjeADrBeCC4P53iCMga7fv0Uxic9EYRY73zIkr7aAqsAFql3nOsfaopCrkf/WC9qvKgDAeuBfKcTNjj+rfHn5HXgVM4BOpomSXxBc0CHUe3Heqw2mD9+Hy99flWI60pgPB+umunXeOjz5HC4W1q39ROTzvMkdpJzvXoUgG/dbgjJ9vEvZ0VC4z+ZwRAYSNgOgiRt3zApcZJ4iSsF/XgrQNs2L2ThcQyc84+lKKAaKPrSl6Lwm1bH+HTFYIm9KPyhvlbfEbp5buj/wQgn4Na/3qrhgD + page_age: null + title: May 26 + type: web_search_result + url: https://www.nationaldaycalendar.com/may/may-26 + - encrypted_content: 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 + page_age: null + title: Day Numbers for 2025 + type: web_search_result + url: https://www.epochconverter.com/days/2025 + - encrypted_content: EosGCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDDVXhko+GaoaARLiWxoMhhwixTlmn7YeimyXIjBqLMdGYisjngIKCxw2kKV4whivBWinF+rFSah3+1JUtoRUor9o+HmU0StGZxaPydsqjgUGl0OUiZ7Dlc0YqCN8bOGaoUeUv7MpoODHTH97tj67PKZmSbEkDp0J1bJzxHd4WeL1SdNnExDsDcSk4joJFA4lBVAAgxvBogir7w/ws8fRoANAp3F4T9IoZHSQVR2PhtRpymmT1JIaelypYDnda1cLVKrOhF26o8zSp3sDKsilZRW7TSGG1YmzEEKdFK0h/jrGO9yr35kL8vzIF1vdXeJbJa79pFo8e1OLxq9Z2e3y5thBAB3aMK+WMT6n3vRaaRpG4/sqL69lUB/J8Ju1X2VAqfUhYe1GbTKVwAqv+Fllq/NQfZywAaqkHF0YqzMFNYYNB0KTpzrPetfmvXMvog2I0qn8Xuuefw6ROAgsUJaIbyY2b2AbO9Ohxlqv08Lgt/CEmghIi2I/zvt4Y5AjUZzpRUqYAomrkagze50qj5P5Mj191pU+SLehkArpjDp131C5k3jhJ/6m7EaRpv7R4JWxWZCETvqonBRkooPRYqTZkHAD61WjNrFzDOn3fOHjrK9XjQMYE6C9rLOQf/Cy3XdlJgmSa6OKzak0NhRzIA8h7O16Mlf5kaMz5gW4vhIY/luKVQCgo7O39nxitIw94BlW0u0qT0XzCFgS05ADWdIC7SHJaU8NB4x2h0zQTTX2P5m0U2giLYPO86lUWicae08l14+JUB+uPlpDhNU7UQl29SM77+XnzdGiX/Kk99k8FcMrgp6+X5riQWuE0+rBhuDzOnVhGOgFCazxWCIpXIAvYqin429shbJtttU/upLPrbj9HsXpCJjOPI7+FLK7JXH5tH3rz1OCa/14jkNd4GTg5eGNnJSDgSJ2dWxC9oRQyFub6rPc58n9BCkHzcqrF502Q4TTEfNUuQsqBMJL8yEYAw== + page_age: null + title: Countdown to May 26, 2025 in Washington DC, District of Columbia + type: web_search_result + url: https://www.timeanddate.com/countdown/to?msg=Cressida_Glitter's+birthday&year=2025&month=5&day=26&hour=0&min=0&sec=0&fromtheme=birthday + tool_use_id: srvtoolu_01BJh8n7va96puUF3hhNnYnY + type: web_search_tool_result + - text: "\n\nBased on the search results, " + type: text + - citations: + - cited_text: Current moon phase · Moon calendar 2025 · Moon phases (Full Moon) 2025 & 2026 · World Clock · World + Clock · Calculate · Period between two dates · Mon... + encrypted_index: Eo8BCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDEgJNRfMEmnW19PSuBoMpvnoqkDvIRkx6yxdIjBNsAkQg3SrCCN1zCEKO4LtptywdqMNvgULDnwzA4e8JoIj6nDuov4EZIdg37AOh2QqEx0w/3OTuMMUW8z0FsIsEkBStrkYBA== + title: May 2025 Calendar + type: web_search_result_location + url: https://www.calendar-365.com/calendar/2025/May.html + text: today is Monday, May 26, 2025 (Week 22) + type: text + - text: '. This is notably ' + type: text + - citations: + - cited_text: The custom of honoring ancestors by cleaning cemeteries and decorating graves is an ancient and worldwide + tradition, but the specific origin of Memori... + encrypted_index: Eo8BCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDDh1HLd3wIXrMlbIYRoMJbIyO6jhVRytVw9tIjBp5E9G6P/4oCUT+AvhQia2q7og82j1ZKFJMEyZllOT5wNB8wxo/hua8sprObTuApUqEwNbgxwhB3Rzdzbu8jotXE3VzSYYBA== + title: Daily Calendar for Monday, May 26, 2025 | Almanac.com + type: web_search_result_location + url: https://www.almanac.com/calendar/date/2025-05-26 + text: Memorial Day, which was originally known as Decoration Day + type: text + - text: '. ' + type: text + - citations: + - cited_text: 'The year 2025 has 365 days. ' + encrypted_index: Eo8BCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDGSJfkRRZt9POYx8TRoM9ZykWxngb2XQ3vvZIjDwg7OYkVRW8t1wzFmTQ1TL5akbS2y3zcQRN/I2nU4v3NsNZbfOSHEBhWOql3U/nekqE4EtVZ7XYLel8iTWpvOfRFX8iUAYBA== + title: Day Numbers for 2025 + type: web_search_result_location + url: https://www.epochconverter.com/days/2025 + text: The year 2025 is a regular year with 365 days + type: text + - text: . + type: text + id: msg_014DEwKKUs2hUThC8aqhrc5d + model: claude-3-5-sonnet-20241022 + role: assistant + stop_reason: end_turn + stop_sequence: null + type: message + usage: + cache_creation_input_tokens: 0 + cache_read_input_tokens: 0 + input_tokens: 9582 + output_tokens: 178 + server_tool_use: + web_search_requests: 1 + service_tier: standard + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '732' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: What day is today? + role: user + - content: Let me search for today's date. + role: assistant + - content: "\n\nBased on the search results, " + role: assistant + - content: today is Monday, May 26, 2025 (Week 22) + role: assistant + - content: '. This is notably ' + role: assistant + - content: Memorial Day, which was originally known as Decoration Day + role: assistant + - content: '. ' + role: assistant + - content: The year 2025 is a regular year with 365 days + role: assistant + - content: . + role: assistant + - content: What day is tomorrow? + role: user + model: gpt-4.1 + stream: false + tool_choice: auto + tools: + - search_context_size: medium + type: web_search_preview + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '1494' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '1271' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + background: false + created_at: 1748263711 + error: null + id: resp_6834631faf2481918638284f62855ddf040b4e5d7e74f261 + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: gpt-4.1-2025-04-14 + object: response + output: + - content: + - annotations: [] + text: Tomorrow will be **Tuesday, May 27, 2025**. + type: output_text + id: msg_68346320b7608191a49fcd12e06dd3b5040b4e5d7e74f261 + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: null + summary: null + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: + - search_context_size: medium + type: web_search_preview + user_location: + city: null + country: US + region: null + timezone: null + type: approximate + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 410 + input_tokens_details: + cached_tokens: 0 + output_tokens: 17 + output_tokens_details: + reasoning_tokens: 0 + total_tokens: 427 + user: null + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_anthropic/test_anthropic_web_search_tool.yaml b/tests/models/cassettes/test_anthropic/test_anthropic_web_search_tool.yaml new file mode 100644 index 000000000..57f5e285c --- /dev/null +++ b/tests/models/cassettes/test_anthropic/test_anthropic_web_search_tool.yaml @@ -0,0 +1,166 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '312' + content-type: + - application/json + host: + - api.anthropic.com + method: POST + parsed_body: + max_tokens: 1024 + messages: + - content: + - text: What day is today? + type: text + role: user + model: claude-3-5-sonnet-latest + stream: false + tool_choice: + type: auto + tools: + - allowed_domains: null + blocked_domains: null + name: web_search + type: web_search_20250305 + user_location: null + uri: https://api.anthropic.com/v1/messages?beta=true + response: + headers: + connection: + - keep-alive + content-length: + - '42593' + content-type: + - application/json + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + content: + - text: Let me search for current events to help establish today's date. + type: text + - id: srvtoolu_01MqVvTi9LWTrMRuZ2KttD3M + input: + query: current events news today May 26 2025 + name: web_search + type: server_tool_use + - content: + - encrypted_content: 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 + page_age: null + title: 'News: U.S. and World News Headlines : NPR' + type: web_search_result + url: https://www.npr.org/sections/news/ + - encrypted_content: ErwHCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDK2W0Qu0wNgI6mf5EhoMNCqr1gVeM/Fj3PSYIjBrgyGKmTOrJLgDCXcOvRtrbigKDeccd5oypMBGnMVhm6h3Ade/9+vNOwI3ByflKmwqvwZqUUdfJ6+k9ZDrmb7VM6ktRqsZ4Z++yOdyubDNbsyM6RdwYuNi+bS5ZUON+rMd8+ZrQYlGYqq7NF43o5klxpac+Dsgx3OlKbu6Hq6eiKOQ3rdPGYlUYKdDouAx6RjypXjhYkqErPrjlFZhNv2lO6cohI0QU66p6b7G8UMVyweqYZ+2QYTFfbwU5VdIAOiQW8PBgNwPC5LRnidfbiT04VY+cEsNW04zOq9coXs4NgFRw2WDCZDBPGTEJex0xv7vD0/D0YpBhfiawNJ8FgBTI6q0gXQ2+YwqelVaZ+BDpu2JeRABLXiXQAMIiBBiayofacvfgJZ4omPY1JRiJwX5IpbLFqLcNz2fWr8veYedwrDZV/lOjyn755WTp2i89GD4Pv53htWrDOH8/YJBQ9u5KA2DFz7zAtRLyPqvPz3YaLMr3ATFvs8m0igrllgC5uaWPWfO/28RU7QNnxyBLGNonF3dtz3Uu2naeNvxjRhqCtUOON5odOahtPrRs5qkjv/UrL2YzlnfsRL4Qb/qsGJE6YWScvLhjBaum29Whk2p6RtYJqzzSqDbk0jxKe/hNatl3s2JF1bAW4L7p9FnsK1v/G7AYSaIYl4RDLGuL1bFOKGKVlUZtohNMws+gvTCYKdhQzfurimTsNIpBP4Ci6aJ+/yACa22AXGhZQqyiOS7yxI6zj3vZdQGFBle1TjDpzveY2Nz/kuuTCPbGsWt5kd9v7BkWvkNacqZ70KijyIk5dVt3H0q4eavyNLU0gF4hSCPDHW7eeWXTmNs1YniKiaHrwmOOqXjw2PCQrZv0i7UQRjDmRQqx9NtuqzMup9DRPbQuZM23b8JwzqA0Qjyxc5pTlWRL9aU+U7ZKOD1OdBszAU54c5N9jOca8S2Plt4TGJcAv2Wy73Bex74GPlkHcKWO8TJYhrV4ZF2nMjssncQEKCltJaZg6TJpazpLKoQ1XmYmgzebbVMRc8RTDXk335AYKkN62xRnfrDd5T5wBhGbPNQeF7PGigtAK/SpSpTna/vmGOBul/cONWOFFKNdY+FtCAGd4AOo3s/N8QUnKR66TEv9ocuVep1UZxV2fJcqIuJukutfT9eWPcou6VImLUzRQMYAw== + page_age: 4 days ago + title: The Biggest News Stories Of 2025 + type: web_search_result + url: https://92q.com/playlist/the-biggest-news-stories-of-2025/ + - encrypted_content: EuYCCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDCmLeaYgzUtJ4Mi+fBoMpktwxWvlSdpeNRRlIjDckkEHzeMKWP+vkSJ+7ci91OlLvn1nTU4wG+0am9miZ+68Q8XjsyCBGekIPeSsgpkq6QFTAvqrNhd55GMbj8VQtB/7oV66lwp8PzaymgQlLzCnxBdZ6IRYyEd6XwFOPrWCwyjtlKbwRiM2NIaNsGcrraBVrDfsjCz20qsDPGNsQf587z/TD3zWUSelhjhf+T5nDCEXUkYM2+4MaGP5Ty57Khh3WQr5q6Q46m85jBBF+akWf1uKZEgjgFug1ufj/8TXEEAaKCVY9YeXTXfYH8DocKveCXH4Bp9TNbgx55UrL8NdXiwdtpI/zqY+8hM/SiaVeXXI/Rbmjg3HzFTLfrH4wSrl5awdKWuGwQy8nqRISZlwNVnwFY0e8uc08xgD + page_age: null + title: ABC News – Breaking News, Latest News and Videos + type: web_search_result + url: https://abcnews.go.com/ + - encrypted_content: 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 + page_age: null + title: Breaking News, Latest News and Videos | CNN + type: web_search_result + url: https://www.cnn.com/ + - encrypted_content: ErQCCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDGPat3RtBffd6jd9uxoMkx9uAfM4hgJRbrR4IjCBVNWqux+TsqDP0poLm+ss84SLrVR4rAcjrQSDPna9ZfR0OFhPjv2ko1ZVuBzeRE4qtwGOPV6my0G/y4nPEH8gNVc3y/8uZzh7O8CBrduzchEMd5RRXLlsC+bU/SjZ+5LBYGzAVwRCfVXIdaJ0/d8RYdJWHo3bvKc5Lu/WFPV6Po9gVHLOU5WVDsyzwmrvqzCYC0UhkUMa0yf5j7WTFaT+kgHZcFcbvYPG53USqNh0seahaaCC5fJRjRBTAvuyj4md+ppTjIXGZEp3rTMG3MTkv8t60MgPzn4ObLGEmBQIQrfES9G2BT1k7lUYAw== + page_age: null + title: 'Philippines Top Stories: Politics, Environment, Education, Trending | Inquirer.net' + type: web_search_result + url: https://newsinfo.inquirer.net + - encrypted_content: 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 + page_age: null + title: Portal:Current events/May 2025 - Wikipedia + type: web_search_result + url: https://en.wikipedia.org/wiki/Portal:Current_events/May_2025 + - encrypted_content: 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 + page_age: null + title: Portal:Current events - Wikipedia + type: web_search_result + url: https://en.wikipedia.org/wiki/Portal:Current_events + - encrypted_content: EsoJCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDAYjLeq1Kci5o2pi8BoMqJacE/46sh+pR01VIjDPMDUx0d3wj2zbUnowpxFwHvCCnCwLoPMxQsQm/dnvm0Fzfga5o6zXqDwWpXvUzhEqzQg/X9w2opL/m5o7bUw/TubgkYaR6l4t2n0oQlGgetbSj1gOEor/WWJ8bWXL3BZnS2xkIzwGrbLdlPDn/NoXICDQZ+P3IlA6B8CVwiijOnNq+x5nTpX0m794VFJIfO5SdupAiWqhWmtqt8XhcWs8W2gnhDDvNsBG6oH2ZsRenxt3n7a7eWo7yRk/KSHdBM9c+L5r3wu3Ul81DW9CuE6KqUdFjjePJfWKL8OvzfkvJjIqcRaqc/3RIRZbSPbimBiRMXtCBZeCYE1yeBs3xLQ7TJXgRM/9ScKromcFWckYpGXBYSGL8SiXXoBUD7pLsuP5FnRnZUkQLCHTLoId0/w4jVbuXmDh3oipIlGUQCSbp3FkogFB/CZFpKz4tY5E9WQ4pBkApGYgAeGgOOStiUW3pE9oCy5TRpCfilrg66RtJozGI+LWM/XYuuOwSK+f+/c6AaUJ7av+LCUSPFI6G1XErfHK/KeBSJp7ZVoRXn/f7yJXlZvybKQXdN6UtxqxRJbil9RnmmXsBc6cesWW/cHbz01V8tkaqcYdrtJdVM/LesICK77C/JYiA6PQsneeg5xdZDCUp7yUO9P/CHMBqhPB8geS9y4dG7UIdJrFbv43cGOiqoSBsBGCLCc7crptYYGydT6YBgKb+ktUJm14MfbF8lzKt6SVYpn8KWL2dyhsDbfi88h51fvZqDV6loTDpyHbMHeJoA4pIxLhkBIriQOLNnEIEwqTGy2XFy326bahzINKJVTY1mMq2v3O0Snl0DNcAZ1X/iHt393xPgdcSy6c2+sDRexvpU4grX1GGFD4E8kg1QP0fErasq17XzRVpnU7Kedk/ntU/X6zeI3aTEeyRNG7IPH67w6GyIF8XmgCh25H6bCBGN87N8hnPSVAy8/qIMcfZYaF1c8W/QB9n7HBWhQgdyZv3relj0Ur0xdRi2osqo+k2c0a9mmIVupbzpLAxfY7LiwU8Edsr+1WY62x1omk+b4XNiGnhHnrF4B2o+f89icgAVSqRo2ydqIUDnZUYewu8jjUg/j+WUI8yKqZHCgCRdkm4fDSOcK8faTeaITl1iI6XFbUicEWZzG87tFykNSv5fz+ueDbMj936cm97rPUhp/qMnS2uloAxmiWLcS2/oV605i97ccR9IlwB0tt259e9iCvltjxzcC6P95vbhLS94+xVNOG2fmQtzE8oyaREZBkwSjVHuJ3lDAxvHDRYY8F+lkuLE4AvLiye3CDAMXNyCrG+/xiQIBNUGs+1aV9edHMmwpCVs99Q+nHO1RBVPljY607Q6u06Wt4VHnY+45+IxzpHHWXxg3Jn8Lh1AuzFKEaRWaI7JDSCgJmYxjIwkUO7988PWjOmFLquOd6mQsQ6iVG/89zSwr019RlAQRDIbMimefHIYhLm4S/Y8TzPhLFXJ6FaxrPFAkkkp2LnLQUoNKlo2h64JaAerGAku2FEwn/vo3hsCXwILg6R4QYAw== + page_age: null + title: Current Affairs Today – Current Affairs – 2025-26 - GKToday + type: web_search_result + url: https://www.gktoday.in/current-affairs/ + - encrypted_content: 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 + page_age: 3 weeks ago + title: 'May 6, 2025: Top news events to look out for today - People Daily' + type: web_search_result + url: https://peopledaily.digital/news/may-6-2025-top-news-events-to-look-out-for-today + - encrypted_content: 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 + page_age: 7 hours ago + title: 26 May 2025 UPSC Current Affairs - Daily News Headlines + type: web_search_result + url: https://testbook.com/ias-preparation/upsc-current-affairs-for-26-may-2025 + tool_use_id: srvtoolu_01MqVvTi9LWTrMRuZ2KttD3M + type: web_search_tool_result + - text: "\n\nBased on the search results, today is Monday, May 26, 2025. This is confirmed by several sources:\n\n1. " + type: text + - citations: + - cited_text: "Katja Ridderbusch hide caption toggle caption Katja Ridderbusch · May 26, 2025 \x95 Efforts to improve + officers' mental health have grown over the p..." + encrypted_index: Eo8BCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDDbwqv5slJiinAczsRoMhSEnYjGPJgqqehvhIjD+BvlqTC7HRjtE/aw2RZWQrImtkFRHsMc+fLuePmKCTV6CchthAUcDrpTbM2sVfeoqE2azhBPbtwuu/6GGPopddo8c5owYBA== + title: 'News: U.S. and World News Headlines : NPR' + type: web_search_result_location + url: https://www.npr.org/sections/news/ + - cited_text: "May 26, 2025 \x95 It's Memorial Day. " + encrypted_index: EpABCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDP+cEzOyt7FZcwJ+GBoMyXx/ouZvvFOJk680IjAWGSs9Nrqov5SEum6N3Gk0FGVUoIgOxF4aOdlcLDVixGpcVil7pLWnwcKf6aH1DhIqFFQUWnEOplUMZH6nQ1RQprK0YB59GAQ= + title: 'News: U.S. and World News Headlines : NPR' + type: web_search_result_location + url: https://www.npr.org/sections/news/ + text: It's Memorial Day today, May 26, 2025 + type: text + - text: "\n\n2. " + type: text + - citations: + - cited_text: 'May 2025 is the fifth month of the current common year. The month, which began on a Thursday, will + end on a Saturday after 31 days. ' + encrypted_index: EpMBCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDKg1IA50Gwr+acWT5BoMGYg/QqdGIWZ1xBQKIjAkgAmLPkrAfHcJ5l/9cBkuIDZFR5HqWIMts7szVwtYu+KUtw636GWrp1YgAWw+PHkqF0xqh9pIZ2wPGUKGN4beDYqhKyS3yKNSGAQ= + title: Portal:Current events/May 2025 - Wikipedia + type: web_search_result_location + url: https://en.wikipedia.org/wiki/Portal:Current_events/May_2025 + text: May 2025 is the fifth month of the current common year. The month began on a Thursday and will end on a Saturday + after 31 days + type: text + - text: "\n\n3. " + type: text + - citations: + - cited_text: On May 26, 2025, India and the world witnessed significant developments across various sectors. In recent + developments shaping global and national aff... + encrypted_index: EpIBCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDFkt41LpatakOxyiFhoMv3NkIlXjrN17gwJmIjBYF1Ds1OSA6s5ysr6ObQrej6qB8TY2C7CLY3A9izWkBKF92leDuAKzxrbr0q2HuTYqFvMJ033dlXOze2WorB4B4VxlNRvBw7EYBA== + title: 26 May 2025 UPSC Current Affairs - Daily News Headlines + type: web_search_result_location + url: https://testbook.com/ias-preparation/upsc-current-affairs-for-26-may-2025 + text: On May 26, 2025, there are significant developments happening, including India's launch of the Bharat Forecasting + System to boost weather prediction and disaster preparedness + type: text + id: msg_01WWvGdHT1E2kYaV5ZLWMB2N + model: claude-3-5-sonnet-20241022 + role: assistant + stop_reason: end_turn + stop_sequence: null + type: message + usage: + cache_creation_input_tokens: 0 + cache_read_input_tokens: 0 + input_tokens: 16312 + output_tokens: 258 + server_tool_use: + web_search_requests: 1 + service_tier: standard + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_google/test_google_model_code_execution_tool.yaml b/tests/models/cassettes/test_google/test_google_model_code_execution_tool.yaml new file mode 100644 index 000000000..7301ab260 --- /dev/null +++ b/tests/models/cassettes/test_google/test_google_model_code_execution_tool.yaml @@ -0,0 +1,89 @@ +interactions: +- request: + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '234' + content-type: + - application/json + host: + - generativelanguage.googleapis.com + method: POST + parsed_body: + contents: + - parts: + - text: What day is today in Utrecht? + role: user + generationConfig: {} + systemInstruction: + parts: + - text: You are a helpful chatbot. + role: user + tools: + - codeExecution: {} + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent + response: + headers: + alt-svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + content-length: + - '1462' + content-type: + - application/json; charset=UTF-8 + server-timing: + - gfet4t7; dur=7674 + transfer-encoding: + - chunked + vary: + - Origin + - X-Origin + - Referer + parsed_body: + candidates: + - content: + parts: + - text: |+ + To determine the current day in Utrecht, I need to know the current date and time. I will use a tool to get this information. + + - executableCode: + code: | + import datetime + import pytz + + utrecht_timezone = pytz.timezone('Europe/Amsterdam') + now_utrecht = datetime.datetime.now(utrecht_timezone) + print(now_utrecht.strftime("%A, %Y-%m-%d")) + language: PYTHON + - codeExecutionResult: + outcome: OUTCOME_OK + output: | + Wednesday, 2025-05-28 + - text: | + Today is Wednesday, May 28, 2025 in Utrecht. + role: model + finishReason: STOP + modelVersion: gemini-2.0-flash + responseId: 8ww3aLDxJY24qsMP97vYeA + usageMetadata: + candidatesTokenCount: 119 + candidatesTokensDetails: + - modality: TEXT + tokenCount: 119 + promptTokenCount: 13 + promptTokensDetails: + - modality: TEXT + tokenCount: 13 + toolUsePromptTokenCount: 114 + toolUsePromptTokensDetails: + - modality: TEXT + tokenCount: 114 + totalTokenCount: 246 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_google/test_google_model_web_search_tool.yaml b/tests/models/cassettes/test_google/test_google_model_web_search_tool.yaml new file mode 100644 index 000000000..e880750ac --- /dev/null +++ b/tests/models/cassettes/test_google/test_google_model_web_search_tool.yaml @@ -0,0 +1,199 @@ +interactions: +- request: + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '233' + content-type: + - application/json + host: + - generativelanguage.googleapis.com + method: POST + parsed_body: + contents: + - parts: + - text: What day is today in Utrecht? + role: user + generationConfig: {} + systemInstruction: + parts: + - text: You are a helpful chatbot. + role: user + tools: + - googleSearch: {} + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent + response: + headers: + alt-svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + content-length: + - '5991' + content-type: + - application/json; charset=UTF-8 + server-timing: + - gfet4t7; dur=1340 + transfer-encoding: + - chunked + vary: + - Origin + - X-Origin + - Referer + parsed_body: + candidates: + - content: + parts: + - text: | + Today is Wednesday, May 28, 2025, in Utrecht. + role: model + finishReason: STOP + groundingMetadata: + retrievalMetadata: {} + searchEntryPoint: + renderedContent: | + +
+
+ + + + + + + + + + + + + +
+
+ +
+ webSearchQueries: + - current date Utrecht + modelVersion: gemini-2.0-flash + responseId: LN42aKzNCaqvgLUP1Lz-8As + usageMetadata: + candidatesTokenCount: 19 + candidatesTokensDetails: + - modality: TEXT + tokenCount: 19 + promptTokenCount: 13 + promptTokensDetails: + - modality: TEXT + tokenCount: 13 + totalTokenCount: 32 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_groq/test_groq_model_web_search_tool.yaml b/tests/models/cassettes/test_groq/test_groq_model_web_search_tool.yaml new file mode 100644 index 000000000..73e9b042c --- /dev/null +++ b/tests/models/cassettes/test_groq/test_groq_model_web_search_tool.yaml @@ -0,0 +1,273 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '106' + content-type: + - application/json + host: + - api.groq.com + method: POST + parsed_body: + messages: + - content: What day is today? + role: user + model: compound-beta + n: 1 + stream: false + uri: https://api.groq.com/openai/v1/chat/completions + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - private, max-age=0, no-store, no-cache, must-revalidate + connection: + - keep-alive + content-length: + - '13044' + content-type: + - application/json + transfer-encoding: + - chunked + vary: + - Origin + parsed_body: + choices: + - finish_reason: stop + index: 0 + logprobs: null + message: + content: The current day is Tuesday. + executed_tools: + - arguments: '{"query": "What is the current date?"}' + index: 0 + output: |+ + Title: Today's Date - Find Out Quickly What's The Date Today ️ + URL: https://calendarhours.com/todays-date/ + Content: The current date in RFC 2822 Format with shortened day of week, numerical date, three-letter month abbreviation, year, time, and time zone is: Tue, 13 May 2025 06:07:56 -0400; The current date in Unix Epoch Format with number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT) is: + Score: 0.8299 + + Title: Today's Date | Current date now - MaxTables + URL: https://maxtables.com/tools/todays-date.html + Content: The current date, including day of the week, month, day, and year. The exact time, down to seconds. Details on the time zone, its location, and its GMT difference. A tool to select the present date. A visual calendar chart. Why would I need to check Today's Date on this platform instead of my device? + Score: 0.7223 + + Title: Current Time and Date - Exact Time! + URL: https://time-and-calendar.com/ + Content: The actual time is: Mon May 12 2025 22:14:39 GMT-0700 (Pacific Daylight Time) Your computer time is: 22:14:38 The time of your computer is synchronized with our web server. This mean that it is synchonizing in real time with our server clock. + Score: 0.6799 + + Title: Today's Date - CalendarDate.com + URL: https://www.calendardate.com/todays.htm + Content: Details about today's date with count of days, weeks, and months, Sun and Moon cycles, Zodiac signs and holidays. Monday May 12, 2025 . Home; Calendars. 2025 Calendar; ... Current Season Today: Spring with 40 days until the start of Summer. S. Hemishpere flip seasons - i.e. Winter is Summer. + Score: 0.6416 + + Title: What is the date today | Today's Date + URL: https://www.datetoday.info/ + Content: Master time tracking with Today's Date. Stay updated with real-time information on current date, time, day of the week, days left in the week, current day and remaining days of the year. Explore time in globally accepted formats. Keep up with the current week and month, along with the remaining weeks and months for the year. Embrace efficient time tracking with Today's Date. + Score: 0.6282 + + Title: Explore Today's Date, Time Zones, Holidays & More + URL: https://whatdateis.today/ + Content: Check what date and time it is today (May 8, 2025). View current time across different time zones, upcoming holidays, and use our date calculator. Your one-stop destination for all date and time information. + Score: 0.6181 + + Title: Today's Date and Time - Date and Time Tools + URL: https://todaysdatetime.com/ + Content: Discover today's exact date and time, learn about time zones, date formats, and explore our comprehensive collection of date and time tools including calculators, converters, and calendars. ... Get the exact current date and time, along with powerful calculation tools for all your scheduling needs. 12h. Today. Day 76 of year (366) Yesterday + Score: 0.5456 + + Title: Current Time Now - What time is it? - RapidTables.com + URL: https://www.rapidtables.com/tools/current-time.html + Content: This page includes the following information: Current time: hours, minutes, seconds. Today's date: day of week, month, day, year. Time zone with location and GMT offset. + Score: 0.4255 + + Title: Current Time + URL: https://www.timeanddate.com/ + Content: Welcome to the world's top site for time, time zones, and astronomy. Organize your life with free online info and tools you can rely on. No sign-up needed. Sign in. News. News Home; Astronomy News; ... Current Time. Monday May 12, 2025 Roanoke Rapids, North Carolina, USA. Set home location. 11:27: 03 pm. World Clock. + Score: 0.3876 + + Title: Current local time in the United States - World clock + URL: https://dateandtime.info/country.php?code=US + Content: Time and Date of DST Change Time Change; DST started: Sunday, March 9, 2025 at 2:00 AM: The clocks were put forward an hour to 3:00 AM. DST ends: Sunday, November 2, 2025 at 2:00 AM: The clocks will be put back an hour to 1:00 AM. DST starts: Sunday, March 8, 2026 at 2:00 AM: The clocks will be put forward an hour to 3:00 AM. + Score: 0.3042 + + Title: Time.is - exact time, any time zone + URL: https://time.is/ + Content: 7 million locations, 58 languages, synchronized with atomic clock time. Time.is. Get Time.is Ad-free! Exact time now: 05:08:45. Tuesday, 13 May, 2025, week 20. Sun: ↑ 05:09 ↓ 20:45 (15h 36m) - More info - Make London time default - Remove from favorite locations + Score: 0.2796 + + Title: Time in United States now + URL: https://time.is/United_States + Content: Exact time now, time zone, time difference, sunrise/sunset time and key facts for United States. Time.is. Get Time.is Ad-free! Time in United States now . 11:17:42 PM. Monday, May 12, 2025. United States (incl. dependent territories) has 11 time zones. The time zone for the capital Washington, D.C. is used here. + Score: 0.2726 + + Title: Current Local Time in the United States - timeanddate.com + URL: https://www.timeanddate.com/worldclock/usa + Content: United States time now. USA time zones and time zone map with current time in each state. + Score: 0.2519 + + Title: Current local time in United States - World Time Clock & Map + URL: https://24timezones.com/United-States/time + Content: Check the current time in United States and time zone information, the UTC offset and daylight saving time dates in 2025. + Score: 0.2221 + + Title: The World Clock — Worldwide - timeanddate.com + URL: https://www.timeanddate.com/worldclock/ + Content: World time and date for cities in all time zones. International time right now. Takes into account all DST clock changes. + Score: 0.2134 + + type: search + reasoning: |2- + + To determine the current day, I need to access real-time information. I will use the search tool to find out the current date. + + + search(What is the current date?) + + Title: Today's Date - Find Out Quickly What's The Date Today ️ + URL: https://calendarhours.com/todays-date/ + Content: The current date in RFC 2822 Format with shortened day of week, numerical date, three-letter month abbreviation, year, time, and time zone is: Tue, 13 May 2025 06:07:56 -0400; The current date in Unix Epoch Format with number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT) is: + Score: 0.8299 + + Title: Today's Date | Current date now - MaxTables + URL: https://maxtables.com/tools/todays-date.html + Content: The current date, including day of the week, month, day, and year. The exact time, down to seconds. Details on the time zone, its location, and its GMT difference. A tool to select the present date. A visual calendar chart. Why would I need to check Today's Date on this platform instead of my device? + Score: 0.7223 + + Title: Current Time and Date - Exact Time! + URL: https://time-and-calendar.com/ + Content: The actual time is: Mon May 12 2025 22:14:39 GMT-0700 (Pacific Daylight Time) Your computer time is: 22:14:38 The time of your computer is synchronized with our web server. This mean that it is synchonizing in real time with our server clock. + Score: 0.6799 + + Title: Today's Date - CalendarDate.com + URL: https://www.calendardate.com/todays.htm + Content: Details about today's date with count of days, weeks, and months, Sun and Moon cycles, Zodiac signs and holidays. Monday May 12, 2025 . Home; Calendars. 2025 Calendar; ... Current Season Today: Spring with 40 days until the start of Summer. S. Hemishpere flip seasons - i.e. Winter is Summer. + Score: 0.6416 + + Title: What is the date today | Today's Date + URL: https://www.datetoday.info/ + Content: Master time tracking with Today's Date. Stay updated with real-time information on current date, time, day of the week, days left in the week, current day and remaining days of the year. Explore time in globally accepted formats. Keep up with the current week and month, along with the remaining weeks and months for the year. Embrace efficient time tracking with Today's Date. + Score: 0.6282 + + Title: Explore Today's Date, Time Zones, Holidays & More + URL: https://whatdateis.today/ + Content: Check what date and time it is today (May 8, 2025). View current time across different time zones, upcoming holidays, and use our date calculator. Your one-stop destination for all date and time information. + Score: 0.6181 + + Title: Today's Date and Time - Date and Time Tools + URL: https://todaysdatetime.com/ + Content: Discover today's exact date and time, learn about time zones, date formats, and explore our comprehensive collection of date and time tools including calculators, converters, and calendars. ... Get the exact current date and time, along with powerful calculation tools for all your scheduling needs. 12h. Today. Day 76 of year (366) Yesterday + Score: 0.5456 + + Title: Current Time Now - What time is it? - RapidTables.com + URL: https://www.rapidtables.com/tools/current-time.html + Content: This page includes the following information: Current time: hours, minutes, seconds. Today's date: day of week, month, day, year. Time zone with location and GMT offset. + Score: 0.4255 + + Title: Current Time + URL: https://www.timeanddate.com/ + Content: Welcome to the world's top site for time, time zones, and astronomy. Organize your life with free online info and tools you can rely on. No sign-up needed. Sign in. News. News Home; Astronomy News; ... Current Time. Monday May 12, 2025 Roanoke Rapids, North Carolina, USA. Set home location. 11:27: 03 pm. World Clock. + Score: 0.3876 + + Title: Current local time in the United States - World clock + URL: https://dateandtime.info/country.php?code=US + Content: Time and Date of DST Change Time Change; DST started: Sunday, March 9, 2025 at 2:00 AM: The clocks were put forward an hour to 3:00 AM. DST ends: Sunday, November 2, 2025 at 2:00 AM: The clocks will be put back an hour to 1:00 AM. DST starts: Sunday, March 8, 2026 at 2:00 AM: The clocks will be put forward an hour to 3:00 AM. + Score: 0.3042 + + Title: Time.is - exact time, any time zone + URL: https://time.is/ + Content: 7 million locations, 58 languages, synchronized with atomic clock time. Time.is. Get Time.is Ad-free! Exact time now: 05:08:45. Tuesday, 13 May, 2025, week 20. Sun: ↑ 05:09 ↓ 20:45 (15h 36m) - More info - Make London time default - Remove from favorite locations + Score: 0.2796 + + Title: Time in United States now + URL: https://time.is/United_States + Content: Exact time now, time zone, time difference, sunrise/sunset time and key facts for United States. Time.is. Get Time.is Ad-free! Time in United States now . 11:17:42 PM. Monday, May 12, 2025. United States (incl. dependent territories) has 11 time zones. The time zone for the capital Washington, D.C. is used here. + Score: 0.2726 + + Title: Current Local Time in the United States - timeanddate.com + URL: https://www.timeanddate.com/worldclock/usa + Content: United States time now. USA time zones and time zone map with current time in each state. + Score: 0.2519 + + Title: Current local time in United States - World Time Clock & Map + URL: https://24timezones.com/United-States/time + Content: Check the current time in United States and time zone information, the UTC offset and daylight saving time dates in 2025. + Score: 0.2221 + + Title: The World Clock — Worldwide - timeanddate.com + URL: https://www.timeanddate.com/worldclock/ + Content: World time and date for cities in all time zones. International time right now. Takes into account all DST clock changes. + Score: 0.2134 + + + The current date is Tuesday, May 13, 2025. + + + + The current day is Tuesday. + role: assistant + created: 1747232793 + id: stub + model: compound-beta + object: chat.completion + system_fingerprint: null + usage: + completion_time: 0.312814 + completion_tokens: 117 + prompt_time: 0.737839 + prompt_tokens: 4287 + queue_time: 1.687734 + total_time: 1.050655 + total_tokens: 4404 + usage_breakdown: + models: + - model: llama-3.3-70b-versatile + usage: + completion_time: 0.033092212 + completion_tokens: 4 + prompt_time: 0.008749282 + prompt_tokens: 134 + queue_time: 0.251916212 + total_time: 0.041841494 + total_tokens: 138 + - model: meta-llama/llama-4-scout-17b-16e-instruct + usage: + completion_time: 0.198660413 + completion_tokens: 82 + prompt_time: 0.026323206 + prompt_tokens: 491 + queue_time: 0.556546565 + total_time: 0.224983619 + total_tokens: 573 + - model: meta-llama/llama-4-scout-17b-16e-instruct + usage: + completion_time: 0.047136438 + completion_tokens: 24 + prompt_time: 0.077990192 + prompt_tokens: 1926 + queue_time: 0.619169638 + total_time: 0.12512663 + total_tokens: 1950 + - model: llama-3.3-70b-versatile + usage: + completion_time: 0.033926045 + completion_tokens: 7 + prompt_time: 0.624777225 + prompt_tokens: 1736 + queue_time: 0.26010064499999996 + total_time: 0.65870327 + total_tokens: 1743 + x_groq: + id: stub + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_openai/test_openai_web_search_tool.yaml b/tests/models/cassettes/test_openai/test_openai_web_search_tool.yaml new file mode 100644 index 000000000..cd48b3ea9 --- /dev/null +++ b/tests/models/cassettes/test_openai/test_openai_web_search_tool.yaml @@ -0,0 +1,79 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '218' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + messages: + - content: You are a helpful assistant. + role: system + - content: What day is today? + role: user + model: gpt-4o-search-preview + stream: false + web_search_options: + search_context_size: low + uri: https://api.openai.com/v1/chat/completions + response: + headers: + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '785' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '2051' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + choices: + - finish_reason: stop + index: 0 + message: + annotations: [] + content: 'May 14, 2025, 8:51:29 AM ' + refusal: null + role: assistant + created: 1747227087 + id: chatcmpl-e05fbf7b-44c0-406d-8662-bc7a9a518747 + model: gpt-4o-search-preview-2025-03-11 + object: chat.completion + system_fingerprint: '' + usage: + completion_tokens: 17 + completion_tokens_details: + accepted_prediction_tokens: 0 + audio_tokens: 0 + reasoning_tokens: 0 + rejected_prediction_tokens: 0 + prompt_tokens: 11 + prompt_tokens_details: + audio_tokens: 0 + cached_tokens: 0 + total_tokens: 28 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_openai/test_openai_web_search_tool_model_not_supported.yaml b/tests/models/cassettes/test_openai/test_openai_web_search_tool_model_not_supported.yaml new file mode 100644 index 000000000..0a102fa79 --- /dev/null +++ b/tests/models/cassettes/test_openai/test_openai_web_search_tool_model_not_supported.yaml @@ -0,0 +1,57 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '203' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + messages: + - content: You are a helpful assistant. + role: system + - content: What day is today? + role: user + model: gpt-4o + stream: false + web_search_options: + search_context_size: low + uri: https://api.openai.com/v1/chat/completions + response: + headers: + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '177' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '23' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + parsed_body: + error: + code: null + message: Web search options not supported with this model. + param: web_search_options + type: invalid_request_error + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/models/cassettes/test_openai/test_openai_web_search_tool_with_user_location.yaml b/tests/models/cassettes/test_openai/test_openai_web_search_tool_with_user_location.yaml new file mode 100644 index 000000000..30a557451 --- /dev/null +++ b/tests/models/cassettes/test_openai/test_openai_web_search_tool_with_user_location.yaml @@ -0,0 +1,91 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '322' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + messages: + - content: You are a helpful assistant. + role: system + - content: What is the current temperature? + role: user + model: gpt-4o-search-preview + stream: false + web_search_options: + search_context_size: medium + user_location: + approximate: + city: Utrecht + country: NL + type: approximate + uri: https://api.openai.com/v1/chat/completions + response: + headers: + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '1656' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '3979' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + choices: + - finish_reason: stop + index: 0 + message: + annotations: [] + content: "Het is momenteel zonnig in Utrecht met een temperatuur van 22°C.\n\n## Weer voor Utrecht, Nederland:\nHuidige + omstandigheden: Zonnig, 72°F (22°C)\n\nDagvoorspelling:\n* woensdag, mei 14: minimum: 48°F (9°C), maximum: 71°F + (22°C), beschrijving: Afnemende bewolking\n* donderdag, mei 15: minimum: 43°F (6°C), maximum: 67°F (20°C), beschrijving: + Na een bewolkt begin keert de zon terug\n* vrijdag, mei 16: minimum: 45°F (7°C), maximum: 64°F (18°C), beschrijving: + Overwegend zonnig\n* zaterdag, mei 17: minimum: 47°F (9°C), maximum: 68°F (20°C), beschrijving: Overwegend zonnig\n* + zondag, mei 18: minimum: 47°F (8°C), maximum: 68°F (20°C), beschrijving: Deels zonnig\n* maandag, mei 19: minimum: + 49°F (9°C), maximum: 70°F (21°C), beschrijving: Deels zonnig\n* dinsdag, mei 20: minimum: 49°F (10°C), maximum: + 72°F (22°C), beschrijving: Zonnig tot gedeeltelijk bewolkt\n " + refusal: null + role: assistant + created: 1747227540 + id: chatcmpl-da029146-a630-4224-9d12-7d808b031fbc + model: gpt-4o-search-preview-2025-03-11 + object: chat.completion + system_fingerprint: '' + usage: + completion_tokens: 293 + completion_tokens_details: + accepted_prediction_tokens: 0 + audio_tokens: 0 + reasoning_tokens: 0 + rejected_prediction_tokens: 0 + prompt_tokens: 12 + prompt_tokens_details: + audio_tokens: 0 + cached_tokens: 0 + total_tokens: 305 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_openai_responses/test_openai_responses_model_web_search_tool.yaml b/tests/models/cassettes/test_openai_responses/test_openai_responses_model_web_search_tool.yaml new file mode 100644 index 000000000..5996ed6c4 --- /dev/null +++ b/tests/models/cassettes/test_openai_responses/test_openai_responses_model_web_search_tool.yaml @@ -0,0 +1,114 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '231' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: What day is it today? + role: user + instructions: You are a helpful assistant. + model: gpt-4o + stream: false + tool_choice: auto + tools: + - search_context_size: medium + type: web_search_preview + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '2569' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '3632' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1747227360 + error: null + id: resp_682492e0aab88191afcadcbbb85e1a490e7f27fcb18d04ed + incomplete_details: null + instructions: You are a helpful assistant. + max_output_tokens: null + metadata: {} + model: gpt-4o-2024-08-06 + object: response + output: + - id: ws_682492e1b7a08191b30170317ea7ee570e7f27fcb18d04ed + status: completed + type: web_search_call + - content: + - annotations: [] + text: "Today is Wednesday, May 14, 2025.\n\n## Weather for San Francisco, CA:\nCurrent Conditions: Mostly clear, + 50°F (10°C)\n\nDaily Forecast:\n* Wednesday, May 14: Low: 51°F (10°C), High: 65°F (18°C), Description: Areas of + low clouds early; otherwise, mostly sunny\n* Thursday, May 15: Low: 53°F (12°C), High: 66°F (19°C), Description: + Areas of low clouds, then sun\n* Friday, May 16: Low: 53°F (12°C), High: 64°F (18°C), Description: Partly sunny\n* + Saturday, May 17: Low: 52°F (11°C), High: 63°F (17°C), Description: Low clouds breaking for some sun; breezy in + the afternoon\n* Sunday, May 18: Low: 51°F (10°C), High: 68°F (20°C), Description: Clouds yielding to sun\n* Monday, + May 19: Low: 53°F (12°C), High: 68°F (20°C), Description: Sunny\n* Tuesday, May 20: Low: 52°F (11°C), High: 70°F + (21°C), Description: Mostly sunny\n " + type: output_text + id: msg_682492e36ab08191813ec707a61c272f0e7f27fcb18d04ed + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: null + summary: null + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: + - search_context_size: medium + type: web_search_preview + user_location: + city: null + country: US + region: null + timezone: null + type: approximate + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 317 + input_tokens_details: + cached_tokens: 0 + output_tokens: 286 + output_tokens_details: + reasoning_tokens: 0 + total_tokens: 603 + user: null + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_openai_responses/test_openai_responses_model_web_search_tool_with_user_location.yaml b/tests/models/cassettes/test_openai_responses/test_openai_responses_model_web_search_tool_with_user_location.yaml new file mode 100644 index 000000000..6ad0ff843 --- /dev/null +++ b/tests/models/cassettes/test_openai_responses/test_openai_responses_model_web_search_tool_with_user_location.yaml @@ -0,0 +1,118 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '313' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: What is the current temperature? + role: user + instructions: You are a helpful assistant. + model: gpt-4o + stream: false + tool_choice: auto + tools: + - search_context_size: medium + type: web_search_preview + user_location: + city: Utrecht + country: NL + type: approximate + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '2631' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '3405' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1747227481 + error: null + id: resp_682493599ce08191a7d279acb969c28b05f032fc13ed3d8b + incomplete_details: null + instructions: You are a helpful assistant. + max_output_tokens: null + metadata: {} + model: gpt-4o-2024-08-06 + object: response + output: + - id: ws_6824935a6ca481918cae37433d3e2f8005f032fc13ed3d8b + status: completed + type: web_search_call + - content: + - annotations: [] + text: "As of 12:58 PM on Wednesday, May 14, 2025, in Utrecht, Netherlands, the weather is sunny with a temperature + of 22°C (71°F).\n\n## Weather for Utrecht, Netherlands:\nCurrent Conditions: Sunny, 71°F (22°C)\n\nDaily Forecast:\n* + Wednesday, May 14: Low: 48°F (9°C), High: 71°F (22°C), Description: Clouds yielding to sun\n* Thursday, May 15: + Low: 43°F (6°C), High: 67°F (20°C), Description: After a cloudy start, sun returns\n* Friday, May 16: Low: 45°F + (7°C), High: 64°F (18°C), Description: Mostly sunny\n* Saturday, May 17: Low: 47°F (9°C), High: 68°F (20°C), Description: + Mostly sunny\n* Sunday, May 18: Low: 47°F (8°C), High: 68°F (20°C), Description: Some sun\n* Monday, May 19: Low: + 49°F (9°C), High: 70°F (21°C), Description: Delightful with partial sunshine\n* Tuesday, May 20: Low: 49°F (10°C), + High: 72°F (22°C), Description: Warm with sunshine and a few clouds\n " + type: output_text + id: msg_6824935c4dfc8191b0abacb1c0fd0a7805f032fc13ed3d8b + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: null + summary: null + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: + - search_context_size: medium + type: web_search_preview + user_location: + city: Utrecht + country: NL + region: null + timezone: null + type: approximate + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 317 + input_tokens_details: + cached_tokens: 0 + output_tokens: 300 + output_tokens_details: + reasoning_tokens: 0 + total_tokens: 617 + user: null + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 8490d6204..47e5ba5ed 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -13,6 +13,7 @@ from inline_snapshot import snapshot from pydantic_ai import Agent, ModelHTTPError, ModelRetry +from pydantic_ai.builtin_tools import CodeExecutionTool, WebSearchTool from pydantic_ai.messages import ( BinaryContent, DocumentUrl, @@ -20,6 +21,8 @@ ModelRequest, ModelResponse, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, ToolCallPart, @@ -36,6 +39,7 @@ from anthropic import NOT_GIVEN, APIStatusError, AsyncAnthropic from anthropic.resources.beta import AsyncBeta from anthropic.types.beta import ( + BetaCodeExecutionResultBlock, BetaContentBlock, BetaInputJSONDelta, BetaMessage, @@ -50,6 +54,7 @@ BetaTextBlock, BetaToolUseBlock, BetaUsage, + BetaWebSearchResultBlock, ) from anthropic.types.beta.beta_raw_message_delta_event import Delta @@ -1063,3 +1068,252 @@ async def test_anthropic_model_empty_message_on_history(allow_model_requests: No What specifically would you like to know about potatoes?\ """) + + +@pytest.mark.vcr() +async def test_anthropic_web_search_tool(allow_model_requests: None, anthropic_api_key: str): + m = AnthropicModel('claude-3-5-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) + agent = Agent(m, builtin_tools=[WebSearchTool()]) + + result = await agent.run('What day is today?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='What day is today?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content="Let me search for current events to help establish today's date."), + ServerToolCallPart( + tool_name='web_search', + args={'query': 'current events news today May 26 2025'}, + tool_call_id='srvtoolu_01MqVvTi9LWTrMRuZ2KttD3M', + model_name='anthropic', + ), + ServerToolReturnPart( + tool_name='web_search_tool_result', + content=[ + BetaWebSearchResultBlock( + encrypted_content='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', + title='News: U.S. and World News Headlines : NPR', + type='web_search_result', + url='https://www.npr.org/sections/news/', + ), + BetaWebSearchResultBlock( + encrypted_content='ErwHCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDK2W0Qu0wNgI6mf5EhoMNCqr1gVeM/Fj3PSYIjBrgyGKmTOrJLgDCXcOvRtrbigKDeccd5oypMBGnMVhm6h3Ade/9+vNOwI3ByflKmwqvwZqUUdfJ6+k9ZDrmb7VM6ktRqsZ4Z++yOdyubDNbsyM6RdwYuNi+bS5ZUON+rMd8+ZrQYlGYqq7NF43o5klxpac+Dsgx3OlKbu6Hq6eiKOQ3rdPGYlUYKdDouAx6RjypXjhYkqErPrjlFZhNv2lO6cohI0QU66p6b7G8UMVyweqYZ+2QYTFfbwU5VdIAOiQW8PBgNwPC5LRnidfbiT04VY+cEsNW04zOq9coXs4NgFRw2WDCZDBPGTEJex0xv7vD0/D0YpBhfiawNJ8FgBTI6q0gXQ2+YwqelVaZ+BDpu2JeRABLXiXQAMIiBBiayofacvfgJZ4omPY1JRiJwX5IpbLFqLcNz2fWr8veYedwrDZV/lOjyn755WTp2i89GD4Pv53htWrDOH8/YJBQ9u5KA2DFz7zAtRLyPqvPz3YaLMr3ATFvs8m0igrllgC5uaWPWfO/28RU7QNnxyBLGNonF3dtz3Uu2naeNvxjRhqCtUOON5odOahtPrRs5qkjv/UrL2YzlnfsRL4Qb/qsGJE6YWScvLhjBaum29Whk2p6RtYJqzzSqDbk0jxKe/hNatl3s2JF1bAW4L7p9FnsK1v/G7AYSaIYl4RDLGuL1bFOKGKVlUZtohNMws+gvTCYKdhQzfurimTsNIpBP4Ci6aJ+/yACa22AXGhZQqyiOS7yxI6zj3vZdQGFBle1TjDpzveY2Nz/kuuTCPbGsWt5kd9v7BkWvkNacqZ70KijyIk5dVt3H0q4eavyNLU0gF4hSCPDHW7eeWXTmNs1YniKiaHrwmOOqXjw2PCQrZv0i7UQRjDmRQqx9NtuqzMup9DRPbQuZM23b8JwzqA0Qjyxc5pTlWRL9aU+U7ZKOD1OdBszAU54c5N9jOca8S2Plt4TGJcAv2Wy73Bex74GPlkHcKWO8TJYhrV4ZF2nMjssncQEKCltJaZg6TJpazpLKoQ1XmYmgzebbVMRc8RTDXk335AYKkN62xRnfrDd5T5wBhGbPNQeF7PGigtAK/SpSpTna/vmGOBul/cONWOFFKNdY+FtCAGd4AOo3s/N8QUnKR66TEv9ocuVep1UZxV2fJcqIuJukutfT9eWPcou6VImLUzRQMYAw==', + page_age='4 days ago', + title='The Biggest News Stories Of 2025', + type='web_search_result', + url='https://92q.com/playlist/the-biggest-news-stories-of-2025/', + ), + BetaWebSearchResultBlock( + encrypted_content='EuYCCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDCmLeaYgzUtJ4Mi+fBoMpktwxWvlSdpeNRRlIjDckkEHzeMKWP+vkSJ+7ci91OlLvn1nTU4wG+0am9miZ+68Q8XjsyCBGekIPeSsgpkq6QFTAvqrNhd55GMbj8VQtB/7oV66lwp8PzaymgQlLzCnxBdZ6IRYyEd6XwFOPrWCwyjtlKbwRiM2NIaNsGcrraBVrDfsjCz20qsDPGNsQf587z/TD3zWUSelhjhf+T5nDCEXUkYM2+4MaGP5Ty57Khh3WQr5q6Q46m85jBBF+akWf1uKZEgjgFug1ufj/8TXEEAaKCVY9YeXTXfYH8DocKveCXH4Bp9TNbgx55UrL8NdXiwdtpI/zqY+8hM/SiaVeXXI/Rbmjg3HzFTLfrH4wSrl5awdKWuGwQy8nqRISZlwNVnwFY0e8uc08xgD', + title='ABC News – Breaking News, Latest News and Videos', + type='web_search_result', + url='https://abcnews.go.com/', + ), + BetaWebSearchResultBlock( + encrypted_content='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', + title='Breaking News, Latest News and Videos | CNN', + type='web_search_result', + url='https://www.cnn.com/', + ), + BetaWebSearchResultBlock( + encrypted_content='ErQCCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDGPat3RtBffd6jd9uxoMkx9uAfM4hgJRbrR4IjCBVNWqux+TsqDP0poLm+ss84SLrVR4rAcjrQSDPna9ZfR0OFhPjv2ko1ZVuBzeRE4qtwGOPV6my0G/y4nPEH8gNVc3y/8uZzh7O8CBrduzchEMd5RRXLlsC+bU/SjZ+5LBYGzAVwRCfVXIdaJ0/d8RYdJWHo3bvKc5Lu/WFPV6Po9gVHLOU5WVDsyzwmrvqzCYC0UhkUMa0yf5j7WTFaT+kgHZcFcbvYPG53USqNh0seahaaCC5fJRjRBTAvuyj4md+ppTjIXGZEp3rTMG3MTkv8t60MgPzn4ObLGEmBQIQrfES9G2BT1k7lUYAw==', + title='Philippines Top Stories: Politics, Environment, Education, Trending | Inquirer.net', + type='web_search_result', + url='https://newsinfo.inquirer.net', + ), + BetaWebSearchResultBlock( + encrypted_content='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', + title='Portal:Current events/May 2025 - Wikipedia', + type='web_search_result', + url='https://en.wikipedia.org/wiki/Portal:Current_events/May_2025', + ), + BetaWebSearchResultBlock( + encrypted_content='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', + title='Portal:Current events - Wikipedia', + type='web_search_result', + url='https://en.wikipedia.org/wiki/Portal:Current_events', + ), + BetaWebSearchResultBlock( + encrypted_content='EsoJCioIAxgCIiQ0NGFlNjc2Yy05NThmLTRkNjgtOTEwOC1lYWU5ZGU3YjM2NmISDAYjLeq1Kci5o2pi8BoMqJacE/46sh+pR01VIjDPMDUx0d3wj2zbUnowpxFwHvCCnCwLoPMxQsQm/dnvm0Fzfga5o6zXqDwWpXvUzhEqzQg/X9w2opL/m5o7bUw/TubgkYaR6l4t2n0oQlGgetbSj1gOEor/WWJ8bWXL3BZnS2xkIzwGrbLdlPDn/NoXICDQZ+P3IlA6B8CVwiijOnNq+x5nTpX0m794VFJIfO5SdupAiWqhWmtqt8XhcWs8W2gnhDDvNsBG6oH2ZsRenxt3n7a7eWo7yRk/KSHdBM9c+L5r3wu3Ul81DW9CuE6KqUdFjjePJfWKL8OvzfkvJjIqcRaqc/3RIRZbSPbimBiRMXtCBZeCYE1yeBs3xLQ7TJXgRM/9ScKromcFWckYpGXBYSGL8SiXXoBUD7pLsuP5FnRnZUkQLCHTLoId0/w4jVbuXmDh3oipIlGUQCSbp3FkogFB/CZFpKz4tY5E9WQ4pBkApGYgAeGgOOStiUW3pE9oCy5TRpCfilrg66RtJozGI+LWM/XYuuOwSK+f+/c6AaUJ7av+LCUSPFI6G1XErfHK/KeBSJp7ZVoRXn/f7yJXlZvybKQXdN6UtxqxRJbil9RnmmXsBc6cesWW/cHbz01V8tkaqcYdrtJdVM/LesICK77C/JYiA6PQsneeg5xdZDCUp7yUO9P/CHMBqhPB8geS9y4dG7UIdJrFbv43cGOiqoSBsBGCLCc7crptYYGydT6YBgKb+ktUJm14MfbF8lzKt6SVYpn8KWL2dyhsDbfi88h51fvZqDV6loTDpyHbMHeJoA4pIxLhkBIriQOLNnEIEwqTGy2XFy326bahzINKJVTY1mMq2v3O0Snl0DNcAZ1X/iHt393xPgdcSy6c2+sDRexvpU4grX1GGFD4E8kg1QP0fErasq17XzRVpnU7Kedk/ntU/X6zeI3aTEeyRNG7IPH67w6GyIF8XmgCh25H6bCBGN87N8hnPSVAy8/qIMcfZYaF1c8W/QB9n7HBWhQgdyZv3relj0Ur0xdRi2osqo+k2c0a9mmIVupbzpLAxfY7LiwU8Edsr+1WY62x1omk+b4XNiGnhHnrF4B2o+f89icgAVSqRo2ydqIUDnZUYewu8jjUg/j+WUI8yKqZHCgCRdkm4fDSOcK8faTeaITl1iI6XFbUicEWZzG87tFykNSv5fz+ueDbMj936cm97rPUhp/qMnS2uloAxmiWLcS2/oV605i97ccR9IlwB0tt259e9iCvltjxzcC6P95vbhLS94+xVNOG2fmQtzE8oyaREZBkwSjVHuJ3lDAxvHDRYY8F+lkuLE4AvLiye3CDAMXNyCrG+/xiQIBNUGs+1aV9edHMmwpCVs99Q+nHO1RBVPljY607Q6u06Wt4VHnY+45+IxzpHHWXxg3Jn8Lh1AuzFKEaRWaI7JDSCgJmYxjIwkUO7988PWjOmFLquOd6mQsQ6iVG/89zSwr019RlAQRDIbMimefHIYhLm4S/Y8TzPhLFXJ6FaxrPFAkkkp2LnLQUoNKlo2h64JaAerGAku2FEwn/vo3hsCXwILg6R4QYAw==', + title='Current Affairs Today – Current Affairs – 2025-26 - GKToday', + type='web_search_result', + url='https://www.gktoday.in/current-affairs/', + ), + BetaWebSearchResultBlock( + encrypted_content='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', + page_age='3 weeks ago', + title='May 6, 2025: Top news events to look out for today - People Daily', + type='web_search_result', + url='https://peopledaily.digital/news/may-6-2025-top-news-events-to-look-out-for-today', + ), + BetaWebSearchResultBlock( + encrypted_content='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', + page_age='7 hours ago', + title='26 May 2025 UPSC Current Affairs - Daily News Headlines', + type='web_search_result', + url='https://testbook.com/ias-preparation/upsc-current-affairs-for-26-may-2025', + ), + ], + tool_call_id=IsStr(), + timestamp=IsDatetime(), + ), + TextPart( + content="""\ + + +Based on the search results, today is Monday, May 26, 2025. This is confirmed by several sources: + +1. \ +""" + ), + TextPart(content="It's Memorial Day today, May 26, 2025"), + TextPart( + content="""\ + + +2. \ +""" + ), + TextPart( + content='May 2025 is the fifth month of the current common year. The month began on a Thursday and will end on a Saturday after 31 days' + ), + TextPart( + content="""\ + + +3. \ +""" + ), + TextPart( + content="On May 26, 2025, there are significant developments happening, including India's launch of the Bharat Forecasting System to boost weather prediction and disaster preparedness" + ), + ], + usage=Usage( + requests=1, + request_tokens=16312, + response_tokens=258, + total_tokens=16570, + details={ + 'cache_creation_input_tokens': 0, + 'cache_read_input_tokens': 0, + 'input_tokens': 16312, + 'output_tokens': 258, + }, + ), + model_name='claude-3-5-sonnet-20241022', + timestamp=IsDatetime(), + vendor_id=IsStr(), + ), + ] + ) + + +@pytest.mark.vcr() +async def test_anthropic_code_execution_tool(allow_model_requests: None, anthropic_api_key: str): + m = AnthropicModel('claude-sonnet-4-0', provider=AnthropicProvider(api_key=anthropic_api_key)) + agent = Agent(m, builtin_tools=[CodeExecutionTool()]) + + result = await agent.run('How much is 3 * 12390?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How much is 3 * 12390?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content="I'll calculate 3 * 12390 for you."), + ServerToolCallPart( + tool_name='code_execution', + args={ + 'code': """\ +result = 3 * 12390 +print(f"3 * 12390 = {result}")\ +""" + }, + tool_call_id=IsStr(), + model_name='anthropic', + ), + ServerToolReturnPart( + tool_name='code_execution_tool_result', + content=BetaCodeExecutionResultBlock( + content=[], + return_code=0, + stderr='', + stdout='3 * 12390 = 37170\n', + type='code_execution_result', + ), + tool_call_id=IsStr(), + timestamp=IsDatetime(), + ), + TextPart(content='The answer is **37,170**.'), + ], + usage=Usage( + requests=1, + request_tokens=1630, + response_tokens=105, + total_tokens=1735, + details={ + 'cache_creation_input_tokens': 0, + 'cache_read_input_tokens': 0, + 'input_tokens': 1630, + 'output_tokens': 105, + }, + ), + model_name='claude-sonnet-4-20250514', + timestamp=IsDatetime(), + vendor_id=IsStr(), + ), + ] + ) + + +@pytest.mark.vcr +async def test_anthropic_server_tool_pass_history_to_another_provider( + allow_model_requests: None, anthropic_api_key: str, openai_api_key: str +): + try: + from pydantic_ai.models.openai import OpenAIResponsesModel + from pydantic_ai.providers.openai import OpenAIProvider + except ImportError: + pytest.skip('OpenAI is not installed') + + openai_model = OpenAIResponsesModel('gpt-4.1', provider=OpenAIProvider(api_key=openai_api_key)) + anthropic_model = AnthropicModel('claude-3-5-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) + agent = Agent(anthropic_model, builtin_tools=[WebSearchTool()]) + + result = await agent.run('What day is today?') + assert result.output == snapshot("""\ +Let me search for today's date. + + + +Based on the search results, \n\ + +today is Monday, May 26, 2025 (Week 22) + +. This is notably \n\ + +Memorial Day, which was originally known as Decoration Day + +. \n\ + +The year 2025 is a regular year with 365 days + +.\ +""") + result = await agent.run('What day is tomorrow?', model=openai_model, message_history=result.all_messages()) + assert result.new_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='What day is tomorrow?', timestamp=IsDatetime())]), + ModelResponse( + parts=[TextPart(content='Tomorrow will be **Tuesday, May 27, 2025**.')], + usage=Usage( + request_tokens=410, + response_tokens=17, + total_tokens=427, + details={'reasoning_tokens': 0, 'cached_tokens': 0}, + ), + model_name='gpt-4.1-2025-04-14', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_fallback.py b/tests/models/test_fallback.py index db6277527..dad5e13a1 100644 --- a/tests/models/test_fallback.py +++ b/tests/models/test_fallback.py @@ -127,7 +127,7 @@ def test_first_failed_instrumented(capfire: CaptureLogfire) -> None: 'end_time': 3000000000, 'attributes': { 'gen_ai.operation.name': 'chat', - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'logfire.span_type': 'span', 'logfire.msg': 'chat fallback:function:failure_response:,function:success_response:', 'gen_ai.system': 'function', @@ -200,7 +200,7 @@ async def test_first_failed_instrumented_stream(capfire: CaptureLogfire) -> None 'end_time': 3000000000, 'attributes': { 'gen_ai.operation.name': 'chat', - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'logfire.span_type': 'span', 'logfire.msg': 'chat fallback:function::failure_response_stream,function::success_response_stream', 'gen_ai.system': 'function', @@ -272,7 +272,7 @@ def test_all_failed_instrumented(capfire: CaptureLogfire) -> None: 'gen_ai.operation.name': 'chat', 'gen_ai.system': 'fallback:function,function', 'gen_ai.request.model': 'fallback:function:failure_response:,function:failure_response:', - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}', 'logfire.span_type': 'span', 'logfire.msg': 'chat fallback:function:failure_response:,function:failure_response:', diff --git a/tests/models/test_google.py b/tests/models/test_google.py index ca8a82a73..d868e92cd 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -13,6 +13,7 @@ from typing_extensions import TypedDict from pydantic_ai.agent import Agent +from pydantic_ai.builtin_tools import CodeExecutionTool, WebSearchTool from pydantic_ai.exceptions import ModelRetry, UnexpectedModelBehavior from pydantic_ai.messages import ( BinaryContent, @@ -26,6 +27,8 @@ PartDeltaEvent, PartStartEvent, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, TextPartDelta, @@ -40,7 +43,7 @@ with try_import() as imports_successful: from google.genai import _api_client - from google.genai.types import HarmBlockThreshold, HarmCategory + from google.genai.types import HarmBlockThreshold, HarmCategory, Language from pydantic_ai.models.google import GoogleModel, GoogleModelSettings from pydantic_ai.providers.google import GoogleProvider @@ -581,3 +584,75 @@ async def test_google_model_safety_settings(allow_model_requests: None, google_p with pytest.raises(UnexpectedModelBehavior, match='Safety settings triggered'): await agent.run('Tell me a joke about a Brazilians.') + + +async def test_google_model_web_search_tool(allow_model_requests: None, google_provider: GoogleProvider): + m = GoogleModel('gemini-2.0-flash', provider=google_provider) + agent = Agent(m, system_prompt='You are a helpful chatbot.', builtin_tools=[WebSearchTool()]) + + result = await agent.run('What day is today in Utrecht?') + assert result.output == snapshot('Today is Wednesday, May 28, 2025, in Utrecht.\n') + + +async def test_google_model_code_execution_tool(allow_model_requests: None, google_provider: GoogleProvider): + m = GoogleModel('gemini-2.0-flash', provider=google_provider) + agent = Agent(m, system_prompt='You are a helpful chatbot.', builtin_tools=[CodeExecutionTool()]) + + result = await agent.run('What day is today in Utrecht?') + assert result.all_messages() == snapshot( + [ + ModelRequest( + parts=[ + SystemPromptPart(content='You are a helpful chatbot.', timestamp=IsDatetime()), + UserPromptPart(content='What day is today in Utrecht?', timestamp=IsDatetime()), + ] + ), + ModelResponse( + parts=[ + TextPart( + content="""\ +To determine the current day in Utrecht, I need to know the current date and time. I will use a tool to get this information. + +""" + ), + ServerToolCallPart( + tool_name='code_execution', + args={ + 'code': """\ +import datetime +import pytz + +utrecht_timezone = pytz.timezone('Europe/Amsterdam') +now_utrecht = datetime.datetime.now(utrecht_timezone) +print(now_utrecht.strftime("%A, %Y-%m-%d")) +""", + 'language': Language.PYTHON, + }, + tool_call_id=IsStr(), + ), + ServerToolReturnPart( + tool_name='code_execution', + content='Wednesday, 2025-05-28\n', + tool_call_id="It doesn't have.", + timestamp=IsDatetime(), + ), + TextPart(content='Today is Wednesday, May 28, 2025 in Utrecht.\n'), + ], + usage=Usage( + requests=1, + request_tokens=13, + response_tokens=119, + total_tokens=246, + details={ + 'tool_use_prompt_tokens': 114, + 'text_candidates_tokens': 119, + 'text_prompt_tokens': 13, + 'text_tool_use_prompt_tokens': 114, + }, + ), + model_name='gemini-2.0-flash', + timestamp=IsDatetime(), + vendor_details={'finish_reason': 'STOP'}, + ), + ] + ) diff --git a/tests/models/test_groq.py b/tests/models/test_groq.py index 12cd6ee65..79e3de48c 100644 --- a/tests/models/test_groq.py +++ b/tests/models/test_groq.py @@ -15,12 +15,15 @@ from typing_extensions import TypedDict from pydantic_ai import Agent, ModelHTTPError, ModelRetry, UnexpectedModelBehavior +from pydantic_ai.builtin_tools import WebSearchTool from pydantic_ai.messages import ( BinaryContent, ImageUrl, ModelRequest, ModelResponse, RetryPromptPart, + ServerToolCallPart, + ServerToolReturnPart, SystemPromptPart, TextPart, ToolCallPart, @@ -682,3 +685,114 @@ async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: ), ] ) + + +@pytest.mark.vcr() +async def test_groq_model_web_search_tool(allow_model_requests: None, groq_api_key: str): + m = GroqModel('compound-beta', provider=GroqProvider(api_key=groq_api_key)) + agent = Agent(m, builtin_tools=[WebSearchTool()]) + + result = await agent.run('What day is today?') + assert result.output == snapshot('The current day is Tuesday.') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='What day is today?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + ServerToolCallPart( + tool_name='search', + args='{"query": "What is the current date?"}', + tool_call_id=IsStr(), + model_name='groq', + ), + ServerToolReturnPart( + tool_name='search', + content="""\ +Title: Today's Date - Find Out Quickly What's The Date Today ️ +URL: https://calendarhours.com/todays-date/ +Content: The current date in RFC 2822 Format with shortened day of week, numerical date, three-letter month abbreviation, year, time, and time zone is: Tue, 13 May 2025 06:07:56 -0400; The current date in Unix Epoch Format with number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT) is: +Score: 0.8299 + +Title: Today's Date | Current date now - MaxTables +URL: https://maxtables.com/tools/todays-date.html +Content: The current date, including day of the week, month, day, and year. The exact time, down to seconds. Details on the time zone, its location, and its GMT difference. A tool to select the present date. A visual calendar chart. Why would I need to check Today's Date on this platform instead of my device? +Score: 0.7223 + +Title: Current Time and Date - Exact Time! +URL: https://time-and-calendar.com/ +Content: The actual time is: Mon May 12 2025 22:14:39 GMT-0700 (Pacific Daylight Time) Your computer time is: 22:14:38 The time of your computer is synchronized with our web server. This mean that it is synchonizing in real time with our server clock. +Score: 0.6799 + +Title: Today's Date - CalendarDate.com +URL: https://www.calendardate.com/todays.htm +Content: Details about today's date with count of days, weeks, and months, Sun and Moon cycles, Zodiac signs and holidays. Monday May 12, 2025 . Home; Calendars. 2025 Calendar; ... Current Season Today: Spring with 40 days until the start of Summer. S. Hemishpere flip seasons - i.e. Winter is Summer. +Score: 0.6416 + +Title: What is the date today | Today's Date +URL: https://www.datetoday.info/ +Content: Master time tracking with Today's Date. Stay updated with real-time information on current date, time, day of the week, days left in the week, current day and remaining days of the year. Explore time in globally accepted formats. Keep up with the current week and month, along with the remaining weeks and months for the year. Embrace efficient time tracking with Today's Date. +Score: 0.6282 + +Title: Explore Today's Date, Time Zones, Holidays & More +URL: https://whatdateis.today/ +Content: Check what date and time it is today (May 8, 2025). View current time across different time zones, upcoming holidays, and use our date calculator. Your one-stop destination for all date and time information. +Score: 0.6181 + +Title: Today's Date and Time - Date and Time Tools +URL: https://todaysdatetime.com/ +Content: Discover today's exact date and time, learn about time zones, date formats, and explore our comprehensive collection of date and time tools including calculators, converters, and calendars. ... Get the exact current date and time, along with powerful calculation tools for all your scheduling needs. 12h. Today. Day 76 of year (366) Yesterday +Score: 0.5456 + +Title: Current Time Now - What time is it? - RapidTables.com +URL: https://www.rapidtables.com/tools/current-time.html +Content: This page includes the following information: Current time: hours, minutes, seconds. Today's date: day of week, month, day, year. Time zone with location and GMT offset. +Score: 0.4255 + +Title: Current Time +URL: https://www.timeanddate.com/ +Content: Welcome to the world's top site for time, time zones, and astronomy. Organize your life with free online info and tools you can rely on. No sign-up needed. Sign in. News. News Home; Astronomy News; ... Current Time. Monday May 12, 2025 Roanoke Rapids, North Carolina, USA. Set home location. 11:27: 03 pm. World Clock. +Score: 0.3876 + +Title: Current local time in the United States - World clock +URL: https://dateandtime.info/country.php?code=US +Content: Time and Date of DST Change Time Change; DST started: Sunday, March 9, 2025 at 2:00 AM: The clocks were put forward an hour to 3:00 AM. DST ends: Sunday, November 2, 2025 at 2:00 AM: The clocks will be put back an hour to 1:00 AM. DST starts: Sunday, March 8, 2026 at 2:00 AM: The clocks will be put forward an hour to 3:00 AM. +Score: 0.3042 + +Title: Time.is - exact time, any time zone +URL: https://time.is/ +Content: 7 million locations, 58 languages, synchronized with atomic clock time. Time.is. Get Time.is Ad-free! Exact time now: 05:08:45. Tuesday, 13 May, 2025, week 20. Sun: ↑ 05:09 ↓ 20:45 (15h 36m) - More info - Make London time default - Remove from favorite locations +Score: 0.2796 + +Title: Time in United States now +URL: https://time.is/United_States +Content: Exact time now, time zone, time difference, sunrise/sunset time and key facts for United States. Time.is. Get Time.is Ad-free! Time in United States now . 11:17:42 PM. Monday, May 12, 2025. United States (incl. dependent territories) has 11 time zones. The time zone for the capital Washington, D.C. is used here. +Score: 0.2726 + +Title: Current Local Time in the United States - timeanddate.com +URL: https://www.timeanddate.com/worldclock/usa +Content: United States time now. USA time zones and time zone map with current time in each state. +Score: 0.2519 + +Title: Current local time in United States - World Time Clock & Map +URL: https://24timezones.com/United-States/time +Content: Check the current time in United States and time zone information, the UTC offset and daylight saving time dates in 2025. +Score: 0.2221 + +Title: The World Clock — Worldwide - timeanddate.com +URL: https://www.timeanddate.com/worldclock/ +Content: World time and date for cities in all time zones. International time right now. Takes into account all DST clock changes. +Score: 0.2134 + +""", + tool_call_id=IsStr(), + timestamp=IsDatetime(), + ), + TextPart(content='The current day is Tuesday.'), + ], + usage=Usage(requests=1, request_tokens=4287, response_tokens=117, total_tokens=4404), + model_name='compound-beta', + timestamp=IsDatetime(), + vendor_id='stub', + ), + ] + ) diff --git a/tests/models/test_instrumented.py b/tests/models/test_instrumented.py index f7caad399..ad774292b 100644 --- a/tests/models/test_instrumented.py +++ b/tests/models/test_instrumented.py @@ -151,7 +151,7 @@ async def test_instrumented_model(capfire: CaptureLogfire): 'gen_ai.request.model': 'my_model', 'server.address': 'example.com', 'server.port': 8000, - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}', 'gen_ai.request.temperature': 1, 'logfire.msg': 'chat my_model', @@ -375,7 +375,7 @@ async def test_instrumented_model_stream(capfire: CaptureLogfire): 'gen_ai.request.model': 'my_model', 'server.address': 'example.com', 'server.port': 8000, - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}', 'gen_ai.request.temperature': 1, 'logfire.msg': 'chat my_model', @@ -460,7 +460,7 @@ async def test_instrumented_model_stream_break(capfire: CaptureLogfire): 'gen_ai.request.model': 'my_model', 'server.address': 'example.com', 'server.port': 8000, - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}', 'gen_ai.request.temperature': 1, 'logfire.msg': 'chat my_model', @@ -560,7 +560,7 @@ async def test_instrumented_model_attributes_mode(capfire: CaptureLogfire): 'gen_ai.request.model': 'my_model', 'server.address': 'example.com', 'server.port': 8000, - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': '{"function_tools": [], "builtin_tools": [], "allow_text_output": true, "output_tools": []}', 'gen_ai.request.temperature': 1, 'logfire.msg': 'chat my_model', 'logfire.span_type': 'span', diff --git a/tests/models/test_model_request_parameters.py b/tests/models/test_model_request_parameters.py index 03910db11..abba5ae54 100644 --- a/tests/models/test_model_request_parameters.py +++ b/tests/models/test_model_request_parameters.py @@ -7,6 +7,7 @@ def test_model_request_parameters_are_serializable(): params = ModelRequestParameters(function_tools=[], allow_text_output=False, output_tools=[]) assert TypeAdapter(ModelRequestParameters).dump_python(params) == { 'function_tools': [], + 'builtin_tools': [], 'allow_text_output': False, 'output_tools': [], } diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index b0c8cbf62..0193ae5de 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -15,6 +15,7 @@ from typing_extensions import TypedDict from pydantic_ai import Agent, ModelHTTPError, ModelRetry, UnexpectedModelBehavior +from pydantic_ai.builtin_tools import WebSearchTool from pydantic_ai.messages import ( AudioUrl, BinaryContent, @@ -1577,7 +1578,6 @@ async def get_temperature(city: str) -> float: ) -@pytest.mark.vcr() async def test_openai_instructions_with_logprobs(allow_model_requests: None): # Create a mock response with logprobs c = completion_message( @@ -1596,10 +1596,7 @@ async def test_openai_instructions_with_logprobs(allow_model_requests: None): 'gpt-4o', provider=OpenAIProvider(openai_client=mock_client), ) - agent = Agent( - m, - instructions='You are a helpful assistant.', - ) + agent = Agent(m, instructions='You are a helpful assistant.') result = await agent.run( 'What is the capital of Minas Gerais?', model_settings=OpenAIModelSettings(openai_logprobs=True), @@ -1617,6 +1614,57 @@ async def test_openai_instructions_with_logprobs(allow_model_requests: None): ] +@pytest.mark.vcr() +async def test_openai_web_search_tool_model_not_supported(allow_model_requests: None, openai_api_key: str): + m = OpenAIModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) + agent = Agent( + m, instructions='You are a helpful assistant.', builtin_tools=[WebSearchTool(search_context_size='low')] + ) + + with pytest.raises(ModelHTTPError, match='.*Web search options not supported with this model.*'): + await agent.run('What day is today?') + + +@pytest.mark.vcr() +async def test_openai_web_search_tool(allow_model_requests: None, openai_api_key: str): + m = OpenAIModel('gpt-4o-search-preview', provider=OpenAIProvider(api_key=openai_api_key)) + agent = Agent( + m, instructions='You are a helpful assistant.', builtin_tools=[WebSearchTool(search_context_size='low')] + ) + + result = await agent.run('What day is today?') + assert result.output == snapshot('May 14, 2025, 8:51:29 AM ') + + +@pytest.mark.vcr() +async def test_openai_web_search_tool_with_user_location(allow_model_requests: None, openai_api_key: str): + m = OpenAIModel('gpt-4o-search-preview', provider=OpenAIProvider(api_key=openai_api_key)) + agent = Agent( + m, + instructions='You are a helpful assistant.', + builtin_tools=[WebSearchTool(user_location={'city': 'Utrecht', 'country': 'NL'})], + ) + + result = await agent.run('What is the current temperature?') + assert result.output == snapshot("""\ +Het is momenteel zonnig in Utrecht met een temperatuur van 22°C. + +## Weer voor Utrecht, Nederland: +Huidige omstandigheden: Zonnig, 72°F (22°C) + +Dagvoorspelling: +* woensdag, mei 14: minimum: 48°F (9°C), maximum: 71°F (22°C), beschrijving: Afnemende bewolking +* donderdag, mei 15: minimum: 43°F (6°C), maximum: 67°F (20°C), beschrijving: Na een bewolkt begin keert de zon terug +* vrijdag, mei 16: minimum: 45°F (7°C), maximum: 64°F (18°C), beschrijving: Overwegend zonnig +* zaterdag, mei 17: minimum: 47°F (9°C), maximum: 68°F (20°C), beschrijving: Overwegend zonnig +* zondag, mei 18: minimum: 47°F (8°C), maximum: 68°F (20°C), beschrijving: Deels zonnig +* maandag, mei 19: minimum: 49°F (9°C), maximum: 70°F (21°C), beschrijving: Deels zonnig +* dinsdag, mei 20: minimum: 49°F (10°C), maximum: 72°F (22°C), beschrijving: Zonnig tot gedeeltelijk bewolkt + \ +""") + + +@pytest.mark.vcr() def test_openai_model_profile(): m = OpenAIModel('gpt-4o', provider=OpenAIProvider(api_key='foobar')) assert isinstance(m.profile, OpenAIModelProfile) diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index 736ceae08..53865b9b1 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -6,6 +6,7 @@ from typing_extensions import TypedDict from pydantic_ai.agent import Agent +from pydantic_ai.builtin_tools import WebSearchTool from pydantic_ai.exceptions import ModelHTTPError, ModelRetry from pydantic_ai.messages import ( BinaryContent, @@ -467,6 +468,58 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o ) +async def test_openai_responses_model_web_search_tool(allow_model_requests: None, openai_api_key: str): + m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) + agent = Agent(m, instructions='You are a helpful assistant.', builtin_tools=['web-search']) + + result = await agent.run('What day is it today?') + assert result.output == snapshot("""\ +Today is Wednesday, May 14, 2025. + +## Weather for San Francisco, CA: +Current Conditions: Mostly clear, 50°F (10°C) + +Daily Forecast: +* Wednesday, May 14: Low: 51°F (10°C), High: 65°F (18°C), Description: Areas of low clouds early; otherwise, mostly sunny +* Thursday, May 15: Low: 53°F (12°C), High: 66°F (19°C), Description: Areas of low clouds, then sun +* Friday, May 16: Low: 53°F (12°C), High: 64°F (18°C), Description: Partly sunny +* Saturday, May 17: Low: 52°F (11°C), High: 63°F (17°C), Description: Low clouds breaking for some sun; breezy in the afternoon +* Sunday, May 18: Low: 51°F (10°C), High: 68°F (20°C), Description: Clouds yielding to sun +* Monday, May 19: Low: 53°F (12°C), High: 68°F (20°C), Description: Sunny +* Tuesday, May 20: Low: 52°F (11°C), High: 70°F (21°C), Description: Mostly sunny + \ +""") + + +async def test_openai_responses_model_web_search_tool_with_user_location( + allow_model_requests: None, openai_api_key: str +): + m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) + agent = Agent( + m, + instructions='You are a helpful assistant.', + builtin_tools=[WebSearchTool(user_location={'city': 'Utrecht', 'country': 'NL'})], + ) + + result = await agent.run('What is the current temperature?') + assert result.output == snapshot("""\ +As of 12:58 PM on Wednesday, May 14, 2025, in Utrecht, Netherlands, the weather is sunny with a temperature of 22°C (71°F). + +## Weather for Utrecht, Netherlands: +Current Conditions: Sunny, 71°F (22°C) + +Daily Forecast: +* Wednesday, May 14: Low: 48°F (9°C), High: 71°F (22°C), Description: Clouds yielding to sun +* Thursday, May 15: Low: 43°F (6°C), High: 67°F (20°C), Description: After a cloudy start, sun returns +* Friday, May 16: Low: 45°F (7°C), High: 64°F (18°C), Description: Mostly sunny +* Saturday, May 17: Low: 47°F (9°C), High: 68°F (20°C), Description: Mostly sunny +* Sunday, May 18: Low: 47°F (8°C), High: 68°F (20°C), Description: Some sun +* Monday, May 19: Low: 49°F (9°C), High: 70°F (21°C), Description: Delightful with partial sunshine +* Tuesday, May 20: Low: 49°F (10°C), High: 72°F (22°C), Description: Warm with sunshine and a few clouds + \ +""") + + def test_model_profile_strict_not_supported(): my_tool = ToolDefinition( 'my_tool', diff --git a/tests/test_logfire.py b/tests/test_logfire.py index e63f358f3..3fe9f061b 100644 --- a/tests/test_logfire.py +++ b/tests/test_logfire.py @@ -223,6 +223,7 @@ async def my_ret(x: int) -> str: 'strict': None, } ], + 'builtin_tools': [], 'allow_text_output': True, 'output_tools': [], } @@ -404,14 +405,37 @@ async def test_feedback(capfire: CaptureLogfire) -> None: 'gen_ai.operation.name': 'chat', 'gen_ai.system': 'test', 'gen_ai.request.model': 'test', - 'model_request_parameters': '{"function_tools": [], "allow_text_output": true, "output_tools": []}', + 'model_request_parameters': IsJson( + {'function_tools': [], 'builtin_tools': [], 'allow_text_output': True, 'output_tools': []} + ), 'logfire.span_type': 'span', 'logfire.msg': 'chat test', 'gen_ai.usage.input_tokens': 51, 'gen_ai.usage.output_tokens': 4, 'gen_ai.response.model': 'test', - 'events': '[{"content": "Hello", "role": "user", "gen_ai.system": "test", "gen_ai.message.index": 0, "event.name": "gen_ai.user.message"}, {"index": 0, "message": {"role": "assistant", "content": "success (no tool calls)"}, "gen_ai.system": "test", "event.name": "gen_ai.choice"}]', - 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}, "model_request_parameters": {"type": "object"}}}', + 'events': IsJson( + [ + { + 'content': 'Hello', + 'role': 'user', + 'gen_ai.system': 'test', + 'gen_ai.message.index': 0, + 'event.name': 'gen_ai.user.message', + }, + { + 'index': 0, + 'message': {'role': 'assistant', 'content': 'success (no tool calls)'}, + 'gen_ai.system': 'test', + 'event.name': 'gen_ai.choice', + }, + ] + ), + 'logfire.json_schema': IsJson( + { + 'type': 'object', + 'properties': {'events': {'type': 'array'}, 'model_request_parameters': {'type': 'object'}}, + } + ), }, }, { diff --git a/uv.lock b/uv.lock index 1da96b32e..da28ffdd1 100644 --- a/uv.lock +++ b/uv.lock @@ -1288,7 +1288,7 @@ wheels = [ [[package]] name = "groq" -version = "0.18.0" +version = "0.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1298,9 +1298,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/8c/e72c164474a88dfed6c7327ad53cb87ff11566b74b3a76d41dc7b94fc51c/groq-0.18.0.tar.gz", hash = "sha256:8e2ccfea406d68b3525af4b7c0e321fcb3d2a73fc60bb70b4156e6cd88c72f03", size = 117322, upload-time = "2025-02-05T01:30:14.551Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/fc/29e9c24ab59602747027f41b9d761d24cf9e5771014c9a731137f51e9cce/groq-0.25.0.tar.gz", hash = "sha256:6e1c7466b0da0130498187b825bd239f86fb77bf7551eacfbfa561d75048746a", size = 128199, upload-time = "2025-05-16T19:57:43.381Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/6c/5a53d632b44ef7655ac8d9b34432e13160917f9307c94b1467efd34e336e/groq-0.18.0-py3-none-any.whl", hash = "sha256:81d5ac00057a45d8ce559d23ab5d3b3893011d1f12c35187ab35a9182d826ea6", size = 121911, upload-time = "2025-02-05T01:30:12.504Z" }, + { url = "https://files.pythonhosted.org/packages/4d/11/1019a6cfdb2e520cb461cf70d859216be8ca122ddf5ad301fc3b0ee45fd4/groq-0.25.0-py3-none-any.whl", hash = "sha256:aadc78b40b1809cdb196b1aa8c7f7293108767df1508cafa3e0d5045d9328e7a", size = 129371, upload-time = "2025-05-16T19:57:41.786Z" }, ] [[package]] @@ -3082,7 +3082,7 @@ requires-dist = [ { name = "google-auth", marker = "extra == 'vertexai'", specifier = ">=2.36.0" }, { name = "google-genai", marker = "extra == 'google'", specifier = ">=1.15.0" }, { name = "griffe", specifier = ">=1.3.2" }, - { name = "groq", marker = "extra == 'groq'", specifier = ">=0.15.0" }, + { name = "groq", marker = "extra == 'groq'", specifier = ">=0.25.0" }, { name = "httpx", specifier = ">=0.27" }, { name = "logfire", marker = "extra == 'logfire'", specifier = ">=3.11.0" }, { name = "mcp", marker = "python_full_version >= '3.10' and extra == 'mcp'", specifier = ">=1.9.0" },