pydantic-ai-slim 0.1.0__py3-none-any.whl → 0.1.1__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.
@@ -3,11 +3,11 @@ from __future__ import annotations as _annotations
3
3
  import asyncio
4
4
  import dataclasses
5
5
  import json
6
- from collections.abc import AsyncIterator, Iterator, Sequence
6
+ from collections.abc import AsyncIterator, Awaitable, Iterator, Sequence
7
7
  from contextlib import asynccontextmanager, contextmanager
8
8
  from contextvars import ContextVar
9
9
  from dataclasses import field
10
- from typing import TYPE_CHECKING, Any, Generic, Literal, Union, cast
10
+ from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, Union, cast
11
11
 
12
12
  from opentelemetry.trace import Span, Tracer
13
13
  from typing_extensions import TypeGuard, TypeVar, assert_never
@@ -87,6 +87,7 @@ class GraphAgentDeps(Generic[DepsT, OutputDataT]):
87
87
  usage_limits: _usage.UsageLimits
88
88
  max_result_retries: int
89
89
  end_strategy: EndStrategy
90
+ get_instructions: Callable[[RunContext[DepsT]], Awaitable[str | None]]
90
91
 
91
92
  output_schema: _output.OutputSchema[OutputDataT] | None
92
93
  output_validators: list[_output.OutputValidator[DepsT, OutputDataT]]
@@ -141,7 +142,9 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]):
141
142
  self, ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, NodeRunEndT]]
142
143
  ) -> _messages.ModelRequest:
143
144
  run_context = build_run_context(ctx)
144
- history, next_message = await self._prepare_messages(self.user_prompt, ctx.state.message_history, run_context)
145
+ history, next_message = await self._prepare_messages(
146
+ self.user_prompt, ctx.state.message_history, ctx.deps.get_instructions, run_context
147
+ )
145
148
  ctx.state.message_history = history
146
149
  run_context.messages = history
147
150
 
@@ -155,6 +158,7 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]):
155
158
  self,
156
159
  user_prompt: str | Sequence[_messages.UserContent] | None,
157
160
  message_history: list[_messages.ModelMessage] | None,
161
+ get_instructions: Callable[[RunContext[DepsT]], Awaitable[str | None]],
158
162
  run_context: RunContext[DepsT],
159
163
  ) -> tuple[list[_messages.ModelMessage], _messages.ModelRequest]:
160
164
  try:
@@ -169,7 +173,7 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]):
169
173
  ctx_messages.used = True
170
174
 
171
175
  parts: list[_messages.ModelRequestPart] = []
172
- instructions = await self._instructions(run_context)
176
+ instructions = await get_instructions(run_context)
173
177
  if message_history:
174
178
  # Shallow copy messages
175
179
  messages.extend(message_history)
@@ -210,15 +214,6 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]):
210
214
  messages.append(_messages.SystemPromptPart(prompt))
211
215
  return messages
212
216
 
213
- async def _instructions(self, run_context: RunContext[DepsT]) -> str | None:
214
- if self.instructions is None and not self.instructions_functions:
215
- return None
216
-
217
- instructions = self.instructions or ''
218
- for instructions_runner in self.instructions_functions:
219
- instructions += await instructions_runner.run(run_context)
220
- return instructions
221
-
222
217
 
223
218
  async def _prepare_request_parameters(
224
219
  ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, NodeRunEndT]],
@@ -479,7 +474,11 @@ class CallToolsNode(AgentNode[DepsT, NodeRunEndT]):
479
474
  else:
480
475
  if tool_responses:
481
476
  parts.extend(tool_responses)
482
- self._next_node = ModelRequestNode[DepsT, NodeRunEndT](_messages.ModelRequest(parts=parts))
477
+ run_context = build_run_context(ctx)
478
+ instructions = await ctx.deps.get_instructions(run_context)
479
+ self._next_node = ModelRequestNode[DepsT, NodeRunEndT](
480
+ _messages.ModelRequest(parts=parts, instructions=instructions)
481
+ )
483
482
 
484
483
  def _handle_final_result(
485
484
  self,
pydantic_ai/agent.py CHANGED
@@ -620,6 +620,15 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
620
620
  },
621
621
  )
622
622
 
