pydantic-ai-slim 0.0.6a4__py3-none-any.whl → 0.0.8__py3-none-any.whl

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.

Potentially problematic release.


This version of pydantic-ai-slim might be problematic. Click here for more details.

pydantic_ai/messages.py CHANGED
@@ -55,7 +55,7 @@ json_ta: TypeAdapter[JsonData] = TypeAdapter(JsonData)
55
55
 
56
56
  @dataclass
57
57
  class ToolReturn:
58
- """A tool return message, this encodes the result of running a retriever."""
58
+ """A tool return message, this encodes the result of running a tool."""
59
59
 
60
60
  tool_name: str
61
61
  """The name of the "tool" was called."""
@@ -89,10 +89,10 @@ class RetryPrompt:
89
89
 
90
90
  This can be sent for a number of reasons:
91
91
 
92
- * Pydantic validation of retriever arguments failed, here content is derived from a Pydantic
92
+ * Pydantic validation of tool arguments failed, here content is derived from a Pydantic
93
93
  [`ValidationError`][pydantic_core.ValidationError]
94
- * a retriever raised a [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] exception
95
- * no retriever was found for the tool name
94
+ * a tool raised a [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] exception
95
+ * no tool was found for the tool name
96
96
  * the model returned plain text when a structured response was expected
97
97
  * Pydantic validation of a structured response failed, here content is derived from a Pydantic
98
98
  [`ValidationError`][pydantic_core.ValidationError]
@@ -139,13 +139,17 @@ class ModelTextResponse:
139
139
 
140
140
  @dataclass
141
141
  class ArgsJson:
142
+ """Tool arguments as a JSON string."""
143
+
142
144
  args_json: str
143
145
  """A JSON string of arguments."""
144
146
 
145
147
 
146
148
  @dataclass
147
- class ArgsObject:
148
- args_object: dict[str, Any]
149
+ class ArgsDict:
150
+ """Tool arguments as a Python dictionary."""
151
+
152
+ args_dict: dict[str, Any]
149
153
  """A python dictionary of arguments."""
150
154
 
151
155
 
@@ -155,7 +159,7 @@ class ToolCall:
155
159
 
156
160
  tool_name: str
157
161
  """The name of the tool to call."""
158
- args: ArgsJson | ArgsObject
162
+ args: ArgsJson | ArgsDict
159
163
  """The arguments to pass to the tool.
160
164
 
161
165
  Either as JSON or a Python dictionary depending on how data was returned.
@@ -168,12 +172,12 @@ class ToolCall:
168
172
  return cls(tool_name, ArgsJson(args_json), tool_id)
169
173
 
170
174
  @classmethod
171
- def from_object(cls, tool_name: str, args_object: dict[str, Any]) -> ToolCall:
172
- return cls(tool_name, ArgsObject(args_object))
175
+ def from_dict(cls, tool_name: str, args_dict: dict[str, Any]) -> ToolCall:
176
+ return cls(tool_name, ArgsDict(args_dict))
173
177
 
174
178
  def has_content(self) -> bool:
175
- if isinstance(self.args, ArgsObject):
176
- return any(self.args.args_object.values())
179
+ if isinstance(self.args, ArgsDict):
180
+ return any(self.args.args_dict.values())
177
181
  else:
178
182
  return bool(self.args.args_json)
179
183
 
@@ -182,7 +186,7 @@ class ToolCall:
182
186
  class ModelStructuredResponse:
183
187
  """A structured response from a model.
184
188
 
185
- This is used either to call a retriever or to return a structured response from an agent run.
189
+ This is used either to call a tool or to return a structured response from an agent run.
186
190
  """
187
191
 
188
192
  calls: list[ToolCall]
@@ -63,7 +63,7 @@ class Model(ABC):
63
63
  @abstractmethod
64
64
  async def agent_model(
65
65
  self,
66
- retrievers: Mapping[str, AbstractToolDefinition],
66
+ function_tools: Mapping[str, AbstractToolDefinition],
67
67
  allow_text_result: bool,
68
68
  result_tools: Sequence[AbstractToolDefinition] | None,
69
69
  ) -> AgentModel:
@@ -72,7 +72,7 @@ class Model(ABC):
72
72
  This is async in case slow/async config checks need to be performed that can't be done in `__init__`.
73
73
 
74
74
  Args:
75
- retrievers: The retrievers available to the agent.
75
+ function_tools: The tools available to the agent.
76
76
  allow_text_result: Whether a plain text final response/result is permitted.
77
77
  result_tools: Tool definitions for the final result tool(s), if any.
78
78
 
@@ -259,7 +259,7 @@ def infer_model(model: Model | KnownModelName) -> Model:
259
259
  class AbstractToolDefinition(Protocol):
260
260
  """Abstract definition of a function/tool.
