pydantic-ai-slim 0.2.8__tar.gz → 0.2.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/PKG-INFO +6 -6
  2. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_cli.py +1 -1
  3. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/mcp.py +49 -32
  4. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/__init__.py +39 -15
  5. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/anthropic.py +3 -8
  6. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/gemini.py +35 -21
  7. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/google.py +9 -5
  8. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pyproject.toml +2 -2
  9. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/.gitignore +0 -0
  10. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/LICENSE +0 -0
  11. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/README.md +0 -0
  12. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/__init__.py +0 -0
  13. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/__main__.py +0 -0
  14. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_a2a.py +0 -0
  15. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_agent_graph.py +0 -0
  16. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_griffe.py +0 -0
  17. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_output.py +0 -0
  18. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_parts_manager.py +0 -0
  19. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_pydantic.py +0 -0
  20. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_system_prompt.py +0 -0
  21. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/_utils.py +0 -0
  22. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/agent.py +0 -0
  23. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/common_tools/__init__.py +0 -0
  24. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/common_tools/duckduckgo.py +0 -0
  25. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/common_tools/tavily.py +0 -0
  26. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/direct.py +0 -0
  27. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/exceptions.py +0 -0
  28. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/format_as_xml.py +0 -0
  29. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/format_prompt.py +0 -0
  30. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/messages.py +0 -0
  31. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/_json_schema.py +0 -0
  32. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/bedrock.py +0 -0
  33. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/cohere.py +0 -0
  34. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/fallback.py +0 -0
  35. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/function.py +0 -0
  36. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/groq.py +0 -0
  37. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/instrumented.py +0 -0
  38. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/mistral.py +0 -0
  39. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/openai.py +0 -0
  40. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/test.py +0 -0
  41. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/models/wrapper.py +0 -0
  42. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/__init__.py +0 -0
  43. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/anthropic.py +0 -0
  44. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/azure.py +0 -0
  45. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/bedrock.py +0 -0
  46. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/cohere.py +0 -0
  47. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/deepseek.py +0 -0
  48. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/google.py +0 -0
  49. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/google_gla.py +0 -0
  50. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/google_vertex.py +0 -0
  51. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/groq.py +0 -0
  52. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/mistral.py +0 -0
  53. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/openai.py +0 -0
  54. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/providers/openrouter.py +0 -0
  55. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/py.typed +0 -0
  56. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/result.py +0 -0
  57. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/settings.py +0 -0
  58. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/tools.py +0 -0
  59. {pydantic_ai_slim-0.2.8 → pydantic_ai_slim-0.2.10}/pydantic_ai/usage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 0.2.8
3
+ Version: 0.2.10
4
4
  Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
5
5
  Author-email: Samuel Colvin <samuel@pydantic.dev>, Marcelo Trylesinski <marcelotryle@gmail.com>, David Montague <david@pydantic.dev>, Alex Hall <alex@pydantic.dev>
6
6
  License-Expression: MIT
@@ -30,13 +30,13 @@ Requires-Dist: exceptiongroup; python_version < '3.11'
30
30
  Requires-Dist: griffe>=1.3.2
31
31
  Requires-Dist: httpx>=0.27
32
32
  Requires-Dist: opentelemetry-api>=1.28.0
33
- Requires-Dist: pydantic-graph==0.2.8
33
+ Requires-Dist: pydantic-graph==0.2.10
34
34
  Requires-Dist: pydantic>=2.10
35
35
  Requires-Dist: typing-inspection>=0.4.0
36
36
  Provides-Extra: a2a
37
- Requires-Dist: fasta2a==0.2.8; extra == 'a2a'
37
+ Requires-Dist: fasta2a==0.2.10; extra == 'a2a'
38
38
  Provides-Extra: anthropic
39
- Requires-Dist: anthropic>=0.49.0; extra == 'anthropic'
39
+ Requires-Dist: anthropic>=0.52.0; extra == 'anthropic'
40
40
  Provides-Extra: bedrock
41
41
  Requires-Dist: boto3>=1.35.74; extra == 'bedrock'
