pydantic-ai-slim 0.0.10__py3-none-any.whl → 0.0.12__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/_pydantic.py CHANGED
@@ -17,10 +17,10 @@ from pydantic.plugin._schema_validator import create_schema_validator
17
17
  from pydantic_core import SchemaValidator, core_schema
18
18
 
19
19
  from ._griffe import doc_descriptions
20
- from ._utils import ObjectJsonSchema, check_object_json_schema, is_model_like
20
+ from ._utils import check_object_json_schema, is_model_like
21
21
 
22
22
  if TYPE_CHECKING:
23
- pass
23
+ from .tools import ObjectJsonSchema
24
24
 
25
25
 
26
26
  __all__ = 'function_schema', 'LazyTypeAdapter'
@@ -168,11 +168,13 @@ def takes_ctx(function: Callable[..., Any]) -> bool:
168
168
  """
169
169
  sig = signature(function)
170
170
  try:
171
- _, first_param = next(iter(sig.parameters.items()))
171
+ first_param_name = next(iter(sig.parameters.keys()))
172
172
  except StopIteration:
173
173
  return False
174
174
  else:
175
- return first_param.annotation is not sig.empty and _is_call_ctx(first_param.annotation)
175
+ type_hints = _typing_extra.get_function_type_hints(function)
176
+ annotation = type_hints[first_param_name]
177
+ return annotation is not sig.empty and _is_call_ctx(annotation)
176
178
 
177
179
 
178
180
  def _build_schema(
pydantic_ai/_result.py CHANGED
@@ -14,7 +14,7 @@ from . import _utils, messages
14
14
  from .exceptions import ModelRetry
15
15
  from .messages import ModelStructuredResponse, ToolCall
16
16
  from .result import ResultData
17
- from .tools import AgentDeps, ResultValidatorFunc, RunContext
17
+ from .tools import AgentDeps, ResultValidatorFunc, RunContext, ToolDefinition
18
18
 
19
19
 
20
20
  @dataclass
@@ -94,10 +94,7 @@ class ResultSchema(Generic[ResultData]):
94
94
  allow_text_result = False
95
95
 
96
96
  def _build_tool(a: Any, tool_name_: str, multiple: bool) -> ResultTool[ResultData]:
97
- return cast(
98
- ResultTool[ResultData],
99
- ResultTool.build(a, tool_name_, description, multiple), # pyright: ignore[reportUnknownMemberType]
100
- )
97
+ return cast(ResultTool[ResultData], ResultTool(a, tool_name_, description, multiple))
101
98
 
102
99
  tools: dict[str, ResultTool[ResultData]] = {}
103
100
  if args := get_union_args(response_type):
@@ -121,38 +118,38 @@ class ResultSchema(Generic[ResultData]):
121
118
  """Return the names of the tools."""
122
119
  return list(self.tools.keys())
123
120
 
121
+ def tool_defs(self) -> list[ToolDefinition]:
122
+ """Get tool definitions to register with the model."""
123
+ return [t.tool_def for t in self.tools.values()]
124
+
124
125
 
125
126
  DEFAULT_DESCRIPTION = 'The final response which ends this conversation'
126
127
 
127
128
 
128
- @dataclass
129
+ @dataclass(init=False)
129
130
  class ResultTool(Generic[ResultData]):
130
- name: str
131
- description: str
131
+ tool_def: ToolDefinition
132
132
  type_adapter: TypeAdapter[Any]
133
- json_schema: _utils.ObjectJsonSchema
134
- outer_typed_dict_key: str | None
135
133
 
136
- @classmethod
137
- def build(cls, response_type: type[ResultData], name: str, description: str | None, multiple: bool) -> Self | None:
134
+ def __init__(self, response_type: type[ResultData], name: str, description: str | None, multiple: bool):
138
135
  """Build a ResultTool dataclass from a response type."""
139
136
  assert response_type is not str, 'ResultTool does not support str as a response type'
140
137
 
141
138
  if _utils.is_model_like(response_type):
142
- type_adapter = TypeAdapter(response_type)
139
+ self.type_adapter = TypeAdapter(response_type)
143
140
  outer_typed_dict_key: str | None = None
144
141
  # noinspection PyArgumentList
145
- json_schema = _utils.check_object_json_schema(type_adapter.json_schema())
142
+ parameters_json_schema = _utils.check_object_json_schema(self.type_adapter.json_schema())
146
143
  else:
147
144
  response_data_typed_dict = TypedDict('response_data_typed_dict', {'response': response_type}) # noqa
148
- type_adapter = TypeAdapter(response_data_typed_dict)
145
+ self.type_adapter = TypeAdapter(response_data_typed_dict)
149
146
  outer_typed_dict_key = 'response'
150
147
  # noinspection PyArgumentList
151
- json_schema = _utils.check_object_json_schema(type_adapter.json_schema())
148
+ parameters_json_schema = _utils.check_object_json_schema(self.type_adapter.json_schema())
152
149
  # including `response_data_typed_dict` as a title here doesn't add anything and could confuse the LLM
153
- json_schema.pop('title')
150
+ parameters_json_schema.pop('title')
154
151
 
155
- if json_schema_description := json_schema.pop('description', None):
152
+ if json_schema_description := parameters_json_schema.pop('description', None):
156
153
  if description is None:
157
154
  tool_description = json_schema_description
158
155
  else:
@@ -162,11 +159,10 @@ class ResultTool(Generic[ResultData]):
162
159
  if multiple:
163
160
  tool_description = f'{union_arg_name(response_type)}: {tool_description}'
164
161
 
165
- return cls(
162
+ self.tool_def = ToolDefinition(
166
163
  name=name,
167
164
  description=tool_description,
168
- type_adapter=type_adapter,
169
- json_schema=json_schema,
165
+ parameters_json_schema=parameters_json_schema,
170
166
  outer_typed_dict_key=outer_typed_dict_key,
171
167
  )
172
168
 
@@ -204,7 +200,7 @@ class ResultTool(Generic[ResultData]):
204
200
  else:
205
201
  raise
206
202
  else:
207
- if k := self.outer_typed_dict_key:
203
+ if k := self.tool_def.outer_typed_dict_key:
208
204
  result = result[k]
209
205
  return result
210
206
 
@@ -21,7 +21,7 @@ class SystemPromptRunner(Generic[AgentDeps]):
21
21
 
22
22
  async def run(self, deps: AgentDeps) -> str:
23
23
  if self._takes_ctx:
24
- args = (RunContext(deps, 0, None),)
24
+ args = (RunContext(deps, 0),)
25
25
  else:
26
26
  args = ()
27
27
 
pydantic_ai/_utils.py CHANGED
@@ -8,12 +8,15 @@ from dataclasses import dataclass, is_dataclass
8
8
  from datetime import datetime, timezone
9
9
  from functools import partial
10
10
  from types import GenericAlias
11
- from typing import Any, Callable, Generic, TypeVar, Union, cast, overload
11
+ from typing import TYPE_CHECKING, Any, Callable, Generic, TypeVar, Union, cast, overload
12
12
 
13
13
  from pydantic import BaseModel
14
14
  from pydantic.json_schema import JsonSchemaValue
15
15
  from typing_extensions import ParamSpec, TypeAlias, TypeGuard, is_typeddict
16
16
 
17
+ if TYPE_CHECKING:
18
+ from .tools import ObjectJsonSchema
19
+
17
20
  _P = ParamSpec('_P')
18
21
  _R = TypeVar('_R')
19
22
 
@@ -39,10 +42,6 @@ def is_model_like(type_: Any) -> bool:
39
42
  )
40
43
 
41
44
 
42
- # With PEP-728 this should be a TypedDict with `type: Literal['object']`, and `extra_items=Any`
43
- ObjectJsonSchema: TypeAlias = dict[str, Any]
44
-
45
-
46
45
  def check_object_json_schema(schema: JsonSchemaValue) -> ObjectJsonSchema:
47
46
  from .exceptions import UserError
48
47
 
@@ -127,6 +126,12 @@ class Either(Generic[Left, Right]):
127
126
  def whichever(self) -> Left | Right:
128
127
  return self._left.value if self._left is not None else self.right
129
128
 
129
+ def __repr__(self):
130
+ if left := self._left:
131
+ return f'Either(left={left.value!r})'
132
+ else:
133
+ return f'Either(right={self.right!r})'
134
+
130
135
 
131
136
  @asynccontextmanager
132
137
  async def group_by_temporal(
@@ -218,7 +223,7 @@ async def group_by_temporal(
218
223
 
219
224
  try:
220
225
  yield async_iter_groups()
221
- finally:
226
+ finally: # pragma: no cover
222
227
  # after iteration if a tasks still exists, cancel it, this will only happen if an error occurred
223
228
  if task:
224
229
  task.cancel('Cancelling due to error in iterator')