623
+ async def get_instructions(run_context: RunContext[AgentDepsT]) -> str | None:
624
+ if self._instructions is None and not self._instructions_functions:
625
+ return None
626
+
627
+ instructions = self._instructions or ''
628
+ for instructions_runner in self._instructions_functions:
629
+ instructions += await instructions_runner.run(run_context)
630
+ return instructions
631
+
623
632
  graph_deps = _agent_graph.GraphAgentDeps[AgentDepsT, RunOutputDataT](
624
633
  user_deps=deps,
625
634
  prompt=user_prompt,
@@ -635,6 +644,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
635
644
  mcp_servers=self._mcp_servers,
636
645
  run_span=run_span,
637
646
  tracer=tracer,
647
+ get_instructions=get_instructions,
638
648
  )
639
649
  start_node = _agent_graph.UserPromptNode[AgentDepsT](
640
650
  user_prompt=user_prompt,
@@ -20,11 +20,11 @@ class WalkJsonSchema(ABC):
20
20
  def __init__(
21
21
  self, schema: JsonSchema, *, prefer_inlined_defs: bool = False, simplify_nullable_unions: bool = False
22
22
  ):
23
- self.schema = deepcopy(schema)
23
+ self.schema = schema
24
24
  self.prefer_inlined_defs = prefer_inlined_defs
25
25
  self.simplify_nullable_unions = simplify_nullable_unions
26
26
 
27
- self.defs: dict[str, JsonSchema] = self.schema.pop('$defs', {})
27
+ self.defs: dict[str, JsonSchema] = self.schema.get('$defs', {})
28
28
  self.refs_stack = tuple[str, ...]()
29
29
  self.recursive_refs = set[str]()
30
30
 
@@ -34,7 +34,11 @@ class WalkJsonSchema(ABC):
34
34
  return schema
35
35
 
36
36
  def walk(self) -> JsonSchema:
37
- handled = self._handle(deepcopy(self.schema))
37
+ schema = deepcopy(self.schema)
38
+
39
+ # First, handle everything but $defs:
40
+ schema.pop('$defs', None)
41
+ handled = self._handle(schema)
38
42
 
39
43
  if not self.prefer_inlined_defs and self.defs:
40
44
  handled['$defs'] = {k: self._handle(v) for k, v in self.defs.items()}
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations as _annotations
2
2
 
3
3
  import base64
4
+ import warnings
4
5
  from collections.abc import AsyncIterator, Sequence
5
6
  from contextlib import asynccontextmanager
6
7
  from dataclasses import dataclass, field, replace
@@ -776,6 +777,22 @@ class _GeminiJsonSchema(WalkJsonSchema):
776
777
  super().__init__(schema, prefer_inlined_defs=True, simplify_nullable_unions=True)
777
778
 
778
779
  def transform(self, schema: JsonSchema) -> JsonSchema:
780
+ # Note: we need to remove `additionalProperties: False` since it is currently mishandled by Gemini
781
+ additional_properties = schema.pop(
782
+ 'additionalProperties', None
783
+ ) # don't pop yet so it's included in the warning
784
+ if additional_properties: # pragma: no cover
785
+ original_schema = {**schema, 'additionalProperties': additional_properties}
786
+ warnings.warn(
787
+ '`additionalProperties` is not supported by Gemini; it will be removed from the tool JSON schema.'
788
+ f' Full schema: {self.schema}\n\n'
789
+ f'Source of additionalProperties within the full schema: {original_schema}\n\n'
790
+ 'If this came from a field with a type like `dict[str, MyType]`, that field will always be empty.\n\n'
791
+ "If Google's APIs are updated to support this properly, please create an issue on the PydanticAI GitHub"
792
+ ' and we will fix this behavior.',
793
+ UserWarning,
794
+ )
795
+
779
796
  schema.pop('title', None)
780
797
  schema.pop('default', None)
781
798
  schema.pop('$schema', None)
pydantic_ai/tools.py CHANGED
@@ -333,7 +333,7 @@ class Tool(Generic[AgentDepsT]):
333
333
  ) -> _messages.ToolReturnPart | _messages.RetryPromptPart:
334
334
  try:
335
335
  if isinstance(message.args, str):
336
- args_dict = self._validator.validate_json(message.args)
336
+ args_dict = self._validator.validate_json(message.args or '{}')
337
337
  else:
338
338
  args_dict = self._validator.validate_python(message.args)
339
339
  except ValidationError as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
5
5
  Author-email: Samuel Colvin <samuel@pydantic.dev>
6
6
  License-Expression: MIT
@@ -29,7 +29,7 @@ Requires-Dist: exceptiongroup; python_version < '3.11'
29
29
  Requires-Dist: griffe>=1.3.2
30
30
  Requires-Dist: httpx>=0.27
31
31
  Requires-Dist: opentelemetry-api>=1.28.0