42
42
  Provides-Extra: cli
@@ -48,7 +48,7 @@ Requires-Dist: cohere>=5.13.11; (platform_system != 'Emscripten') and extra == '
48
48
  Provides-Extra: duckduckgo
49
49
  Requires-Dist: duckduckgo-search>=7.0.0; extra == 'duckduckgo'
50
50
  Provides-Extra: evals
51
- Requires-Dist: pydantic-evals==0.2.8; extra == 'evals'
51
+ Requires-Dist: pydantic-evals==0.2.10; extra == 'evals'
52
52
  Provides-Extra: google
53
53
  Requires-Dist: google-genai>=1.15.0; extra == 'google'
54
54
  Provides-Extra: groq
@@ -56,7 +56,7 @@ Requires-Dist: groq>=0.15.0; extra == 'groq'
56
56
  Provides-Extra: logfire
57
57
  Requires-Dist: logfire>=3.11.0; extra == 'logfire'
58
58
  Provides-Extra: mcp
59
- Requires-Dist: mcp>=1.6.0; (python_version >= '3.10') and extra == 'mcp'
59
+ Requires-Dist: mcp>=1.8.0; (python_version >= '3.10') and extra == 'mcp'
60
60
  Provides-Extra: mistral
61
61
  Requires-Dist: mistralai>=1.2.5; extra == 'mistral'
62
62
  Provides-Extra: openai
