pydantic-ai-slim 0.4.9__py3-none-any.whl → 0.4.11__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/_agent_graph.py +21 -19
- pydantic_ai/_parts_manager.py +8 -9
- pydantic_ai/_thinking_part.py +7 -12
- pydantic_ai/ag_ui.py +346 -316
- pydantic_ai/agent.py +88 -85
- pydantic_ai/messages.py +2 -2
- pydantic_ai/models/__init__.py +2 -2
- pydantic_ai/models/cohere.py +1 -1
- pydantic_ai/models/gemini.py +1 -1
- pydantic_ai/models/google.py +1 -1
- pydantic_ai/models/groq.py +7 -3
- pydantic_ai/models/huggingface.py +7 -2
- pydantic_ai/models/mistral.py +1 -1
- pydantic_ai/models/openai.py +10 -5
- pydantic_ai/models/test.py +3 -1
- pydantic_ai/profiles/__init__.py +3 -0
- pydantic_ai/profiles/anthropic.py +1 -1
- pydantic_ai/providers/vercel.py +8 -2
- {pydantic_ai_slim-0.4.9.dist-info → pydantic_ai_slim-0.4.11.dist-info}/METADATA +3 -3
- {pydantic_ai_slim-0.4.9.dist-info → pydantic_ai_slim-0.4.11.dist-info}/RECORD +23 -23
- {pydantic_ai_slim-0.4.9.dist-info → pydantic_ai_slim-0.4.11.dist-info}/WHEEL +0 -0
- {pydantic_ai_slim-0.4.9.dist-info → pydantic_ai_slim-0.4.11.dist-info}/entry_points.txt +0 -0
- {pydantic_ai_slim-0.4.9.dist-info → pydantic_ai_slim-0.4.11.dist-info}/licenses/LICENSE +0 -0
pydantic_ai/agent.py
CHANGED
|
@@ -774,90 +774,91 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
|
|
|
774
774
|
|
|
775
775
|
toolset = self._get_toolset(output_toolset=output_toolset, additional_toolsets=toolsets)
|
|
776
776
|
# This will raise errors for any name conflicts
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
async def get_instructions(run_context: RunContext[AgentDepsT]) -> str | None:
|
|
794
|
-
parts = [
|
|
795
|
-
self._instructions,
|
|
796
|
-
*[await func.run(run_context) for func in self._instructions_functions],
|
|
797
|
-
]
|
|
798
|
-
|
|
799
|
-
model_profile = model_used.profile
|
|
800
|
-
if isinstance(output_schema, _output.PromptedOutputSchema):
|
|
801
|
-
instructions = output_schema.instructions(model_profile.prompted_output_template)
|
|
802
|
-
parts.append(instructions)
|
|
777
|
+
async with toolset:
|
|
778
|
+
run_toolset = await ToolManager[AgentDepsT].build(toolset, run_context)
|
|
779
|
+
|
|
780
|
+
# Merge model settings in order of precedence: run > agent > model
|
|
781
|
+
merged_settings = merge_model_settings(model_used.settings, self.model_settings)
|
|
782
|
+
model_settings = merge_model_settings(merged_settings, model_settings)
|
|
783
|
+
usage_limits = usage_limits or _usage.UsageLimits()
|
|
784
|
+
agent_name = self.name or 'agent'
|
|
785
|
+
run_span = tracer.start_span(
|
|
786
|
+
'agent run',
|
|
787
|
+
attributes={
|
|
788
|
+
'model_name': model_used.model_name if model_used else 'no-model',
|
|
789
|
+
'agent_name': agent_name,
|
|
790
|
+
'logfire.msg': f'{agent_name} run',
|
|
791
|
+
},
|
|
792
|
+
)
|
|
803
793
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
794
|
+
async def get_instructions(run_context: RunContext[AgentDepsT]) -> str | None:
|
|
795
|
+
parts = [
|
|
796
|
+
self._instructions,
|
|
797
|
+
*[await func.run(run_context) for func in self._instructions_functions],
|
|
798
|
+
]
|
|
808
799
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
800
|
+
model_profile = model_used.profile
|
|
801
|
+
if isinstance(output_schema, _output.PromptedOutputSchema):
|
|
802
|
+
instructions = output_schema.instructions(model_profile.prompted_output_template)
|
|
803
|
+
parts.append(instructions)
|
|
804
|
+
|
|
805
|
+
parts = [p for p in parts if p]
|
|
806
|
+
if not parts:
|
|
807
|
+
return None
|
|
808
|
+
return '\n\n'.join(parts).strip()
|
|
809
|
+
|
|
810
|
+
graph_deps = _agent_graph.GraphAgentDeps[AgentDepsT, RunOutputDataT](
|
|
811
|
+
user_deps=deps,
|
|
812
|
+
prompt=user_prompt,
|
|
813
|
+
new_message_index=new_message_index,
|
|
814
|
+
model=model_used,
|
|
815
|
+
model_settings=model_settings,
|
|
816
|
+
usage_limits=usage_limits,
|
|
817
|
+
max_result_retries=self._max_result_retries,
|
|
818
|
+
end_strategy=self.end_strategy,
|
|
819
|
+
output_schema=output_schema,
|
|
820
|
+
output_validators=output_validators,
|
|
821
|
+
history_processors=self.history_processors,
|
|
822
|
+
tool_manager=run_toolset,
|
|
823
|
+
tracer=tracer,
|
|
824
|
+
get_instructions=get_instructions,
|
|
825
|
+
instrumentation_settings=instrumentation_settings,
|
|
826
|
+
)
|
|
827
|
+
start_node = _agent_graph.UserPromptNode[AgentDepsT](
|
|
828
|
+
user_prompt=user_prompt,
|
|
829
|
+
instructions=self._instructions,
|
|
830
|
+
instructions_functions=self._instructions_functions,
|
|
831
|
+
system_prompts=self._system_prompts,
|
|
832
|
+
system_prompt_functions=self._system_prompt_functions,
|
|
833
|
+
system_prompt_dynamic_functions=self._system_prompt_dynamic_functions,
|
|
834
|
+
)
|
|
834
835
|
|
|
835
|
-
try:
|
|
836
|
-
async with graph.iter(
|
|
837
|
-
start_node,
|
|
838
|
-
state=state,
|
|
839
|
-
deps=graph_deps,
|
|
840
|
-
span=use_span(run_span) if run_span.is_recording() else None,
|
|
841
|
-
infer_name=False,
|
|
842
|
-
) as graph_run:
|
|
843
|
-
agent_run = AgentRun(graph_run)
|
|
844
|
-
yield agent_run
|
|
845
|
-
if (final_result := agent_run.result) is not None and run_span.is_recording():
|
|
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
|
-
)
|
|
855
|
-
finally:
|
|
856
836
|
try:
|
|
857
|
-
|
|
858
|
-
|
|
837
|
+
async with graph.iter(
|
|
838
|
+
start_node,
|
|
839
|
+
state=state,
|
|
840
|
+
deps=graph_deps,
|
|
841
|
+
span=use_span(run_span) if run_span.is_recording() else None,
|
|
842
|
+
infer_name=False,
|
|
843
|
+
) as graph_run:
|
|
844
|
+
agent_run = AgentRun(graph_run)
|
|
845
|
+
yield agent_run
|
|
846
|
+
if (final_result := agent_run.result) is not None and run_span.is_recording():
|
|
847
|
+
if instrumentation_settings and instrumentation_settings.include_content:
|
|
848
|
+
run_span.set_attribute(
|
|
849
|
+
'final_result',
|
|
850
|
+
(
|
|
851
|
+
final_result.output
|
|
852
|
+
if isinstance(final_result.output, str)
|
|
853
|
+
else json.dumps(InstrumentedModel.serialize_any(final_result.output))
|
|
854
|
+
),
|
|
855
|
+
)
|
|
859
856
|
finally:
|
|
860
|
-
|
|
857
|
+
try:
|
|
858
|
+
if instrumentation_settings and run_span.is_recording():
|
|
859
|
+
run_span.set_attributes(self._run_span_end_attributes(state, usage, instrumentation_settings))
|
|
860
|
+
finally:
|
|
861
|
+
run_span.end()
|
|
861
862
|
|
|
862
863
|
def _run_span_end_attributes(
|
|
863
864
|
self, state: _agent_graph.GraphAgentState, usage: _usage.Usage, settings: InstrumentationSettings
|
|
@@ -1869,9 +1870,13 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
|
|
|
1869
1870
|
on_shutdown: Sequence[Callable[[], Any]] | None = None,
|
|
1870
1871
|
lifespan: Lifespan[AGUIApp[AgentDepsT, OutputDataT]] | None = None,
|
|
1871
1872
|
) -> AGUIApp[AgentDepsT, OutputDataT]:
|
|
1872
|
-
"""
|
|
1873
|
+
"""Returns an ASGI application that handles every AG-UI request by running the agent.
|
|
1873
1874
|
|
|
1874
|
-
|
|
1875
|
+
Note that the `deps` will be the same for each request, with the exception of the AG-UI state that's
|
|
1876
|
+
injected into the `state` field of a `deps` object that implements the [`StateHandler`][pydantic_ai.ag_ui.StateHandler] protocol.
|
|
1877
|
+
To provide different `deps` for each request (e.g. based on the authenticated user),
|
|
1878
|
+
use [`pydantic_ai.ag_ui.run_ag_ui`][pydantic_ai.ag_ui.run_ag_ui] or
|
|
1879
|
+
[`pydantic_ai.ag_ui.handle_ag_ui_request`][pydantic_ai.ag_ui.handle_ag_ui_request] instead.
|
|
1875
1880
|
|
|
1876
1881
|
Example:
|
|
1877
1882
|
```python
|
|
@@ -1881,8 +1886,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
|
|
|
1881
1886
|
app = agent.to_ag_ui()
|
|
1882
1887
|
```
|
|
1883
1888
|
|
|
1884
|
-
The `app` is an ASGI application that can be used with any ASGI server.
|
|
1885
|
-
|
|
1886
1889
|
To run the application, you can use the following command:
|
|
1887
1890
|
|
|
1888
1891
|
```bash
|
|
@@ -1901,7 +1904,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
|
|
|
1901
1904
|
usage_limits: Optional limits on model request count or token usage.
|
|
1902
1905
|
usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
|
|
1903
1906
|
infer_name: Whether to try to infer the agent name from the call frame if it's not set.
|
|
1904
|
-
toolsets: Optional
|
|
1907
|
+
toolsets: Optional additional toolsets for this run.
|
|
1905
1908
|
|
|
1906
1909
|
debug: Boolean indicating if debug tracebacks should be returned on errors.
|
|
1907
1910
|
routes: A list of routes to serve incoming HTTP and WebSocket requests.
|
|
@@ -2173,7 +2176,7 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
|
|
|
2173
2176
|
) -> _agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]:
|
|
2174
2177
|
"""Advance to the next node automatically based on the last returned node."""
|
|
2175
2178
|
next_node = await self._graph_run.__anext__()
|
|
2176
|
-
if _agent_graph.is_agent_node(next_node):
|
|
2179
|
+
if _agent_graph.is_agent_node(node=next_node):
|
|
2177
2180
|
return next_node
|
|
2178
2181
|
assert isinstance(next_node, End), f'Unexpected node type: {type(next_node)}'
|
|
2179
2182
|
return next_node
|
pydantic_ai/messages.py
CHANGED
|
@@ -412,8 +412,8 @@ class ToolReturn:
|
|
|
412
412
|
return_value: Any
|
|
413
413
|
"""The return value to be used in the tool response."""
|
|
414
414
|
|
|
415
|
-
content: Sequence[UserContent] | None = None
|
|
416
|
-
"""The content
|
|
415
|
+
content: str | Sequence[UserContent] | None = None
|
|
416
|
+
"""The content to be sent to the model as a UserPromptPart."""
|
|
417
417
|
|
|
418
418
|
metadata: Any = None
|
|
419
419
|
"""Additional data that can be accessed programmatically by the application but is not sent to the LLM."""
|
pydantic_ai/models/__init__.py
CHANGED
|
@@ -137,12 +137,12 @@ KnownModelName = TypeAliasType(
|
|
|
137
137
|
'google-gla:gemini-2.0-flash',
|
|
138
138
|
'google-gla:gemini-2.0-flash-lite',
|
|
139
139
|
'google-gla:gemini-2.5-flash',
|
|
140
|
-
'google-gla:gemini-2.5-flash-lite
|
|
140
|
+
'google-gla:gemini-2.5-flash-lite',
|
|
141
141
|
'google-gla:gemini-2.5-pro',
|
|
142
142
|
'google-vertex:gemini-2.0-flash',
|
|
143
143
|
'google-vertex:gemini-2.0-flash-lite',
|
|
144
144
|
'google-vertex:gemini-2.5-flash',
|
|
145
|
-
'google-vertex:gemini-2.5-flash-lite
|
|
145
|
+
'google-vertex:gemini-2.5-flash-lite',
|
|
146
146
|
'google-vertex:gemini-2.5-pro',
|
|
147
147
|
'gpt-3.5-turbo',
|
|
148
148
|
'gpt-3.5-turbo-0125',
|
pydantic_ai/models/cohere.py
CHANGED
|
@@ -192,7 +192,7 @@ class CohereModel(Model):
|
|
|
192
192
|
# While Cohere's API returns a list, it only does that for future proofing
|
|
193
193
|
# and currently only one item is being returned.
|
|
194
194
|
choice = response.message.content[0]
|
|
195
|
-
parts.extend(split_content_into_text_and_thinking(choice.text))
|
|
195
|
+
parts.extend(split_content_into_text_and_thinking(choice.text, self.profile.thinking_tags))
|
|
196
196
|
for c in response.message.tool_calls or []:
|
|
197
197
|
if c.function and c.function.name and c.function.arguments: # pragma: no branch
|
|
198
198
|
parts.append(
|
pydantic_ai/models/gemini.py
CHANGED
pydantic_ai/models/google.py
CHANGED
pydantic_ai/models/groq.py
CHANGED
|
@@ -30,7 +30,7 @@ from ..messages import (
|
|
|
30
30
|
ToolReturnPart,
|
|
31
31
|
UserPromptPart,
|
|
32
32
|
)
|
|
33
|
-
from ..profiles import ModelProfileSpec
|
|
33
|
+
from ..profiles import ModelProfile, ModelProfileSpec
|
|
34
34
|
from ..providers import Provider, infer_provider
|
|
35
35
|
from ..settings import ModelSettings
|
|
36
36
|
from ..tools import ToolDefinition
|
|
@@ -261,7 +261,7 @@ class GroqModel(Model):
|
|
|
261
261
|
items.append(ThinkingPart(content=choice.message.reasoning))
|
|
262
262
|
if choice.message.content is not None:
|
|
263
263
|
# NOTE: The `<think>` tag is only present if `groq_reasoning_format` is set to `raw`.
|
|
264
|
-
items.extend(split_content_into_text_and_thinking(choice.message.content))
|
|
264
|
+
items.extend(split_content_into_text_and_thinking(choice.message.content, self.profile.thinking_tags))
|
|
265
265
|
if choice.message.tool_calls is not None:
|
|
266
266
|
for c in choice.message.tool_calls:
|
|
267
267
|
items.append(ToolCallPart(tool_name=c.function.name, args=c.function.arguments, tool_call_id=c.id))
|
|
@@ -281,6 +281,7 @@ class GroqModel(Model):
|
|
|
281
281
|
return GroqStreamedResponse(
|
|
282
282
|
_response=peekable_response,
|
|
283
283
|
_model_name=self._model_name,
|
|
284
|
+
_model_profile=self.profile,
|
|
284
285
|
_timestamp=number_to_datetime(first_chunk.created),
|
|
285
286
|
)
|
|
286
287
|
|
|
@@ -400,6 +401,7 @@ class GroqStreamedResponse(StreamedResponse):
|
|
|
400
401
|
"""Implementation of `StreamedResponse` for Groq models."""
|
|
401
402
|
|
|
402
403
|
_model_name: GroqModelName
|
|
404
|
+
_model_profile: ModelProfile
|
|
403
405
|
_response: AsyncIterable[chat.ChatCompletionChunk]
|
|
404
406
|
_timestamp: datetime
|
|
405
407
|
|
|
@@ -416,7 +418,9 @@ class GroqStreamedResponse(StreamedResponse):
|
|
|
416
418
|
content = choice.delta.content
|
|
417
419
|
if content is not None:
|
|
418
420
|
maybe_event = self._parts_manager.handle_text_delta(
|
|
419
|
-
vendor_part_id='content',
|
|
421
|
+
vendor_part_id='content',
|
|
422
|
+
content=content,
|
|
423
|
+
thinking_tags=self._model_profile.thinking_tags,
|
|
420
424
|
)
|
|
421
425
|
if maybe_event is not None: # pragma: no branch
|
|
422
426
|
yield maybe_event
|
|
@@ -33,6 +33,7 @@ from ..messages import (
|
|
|
33
33
|
UserPromptPart,
|
|
34
34
|
VideoUrl,
|
|
35
35
|
)
|
|
36
|
+
from ..profiles import ModelProfile
|
|
36
37
|
from ..settings import ModelSettings
|
|
37
38
|
from ..tools import ToolDefinition
|
|
38
39
|
from . import Model, ModelRequestParameters, StreamedResponse, check_allow_model_requests
|
|
@@ -244,7 +245,7 @@ class HuggingFaceModel(Model):
|
|
|
244
245
|
items: list[ModelResponsePart] = []
|
|
245
246
|
|
|
246
247
|
if content is not None:
|
|
247
|
-
items.extend(split_content_into_text_and_thinking(content))
|
|
248
|
+
items.extend(split_content_into_text_and_thinking(content, self.profile.thinking_tags))
|
|
248
249
|
if tool_calls is not None:
|
|
249
250
|
for c in tool_calls:
|
|
250
251
|
items.append(ToolCallPart(c.function.name, c.function.arguments, tool_call_id=c.id))
|
|
@@ -267,6 +268,7 @@ class HuggingFaceModel(Model):
|
|
|
267
268
|
|
|
268
269
|
return HuggingFaceStreamedResponse(
|
|
269
270
|
_model_name=self._model_name,
|
|
271
|
+
_model_profile=self.profile,
|
|
270
272
|
_response=peekable_response,
|
|
271
273
|
_timestamp=datetime.fromtimestamp(first_chunk.created, tz=timezone.utc),
|
|
272
274
|
)
|
|
@@ -412,6 +414,7 @@ class HuggingFaceStreamedResponse(StreamedResponse):
|
|
|
412
414
|
"""Implementation of `StreamedResponse` for Hugging Face models."""
|
|
413
415
|
|
|
414
416
|
_model_name: str
|
|
417
|
+
_model_profile: ModelProfile
|
|
415
418
|
_response: AsyncIterable[ChatCompletionStreamOutput]
|
|
416
419
|
_timestamp: datetime
|
|
417
420
|
|
|
@@ -428,7 +431,9 @@ class HuggingFaceStreamedResponse(StreamedResponse):
|
|
|
428
431
|
content = choice.delta.content
|
|
429
432
|
if content:
|
|
430
433
|
maybe_event = self._parts_manager.handle_text_delta(
|
|
431
|
-
vendor_part_id='content',
|
|
434
|
+
vendor_part_id='content',
|
|
435
|
+
content=content,
|
|
436
|
+
thinking_tags=self._model_profile.thinking_tags,
|
|
432
437
|
)
|
|
433
438
|
if maybe_event is not None: # pragma: no branch
|
|
434
439
|
yield maybe_event
|
pydantic_ai/models/mistral.py
CHANGED
|
@@ -333,7 +333,7 @@ class MistralModel(Model):
|
|
|
333
333
|
|
|
334
334
|
parts: list[ModelResponsePart] = []
|
|
335
335
|
if text := _map_content(content):
|
|
336
|
-
parts.extend(split_content_into_text_and_thinking(text))
|
|
336
|
+
parts.extend(split_content_into_text_and_thinking(text, self.profile.thinking_tags))
|
|
337
337
|
|
|
338
338
|
if isinstance(tool_calls, list):
|
|
339
339
|
for tool_call in tool_calls:
|
pydantic_ai/models/openai.py
CHANGED
|
@@ -37,7 +37,7 @@ from ..messages import (
|
|
|
37
37
|
UserPromptPart,
|
|
38
38
|
VideoUrl,
|
|
39
39
|
)
|
|
40
|
-
from ..profiles import ModelProfileSpec
|
|
40
|
+
from ..profiles import ModelProfile, ModelProfileSpec
|
|
41
41
|
from ..settings import ModelSettings
|
|
42
42
|
from ..tools import ToolDefinition
|
|
43
43
|
from . import (
|
|
@@ -120,10 +120,10 @@ class OpenAIModelSettings(ModelSettings, total=False):
|
|
|
120
120
|
See [OpenAI's safety best practices](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids) for more details.
|
|
121
121
|
"""
|
|
122
122
|
|
|
123
|
-
openai_service_tier: Literal['auto', 'default', 'flex']
|
|
123
|
+
openai_service_tier: Literal['auto', 'default', 'flex', 'priority']
|
|
124
124
|
"""The service tier to use for the model request.
|
|
125
125
|
|
|
126
|
-
Currently supported values are `auto`, `default`, and `
|
|
126
|
+
Currently supported values are `auto`, `default`, `flex`, and `priority`.
|
|
127
127
|
For more information, see [OpenAI's service tiers documentation](https://platform.openai.com/docs/api-reference/chat/object#chat/object-service_tier).
|
|
128
128
|
"""
|
|
129
129
|
|
|
@@ -407,7 +407,7 @@ class OpenAIModel(Model):
|
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
if choice.message.content is not None:
|
|
410
|
-
items.extend(split_content_into_text_and_thinking(choice.message.content))
|
|
410
|
+
items.extend(split_content_into_text_and_thinking(choice.message.content, self.profile.thinking_tags))
|
|
411
411
|
if choice.message.tool_calls is not None:
|
|
412
412
|
for c in choice.message.tool_calls:
|
|
413
413
|
part = ToolCallPart(c.function.name, c.function.arguments, tool_call_id=c.id)
|
|
@@ -433,6 +433,7 @@ class OpenAIModel(Model):
|
|
|
433
433
|
|
|
434
434
|
return OpenAIStreamedResponse(
|
|
435
435
|
_model_name=self._model_name,
|
|
436
|
+
_model_profile=self.profile,
|
|
436
437
|
_response=peekable_response,
|
|
437
438
|
_timestamp=number_to_datetime(first_chunk.created),
|
|
438
439
|
)
|
|
@@ -803,6 +804,7 @@ class OpenAIResponsesModel(Model):
|
|
|
803
804
|
top_p=sampling_settings.get('top_p', NOT_GIVEN),
|
|
804
805
|
truncation=model_settings.get('openai_truncation', NOT_GIVEN),
|
|
805
806
|
timeout=model_settings.get('timeout', NOT_GIVEN),
|
|
807
|
+
service_tier=model_settings.get('openai_service_tier', NOT_GIVEN),
|
|
806
808
|
reasoning=reasoning,
|
|
807
809
|
user=model_settings.get('openai_user', NOT_GIVEN),
|
|
808
810
|
text=text or NOT_GIVEN,
|
|
@@ -1008,6 +1010,7 @@ class OpenAIStreamedResponse(StreamedResponse):
|
|
|
1008
1010
|
"""Implementation of `StreamedResponse` for OpenAI models."""
|
|
1009
1011
|
|
|
1010
1012
|
_model_name: OpenAIModelName
|
|
1013
|
+
_model_profile: ModelProfile
|
|
1011
1014
|
_response: AsyncIterable[ChatCompletionChunk]
|
|
1012
1015
|
_timestamp: datetime
|
|
1013
1016
|
|
|
@@ -1024,7 +1027,9 @@ class OpenAIStreamedResponse(StreamedResponse):
|
|
|
1024
1027
|
content = choice.delta.content
|
|
1025
1028
|
if content:
|
|
1026
1029
|
maybe_event = self._parts_manager.handle_text_delta(
|
|
1027
|
-
vendor_part_id='content',
|
|
1030
|
+
vendor_part_id='content',
|
|
1031
|
+
content=content,
|
|
1032
|
+
thinking_tags=self._model_profile.thinking_tags,
|
|
1028
1033
|
)
|
|
1029
1034
|
if maybe_event is not None: # pragma: no branch
|
|
1030
1035
|
yield maybe_event
|
pydantic_ai/models/test.py
CHANGED
|
@@ -123,7 +123,9 @@ class TestModel(Model):
|
|
|
123
123
|
|
|
124
124
|
model_response = self._request(messages, model_settings, model_request_parameters)
|
|
125
125
|
yield TestStreamedResponse(
|
|
126
|
-
_model_name=self._model_name,
|
|
126
|
+
_model_name=self._model_name,
|
|
127
|
+
_structured_response=model_response,
|
|
128
|
+
_messages=messages,
|
|
127
129
|
)
|
|
128
130
|
|
|
129
131
|
@property
|
pydantic_ai/profiles/__init__.py
CHANGED
|
@@ -35,6 +35,9 @@ class ModelProfile:
|
|
|
35
35
|
json_schema_transformer: type[JsonSchemaTransformer] | None = None
|
|
36
36
|
"""The transformer to use to make JSON schemas for tools and structured output compatible with the model."""
|
|
37
37
|
|
|
38
|
+
thinking_tags: tuple[str, str] = ('<think>', '</think>')
|
|
39
|
+
"""The tags used to indicate thinking parts in the model's output. Defaults to ('<think>', '</think>')."""
|
|
40
|
+
|
|
38
41
|
@classmethod
|
|
39
42
|
def from_profile(cls, profile: ModelProfile | None) -> Self:
|
|
40
43
|
"""Build a ModelProfile subclass instance from a ModelProfile instance."""
|
pydantic_ai/providers/vercel.py
CHANGED
|
@@ -98,10 +98,16 @@ class VercelProvider(Provider[AsyncOpenAI]):
|
|
|
98
98
|
'or pass the API key via `VercelProvider(api_key=...)` to use the Vercel provider.'
|
|
99
99
|
)
|
|
100
100
|
|
|
101
|
+
default_headers = {'http-referer': 'https://ai.pydantic.dev/', 'x-title': 'pydantic-ai'}
|
|
102
|
+
|
|
101
103
|
if openai_client is not None:
|
|
102
104
|
self._client = openai_client
|
|
103
105
|
elif http_client is not None:
|
|
104
|
-
self._client = AsyncOpenAI(
|
|
106
|
+
self._client = AsyncOpenAI(
|
|
107
|
+
base_url=self.base_url, api_key=api_key, http_client=http_client, default_headers=default_headers
|
|
108
|
+
)
|
|
105
109
|
else:
|
|
106
110
|
http_client = cached_async_http_client(provider='vercel')
|
|
107
|
-
self._client = AsyncOpenAI(
|
|
111
|
+
self._client = AsyncOpenAI(
|
|
112
|
+
base_url=self.base_url, api_key=api_key, http_client=http_client, default_headers=default_headers
|
|
113
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-slim
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.11
|
|
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.
|
|
33
|
+
Requires-Dist: pydantic-graph==0.4.11
|
|
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.16.0; (platform_system != 'Emscripten') and extra == 'c
|
|
|
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.
|
|
54
|
+
Requires-Dist: pydantic-evals==0.4.11; extra == 'evals'
|
|
55
55
|
Provides-Extra: google
|
|
56
56
|
Requires-Dist: google-genai>=1.24.0; extra == 'google'
|
|
57
57
|
Provides-Extra: groq
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
pydantic_ai/__init__.py,sha256=h6Rll8pEzUUUX6SckosummoAFbq7ctfBlI6WSyaXR4I,1300
|
|
2
2
|
pydantic_ai/__main__.py,sha256=Q_zJU15DUA01YtlJ2mnaLCoId2YmgmreVEERGuQT-Y0,132
|
|
3
3
|
pydantic_ai/_a2a.py,sha256=Tw_j9VRud0rLEk5kRs4GhRyhWYioXnsoZaTTyISq4M4,12126
|
|
4
|
-
pydantic_ai/_agent_graph.py,sha256
|
|
4
|
+
pydantic_ai/_agent_graph.py,sha256=-D_X7qyg4fHRbgR9ffKM_FU4KZ3qas-YgVvSmS0eXeI,37347
|
|
5
5
|
pydantic_ai/_cli.py,sha256=YkiW2u9HGPd9fsgo9dpK1DZvtUPk4uXGQJcm75XgfhU,13250
|
|
6
6
|
pydantic_ai/_function_schema.py,sha256=6Xuash0DVpfPF0rWQce0bhtgti8YRyk3B1-OK_n6dqs,11099
|
|
7
7
|
pydantic_ai/_griffe.py,sha256=Ugft16ZHw9CN_6-lW0Svn6jESK9zHXO_x4utkGBkbBI,5253
|
|
8
8
|
pydantic_ai/_mcp.py,sha256=PuvwnlLjv7YYOa9AZJCrklevBug99zGMhwJCBGG7BHQ,5626
|
|
9
9
|
pydantic_ai/_output.py,sha256=2k-nxfPNLJEb-wjnPhQo63lh-yQH1XsIhNG1hjsrim0,37462
|
|
10
|
-
pydantic_ai/_parts_manager.py,sha256=
|
|
10
|
+
pydantic_ai/_parts_manager.py,sha256=lWXN75zLy_MSDz4Wib65lqIPHk1SY8KDU8_OYaxG3yw,17788
|
|
11
11
|
pydantic_ai/_run_context.py,sha256=pqb_HPXytE1Z9zZRRuBboRYes_tVTC75WGTpZgnb2Ko,1691
|
|
12
12
|
pydantic_ai/_system_prompt.py,sha256=lUSq-gDZjlYTGtd6BUm54yEvTIvgdwBmJ8mLsNZZtYU,1142
|
|
13
|
-
pydantic_ai/_thinking_part.py,sha256=
|
|
13
|
+
pydantic_ai/_thinking_part.py,sha256=x80-Vkon16GOyq3W6f2qzafTVPC5dCgF7QD3k8ZMmYU,1304
|
|
14
14
|
pydantic_ai/_tool_manager.py,sha256=BdjPntbSshNvYVpYZUNxb-yib5n4GPqcDinbNpzhBVo,8960
|
|
15
15
|
pydantic_ai/_utils.py,sha256=0Pte4mjir4YFZJTa6i-H6Cra9NbVwSKjOKegArzUggk,16283
|
|
16
|
-
pydantic_ai/ag_ui.py,sha256=
|
|
17
|
-
pydantic_ai/agent.py,sha256=
|
|
16
|
+
pydantic_ai/ag_ui.py,sha256=snIBVMcUUm3WWZ5P5orikyAzvM-7vGunNMgIudhvK-A,26156
|
|
17
|
+
pydantic_ai/agent.py,sha256=VJOvadfilVm60BxWqxtXrzmNTnN8tuhapvFk2r13RO4,107234
|
|
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
21
|
pydantic_ai/format_prompt.py,sha256=Or-Ytq55RQb1UJqy2HKIyPpZ-knWXfdDP3Z6tNc6Orw,4244
|
|
22
22
|
pydantic_ai/mcp.py,sha256=v_f4CRzJ399uPC96aqTiEzpaYvuo6vIQyLIpXQBudsY,26271
|
|
23
|
-
pydantic_ai/messages.py,sha256=
|
|
23
|
+
pydantic_ai/messages.py,sha256=jeaB0o4T4YUdEtnW-whf_2jAiXZ3HPSInvccqTwUcgE,42545
|
|
24
24
|
pydantic_ai/output.py,sha256=54Cwd1RruXlA5hucZ1h-SxFrzKHJuLvYvLtH9iyg2GI,11988
|
|
25
25
|
pydantic_ai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
26
|
pydantic_ai/result.py,sha256=bFo2oQZiSw1wvpa6k3rZ3ae2KhzoiQno0F8glKWpvgg,25328
|
|
@@ -34,26 +34,26 @@ pydantic_ai/common_tools/tavily.py,sha256=Q1xxSF5HtXAaZ10Pp-OaDOHXwJf2mco9wScGEQ
|
|
|
34
34
|
pydantic_ai/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
35
|
pydantic_ai/ext/aci.py,sha256=vUaNIj6pRM52x6RkPW_DohSYxJPm75pPUfOMw2i5Xx0,2515
|
|
36
36
|
pydantic_ai/ext/langchain.py,sha256=GemxfhpyG1JPxj69PbRiSJANnY8Q5s4hSB7wqt-uTbo,2266
|
|
37
|
-
pydantic_ai/models/__init__.py,sha256=
|
|
37
|
+
pydantic_ai/models/__init__.py,sha256=UDi-zXjRt_Zb8kaN5OKMxGXnJtDkROpfa66tSz_wNdI,30884
|
|
38
38
|
pydantic_ai/models/anthropic.py,sha256=dMPFqIeYCIhoeU_4uk9PmZYQWL1NbkSVmVrBKXplTiI,24167
|
|
39
39
|
pydantic_ai/models/bedrock.py,sha256=O6wKZDu4L18L1L2Nsa-XMW4ch073FjcLKRA5t_NXcHU,29511
|
|
40
|
-
pydantic_ai/models/cohere.py,sha256=
|
|
40
|
+
pydantic_ai/models/cohere.py,sha256=GYhQ6jkCYDHf3ca1835aig9o59XTvsyw4ISAVThYejA,12828
|
|
41
41
|
pydantic_ai/models/fallback.py,sha256=URaV-dTQWkg99xrlkmknue5lXZWDcEt7cJ1Vsky4oB4,5130
|
|
42
42
|
pydantic_ai/models/function.py,sha256=iHhG6GYN14XDo3_qbdliv_umY10B7-k11aoDoVF4xP8,13563
|
|
43
|
-
pydantic_ai/models/gemini.py,sha256=
|
|
44
|
-
pydantic_ai/models/google.py,sha256=
|
|
45
|
-
pydantic_ai/models/groq.py,sha256=
|
|
46
|
-
pydantic_ai/models/huggingface.py,sha256=
|
|
43
|
+
pydantic_ai/models/gemini.py,sha256=J-05fngctXSqk3NzLaemt0h6r3S6jmr9ArvlWQE5Q0A,38124
|
|
44
|
+
pydantic_ai/models/google.py,sha256=PNN5Z5VYPioT0-FzS4PoZ33es26AfUqwMBLfHhrElnw,24380
|
|
45
|
+
pydantic_ai/models/groq.py,sha256=JX3Hi8tUJTsTj2A6CGoDhpW4IwNUxgOk0Ta58OCEL_A,19035
|
|
46
|
+
pydantic_ai/models/huggingface.py,sha256=g4Z2C_e_OddYyGKLSOtP4nCL-AbWxmOdkW4zFcFtLq0,19222
|
|
47
47
|
pydantic_ai/models/instrumented.py,sha256=aqvzspcGexn1Molbu6Mn4EEPRBSoQCCCS_yknJvJJ-8,16205
|
|
48
48
|
pydantic_ai/models/mcp_sampling.py,sha256=q9nnjNEAAbhrfRc_Qw5z9TtCHMG_SwlCWW9FvKWjh8k,3395
|
|
49
|
-
pydantic_ai/models/mistral.py,sha256=
|
|
50
|
-
pydantic_ai/models/openai.py,sha256=
|
|
51
|
-
pydantic_ai/models/test.py,sha256=
|
|
49
|
+
pydantic_ai/models/mistral.py,sha256=bj56Meckuji8r4vowiFJMDSli-HZktocqSqtbzgpXa0,31455
|
|
50
|
+
pydantic_ai/models/openai.py,sha256=Soqb7kZpQLBS6En7hVlhzBMlS07rjISJ9IlH96bBBBU,56122
|
|
51
|
+
pydantic_ai/models/test.py,sha256=lGMblastixKF_f5MhP3TcvLWx7jj94H4ohmL7DMpdGo,18482
|
|
52
52
|
pydantic_ai/models/wrapper.py,sha256=A5-ncYhPF8c9S_czGoXkd55s2KOQb65p3jbVpwZiFPA,2043
|
|
53
|
-
pydantic_ai/profiles/__init__.py,sha256=
|
|
53
|
+
pydantic_ai/profiles/__init__.py,sha256=uC1_64Pb0O1IMt_SwzvU3W7a2_T3pvdoSDcm8_WI7hw,2592
|
|
54
54
|
pydantic_ai/profiles/_json_schema.py,sha256=sTNHkaK0kbwmbldZp9JRGQNax0f5Qvwy0HkWuu_nGxU,7179
|
|
55
55
|
pydantic_ai/profiles/amazon.py,sha256=O4ijm1Lpz01vaSiHrkSeGQhbCKV5lyQVtHYqh0pCW_k,339
|
|
56
|
-
pydantic_ai/profiles/anthropic.py,sha256=
|
|
56
|
+
pydantic_ai/profiles/anthropic.py,sha256=J9N46G8eOjHdQ5CwZSLiwGdPb0eeIMdsMjwosDpvNhI,275
|
|
57
57
|
pydantic_ai/profiles/cohere.py,sha256=lcL34Ht1jZopwuqoU6OV9l8vN4zwF-jiPjlsEABbSRo,215
|
|
58
58
|
pydantic_ai/profiles/deepseek.py,sha256=DS_idprnXpMliKziKF0k1neLDJOwUvpatZ3YLaiYnCM,219
|
|
59
59
|
pydantic_ai/profiles/google.py,sha256=cd5zwtx0MU1Xwm8c-oqi2_OJ2-PMJ8Vy23mxvSJF7ik,4856
|
|
@@ -83,7 +83,7 @@ pydantic_ai/providers/moonshotai.py,sha256=3BAE9eC9QaD3kblVwxtQWEln0-PhgK7bRvrYT
|
|
|
83
83
|
pydantic_ai/providers/openai.py,sha256=7iGij0EaFylab7dTZAZDgXr78tr-HsZrn9EI9AkWBNQ,3091
|
|
84
84
|
pydantic_ai/providers/openrouter.py,sha256=NXjNdnlXIBrBMMqbzcWQnowXOuZh4NHikXenBn5h3mc,4061
|
|
85
85
|
pydantic_ai/providers/together.py,sha256=zFVSMSm5jXbpkNouvBOTjWrPmlPpCp6sQS5LMSyVjrQ,3482
|
|
86
|
-
pydantic_ai/providers/vercel.py,sha256=
|
|
86
|
+
pydantic_ai/providers/vercel.py,sha256=wFIfyfD2RCAVRWtveDDMjumOkP8v9AHy94KV1HXF180,4285
|
|
87
87
|
pydantic_ai/toolsets/__init__.py,sha256=JCnqqAFeuHhmVW4XK0LM6Op_9B1cvsQUJ3vTmQ9Z5cQ,590
|
|
88
88
|
pydantic_ai/toolsets/abstract.py,sha256=LqunlpwUsoHVn4VMtdjEoLY5kiMUF74PZ4KW539K8tQ,6027
|
|
89
89
|
pydantic_ai/toolsets/combined.py,sha256=UBSZ5quJAm4aITkI4enOTJ6sEDndkJ2sKvT1sTeX5LU,3440
|
|
@@ -94,8 +94,8 @@ pydantic_ai/toolsets/prefixed.py,sha256=MIStkzUdiU0rk2Y6P19IrTBxspH5pTstGxsqCBt-
|
|
|
94
94
|
pydantic_ai/toolsets/prepared.py,sha256=Zjfz6S8In6PBVxoKFN9sKPN984zO6t0awB7Lnq5KODw,1431
|
|
95
95
|
pydantic_ai/toolsets/renamed.py,sha256=JuLHpi-hYPiSPlaTpN8WiXLiGsywYK0axi2lW2Qs75k,1637
|
|
96
96
|
pydantic_ai/toolsets/wrapper.py,sha256=WjLoiM1WDuffSJ4mDS6pZrEZGHgZ421fjrqFcB66W94,1205
|
|
97
|
-
pydantic_ai_slim-0.4.
|
|
98
|
-
pydantic_ai_slim-0.4.
|
|
99
|
-
pydantic_ai_slim-0.4.
|
|
100
|
-
pydantic_ai_slim-0.4.
|
|
101
|
-
pydantic_ai_slim-0.4.
|
|
97
|
+
pydantic_ai_slim-0.4.11.dist-info/METADATA,sha256=csPdqlBPAN-VkDDT1zV3WRxgwQLM_6saa0dNDI9Iyqs,4176
|
|
98
|
+
pydantic_ai_slim-0.4.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
99
|
+
pydantic_ai_slim-0.4.11.dist-info/entry_points.txt,sha256=kbKxe2VtDCYS06hsI7P3uZGxcVC08-FPt1rxeiMpIps,50
|
|
100
|
+
pydantic_ai_slim-0.4.11.dist-info/licenses/LICENSE,sha256=vA6Jc482lEyBBuGUfD1pYx-cM7jxvLYOxPidZ30t_PQ,1100
|
|
101
|
+
pydantic_ai_slim-0.4.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|