261
261
 
262
- This is used for both retrievers and result tools.
262
+ This is used for both tools and result tools.
263
263
  """
264
264
 
265
265
  name: str
@@ -1,11 +1,3 @@
1
- """A model controlled by a local function.
2
-
3
- [FunctionModel][pydantic_ai.models.function.FunctionModel] is similar to [TestModel][pydantic_ai.models.test.TestModel],
4
- but allows greater control over the model's behavior.
5
-
6
- It's primary use case for more advanced unit testing than is possible with `TestModel`.
7
- """
8
-
9
1
  from __future__ import annotations as _annotations
10
2
 
11
3
  import inspect
@@ -67,13 +59,13 @@ class FunctionModel(Model):
67
59
 
68
60
  async def agent_model(
69
61
  self,
70
- retrievers: Mapping[str, AbstractToolDefinition],
62
+ function_tools: Mapping[str, AbstractToolDefinition],
71
63
  allow_text_result: bool,
72
64
  result_tools: Sequence[AbstractToolDefinition] | None,
73
65
  ) -> AgentModel:
74
66
  result_tools = list(result_tools) if result_tools is not None else None
75
67
  return FunctionAgentModel(
76
- self.function, self.stream_function, AgentInfo(retrievers, allow_text_result, result_tools)
68
+ self.function, self.stream_function, AgentInfo(function_tools, allow_text_result, result_tools)
77
69
  )
78
70
 
79
71
  def name(self) -> str:
@@ -89,11 +81,15 @@ class FunctionModel(Model):
89
81
  class AgentInfo:
90
82
  """Information about an agent.
91
83
 