@@ -284,7 +284,7 @@ async def ask_agent(
284
284
  stack.enter_context(live) # entering multiple times is idempotent
285
285
 
286
286
  async for content in handle_stream.stream_output(debounce_by=None):
287
- live.update(Markdown(content, code_theme=code_theme))
287
+ live.update(Markdown(str(content), code_theme=code_theme))
288
288
 
289
289
  assert agent_run.result is not None
290
290
  return agent_run.result.all_messages()
@@ -6,16 +6,18 @@ from abc import ABC, abstractmethod
6
6
  from collections.abc import AsyncIterator, Sequence
7
7
  from contextlib import AsyncExitStack, asynccontextmanager
8
8
  from dataclasses import dataclass
9
+ from datetime import timedelta
9
10
  from pathlib import Path
10
11
  from types import TracebackType
11
12
  from typing import Any
12
13
 
14
+ import anyio
13
15
  from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
16
+ from mcp.shared.message import SessionMessage
14
17
  from mcp.types import (
15
18
  BlobResourceContents,
16
19
  EmbeddedResource,
17
20
  ImageContent,
18
- JSONRPCMessage,
19
21
  LoggingLevel,
20
22
  TextContent,
21
23
  TextResourceContents,
@@ -28,8 +30,8 @@ from pydantic_ai.tools import ToolDefinition
28
30
 
29
31
  try:
30
32
  from mcp.client.session import ClientSession
31
- from mcp.client.sse import sse_client
32
33
  from mcp.client.stdio import StdioServerParameters, stdio_client
34
+ from mcp.client.streamable_http import streamablehttp_client
33
35
  except ImportError as _import_error:
34
36
  raise ImportError(
35
37
  'Please install the `mcp` package to use the MCP server, '
@@ -55,8 +57,8 @@ class MCPServer(ABC):
55
57
  """
56
58
 
57
59
  _client: ClientSession
58
- _read_stream: MemoryObjectReceiveStream[JSONRPCMessage | Exception]
59
- _write_stream: MemoryObjectSendStream[JSONRPCMessage]
60
+ _read_stream: MemoryObjectReceiveStream[SessionMessage | Exception]
61
+ _write_stream: MemoryObjectSendStream[SessionMessage]
60
62
  _exit_stack: AsyncExitStack
61
63
 
62
64
  @abstractmethod
@@ -64,10 +66,7 @@ class MCPServer(ABC):
64
66
  async def client_streams(
65
67
  self,
66
68
  ) -> AsyncIterator[
67
- tuple[
68
- MemoryObjectReceiveStream[JSONRPCMessage | Exception],
69
- MemoryObjectSendStream[JSONRPCMessage],
70
- ]
69
+ tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]]
71
70
  ]:
72
71
  """Create the streams for the MCP server."""
73
72
  raise NotImplementedError('MCP Server subclasses must implement this method.')
@@ -78,6 +77,9 @@ class MCPServer(ABC):
78
77
  """Get the log level for the MCP server."""
79
78
  raise NotImplementedError('MCP Server subclasses must implement this method.')
80
79
 
80
+ def _get_client_initialize_timeout(self) -> float:
81
+ return 5 # pragma: no cover
82
+
81
83
  def get_prefixed_tool_name(self, tool_name: str) -> str:
82
84
  """Get the tool name with prefix if `tool_prefix` is set."""
83
85
  return f'{self.tool_prefix}_{tool_name}' if self.tool_prefix else tool_name
@@ -137,7 +139,9 @@ class MCPServer(ABC):
137
139
  client = ClientSession(read_stream=self._read_stream, write_stream=self._write_stream)
138
140
  self._client = await self._exit_stack.enter_async_context(client)
139
141
 
140
- await self._client.initialize()
142
+ with anyio.fail_after(self._get_client_initialize_timeout()):
143
+ await self._client.initialize()
144
+
141
145
  if log_level := self._get_log_level():
142
146
  await self._client.set_logging_level(log_level)
143
147
  self.is_running = True
@@ -252,14 +256,14 @@ class MCPServerStdio(MCPServer):
252
256
  e.g. if `tool_prefix='foo'`, then a tool named `bar` will be registered as `foo_bar`
253
257
  """
254
258
 
259
+ timeout: float = 5
260
+ """ The timeout in seconds to wait for the client to initialize."""
261
+
255
262
  @asynccontextmanager
256
263
  async def client_streams(
257
264
  self,
258
265
  ) -> AsyncIterator[
259
- tuple[
260
- MemoryObjectReceiveStream[JSONRPCMessage | Exception],
261
- MemoryObjectSendStream[JSONRPCMessage],
262
- ]
266
+ tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]]
263
267
  ]:
264
268
  server = StdioServerParameters(command=self.command, args=list(self.args), env=self.env, cwd=self.cwd)
265
269
  async with stdio_client(server=server) as (read_stream, write_stream):
@@ -271,16 +275,19 @@ class MCPServerStdio(MCPServer):
271
275
  def __repr__(self) -> str:
272
276
  return f'MCPServerStdio(command={self.command!r}, args={self.args!r}, tool_prefix={self.tool_prefix!r})'
273
277
 
278
+ def _get_client_initialize_timeout(self) -> float:
279
+ return self.timeout
280
+
274
281
 
275
282
  @dataclass
276
283
  class MCPServerHTTP(MCPServer):
277
284
  """An MCP server that connects over streamable HTTP connections.
278
285
 
279
- This class implements the SSE transport from the MCP specification.
280
- See <https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse> for more information.
286
+ This class implements the Streamable HTTP transport from the MCP specification.
287
+ See <https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http> for more information.
281
288
 
282
- The name "HTTP" is used since this implemented will be adapted in future to use the new
283
- [Streamable HTTP](https://github.com/modelcontextprotocol/specification/pull/206) currently in development.
289
+ The Streamable HTTP transport is intended to replace the SSE transport from the previous protocol, but it is fully
290
+ backwards compatible with SSE-based servers.
284
291
 
285
292
  !!! note
286
293
  Using this class as an async context manager will create a new pool of HTTP connections to connect
@@ -291,7 +298,7 @@ class MCPServerHTTP(MCPServer):
291
298
  from pydantic_ai import Agent
292
299
  from pydantic_ai.mcp import MCPServerHTTP
293
300
 
294
- server = MCPServerHTTP('http://localhost:3001/sse') # (1)!
301
+ server = MCPServerHTTP('http://localhost:3001/mcp') # (1)!
295
302
  agent = Agent('openai:gpt-4o', mcp_servers=[server])
296
303
 
297
304
  async def main():
@@ -304,27 +311,27 @@ class MCPServerHTTP(MCPServer):
304
311
  """
305
312
 
306
313
  url: str
307
- """The URL of the SSE endpoint on the MCP server.
314
+ """The URL of the SSE or MCP endpoint on the MCP server.
308
315
 
309
- For example for a server running locally, this might be `http://localhost:3001/sse`.
316
+ For example for a server running locally, this might be `http://localhost:3001/mcp`.
310
317
  """
311
318
 
312
319
  headers: dict[str, Any] | None = None
313
- """Optional HTTP headers to be sent with each request to the SSE endpoint.
320
+ """Optional HTTP headers to be sent with each request to the endpoint.
314
321
 
315
322
  These headers will be passed directly to the underlying `httpx.AsyncClient`.
316
323
  Useful for authentication, custom headers, or other HTTP-specific configurations.
317
324
  """
318
325
 
319
326
  timeout: float = 5
320
- """Initial connection timeout in seconds for establishing the SSE connection.
327
+ """Initial connection timeout in seconds for establishing the connection.
321
328
 
322
329
  This timeout applies to the initial connection setup and handshake.
323
330
  If the connection cannot be established within this time, the operation will fail.
324
331
  """
325
332
 
326
- sse_read_timeout: float = 60 * 5
327
- """Maximum time in seconds to wait for new SSE messages before timing out.
333
+ sse_read_timeout: float = 300
334
+ """Maximum time as in seconds to wait for new SSE messages before timing out.
328
335
 
329
336
  This timeout applies to the long-lived SSE connection after it's established.
330
337
  If no new messages are received within this time, the connection will be considered stale
@@ -346,21 +353,28 @@ class MCPServerHTTP(MCPServer):
346
353
  For example, if `tool_prefix='foo'`, then a tool named `bar` will be registered as `foo_bar`
347
354
  """
348
355
 
356
+ def __post_init__(self):
357
+ # streamablehttp_client expects timedeltas, so we accept them too to match,
358
+ # but primarily work with floats for a simpler user API.
359
+
360
+ if isinstance(self.timeout, timedelta):
361
+ self.timeout = self.timeout.total_seconds()
362
+
363
+ if isinstance(self.sse_read_timeout, timedelta):
364
+ self.sse_read_timeout = self.sse_read_timeout.total_seconds()
365
+
349
366
  @asynccontextmanager
350
367
  async def client_streams(
351
368
  self,
352
369
  ) -> AsyncIterator[
353
- tuple[
354
- MemoryObjectReceiveStream[JSONRPCMessage | Exception],
355
- MemoryObjectSendStream[JSONRPCMessage],
356
- ]
370
+ tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]]
357
371
  ]: # pragma: no cover
