pydantic-ai-slim 0.1.7__py3-none-any.whl → 0.1.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.

@@ -546,7 +546,7 @@ def build_run_context(ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT
546
546
  )
547
547
 
548
548
 
549
- async def process_function_tools(
549
+ async def process_function_tools( # noqa C901
550
550
  tool_calls: list[_messages.ToolCallPart],
551
551
  output_tool_name: str | None,
552
552
  output_tool_call_id: str | None,
@@ -632,6 +632,8 @@ async def process_function_tools(
632
632
  if not calls_to_run:
633
633
  return
634
634
 
635
+ user_parts: list[_messages.UserPromptPart] = []
636
+
635
637
  # Run all tool tasks in parallel
636
638
  results_by_index: dict[int, _messages.ModelRequestPart] = {}
637
639
  with ctx.deps.tracer.start_as_current_span(
@@ -645,6 +647,9 @@ async def process_function_tools(
645
647
  asyncio.create_task(tool.run(call, run_context, ctx.deps.tracer), name=call.tool_name)
646
648
  for tool, call in calls_to_run
647
649
  ]
650
+
651
+ file_index = 1
652
+
648
653
  pending = tasks
649
654
  while pending:
650
655
  done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
@@ -652,7 +657,22 @@ async def process_function_tools(
652
657
  index = tasks.index(task)
653
658
  result = task.result()
654
659
  yield _messages.FunctionToolResultEvent(result, tool_call_id=call_index_to_event_id[index])
655
- if isinstance(result, (_messages.ToolReturnPart, _messages.RetryPromptPart)):
660
+
661
+ if isinstance(result, _messages.RetryPromptPart):
662
+ results_by_index[index] = result
663
+ elif isinstance(result, _messages.ToolReturnPart):
664
+ if isinstance(result.content, _messages.MultiModalContentTypes):
665
+ user_parts.append(
666
+ _messages.UserPromptPart(
667
+ content=[f'This is file {file_index}:', result.content],
668
+ timestamp=result.timestamp,
669
+ part_kind='user-prompt',
670
+ )
671
+ )
672
+
673
+ result.content = f'See file {file_index}.'
674
+ file_index += 1
675
+
656
676
  results_by_index[index] = result
657
677
  else:
658
678
  assert_never(result)
@@ -662,6 +682,8 @@ async def process_function_tools(
662
682
  for k in sorted(results_by_index):
663
683
  output_parts.append(results_by_index[k])
664
684
 
685
+ output_parts.extend(user_parts)
686
+
665
687
 
666
688
  async def _tool_from_mcp_server(
667
689
  tool_name: str,
pydantic_ai/messages.py CHANGED
@@ -253,6 +253,9 @@ class BinaryContent:
253
253
 
254
254
  UserContent: TypeAlias = 'str | ImageUrl | AudioUrl | DocumentUrl | VideoUrl | BinaryContent'
255
255
 
256
+ # Ideally this would be a Union of types, but Python 3.9 requires it to be a string, and strings don't work with `isinstance``.
257
+ MultiModalContentTypes = (ImageUrl, AudioUrl, DocumentUrl, VideoUrl, BinaryContent)
258
+
256
259
 
257
260
  def _document_format(media_type: str) -> DocumentFormat:
258
261
  if media_type == 'application/pdf':
@@ -483,7 +483,20 @@ class MistralModel(Model):
483
483
  assert_never(message)
484
484
  if instructions := self._get_instructions(messages):
485
485
  mistral_messages.insert(0, MistralSystemMessage(content=instructions))
486
- return mistral_messages
486
+
487
+ # Post-process messages to insert fake assistant message after tool message if followed by user message
488
+ # to work around `Unexpected role 'user' after role 'tool'` error.
489
+ processed_messages: list[MistralMessages] = []
490
+ for i, current_message in enumerate(mistral_messages):
491
+ processed_messages.append(current_message)
492
+
493
+ if isinstance(current_message, MistralToolMessage) and i + 1 < len(mistral_messages):
494
+ next_message = mistral_messages[i + 1]
495
+ if isinstance(next_message, MistralUserMessage):
496
+ # Insert a dummy assistant message
497
+ processed_messages.append(MistralAssistantMessage(content=[MistralTextChunk(text='OK')]))
498
+
499
+ return processed_messages
487
500
 
488
501
  def _map_user_prompt(self, part: UserPromptPart) -> MistralUserMessage:
489
502
  content: str | list[MistralContentChunk]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 0.1.7
3
+ Version: 0.1.8
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.7
32
+ Requires-Dist: pydantic-graph==0.1.8
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.7; extra == 'evals'
48
+ Requires-Dist: pydantic-evals==0.1.8; 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=CTDDuRWB7ljaRZsSPLXXVsEVV9nqZRTjt2GY9JfYR_o,33106
3
+ pydantic_ai/_agent_graph.py,sha256=2DKbmiiA1OooCXQ9WYh7sup0XpYxuvEtPiVsweMnXIU,33880
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
@@ -13,7 +13,7 @@ pydantic_ai/exceptions.py,sha256=gvbFsFkAzSXOo_d1nfjy09kDHUGv1j5q70Uk-wKYGi8,316
13
13
  pydantic_ai/format_as_xml.py,sha256=IINfh1evWDphGahqHNLBArB5dQ4NIqS3S-kru35ztGg,372
14
14
  pydantic_ai/format_prompt.py,sha256=qdKep95Sjlr7u1-qag4JwPbjoURbG0GbeU_l5ODTNw4,4466
15
15
  pydantic_ai/mcp.py,sha256=l33wV5JaZTXBYEHMxfdFP2e5SlqGw_D7bB90zDNKAdA,9440
16
- pydantic_ai/messages.py,sha256=qA9X0GVS-EL3e-1XliQylcNllp3bE3R5iEJP6tywq5c,30113
16
+ pydantic_ai/messages.py,sha256=QASltyfRh5Rs6zK-QJL7vWAmyuM6gpsQhxnFAxQxlYo,30326
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=n-Y69s0Tkbo2k65ZwNmIu1nMypO9HadqUDLjZgGQS_Q,3374
@@ -32,7 +32,7 @@ pydantic_ai/models/function.py,sha256=FJvTMwT7p8I_h14ZrudLAI5mmbXxF8AX-Nhz8LXy5U
32
32
  pydantic_ai/models/gemini.py,sha256=78Geduf2rU5zKQeq7f0y95H5hTW9vPdXIhhnCV6QP2Q,35255
33
33
  pydantic_ai/models/groq.py,sha256=-_qk5hPUVi3TjA97bZCszME2hyZIVJ11MLGGTamjSMA,17095
34
34
  pydantic_ai/models/instrumented.py,sha256=vJxd68CH-PsNNzRGfqfq-UzLMbpgol6BnrkqxYFpZ1I,11490
35
- pydantic_ai/models/mistral.py,sha256=sNujNLxpPFZA_vrh-74rDRl2syE1QTgILm6hMZNR4SI,28226
35
+ pydantic_ai/models/mistral.py,sha256=jcZcw7i0z2j59JuE9S845knDPRqrxNvwMAsemEAOPRs,28974
36
36
  pydantic_ai/models/openai.py,sha256=mKAIAO0n827b9OVvb6QhREnZDzjRersWZP9pnURqBrQ,48056
37
37
  pydantic_ai/models/test.py,sha256=_Fd7oKNA2p_1zXBMvQStnizGlx-ii-zisJx1nIEZn7c,16973
38
38
  pydantic_ai/models/wrapper.py,sha256=8wm4RF-MRZOxRVLefwMsxToopCX5Y4Xq2-Ugs5MtCK4,1710
@@ -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.7.dist-info/METADATA,sha256=UnAoroMbUg707c_AfbgUwkhnUuKU6pcviJO7k1GwnK8,3551
51
- pydantic_ai_slim-0.1.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
- pydantic_ai_slim-0.1.7.dist-info/entry_points.txt,sha256=KxQSmlMS8GMTkwTsl4_q9a5nJvBjj3HWeXx688wLrKg,45
53
- pydantic_ai_slim-0.1.7.dist-info/RECORD,,
50
+ pydantic_ai_slim-0.1.8.dist-info/METADATA,sha256=Iu_mDDcuYRSoDW0IpokZRW0HGWkwVaBoiK-6MBx_71o,3551
51
+ pydantic_ai_slim-0.1.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
+ pydantic_ai_slim-0.1.8.dist-info/entry_points.txt,sha256=KxQSmlMS8GMTkwTsl4_q9a5nJvBjj3HWeXx688wLrKg,45
53
+ pydantic_ai_slim-0.1.8.dist-info/RECORD,,