92
- This is passed as the second to functions.
84
+ This is passed as the second to functions used within [`FunctionModel`][pydantic_ai.models.function.FunctionModel].
93
85
  """
94
86
 
95
- retrievers: Mapping[str, AbstractToolDefinition]
96
- """The retrievers available on this agent."""
87
+ function_tools: Mapping[str, AbstractToolDefinition]
88
+ """The function tools available on this agent.
89
+
90
+ These are the tools registered via the [`tool`][pydantic_ai.Agent.tool] and
91
+ [`tool_plain`][pydantic_ai.Agent.tool_plain] decorators.
92
+ """
97
93
  allow_text_result: bool
98
94
  """Whether a plain text result is allowed."""
99
95
  result_tools: list[AbstractToolDefinition] | None
@@ -254,7 +250,7 @@ def _estimate_cost(messages: Iterable[Message]) -> result.Cost:
254
250
  if isinstance(call.args, ArgsJson):
255
251
  args_str = call.args.args_json
256
252
  else:
257
- args_str = pydantic_core.to_json(call.args.args_object).decode()
253
+ args_str = pydantic_core.to_json(call.args.args_dict).decode()
258
254
 
259
255
  response_tokens += 1 + _string_cost(args_str)
260
256
  else:
@@ -1,25 +1,3 @@
1
- """Custom interface to the `generativelanguage.googleapis.com` API using [HTTPX] and [Pydantic].
2
-
3
- The Google SDK for interacting with the `generativelanguage.googleapis.com` API
4
- [`google-generativeai`](https://ai.google.dev/gemini-api/docs/quickstart?lang=python) reads like it was written by a
5
- Java developer who thought they knew everything about OOP, spent 30 minutes trying to learn Python,
6
- gave up and decided to build the library to prove how horrible Python is. It also doesn't use httpx for HTTP requests,
7
- and tries to implement tool calling itself, but doesn't use Pydantic or equivalent for validation.
8
-
9
- We could also use the Google Vertex SDK,
10
- [`google-cloud-aiplatform`](https://cloud.google.com/vertex-ai/docs/python-sdk/use-vertex-ai-python-sdk)
11
- which uses the `*-aiplatform.googleapis.com` API, but that requires a service account for authentication
12
- which is a faff to set up and manage.
13
-
14
- Both APIs claim compatibility with OpenAI's API, but that breaks down with even the simplest of requests,
15
- hence this custom interface.
16
-
17
- Despite these limitations, the Gemini model is actually quite powerful and very fast.
18
-
19
- [HTTPX]: https://www.python-httpx.org/
20
- [Pydantic]: https://docs.pydantic.dev/latest/
21
- """
22
-
23
1
  from __future__ import annotations as _annotations
24
2
 
25
3
  import os
@@ -38,7 +16,7 @@ from typing_extensions import NotRequired, TypedDict, TypeGuard, assert_never
38
16
 
39
17
  from .. import UnexpectedModelBehavior, _pydantic, _utils, exceptions, result
40
18
  from ..messages import (
41
- ArgsObject,
19
+ ArgsDict,
42
20
  Message,
43
21
  ModelAnyResponse,
44
22
  ModelStructuredResponse,
@@ -112,7 +90,7 @@ class GeminiModel(Model):
112
90
 
113
91
  async def agent_model(
114
92
  self,
115
- retrievers: Mapping[str, AbstractToolDefinition],
93
+ function_tools: Mapping[str, AbstractToolDefinition],
116
94
  allow_text_result: bool,
117
95
  result_tools: Sequence[AbstractToolDefinition] | None,
118
96
  ) -> GeminiAgentModel:
@@ -121,7 +99,7 @@ class GeminiModel(Model):
121
99
  model_name=self.model_name,
122
100
  auth=self.auth,
123
101
  url=self.url,
124
- retrievers=retrievers,
102
+ function_tools=function_tools,
125
103
  allow_text_result=allow_text_result,
126
104
  result_tools=result_tools,
127
105
  )
@@ -131,11 +109,15 @@ class GeminiModel(Model):
131
109
 
132
110
 
133
111
  class AuthProtocol(Protocol):
112
+ """Abstract definition for Gemini authentication."""
113
+
134
114
  async def headers(self) -> dict[str, str]: ...
135
115
 
136
116
 
137
117
  @dataclass
138
118
  class ApiKeyAuth:
119
+ """Authentication using an API key for the `X-Goog-Api-Key` header."""
120
+
139
121
  api_key: str
140
122
 
141
123
  async def headers(self) -> dict[str, str]:
@@ -160,12 +142,12 @@ class GeminiAgentModel(AgentModel):
160
142
  model_name: GeminiModelName,
161
143
  auth: AuthProtocol,
162
144
  url: str,
163
- retrievers: Mapping[str, AbstractToolDefinition],
145
+ function_tools: Mapping[str, AbstractToolDefinition],
164
146
  allow_text_result: bool,
165
147
  result_tools: Sequence[AbstractToolDefinition] | None,
166
148
  ):
167
149
  check_allow_model_requests()
168
- tools = [_function_from_abstract_tool(t) for t in retrievers.values()]
150
+ tools = [_function_from_abstract_tool(t) for t in function_tools.values()]
169
151
  if result_tools is not None:
170
152
  tools += [_function_from_abstract_tool(t) for t in result_tools]
171
153
 
@@ -442,15 +424,15 @@ class _GeminiFunctionCallPart(TypedDict):
442
424
 
443
425
 
444
426
  def _function_call_part_from_call(tool: ToolCall) -> _GeminiFunctionCallPart:
445
- assert isinstance(tool.args, ArgsObject), f'Expected ArgsObject, got {tool.args}'
446
- return _GeminiFunctionCallPart(function_call=_GeminiFunctionCall(name=tool.tool_name, args=tool.args.args_object))
427
+ assert isinstance(tool.args, ArgsDict), f'Expected ArgsObject, got {tool.args}'
428
+ return _GeminiFunctionCallPart(function_call=_GeminiFunctionCall(name=tool.tool_name, args=tool.args.args_dict))
447
429
 
448
430
 
449
431
  def _structured_response_from_parts(
450
432
  parts: list[_GeminiFunctionCallPart], timestamp: datetime | None = None
451
433
  ) -> ModelStructuredResponse:
452
434
  return ModelStructuredResponse(
453
- calls=[ToolCall.from_object(part['function_call']['name'], part['function_call']['args']) for part in parts],
435
+ calls=[ToolCall.from_dict(part['function_call']['name'], part['function_call']['args']) for part in parts],
454
436
  timestamp=timestamp or _utils.now_utc(),
455
437
  )
456
438
 
@@ -109,12 +109,12 @@ class GroqModel(Model):
109
109
 
110
110
  async def agent_model(
111
111
  self,
112
- retrievers: Mapping[str, AbstractToolDefinition],
112
+ function_tools: Mapping[str, AbstractToolDefinition],
113
113
  allow_text_result: bool,
114
114
  result_tools: Sequence[AbstractToolDefinition] | None,
115
115
  ) -> AgentModel:
116
116
  check_allow_model_requests()
117
- tools = [self._map_tool_definition(r) for r in retrievers.values()]
117
+ tools = [self._map_tool_definition(r) for r in function_tools.values()]
118
118
  if result_tools is not None:
119
119
  tools += [self._map_tool_definition(r) for r in result_tools]
120
120
  return GroqAgentModel(
@@ -89,12 +89,12 @@ class OpenAIModel(Model):
89
89
 
90
90
  async def agent_model(
91
91
  self,
92
- retrievers: Mapping[str, AbstractToolDefinition],
92
+ function_tools: Mapping[str, AbstractToolDefinition],
93
93
  allow_text_result: bool,
94
94
  result_tools: Sequence[AbstractToolDefinition] | None,
95
95
  ) -> AgentModel:
96
96
  check_allow_model_requests()
97
- tools = [self._map_tool_definition(r) for r in retrievers.values()]
97
+ tools = [self._map_tool_definition(r) for r in function_tools.values()]
98
98
  if result_tools is not None:
99
99
  tools += [self._map_tool_definition(r) for r in result_tools]
100
100
  return OpenAIAgentModel(
@@ -1,5 +1,3 @@
1
- """Utilities for testing apps built with PydanticAI."""
2
-
3
1
  from __future__ import annotations as _annotations
4
2
 
5
3
  import re
@@ -7,7 +5,7 @@ import string
7
5
  from collections.abc import AsyncIterator, Iterable, Iterator, Mapping, Sequence
8
6
  from contextlib import asynccontextmanager
9
7
  from dataclasses import dataclass, field
10
- from datetime import datetime
8
+ from datetime import date, datetime, timedelta
11
9
  from typing import Any, Literal
12
10
 
13
11
  import pydantic_core
@@ -33,22 +31,14 @@ from . import (
33
31
  )
34
32
 
35
33
 
36
- class UnSetType:
37
- def __repr__(self):
38
- return 'UnSet'
39
-
40
-
41
- UnSet = UnSetType()
42
-
43
-
44
34
  @dataclass
45
35
  class TestModel(Model):
46
36
  """A model specifically for testing purposes.
47
37
 
48
- This will (by default) call all retrievers in the agent model, then return a tool response if possible,
38
+ This will (by default) call all tools in the agent, then return a tool response if possible,
49
39
  otherwise a plain response.
50
40
 
51
- How useful this function will be is unknown, it may be useless, it may require significant changes to be useful.
41
+ How useful this model is will vary significantly.
52
42
 
53
43
  Apart from `__init__` derived by the `dataclass` decorator, all methods are private or match those
54
44
  of the base class.
@@ -57,8 +47,8 @@ class TestModel(Model):
57
47
  # NOTE: Avoid test discovery by pytest.
58
48
  __test__ = False
59
49
 
60
- call_retrievers: list[str] | Literal['all'] = 'all'
61
- """List of retrievers to call. If `'all'`, all retrievers will be called."""
50
+ call_tools: list[str] | Literal['all'] = 'all'
51
+ """List of tools to call. If `'all'`, all tools will be called."""
62
52
  custom_result_text: str | None = None
63
53
  """If set, this text is return as the final result."""
64
54
  custom_result_args: Any | None = None
@@ -66,25 +56,25 @@ class TestModel(Model):
66
56
  seed: int = 0
67
57
  """Seed for generating random data."""
68
58
  # these fields are set when the model is called by the agent
69
- agent_model_retrievers: Mapping[str, AbstractToolDefinition] | None = field(default=None, init=False)
59
+ agent_model_tools: Mapping[str, AbstractToolDefinition] | None = field(default=None, init=False)
70
60
  agent_model_allow_text_result: bool | None = field(default=None, init=False)
71
61
  agent_model_result_tools: list[AbstractToolDefinition] | None = field(default=None, init=False)
72
62
 
73
63
  async def agent_model(
74
64
  self,
75
- retrievers: Mapping[str, AbstractToolDefinition],
65
+ function_tools: Mapping[str, AbstractToolDefinition],
76
66
  allow_text_result: bool,
77
67
  result_tools: Sequence[AbstractToolDefinition] | None,
78
68
  ) -> AgentModel:
79
- self.agent_model_retrievers = retrievers
69
+ self.agent_model_tools = function_tools
80
70
  self.agent_model_allow_text_result = allow_text_result
81
71
  self.agent_model_result_tools = list(result_tools) if result_tools is not None else None
82
72
 
83
- if self.call_retrievers == 'all':
84
- retriever_calls = [(r.name, r) for r in retrievers.values()]
73
+ if self.call_tools == 'all':
74
+ tool_calls = [(r.name, r) for r in function_tools.values()]
85
75
  else:
86
- retrievers_to_call = (retrievers[name] for name in self.call_retrievers)
87
- retriever_calls = [(r.name, r) for r in retrievers_to_call]
76
+ tools_to_call = (function_tools[name] for name in self.call_tools)
77
+ tool_calls = [(r.name, r) for r in tools_to_call]
88
78
 
89
79
  if self.custom_result_text is not None:
90
80
  assert allow_text_result, 'Plain response not allowed, but `custom_result_text` is set.'
@@ -104,7 +94,7 @@ class TestModel(Model):
104
94
  result = _utils.Either(right=None)
105
95
  else:
106
96
  result = _utils.Either(left=None)
107
- return TestAgentModel(retriever_calls, result, self.agent_model_result_tools, self.seed)
97
+ return TestAgentModel(tool_calls, result, self.agent_model_result_tools, self.seed)
108
98
 
109
99
  def name(self) -> str:
110
100
  return 'test-model'
@@ -117,7 +107,7 @@ class TestAgentModel(AgentModel):
117
107
  # NOTE: Avoid test discovery by pytest.
118
108
  __test__ = False
119
109
 
120
- retriever_calls: list[tuple[str, AbstractToolDefinition]]
110
+ tool_calls: list[tuple[str, AbstractToolDefinition]]
121
111
  # left means the text is plain text; right means it's a function call
122
112
  result: _utils.Either[str | None, Any | None]
123
113
  result_tools: list[AbstractToolDefinition] | None
@@ -137,12 +127,12 @@ class TestAgentModel(AgentModel):
137
127
  else:
138
128
  yield TestStreamStructuredResponse(msg, cost)
139
129
 
140
- def gen_retriever_args(self, tool_def: AbstractToolDefinition) -> Any:
130
+ def gen_tool_args(self, tool_def: AbstractToolDefinition) -> Any:
141
131
  return _JsonSchemaTestData(tool_def.json_schema, self.seed).generate()
142
132
 
143
133
  def _request(self, messages: list[Message]) -> ModelAnyResponse:
144
- if self.step == 0 and self.retriever_calls:
145
- calls = [ToolCall.from_object(name, self.gen_retriever_args(args)) for name, args in self.retriever_calls]
134
+ if self.step == 0 and self.tool_calls:
135
+ calls = [ToolCall.from_dict(name, self.gen_tool_args(args)) for name, args in self.tool_calls]
146
136
  self.step += 1
147
137
  self.last_message_count = len(messages)
148
138
  return ModelStructuredResponse(calls=calls)
@@ -152,8 +142,8 @@ class TestAgentModel(AgentModel):
152
142
  new_retry_names = {m.tool_name for m in new_messages if isinstance(m, RetryPrompt)}
153
143
  if new_retry_names:
154
144
  calls = [
155
- ToolCall.from_object(name, self.gen_retriever_args(args))
156
- for name, args in self.retriever_calls
145
+ ToolCall.from_dict(name, self.gen_tool_args(args))
146
+ for name, args in self.tool_calls
157
147
  if name in new_retry_names
158
148
  ]
159
149
  self.step += 1
@@ -162,7 +152,7 @@ class TestAgentModel(AgentModel):
162
152
  if response_text := self.result.left:
163
153
  self.step += 1
164
154
  if response_text.value is None:
165
- # build up details of retriever responses
155
+ # build up details of tool responses
166
156
  output: dict[str, Any] = {}
167
157
  for message in messages:
168
158
  if isinstance(message, ToolReturn):
@@ -170,7 +160,7 @@ class TestAgentModel(AgentModel):
170
160
  if output:
171
161
  return ModelTextResponse(content=pydantic_core.to_json(output).decode())
172
162
  else:
173
- return ModelTextResponse(content='success (no retriever calls)')
163
+ return ModelTextResponse(content='success (no tool calls)')
174
164
  else:
175
165
  return ModelTextResponse(content=response_text.value)
176
166
  else:
@@ -179,15 +169,17 @@ class TestAgentModel(AgentModel):
179
169
  result_tool = self.result_tools[self.seed % len(self.result_tools)]
180
170
  if custom_result_args is not None:
181
171
  self.step += 1
182
- return ModelStructuredResponse(calls=[ToolCall.from_object(result_tool.name, custom_result_args)])
172
+ return ModelStructuredResponse(calls=[ToolCall.from_dict(result_tool.name, custom_result_args)])
183
173
  else:
184
- response_args = self.gen_retriever_args(result_tool)
174
+ response_args = self.gen_tool_args(result_tool)
185
175
  self.step += 1
186
- return ModelStructuredResponse(calls=[ToolCall.from_object(result_tool.name, response_args)])
176
+ return ModelStructuredResponse(calls=[ToolCall.from_dict(result_tool.name, response_args)])
187
177
 
188
178
 
189
179
  @dataclass
190
180
  class TestStreamTextResponse(StreamTextResponse):
181
+ """A text response that streams test data."""
182
+
191
183
  _text: str
192
184
  _cost: Cost
193
185
  _iter: Iterator[str] = field(init=False)
@@ -219,6 +211,8 @@ class TestStreamTextResponse(StreamTextResponse):
219
211
 
220
212
  @dataclass
221
213
  class TestStreamStructuredResponse(StreamStructuredResponse):
214
+ """A structured response that streams test data."""
215
+
222
216
  _structured_response: ModelStructuredResponse
223
217
  _cost: Cost
224
218
  _iter: Iterator[None] = field(default_factory=lambda: iter([None]))
@@ -320,8 +314,12 @@ class _JsonSchemaTestData:
320
314
 
321
315
  if schema.get('maxLength') == 0:
322
316
  return ''
323
- else:
324
- return self._char()
317
+
318
+ if fmt := schema.get('format'):
319
+ if fmt == 'date':
320
+ return (date(2024, 1, 1) + timedelta(days=self.seed)).isoformat()
321
+
322
+ return self._char()
325
323
 
326
324
  def _int_gen(self, schema: dict[str, Any]) -> int:
327
325
  """Generate an integer from a JSON Schema integer."""
@@ -1,60 +1,3 @@
1
- """Custom interface to the `*-aiplatform.googleapis.com` API for Gemini models.
2
-
3
- This model uses [`GeminiAgentModel`][pydantic_ai.models.gemini.GeminiAgentModel] with just the URL and auth method
4
- changed from the default `GeminiModel`, it relies on the VertexAI
5
- [`generateContent` function endpoint](https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.endpoints/generateContent)
6
- and `streamGenerateContent` function endpoints
7
- having the same schemas as the equivalent [Gemini endpoints][pydantic_ai.models.gemini.GeminiModel].
8
-
9
- There are four advantages of using this API over the `generativelanguage.googleapis.com` API which
10
- [`GeminiModel`][pydantic_ai.models.gemini.GeminiModel] uses, and one big disadvantage.
11
-
12
- Advantages:
13
-
14
- 1. The VertexAI API seems to be less flakey, less likely to occasionally return a 503 response.
15
- 2. You can
16
- [purchase provisioned throughput](https://cloud.google.com/vertex-ai/generative-ai/docs/provisioned-throughput#purchase-provisioned-throughput)
17
- with VertexAI.
18
- 3. If you're running PydanticAI inside GCP, you don't need to set up authentication, it should "just work".
19
- 4. You can decide which region to use, which might be important from a regulatory perspective,
20
- and might improve latency.
21
-
22
- Disadvantage:
23
-
24
- 1. When authorization doesn't just work, it's much more painful to set up than an API key.
25
-
26
- ## Example Usage
27
-
28
- With the default google project already configured in your environment:
29
-
30
- ```py title="vertex_example_env.py"
31
- from pydantic_ai import Agent
32
- from pydantic_ai.models.vertexai import VertexAIModel
33
-
34
- model = VertexAIModel('gemini-1.5-flash')
35
- agent = Agent(model)
36
- result = agent.run_sync('Tell me a joke.')
37
- print(result.data)
38
- #> Did you hear about the toothpaste scandal? They called it Colgate.
39
- ```
40
-
41
- Or using a service account JSON file:
42
-
43
- ```py title="vertex_example_service_account.py"
44
- from pydantic_ai import Agent
45
- from pydantic_ai.models.vertexai import VertexAIModel
46
-
47
- model = VertexAIModel(
48
- 'gemini-1.5-flash',
49
- service_account_file='path/to/service-account.json',
50
- )
51
- agent = Agent(model)
52
- result = agent.run_sync('Tell me a joke.')
53
- print(result.data)
54
- #> Did you hear about the toothpaste scandal? They called it Colgate.
55
- ```
56
- """
57
-
58
1
  from __future__ import annotations as _annotations
59
2
 
60
3
  from collections.abc import Mapping, Sequence
@@ -166,7 +109,7 @@ class VertexAIModel(Model):
166
109
 
167
110
  async def agent_model(
168
111
  self,
169
- retrievers: Mapping[str, AbstractToolDefinition],
112
+ function_tools: Mapping[str, AbstractToolDefinition],
170
113
  allow_text_result: bool,
171
114
  result_tools: Sequence[AbstractToolDefinition] | None,
172
115
  ) -> GeminiAgentModel:
@@ -176,7 +119,7 @@ class VertexAIModel(Model):
176
119
  model_name=self.model_name,
177
120
  auth=auth,
178
121
  url=url,
179
- retrievers=retrievers,
122
+ function_tools=function_tools,
180
123
  allow_text_result=allow_text_result,
181
124
  result_tools=result_tools,
182
125
  )
@@ -239,6 +182,8 @@ MAX_TOKEN_AGE = timedelta(seconds=3000)
239
182
 
240
183
  @dataclass
241
184
  class BearerTokenAuth:
185
+ """Authentication using a bearer token generated by google-auth."""
186
+
242
187
  credentials: BaseCredentials | ServiceAccountCredentials
243
188
  token_created: datetime | None = field(default=None, init=False)
244
189
 
pydantic_ai/result.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations as _annotations
2
2
 
3
3
  from abc import ABC, abstractmethod
4
- from collections.abc import AsyncIterator
5
- from dataclasses import dataclass
4
+ from collections.abc import AsyncIterator, Callable
5
+ from dataclasses import dataclass, field
6
6
  from datetime import datetime
7
7
  from typing import Generic, TypeVar, cast
8
8
 
@@ -49,11 +49,11 @@ class Cost:
49
49
  This is provided so it's trivial to sum costs from multiple requests and runs.
50
50
  """
51
51
  counts: dict[str, int] = {}
52
- for field in 'request_tokens', 'response_tokens', 'total_tokens':
53
- self_value = getattr(self, field)
54
- other_value = getattr(other, field)
52
+ for f in 'request_tokens', 'response_tokens', 'total_tokens':
53
+ self_value = getattr(self, f)
54
+ other_value = getattr(other, f)
55
55
  if self_value is not None or other_value is not None:
56
- counts[field] = (self_value or 0) + (other_value or 0)
56
+ counts[f] = (self_value or 0) + (other_value or 0)
57
57
 
58
58
  details = self.details.copy() if self.details is not None else None
59
59
  if other.details is not None:
@@ -122,7 +122,8 @@ class StreamedRunResult(_BaseRunResult[ResultData], Generic[AgentDeps, ResultDat
122
122
  _result_schema: _result.ResultSchema[ResultData] | None
123
123
  _deps: AgentDeps
124
124
  _result_validators: list[_result.ResultValidator[AgentDeps, ResultData]]
125
- is_complete: bool = False
125
+ _on_complete: Callable[[list[messages.Message]], None]
126
+ is_complete: bool = field(default=False, init=False)
126
127
  """Whether the stream has all been received.
127
128
 
128
129
  This is set to `True` when one of
@@ -312,3 +313,4 @@ class StreamedRunResult(_BaseRunResult[ResultData], Generic[AgentDeps, ResultDat
312
313
  else:
313
314
  assert structured_message is not None, 'Either text or structured_message should provided, not both'
314
315
  self._all_messages.append(structured_message)
316
+ self._on_complete(self._all_messages)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pydantic-ai-slim
3
- Version: 0.0.6a4
4
- Summary: Agent Framework / shim to use Pydantic with LLMs
3
+ Version: 0.0.8
4
+ Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
5
5
  Author-email: Samuel Colvin <samuel@pydantic.dev>
6
6
  License: MIT
7
7
  Classifier: Development Status :: 4 - Beta
@@ -40,10 +40,14 @@ Requires-Dist: google-auth>=2.36.0; extra == 'vertexai'
40
40
  Requires-Dist: requests>=2.32.3; extra == 'vertexai'
41
41
  Description-Content-Type: text/markdown
42
42
 
43
- # Coming soon
43
+ # PydanticAI Slim
44
44
 
45
45
  [![CI](https://github.com/pydantic/pydantic-ai/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/pydantic/pydantic-ai/actions/workflows/ci.yml?query=branch%3Amain)
46
46
  [![Coverage](https://coverage-badge.samuelcolvin.workers.dev/pydantic/pydantic-ai.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/pydantic/pydantic-ai)
47
47
  [![PyPI](https://img.shields.io/pypi/v/pydantic-ai.svg)](https://pypi.python.org/pypi/pydantic-ai)
48
48
  [![versions](https://img.shields.io/pypi/pyversions/pydantic-ai.svg)](https://github.com/pydantic/pydantic-ai)
49
49
  [![license](https://img.shields.io/github/license/pydantic/pydantic-ai.svg?v)](https://github.com/pydantic/pydantic-ai/blob/main/LICENSE)
50
+
51
+ PydanticAI core logic with minimal required dependencies.
52
+
53
+ For more information on how to use this package see [ai.pydantic.dev/install](https://ai.pydantic.dev/install/).
@@ -0,0 +1,23 @@
1
+ pydantic_ai/__init__.py,sha256=KaTzG8uBSEpfxk_y2a_O_R2Xa53GXYfiigjWtD4PCeI,317
2
+ pydantic_ai/_griffe.py,sha256=pRjCJ6B1hhx6k46XJgl9zF6aRYxRmqEZKFok8unp4Iw,3449
3
+ pydantic_ai/_pydantic.py,sha256=j1kObPIUDwn1VOHbJBwMFbWLxHM_OYRH7GFAda68ZC0,8010
4
+ pydantic_ai/_result.py,sha256=cAqfPipK39cz-p-ftlJ83Q5_LI1TRb3-HH-iivb5rEM,9674
5
+ pydantic_ai/_system_prompt.py,sha256=63egOej8zHsDVOInPayn0EEEDXKd0HVAbbrqXUTV96s,1092
6
+ pydantic_ai/_tool.py,sha256=5Q9XaGOEXbyOLS644osB1AA5EMoJkr4eYK60MVZo0Z8,4528
7
+ pydantic_ai/_utils.py,sha256=eNb7f3-ZQC8WDEa87iUcXGQ-lyuutFQG-5yBCMD4Vvs,8227
8
+ pydantic_ai/agent.py,sha256=r5DI4ZBqYE67GOMEEu-LXrTa5ty2AchW4szotwm5Qis,34338
9
+ pydantic_ai/dependencies.py,sha256=EHvD68AFkItxMnfHzJLG7T_AD1RGI2MZOfzm1v89hGQ,2399
10
+ pydantic_ai/exceptions.py,sha256=ko_47M0k6Rhg9mUC9P1cj7N4LCH6cC0pEsF65A2vL-U,1561
11
+ pydantic_ai/messages.py,sha256=FFTQ9Bo2Ct4bLuyJF-M9xkeraw05I--NC_ieR6oGtTM,7587
12
+ pydantic_ai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ pydantic_ai/result.py,sha256=qsanb7v4qJ4pJdkdsqpy68kuZ1WNCpQB5jcXeTwGpe0,13658
14
+ pydantic_ai/models/__init__.py,sha256=Cx8PjEsi5gkNOVQic32sf4CmM-A3pRu1LcjpM6poiBI,10138
15
+ pydantic_ai/models/function.py,sha256=Mzc-zXnb2RayWAA8N9NS7KGF49do1S-VW3U9fkc661o,10045
16
+ pydantic_ai/models/gemini.py,sha256=ruO4tnnpDDuHThg7jUOphs8I_KXBJH7gfDMluliED8E,26606
17
+ pydantic_ai/models/groq.py,sha256=Tx2yU3ysmPLBmWGsjzES-XcumzrsoBtB7spCnJBlLiM,14947
18
+ pydantic_ai/models/openai.py,sha256=5ihH25CrS0tnZNW-BZw4GyPe8V-IxIHWw3B9ulPVjQE,14931
19
+ pydantic_ai/models/test.py,sha256=q1wch_E7TSb4qx9PCcP1YyBGZx567MGlAQhlAlON0S8,14463
20
+ pydantic_ai/models/vertexai.py,sha256=5wI8y2YjeRgSE51uKy5OtevQkks65uEbxIUAs5EGBaI,9161
21
+ pydantic_ai_slim-0.0.8.dist-info/METADATA,sha256=CmpvlEAUyaWaPbdRCbFuypVLJ8yNC3TwZ0jgvlR9yps,2561
22
+ pydantic_ai_slim-0.0.8.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
23
+ pydantic_ai_slim-0.0.8.dist-info/RECORD,,