32
- Requires-Dist: pydantic-graph==0.1.0
32
+ Requires-Dist: pydantic-graph==0.1.1
33
33
  Requires-Dist: pydantic>=2.10
34
34
  Requires-Dist: typing-inspection>=0.4.0
35
35
  Provides-Extra: anthropic
@@ -45,7 +45,7 @@ Requires-Dist: cohere>=5.13.11; (platform_system != 'Emscripten') and extra == '
45
45
  Provides-Extra: duckduckgo
46
46
  Requires-Dist: duckduckgo-search>=7.0.0; extra == 'duckduckgo'
47
47
  Provides-Extra: evals
48
- Requires-Dist: pydantic-evals==0.1.0; extra == 'evals'
48
+ Requires-Dist: pydantic-evals==0.1.1; extra == 'evals'
49
49
  Provides-Extra: groq
50
50
  Requires-Dist: groq>=0.15.0; extra == 'groq'
51
51
  Provides-Extra: logfire
@@ -1,6 +1,6 @@
1
1
  pydantic_ai/__init__.py,sha256=5flxyMQJVrHRMQ3MYaZf1el2ctNs0JmPClKbw2Q-Lsk,1160
2
2
  pydantic_ai/__main__.py,sha256=AW8FzscUWPFtIrQBG0QExLxTQehKtt5FnFVnOT200OE,122
3
- pydantic_ai/_agent_graph.py,sha256=9REW7Al14aL34Z6iL8n8wvxXVBSH_dliU4Yl5ExlJK4,33308
3
+ pydantic_ai/_agent_graph.py,sha256=YNBaxws6CXQ5D_G19wIwf8E4Jkf5mN6aFS2q2Nyxk-w,33318
4
4
  pydantic_ai/_cli.py,sha256=j3uSu5lZMNKb876HHMHwVZc1nzJPn6NER5ysrDMFrvo,10730
5
5
  pydantic_ai/_griffe.py,sha256=Sf_DisE9k2TA0VFeVIK2nf1oOct5MygW86PBCACJkFA,5244
6
6
  pydantic_ai/_output.py,sha256=w_kBc5Lx5AmI0APbohxxYgpFd5VAwh6K0IjP7QIOu9U,11209
@@ -8,7 +8,7 @@ pydantic_ai/_parts_manager.py,sha256=HIi6eth7z2g0tOn6iQYc633xMqy4d_xZ8vwka8J8150
8
8
  pydantic_ai/_pydantic.py,sha256=12hX5hON88meO1QxbWrEPXSvr6RTNgr6ubKY6KRwab4,8890
9
9
  pydantic_ai/_system_prompt.py,sha256=602c2jyle2R_SesOrITBDETZqsLk4BZ8Cbo8yEhmx04,1120
10
10
  pydantic_ai/_utils.py,sha256=t0P9DFX3MulMyoqyZDRinmLCOB1q6rvRnMRqQP2MUpI,10585
11
- pydantic_ai/agent.py,sha256=jq8ZPlsM-P3gqP-R59W47eA9xKNep0CyiF5_rpQ6ffc,86354
11
+ pydantic_ai/agent.py,sha256=IjFjHqt-cCkYorCn_Ry6PKAaI_yRpW7tb0lOpozeMGo,86826
12
12
  pydantic_ai/exceptions.py,sha256=gvbFsFkAzSXOo_d1nfjy09kDHUGv1j5q70Uk-wKYGi8,3167
13
13
  pydantic_ai/format_as_xml.py,sha256=IINfh1evWDphGahqHNLBArB5dQ4NIqS3S-kru35ztGg,372
14
14
  pydantic_ai/format_prompt.py,sha256=qdKep95Sjlr7u1-qag4JwPbjoURbG0GbeU_l5ODTNw4,4466
@@ -17,19 +17,19 @@ pydantic_ai/messages.py,sha256=TUfs1AsogZu1YkoJjKwjbKCcaaDg-0gcbIj_wVLUW0E,29748
17
17
  pydantic_ai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  pydantic_ai/result.py,sha256=DgoUd0LqNd9DWPab6iwculKYvZ5JZHuGvToj0kkibvs,27625
19
19
  pydantic_ai/settings.py,sha256=RMQxjsJqyiExxtxCr_L3avojAiANdFE0ME1eitLrjhk,3242
20
- pydantic_ai/tools.py,sha256=YIdB1CuyoBcd2oG9NvL66nwpCBR3ii6I4KqMoThHiAE,16915
20
+ pydantic_ai/tools.py,sha256=Tq-Ba5_7Cx3N3iBExFy06JkelZAz_mOi-K8zLXgCBDU,16923
21
21
  pydantic_ai/usage.py,sha256=9sqoIv_RVVUhKXQScTDqUJc074gifsuSzc9_NOt7C3g,5394