358
- async with sse_client(
372
+ async with streamablehttp_client(
359
373
  url=self.url,
360
374
  headers=self.headers,
361
- timeout=self.timeout,
362
- sse_read_timeout=self.sse_read_timeout,
363
- ) as (read_stream, write_stream):
375
+ timeout=timedelta(seconds=self.timeout),
376
+ sse_read_timeout=timedelta(self.sse_read_timeout),
377
+ ) as (read_stream, write_stream, _):
364
378
  yield read_stream, write_stream
365
379
 
366
380
  def _get_log_level(self) -> LoggingLevel | None:
@@ -368,3 +382,6 @@ class MCPServerHTTP(MCPServer):
368
382
 
369
383
  def __repr__(self) -> str: # pragma: no cover
370
384
  return f'MCPServerHTTP(url={self.url!r}, tool_prefix={self.tool_prefix!r})'
385
+
386
+ def _get_client_initialize_timeout(self) -> float: # pragma: no cover
387
+ return self.timeout
@@ -26,12 +26,25 @@ from ..usage import Usage
26
26
  KnownModelName = TypeAliasType(
27
27
  'KnownModelName',
28
28
  Literal[
29
- 'anthropic:claude-3-7-sonnet-latest',
29
+ 'anthropic:claude-2.0',
30
+ 'anthropic:claude-2.1',
31
+ 'anthropic:claude-3-5-haiku-20241022',
30
32
  'anthropic:claude-3-5-haiku-latest',
33
+ 'anthropic:claude-3-5-sonnet-20240620',
34
+ 'anthropic:claude-3-5-sonnet-20241022',
31
35
  'anthropic:claude-3-5-sonnet-latest',
36
+ 'anthropic:claude-3-7-sonnet-20250219',
37
+ 'anthropic:claude-3-7-sonnet-latest',
38
+ 'anthropic:claude-3-haiku-20240307',
39
+ 'anthropic:claude-3-opus-20240229',
32
40
  'anthropic:claude-3-opus-latest',
33
- 'claude-3-7-sonnet-latest',
34
- 'claude-3-5-haiku-latest',
41
+ 'anthropic:claude-3-sonnet-20240229',
42
+ 'anthropic:claude-4-opus-20250514',
43
+ 'anthropic:claude-4-sonnet-20250514',
44
+ 'anthropic:claude-opus-4-0',
45
+ 'anthropic:claude-opus-4-20250514',
46
+ 'anthropic:claude-sonnet-4-0',
47
+ 'anthropic:claude-sonnet-4-20250514',
35
48
  'bedrock:amazon.titan-tg1-large',
36
49
  'bedrock:amazon.titan-text-lite-v1',
37
50
  'bedrock:amazon.titan-text-express-v1',
@@ -75,8 +88,25 @@ KnownModelName = TypeAliasType(
75
88
  'bedrock:mistral.mixtral-8x7b-instruct-v0:1',
76
89
  'bedrock:mistral.mistral-large-2402-v1:0',
77
90
  'bedrock:mistral.mistral-large-2407-v1:0',
91
+ 'claude-2.0',
92
+ 'claude-2.1',
93
+ 'claude-3-5-haiku-20241022',
94
+ 'claude-3-5-haiku-latest',
95
+ 'claude-3-5-sonnet-20240620',
96
+ 'claude-3-5-sonnet-20241022',
78
97
  'claude-3-5-sonnet-latest',
98
+ 'claude-3-7-sonnet-20250219',
99
+ 'claude-3-7-sonnet-latest',
100
+ 'claude-3-haiku-20240307',
101
+ 'claude-3-opus-20240229',
79
102
  'claude-3-opus-latest',
103
+ 'claude-3-sonnet-20240229',
104
+ 'claude-4-opus-20250514',
105
+ 'claude-4-sonnet-20250514',
106
+ 'claude-opus-4-0',
107
+ 'claude-opus-4-20250514',
108
+ 'claude-sonnet-4-0',
109
+ 'claude-sonnet-4-20250514',
80
110
  'cohere:c4ai-aya-expanse-32b',
81
111
  'cohere:c4ai-aya-expanse-8b',
82
112
  'cohere:command',
@@ -92,32 +122,26 @@ KnownModelName = TypeAliasType(
92
122
  'cohere:command-r7b-12-2024',
93
123
  'deepseek:deepseek-chat',
94
124
  'deepseek:deepseek-reasoner',
95
- 'google-gla:gemini-1.0-pro',
96
125
  'google-gla:gemini-1.5-flash',
97
126
  'google-gla:gemini-1.5-flash-8b',
98
127
  'google-gla:gemini-1.5-pro',
99
- 'google-gla:gemini-2.0-flash-exp',
100
- 'google-gla:gemini-2.0-flash-thinking-exp-01-21',
101
- 'google-gla:gemini-exp-1206',
128
+ 'google-gla:gemini-1.0-pro',
102
129
  'google-gla:gemini-2.0-flash',
103
130
  'google-gla:gemini-2.0-flash-lite-preview-02-05',
104
131
  'google-gla:gemini-2.0-pro-exp-02-05',
105
- 'google-gla:gemini-2.5-flash-preview-04-17',
132
+ 'google-gla:gemini-2.5-flash-preview-05-20',
106
133
  'google-gla:gemini-2.5-pro-exp-03-25',
107
- 'google-gla:gemini-2.5-pro-preview-03-25',
108
- 'google-vertex:gemini-1.0-pro',
134
+ 'google-gla:gemini-2.5-pro-preview-05-06',
109
135
  'google-vertex:gemini-1.5-flash',
110
136
  'google-vertex:gemini-1.5-flash-8b',
111
137
  'google-vertex:gemini-1.5-pro',
112
- 'google-vertex:gemini-2.0-flash-exp',
113
- 'google-vertex:gemini-2.0-flash-thinking-exp-01-21',
114
- 'google-vertex:gemini-exp-1206',
138
+ 'google-vertex:gemini-1.0-pro',
115
139
  'google-vertex:gemini-2.0-flash',
116
140
  'google-vertex:gemini-2.0-flash-lite-preview-02-05',
117
141
  'google-vertex:gemini-2.0-pro-exp-02-05',
118
- 'google-vertex:gemini-2.5-flash-preview-04-17',
142
+ 'google-vertex:gemini-2.5-flash-preview-05-20',
119
143
  'google-vertex:gemini-2.5-pro-exp-03-25',
120
- 'google-vertex:gemini-2.5-pro-preview-03-25',
144
+ 'google-vertex:gemini-2.5-pro-preview-05-06',
121
145
  'gpt-3.5-turbo',
122
146
  'gpt-3.5-turbo-0125',
123
147
  'gpt-3.5-turbo-0301',
@@ -7,7 +7,6 @@ from dataclasses import dataclass, field
7
7
  from datetime import datetime, timezone
8
8
  from typing import Any, Literal, Union, cast, overload
9
9
 
10
- from anthropic import AsyncAnthropic
11
10
  from typing_extensions import assert_never
12
11
 
13
12
  from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage
@@ -41,7 +40,7 @@ from . import (
41
40
  )
42
41
 
43
42
  try:
44
- from anthropic import NOT_GIVEN, APIStatusError, AsyncStream
43
+ from anthropic import NOT_GIVEN, APIStatusError, AsyncAnthropic, AsyncStream
45
44
  from anthropic.types.beta import (
46
45
  BetaBase64PDFBlockParam,
47
46
  BetaBase64PDFSourceParam,
@@ -68,6 +67,7 @@ try:
68
67
  BetaToolUseBlock,
69
68
  BetaToolUseBlockParam,
70
69
  )
70
+ from anthropic.types.model_param import ModelParam
71
71
 
72
72
  except ImportError as _import_error:
73
73
  raise ImportError(
@@ -75,12 +75,7 @@ except ImportError as _import_error:
75
75
  'you can use the `anthropic` optional group — `pip install "pydantic-ai-slim[anthropic]"`'
76
76
  ) from _import_error
77
77
 
78
- LatestAnthropicModelNames = Literal[
79
- 'claude-3-7-sonnet-latest',
80
- 'claude-3-5-haiku-latest',
81
- 'claude-3-5-sonnet-latest',
82
- 'claude-3-opus-latest',
83
- ]
78
+ LatestAnthropicModelNames = ModelParam
84
79
  """Latest Anthropic models."""
85
80
 
86
81
  AnthropicModelName = Union[str, LatestAnthropicModelNames]
@@ -52,15 +52,12 @@ LatestGeminiModelNames = Literal[
52
52
  'gemini-1.5-flash-8b',
53
53
  'gemini-1.5-pro',
54
54
  'gemini-1.0-pro',
55
- 'gemini-2.0-flash-exp',
56
- 'gemini-2.0-flash-thinking-exp-01-21',
57
- 'gemini-exp-1206',
58
55
  'gemini-2.0-flash',
59
56
  'gemini-2.0-flash-lite-preview-02-05',
60
57
  'gemini-2.0-pro-exp-02-05',
61
- 'gemini-2.5-flash-preview-04-17',
58
+ 'gemini-2.5-flash-preview-05-20',
62
59
  'gemini-2.5-pro-exp-03-25',
63
- 'gemini-2.5-pro-preview-03-25',
60
+ 'gemini-2.5-pro-preview-05-06',
64
61
  ]
65
62
  """Latest Gemini models."""
66
63
 
@@ -80,6 +77,7 @@ class GeminiModelSettings(ModelSettings, total=False):
80
77
  """
81
78
 
82
79
  gemini_safety_settings: list[GeminiSafetySettings]
80
+ """Safety settings options for Gemini model request."""
83
81
 
84
82
  gemini_thinking_config: ThinkingConfig
85
83
  """Thinking is "on" by default in both the API and AI Studio.
@@ -93,6 +91,12 @@ class GeminiModelSettings(ModelSettings, total=False):
93
91
  See more about it on <https://ai.google.dev/gemini-api/docs/thinking>.
94
92
  """
95
93
 
94
+ gemini_labels: dict[str, str]
95
+ """User-defined metadata to break down billed charges. Only supported by the Vertex AI provider.
96
+
97
+ See the [Gemini API docs](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/add-labels-to-api-calls) for use cases and limitations.
98
+ """
99
+
96
100
 
97
101
  @dataclass(init=False)
98
102
  class GeminiModel(Model):
@@ -223,25 +227,17 @@ class GeminiModel(Model):
223
227
  if tool_config is not None:
224
228
  request_data['toolConfig'] = tool_config
225
229
 
226
- generation_config: _GeminiGenerationConfig = {}
227
- if model_settings:
228
- if (max_tokens := model_settings.get('max_tokens')) is not None:
229
- generation_config['max_output_tokens'] = max_tokens
230
- if (temperature := model_settings.get('temperature')) is not None:
231
- generation_config['temperature'] = temperature
232
- if (top_p := model_settings.get('top_p')) is not None:
233
- generation_config['top_p'] = top_p
234
- if (presence_penalty := model_settings.get('presence_penalty')) is not None:
235
- generation_config['presence_penalty'] = presence_penalty
236
- if (frequency_penalty := model_settings.get('frequency_penalty')) is not None:
237
- generation_config['frequency_penalty'] = frequency_penalty
238
- if (thinkingConfig := model_settings.get('gemini_thinking_config')) is not None:
239
- generation_config['thinking_config'] = thinkingConfig # pragma: no cover
240
- if (gemini_safety_settings := model_settings.get('gemini_safety_settings')) is not None:
241
- request_data['safetySettings'] = gemini_safety_settings
230
+ generation_config = _settings_to_generation_config(model_settings)
242
231
  if generation_config:
243
232
  request_data['generationConfig'] = generation_config
244
233
 
234
+ if gemini_safety_settings := model_settings.get('gemini_safety_settings'):
235
+ request_data['safetySettings'] = gemini_safety_settings
236
+
237
+ if gemini_labels := model_settings.get('gemini_labels'):
238
+ if self._system == 'google-vertex':
239
+ request_data['labels'] = gemini_labels
240
+
245
241
  headers = {'Content-Type': 'application/json', 'User-Agent': get_user_agent()}
246
242
  url = f'/{self._model_name}:{"streamGenerateContent" if streamed else "generateContent"}'
247
243
 
@@ -362,6 +358,23 @@ class GeminiModel(Model):
362
358
  return content
363
359
 
364
360
 
361
+ def _settings_to_generation_config(model_settings: GeminiModelSettings) -> _GeminiGenerationConfig:
362
+ config: _GeminiGenerationConfig = {}
363
+ if (max_tokens := model_settings.get('max_tokens')) is not None:
364
+ config['max_output_tokens'] = max_tokens
365
+ if (temperature := model_settings.get('temperature')) is not None:
366
+ config['temperature'] = temperature
367
+ if (top_p := model_settings.get('top_p')) is not None:
368
+ config['top_p'] = top_p
369
+ if (presence_penalty := model_settings.get('presence_penalty')) is not None:
370
+ config['presence_penalty'] = presence_penalty
371
+ if (frequency_penalty := model_settings.get('frequency_penalty')) is not None:
372
+ config['frequency_penalty'] = frequency_penalty
373
+ if (thinkingConfig := model_settings.get('gemini_thinking_config')) is not None:
374
+ config['thinking_config'] = thinkingConfig # pragma: no cover
375
+ return config
376
+
377
+
365
378
  class AuthProtocol(Protocol):
366
379
  """Abstract definition for Gemini authentication."""
367
380
 
@@ -483,6 +496,7 @@ class _GeminiRequest(TypedDict):
483
496
  <https://ai.google.dev/gemini-api/docs/system-instructions?lang=rest>
484
497
  """
485
498
  generationConfig: NotRequired[_GeminiGenerationConfig]
499
+ labels: NotRequired[dict[str, str]]
486
500
 
487
501
 
488
502
  class GeminiSafetySettings(TypedDict):
@@ -76,15 +76,12 @@ LatestGoogleModelNames = Literal[
76
76
  'gemini-1.5-flash-8b',
77
77
  'gemini-1.5-pro',
78
78
  'gemini-1.0-pro',
79
- 'gemini-2.0-flash-exp',
80
- 'gemini-2.0-flash-thinking-exp-01-21',
81
- 'gemini-exp-1206',
82
79
  'gemini-2.0-flash',
83
80
  'gemini-2.0-flash-lite-preview-02-05',
84
81
  'gemini-2.0-pro-exp-02-05',
85
- 'gemini-2.5-flash-preview-04-17',
82
+ 'gemini-2.5-flash-preview-05-20',
86
83
  'gemini-2.5-pro-exp-03-25',
87
- 'gemini-2.5-pro-preview-03-25',
84
+ 'gemini-2.5-pro-preview-05-06',
88
85
  ]
89
86
  """Latest Gemini models."""
90
87
 
@@ -115,6 +112,12 @@ class GoogleModelSettings(ModelSettings, total=False):
115
112
  See <https://ai.google.dev/gemini-api/docs/thinking> for more information.
116
113
  """
117
114
 
115
+ google_labels: dict[str, str]
116
+ """User-defined metadata to break down billed charges. Only supported by the Vertex AI API.
117
+
118
+ See the [Gemini API docs](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/add-labels-to-api-calls) for use cases and limitations.
119
+ """
120
+
118
121
 
119
122
  @dataclass(init=False)
120
123
  class GoogleModel(Model):
@@ -269,6 +272,7 @@ class GoogleModel(Model):
269
272
  frequency_penalty=model_settings.get('frequency_penalty'),
270
273
  safety_settings=model_settings.get('google_safety_settings'),
271
274
  thinking_config=model_settings.get('google_thinking_config'),
275
+ labels=model_settings.get('google_labels'),
272
276
  tools=cast(ToolListUnionDict, tools),
273
277
  tool_config=tool_config,
274
278
  )
@@ -65,7 +65,7 @@ openai = ["openai>=1.75.0"]
65
65
  cohere = ["cohere>=5.13.11; platform_system != 'Emscripten'"]
66
66
  vertexai = ["google-auth>=2.36.0", "requests>=2.32.2"]
67
67
  google = ["google-genai>=1.15.0"]
68
- anthropic = ["anthropic>=0.49.0"]
68
+ anthropic = ["anthropic>=0.52.0"]
69
69
  groq = ["groq>=0.15.0"]
70
70
  mistral = ["mistralai>=1.2.5"]
71
71
  bedrock = ["boto3>=1.35.74"]
@@ -75,7 +75,7 @@ tavily = ["tavily-python>=0.5.0"]
75
75
  # CLI
76
76
  cli = ["rich>=13", "prompt-toolkit>=3", "argcomplete>=3.5.0"]
77
77
  # MCP
78
- mcp = ["mcp>=1.6.0; python_version >= '3.10'"]
78
+ mcp = ["mcp>=1.8.0; python_version >= '3.10'"]
79
79
  # Evals
80
80
  evals = ["pydantic-evals=={{ version }}"]
81
81
  # A2A