pydantic-ai-slim 0.4.4__py3-none-any.whl → 0.4.5__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/_a2a.py CHANGED
@@ -59,12 +59,12 @@ except ImportError as _import_error:
59
59
 
60
60
 
61
61
  @asynccontextmanager
62
- async def worker_lifespan(app: FastA2A, worker: Worker) -> AsyncIterator[None]:
62
+ async def worker_lifespan(app: FastA2A, worker: Worker, agent: Agent[AgentDepsT, OutputDataT]) -> AsyncIterator[None]:
63
63
  """Custom lifespan that runs the worker during application startup.
64
64
 
65
65
  This ensures the worker is started and ready to process tasks as soon as the application starts.
66
66
  """
67
- async with app.task_manager:
67
+ async with app.task_manager, agent:
68
68
  async with worker.run():
69
69
  yield
70
70
 
@@ -93,7 +93,7 @@ def agent_to_a2a(
93
93
  broker = broker or InMemoryBroker()
94
94
  worker = AgentWorker(agent=agent, broker=broker, storage=storage)
95
95
 
96
- lifespan = lifespan or partial(worker_lifespan, worker=worker)
96
+ lifespan = lifespan or partial(worker_lifespan, worker=worker, agent=agent)
97
97
 
98
98
  return FastA2A(
99
99
  storage=storage,
pydantic_ai/agent.py CHANGED
@@ -843,14 +843,15 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
843
843
  agent_run = AgentRun(graph_run)
844
844
  yield agent_run
845
845
  if (final_result := agent_run.result) is not None and run_span.is_recording():
846
- run_span.set_attribute(
847
- 'final_result',
848
- (
849
- final_result.output
850
- if isinstance(final_result.output, str)
851
- else json.dumps(InstrumentedModel.serialize_any(final_result.output))
852
- ),
853
- )
846
+ if instrumentation_settings and instrumentation_settings.include_content:
847
+ run_span.set_attribute(
848
+ 'final_result',
849
+ (
850
+ final_result.output
851
+ if isinstance(final_result.output, str)
852
+ else json.dumps(InstrumentedModel.serialize_any(final_result.output))
853
+ ),
854
+ )
854
855
  finally:
855
856
  try:
856
857
  if instrumentation_settings and run_span.is_recording():
@@ -13,9 +13,8 @@ __all__ = ('format_as_xml',)
13
13
 
14
14
  def format_as_xml(
15
15
  obj: Any,
16
- root_tag: str = 'examples',
17
- item_tag: str = 'example',
18
- include_root_tag: bool = True,
16
+ root_tag: str | None = None,
17
+ item_tag: str = 'item',
19
18
  none_str: str = 'null',
20
19
  indent: str | None = ' ',
21
20
  ) -> str:
@@ -32,8 +31,6 @@ def format_as_xml(
32
31
  root_tag: Outer tag to wrap the XML in, use `None` to omit the outer tag.
33
32
  item_tag: Tag to use for each item in an iterable (e.g. list), this is overridden by the class name
34
33
  for dataclasses and Pydantic models.
35
- include_root_tag: Whether to include the root tag in the output
36
- (The root tag is always included if it includes a body - e.g. when the input is a simple value).
37
34
  none_str: String to use for `None` values.
38
35
  indent: Indentation string to use for pretty printing.
39
36
 
@@ -55,7 +52,7 @@ def format_as_xml(
55
52
  ```
56
53
  """
57
54
  el = _ToXml(item_tag=item_tag, none_str=none_str).to_xml(obj, root_tag)
58
- if not include_root_tag and el.text is None:
55
+ if root_tag is None and el.text is None:
59
56
  join = '' if indent is None else '\n'
60
57
  return join.join(_rootless_xml_elements(el, indent))
61
58
  else:
@@ -91,15 +91,6 @@ class GeminiModelSettings(ModelSettings, total=False):
91
91
  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.
92
92
  """
93
93
 
94
- gemini_thinking_config: ThinkingConfig
95
- """Thinking is on by default in both the API and AI Studio.
96
-
97
- Being on by default doesn't mean the model will send back thoughts. For that, you need to set `include_thoughts`
98
- to `True`. If you want to turn it off, set `thinking_budget` to `0`.
99
-
100
- See more about it on <https://ai.google.dev/gemini-api/docs/thinking>.
101
- """
102
-
103
94
 
104
95
  @dataclass(init=False)
105
96
  class GeminiModel(Model):
@@ -156,7 +156,12 @@ class InstrumentationSettings:
156
156
  events: list[Event] = []
157
157
  instructions = InstrumentedModel._get_instructions(messages) # pyright: ignore [reportPrivateUsage]
158
158
  if instructions is not None:
159
- events.append(Event('gen_ai.system.message', body={'content': instructions, 'role': 'system'}))
159
+ events.append(
160
+ Event(
161
+ 'gen_ai.system.message',
162
+ body={**({'content': instructions} if self.include_content else {}), 'role': 'system'},
163
+ )
164
+ )
160
165
 
161
166
  for message_index, message in enumerate(messages):
162
167
  message_events: list[Event] = []
@@ -8,6 +8,7 @@ from dataclasses import dataclass, field
8
8
  from datetime import datetime
9
9
  from typing import Any, Literal, Union, cast, overload
10
10
 
11
+ from pydantic import ValidationError
11
12
  from typing_extensions import assert_never
12
13
 
13
14
  from pydantic_ai._thinking_part import split_content_into_text_and_thinking
@@ -347,8 +348,19 @@ class OpenAIModel(Model):
347
348
  raise ModelHTTPError(status_code=status_code, model_name=self.model_name, body=e.body) from e
348
349
  raise # pragma: no cover
349
350
 
350
- def _process_response(self, response: chat.ChatCompletion) -> ModelResponse:
351
+ def _process_response(self, response: chat.ChatCompletion | str) -> ModelResponse:
351
352
  """Process a non-streamed response, and prepare a message to return."""
353
+ # Although the OpenAI SDK claims to return a Pydantic model (`ChatCompletion`) from the chat completions function:
354
+ # * it hasn't actually performed validation (presumably they're creating the model with `model_construct` or something?!)
355
+ # * if the endpoint returns plain text, the return type is a string
356
+ # Thus we validate it fully here.
357
+ if not isinstance(response, chat.ChatCompletion):
358
+ raise UnexpectedModelBehavior('Invalid response from OpenAI chat completions endpoint, expected JSON data')
359
+
360
+ try:
361
+ response = chat.ChatCompletion.model_validate(response.model_dump())
362
+ except ValidationError as e:
363
+ raise UnexpectedModelBehavior(f'Invalid response from OpenAI chat completions endpoint: {e}') from e
352
364
  timestamp = number_to_datetime(response.created)
353
365
  choice = response.choices[0]
354
366
  items: list[ModelResponsePart] = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 0.4.4
3
+ Version: 0.4.5
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>, Douwe Maan <douwe@pydantic.dev>
6
6
  License-Expression: MIT
@@ -30,7 +30,7 @@ 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.4.4
33
+ Requires-Dist: pydantic-graph==0.4.5
34
34
  Requires-Dist: pydantic>=2.10
35
35
  Requires-Dist: typing-inspection>=0.4.0
36
36
  Provides-Extra: a2a
@@ -51,7 +51,7 @@ Requires-Dist: cohere>=5.13.11; (platform_system != 'Emscripten') and extra == '
51
51
  Provides-Extra: duckduckgo
52
52
  Requires-Dist: ddgs>=9.0.0; extra == 'duckduckgo'
53
53
  Provides-Extra: evals
54
- Requires-Dist: pydantic-evals==0.4.4; extra == 'evals'
54
+ Requires-Dist: pydantic-evals==0.4.5; extra == 'evals'
55
55
  Provides-Extra: google
56
56
  Requires-Dist: google-genai>=1.24.0; extra == 'google'
57
57
  Provides-Extra: groq
@@ -1,6 +1,6 @@
1
1
  pydantic_ai/__init__.py,sha256=h6Rll8pEzUUUX6SckosummoAFbq7ctfBlI6WSyaXR4I,1300
2
2
  pydantic_ai/__main__.py,sha256=Q_zJU15DUA01YtlJ2mnaLCoId2YmgmreVEERGuQT-Y0,132
3
- pydantic_ai/_a2a.py,sha256=PFgqW6I3qh3deY4WFfubTUroig9-NaAWxbeMxYjdtfI,12067
3
+ pydantic_ai/_a2a.py,sha256=Tw_j9VRud0rLEk5kRs4GhRyhWYioXnsoZaTTyISq4M4,12126
4
4
  pydantic_ai/_agent_graph.py,sha256=FrNq9kppV8kFVZf6t-MVGVOWUVBCXQfAinQjMh2gVWw,37192
5
5
  pydantic_ai/_cli.py,sha256=YkiW2u9HGPd9fsgo9dpK1DZvtUPk4uXGQJcm75XgfhU,13250
6
6
  pydantic_ai/_function_schema.py,sha256=BZus5y51eqiGQKxQIcCiDoSPml3AtAb12-st_aujU2k,10813
@@ -14,11 +14,11 @@ pydantic_ai/_thinking_part.py,sha256=mzx2RZSfiQxAKpljEflrcXRXmFKxtp6bKVyorY3UYZk
14
14
  pydantic_ai/_tool_manager.py,sha256=ptVj2oJm7Qm5MlDQHDNj8BPIEPY0HfkrzqeeD_ZuVbQ,8180
15
15
  pydantic_ai/_utils.py,sha256=0Pte4mjir4YFZJTa6i-H6Cra9NbVwSKjOKegArzUggk,16283
16
16
  pydantic_ai/ag_ui.py,sha256=b1Uqc0bGcFCn71hl04gcX_W80lQugueEm-0m--fde2s,25758
17
- pydantic_ai/agent.py,sha256=2kKk22M7kDNUls0bRzwXqviAXjwVaDxVMcFwg8z7Wq8,107794
17
+ pydantic_ai/agent.py,sha256=BIO9-5FGtrI7LfNe8BsjuLmLuzJgIYvR3OB7Bf3vctc,107920
18
18
  pydantic_ai/direct.py,sha256=WRfgke3zm-eeR39LTuh9XI2TrdHXAqO81eDvFwih4Ko,14803
19
19
  pydantic_ai/exceptions.py,sha256=o0l6fBrWI5UhosICVZ2yaT-JEJF05eqBlKlQCW8i9UM,3462
20
20
  pydantic_ai/format_as_xml.py,sha256=IINfh1evWDphGahqHNLBArB5dQ4NIqS3S-kru35ztGg,372
21
- pydantic_ai/format_prompt.py,sha256=qdKep95Sjlr7u1-qag4JwPbjoURbG0GbeU_l5ODTNw4,4466
21
+ pydantic_ai/format_prompt.py,sha256=Or-Ytq55RQb1UJqy2HKIyPpZ-knWXfdDP3Z6tNc6Orw,4244
22
22
  pydantic_ai/mcp.py,sha256=3YvQmTGpWC4stG9CthYCWnEE7XXIGuc2Xtfw4Yiya8c,23817
23
23
  pydantic_ai/messages.py,sha256=ZLV6Evc0-HWiR7nt0C_6Oe9kFhmE0o4Hg19TZPUPTaU,40089
24
24
  pydantic_ai/output.py,sha256=54Cwd1RruXlA5hucZ1h-SxFrzKHJuLvYvLtH9iyg2GI,11988
@@ -39,14 +39,14 @@ pydantic_ai/models/bedrock.py,sha256=WnYykDnkyBd340tpt4l35T8SjT3z50RO83EZ8n77FVA
39
39
  pydantic_ai/models/cohere.py,sha256=PTqwMRsgaLGVUrzb80sh9jS6CNuvDokvPHKT5KTYR_g,12788
40
40
  pydantic_ai/models/fallback.py,sha256=URaV-dTQWkg99xrlkmknue5lXZWDcEt7cJ1Vsky4oB4,5130
41
41
  pydantic_ai/models/function.py,sha256=UIed008-9GgPSox_5uAzmjBLx71kcCWvBS2N3j48Ru4,13586
42
- pydantic_ai/models/gemini.py,sha256=H5se385dnwZUf59LJjCcSkD3wU4gQVo2KUIuqtF4SVw,38356
42
+ pydantic_ai/models/gemini.py,sha256=Pm8KKzrhRrjM39XyQsd9pCzaXwiE1dQ0wPB4Slt10ZI,37973
43
43
  pydantic_ai/models/google.py,sha256=p3EPsZ09LIMGdxedHYKYNlRTL7xLJk2TD93BqzHgq0g,23891
44
44
  pydantic_ai/models/groq.py,sha256=Ll933U1qfWEA3YfGE4dCJBNNSGwH4DmmiKKfhrjdiSM,18700
45
45
  pydantic_ai/models/huggingface.py,sha256=DTkbfySeBfRqIrbMzgUunGnIo-3mLuaDyQjBYTT42bI,18857
46
- pydantic_ai/models/instrumented.py,sha256=dkVCY_SIoPEBLyAr7jODTsJWh6LzslPVzPwOfvqy3iA,16078
46
+ pydantic_ai/models/instrumented.py,sha256=aqvzspcGexn1Molbu6Mn4EEPRBSoQCCCS_yknJvJJ-8,16205
47
47
  pydantic_ai/models/mcp_sampling.py,sha256=q9nnjNEAAbhrfRc_Qw5z9TtCHMG_SwlCWW9FvKWjh8k,3395
48
48
  pydantic_ai/models/mistral.py,sha256=o7bDP7CF8_MzZ3jYtPpjqm8uVDhKTjw1KePPZCxXRhE,30720
49
- pydantic_ai/models/openai.py,sha256=NFFMxWox4HmT8j_kko66yXepZVzpzFQ1sHk06dZLmkQ,54255
49
+ pydantic_ai/models/openai.py,sha256=_35Cp0-m-6ZECNRVcHpi4O4a37lJOc4OipEHHzZCkY4,55092
50
50
  pydantic_ai/models/test.py,sha256=S8hp3fJZJVSwWl01bBi-q7YpijdbstXhGg3aCPon98o,18227
51
51
  pydantic_ai/models/wrapper.py,sha256=A5-ncYhPF8c9S_czGoXkd55s2KOQb65p3jbVpwZiFPA,2043
52
52
  pydantic_ai/profiles/__init__.py,sha256=BXMqUpgRfosmYgcxjKAI9ESCj47JTSa30DhKXEgVLzM,2419
@@ -91,8 +91,8 @@ pydantic_ai/toolsets/prefixed.py,sha256=MIStkzUdiU0rk2Y6P19IrTBxspH5pTstGxsqCBt-
91
91
  pydantic_ai/toolsets/prepared.py,sha256=Zjfz6S8In6PBVxoKFN9sKPN984zO6t0awB7Lnq5KODw,1431
92
92
  pydantic_ai/toolsets/renamed.py,sha256=JuLHpi-hYPiSPlaTpN8WiXLiGsywYK0axi2lW2Qs75k,1637
93
93
  pydantic_ai/toolsets/wrapper.py,sha256=WjLoiM1WDuffSJ4mDS6pZrEZGHgZ421fjrqFcB66W94,1205
94
- pydantic_ai_slim-0.4.4.dist-info/METADATA,sha256=pcwhN2TvSyuzRN7foXXXMgW5AuvTYagRqsN7KE3G0lE,4098
95
- pydantic_ai_slim-0.4.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
- pydantic_ai_slim-0.4.4.dist-info/entry_points.txt,sha256=kbKxe2VtDCYS06hsI7P3uZGxcVC08-FPt1rxeiMpIps,50
97
- pydantic_ai_slim-0.4.4.dist-info/licenses/LICENSE,sha256=vA6Jc482lEyBBuGUfD1pYx-cM7jxvLYOxPidZ30t_PQ,1100
98
- pydantic_ai_slim-0.4.4.dist-info/RECORD,,
94
+ pydantic_ai_slim-0.4.5.dist-info/METADATA,sha256=TfoF7Uy7T5NeiztgTEl2yqUnMYbMnaP-vZL_l9iQ6kI,4098
95
+ pydantic_ai_slim-0.4.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
+ pydantic_ai_slim-0.4.5.dist-info/entry_points.txt,sha256=kbKxe2VtDCYS06hsI7P3uZGxcVC08-FPt1rxeiMpIps,50
97
+ pydantic_ai_slim-0.4.5.dist-info/licenses/LICENSE,sha256=vA6Jc482lEyBBuGUfD1pYx-cM7jxvLYOxPidZ30t_PQ,1100
98
+ pydantic_ai_slim-0.4.5.dist-info/RECORD,,