22
22
  pydantic_ai/common_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  pydantic_ai/common_tools/duckduckgo.py,sha256=Iw8Dl2YQ28S483mzfa8CXs-dc-ujS8un085R2O6oOEw,2241
24
24
  pydantic_ai/common_tools/tavily.py,sha256=h8deBDrpG-8BGzydM_zXs7z1ASrhdVvUxL4-CAbncBo,2589
25
25
  pydantic_ai/models/__init__.py,sha256=R1YV2gE8l_EDlnmLhfxhdojF6gjGWMC14ocRrxiz5XM,19699
26
- pydantic_ai/models/_json_schema.py,sha256=5xqysWdE1uGwrztVzhkOJ8uSKgKnONBe88004ufbWqM,6319
26
+ pydantic_ai/models/_json_schema.py,sha256=GXcELRirUtqfpHlNKlRzCR_p6_-Xl7YgIWYCxnshsLA,6414
27
27
  pydantic_ai/models/anthropic.py,sha256=gkeeIEqI0dk72EIL9zYRtvBd9ipDvT0v1-AcdMF_l20,20272
28
28
  pydantic_ai/models/bedrock.py,sha256=KSmukt2jeKb6uABVR5BRz5Sm7YGYSh56NF0Ftzk11UI,24977
29
29
  pydantic_ai/models/cohere.py,sha256=0clDIXPETo0pjfNgtI-sWqjjZWPkHqFalag_nN3HSNI,11685
30
30
  pydantic_ai/models/fallback.py,sha256=sKHyQ1P6zjWORjWgbuhaxyntOfQyDCS8km8FMrlNy3U,4998
31
31
  pydantic_ai/models/function.py,sha256=FJvTMwT7p8I_h14ZrudLAI5mmbXxF8AX-Nhz8LXy5U0,11373
32
- pydantic_ai/models/gemini.py,sha256=CdhlEpyyDUSEfbx82juJxP0Us0GotNnCQ-0W-RfQD6o,34330
32
+ pydantic_ai/models/gemini.py,sha256=zoYbwDusTX4vYeS1OhD6-ACgJyj8-cHluhL7lxQTDXk,35363
33
33
  pydantic_ai/models/groq.py,sha256=UNyZPqmHRZ9LgtMhV5f9QI1txZ7TCMyu8Abn1ojk5lE,17034
34
34
  pydantic_ai/models/instrumented.py,sha256=_5bV2kkwCix5C25cCAblbhZy1wiKaYBUStmHso4T22g,11163
35
35
  pydantic_ai/models/mistral.py,sha256=sNujNLxpPFZA_vrh-74rDRl2syE1QTgILm6hMZNR4SI,28226
@@ -47,7 +47,7 @@ pydantic_ai/providers/google_vertex.py,sha256=WAwPxKTARVzs8DFs2veEUOJSur0krDOo9-
47
47
  pydantic_ai/providers/groq.py,sha256=DoY6qkfhuemuKB5JXhUkqG-3t1HQkxwSXoE_kHQIAK0,2788
48
48
  pydantic_ai/providers/mistral.py,sha256=fcR1uSwORo0jtevX7-wOjvcfT8ojMAaKY81uN5uYymM,2661
49
49
  pydantic_ai/providers/openai.py,sha256=ePF-QWwLkGkSE5w245gTTDVR3VoTIUqFoIhQ0TAoUiA,2866
50
- pydantic_ai_slim-0.1.0.dist-info/METADATA,sha256=4R4qDPDb8_150bXpKlHbSyO_uIrQVFOud2BgWCLS61k,3551
51
- pydantic_ai_slim-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
- pydantic_ai_slim-0.1.0.dist-info/entry_points.txt,sha256=KxQSmlMS8GMTkwTsl4_q9a5nJvBjj3HWeXx688wLrKg,45
53
- pydantic_ai_slim-0.1.0.dist-info/RECORD,,
50
+ pydantic_ai_slim-0.1.1.dist-info/METADATA,sha256=Aas5s1kUmLhvIoySwub-x_J7xE4okIR2z13C_ZXvPno,3551
51
+ pydantic_ai_slim-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
+ pydantic_ai_slim-0.1.1.dist-info/entry_points.txt,sha256=KxQSmlMS8GMTkwTsl4_q9a5nJvBjj3HWeXx688wLrKg,45
53
+ pydantic_ai_slim-0.1.1.dist-info/RECORD,,