pydantic-ai-slim 0.0.20__py3-none-any.whl → 0.0.21__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/_parts_manager.py +1 -1
- pydantic_ai/_result.py +3 -7
- pydantic_ai/_utils.py +1 -56
- pydantic_ai/agent.py +34 -30
- pydantic_ai/messages.py +21 -46
- pydantic_ai/models/__init__.py +100 -57
- pydantic_ai/models/anthropic.py +17 -10
- pydantic_ai/models/cohere.py +37 -25
- pydantic_ai/models/gemini.py +20 -6
- pydantic_ai/models/groq.py +19 -17
- pydantic_ai/models/mistral.py +22 -23
- pydantic_ai/models/openai.py +19 -11
- pydantic_ai/models/test.py +37 -22
- pydantic_ai/result.py +1 -1
- pydantic_ai/settings.py +41 -1
- pydantic_ai/tools.py +11 -8
- {pydantic_ai_slim-0.0.20.dist-info → pydantic_ai_slim-0.0.21.dist-info}/METADATA +2 -2
- pydantic_ai_slim-0.0.21.dist-info/RECORD +29 -0
- pydantic_ai/models/ollama.py +0 -123
- pydantic_ai_slim-0.0.20.dist-info/RECORD +0 -30
- {pydantic_ai_slim-0.0.20.dist-info → pydantic_ai_slim-0.0.21.dist-info}/WHEEL +0 -0
pydantic_ai/models/test.py
CHANGED
|
@@ -12,7 +12,6 @@ import pydantic_core
|
|
|
12
12
|
|
|
13
13
|
from .. import _utils
|
|
14
14
|
from ..messages import (
|
|
15
|
-
ArgsJson,
|
|
16
15
|
ModelMessage,
|
|
17
16
|
ModelRequest,
|
|
18
17
|
ModelResponse,
|
|
@@ -34,6 +33,20 @@ from . import (
|
|
|
34
33
|
from .function import _estimate_string_tokens, _estimate_usage # pyright: ignore[reportPrivateUsage]
|
|
35
34
|
|
|
36
35
|
|
|
36
|
+
@dataclass
|
|
37
|
+
class _TextResult:
|
|
38
|
+
"""A private wrapper class to tag a result that came from the custom_result_text field."""
|
|
39
|
+
|
|
40
|
+
value: str | None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class _FunctionToolResult:
|
|
45
|
+
"""A wrapper class to tag a result that came from the custom_result_args field."""
|
|
46
|
+
|
|
47
|
+
value: Any | None
|
|
48
|
+
|
|
49
|
+
|
|
37
50
|
@dataclass
|
|
38
51
|
class TestModel(Model):
|
|
39
52
|
"""A model specifically for testing purposes.
|
|
@@ -53,7 +66,7 @@ class TestModel(Model):
|
|
|
53
66
|
call_tools: list[str] | Literal['all'] = 'all'
|
|
54
67
|
"""List of tools to call. If `'all'`, all tools will be called."""
|
|
55
68
|
custom_result_text: str | None = None
|
|
56
|
-
"""If set, this text is
|
|
69
|
+
"""If set, this text is returned as the final result."""
|
|
57
70
|
custom_result_args: Any | None = None
|
|
58
71
|
"""If set, these args will be passed to the result tool."""
|
|
59
72
|
seed: int = 0
|
|
@@ -95,21 +108,21 @@ class TestModel(Model):
|
|
|
95
108
|
if self.custom_result_text is not None:
|
|
96
109
|
assert allow_text_result, 'Plain response not allowed, but `custom_result_text` is set.'
|
|
97
110
|
assert self.custom_result_args is None, 'Cannot set both `custom_result_text` and `custom_result_args`.'
|
|
98
|
-
result:
|
|
111
|
+
result: _TextResult | _FunctionToolResult = _TextResult(self.custom_result_text)
|
|
99
112
|
elif self.custom_result_args is not None:
|
|
100
113
|
assert result_tools is not None, 'No result tools provided, but `custom_result_args` is set.'
|
|
101
114
|
result_tool = result_tools[0]
|
|
102
115
|
|
|
103
116
|
if k := result_tool.outer_typed_dict_key:
|
|
104
|
-
result =
|
|
117
|
+
result = _FunctionToolResult({k: self.custom_result_args})
|
|
105
118
|
else:
|
|
106
|
-
result =
|
|
119
|
+
result = _FunctionToolResult(self.custom_result_args)
|
|
107
120
|
elif allow_text_result:
|
|
108
|
-
result =
|
|
121
|
+
result = _TextResult(None)
|
|
109
122
|
elif result_tools:
|
|
110
|
-
result =
|
|
123
|
+
result = _FunctionToolResult(None)
|
|
111
124
|
else:
|
|
112
|
-
result =
|
|
125
|
+
result = _TextResult(None)
|
|
113
126
|
|
|
114
127
|
return TestAgentModel(tool_calls, result, result_tools, self.seed)
|
|
115
128
|
|
|
@@ -126,7 +139,7 @@ class TestAgentModel(AgentModel):
|
|
|
126
139
|
|
|
127
140
|
tool_calls: list[tuple[str, ToolDefinition]]
|
|
128
141
|
# left means the text is plain text; right means it's a function call
|
|
129
|
-
result:
|
|
142
|
+
result: _TextResult | _FunctionToolResult
|
|
130
143
|
result_tools: list[ToolDefinition]
|
|
131
144
|
seed: int
|
|
132
145
|
model_name: str = 'test'
|
|
@@ -152,7 +165,7 @@ class TestAgentModel(AgentModel):
|
|
|
152
165
|
# if there are tools, the first thing we want to do is call all of them
|
|
153
166
|
if self.tool_calls and not any(isinstance(m, ModelResponse) for m in messages):
|
|
154
167
|
return ModelResponse(
|
|
155
|
-
parts=[ToolCallPart
|
|
168
|
+
parts=[ToolCallPart(name, self.gen_tool_args(args)) for name, args in self.tool_calls],
|
|
156
169
|
model_name=self.model_name,
|
|
157
170
|
)
|
|
158
171
|
|
|
@@ -166,7 +179,7 @@ class TestAgentModel(AgentModel):
|
|
|
166
179
|
# Handle retries for both function tools and result tools
|
|
167
180
|
# Check function tools first
|
|
168
181
|
retry_parts: list[ModelResponsePart] = [
|
|
169
|
-
ToolCallPart
|
|
182
|
+
ToolCallPart(name, self.gen_tool_args(args))
|
|
170
183
|
for name, args in self.tool_calls
|
|
171
184
|
if name in new_retry_names
|
|
172
185
|
]
|
|
@@ -174,15 +187,20 @@ class TestAgentModel(AgentModel):
|
|
|
174
187
|
if self.result_tools:
|
|
175
188
|
retry_parts.extend(
|
|
176
189
|
[
|
|
177
|
-
ToolCallPart
|
|
190
|
+
ToolCallPart(
|
|
191
|
+
tool.name,
|
|
192
|
+
self.result.value
|
|
193
|
+
if isinstance(self.result, _FunctionToolResult) and self.result.value is not None
|
|
194
|
+
else self.gen_tool_args(tool),
|
|
195
|
+
)
|
|
178
196
|
for tool in self.result_tools
|
|
179
197
|
if tool.name in new_retry_names
|
|
180
198
|
]
|
|
181
199
|
)
|
|
182
200
|
return ModelResponse(parts=retry_parts, model_name=self.model_name)
|
|
183
201
|
|
|
184
|
-
if
|
|
185
|
-
if response_text.value is None:
|
|
202
|
+
if isinstance(self.result, _TextResult):
|
|
203
|
+
if (response_text := self.result.value) is None:
|
|
186
204
|
# build up details of tool responses
|
|
187
205
|
output: dict[str, Any] = {}
|
|
188
206
|
for message in messages:
|
|
@@ -197,20 +215,18 @@ class TestAgentModel(AgentModel):
|
|
|
197
215
|
else:
|
|
198
216
|
return ModelResponse(parts=[TextPart('success (no tool calls)')], model_name=self.model_name)
|
|
199
217
|
else:
|
|
200
|
-
return ModelResponse(parts=[TextPart(response_text
|
|
218
|
+
return ModelResponse(parts=[TextPart(response_text)], model_name=self.model_name)
|
|
201
219
|
else:
|
|
202
220
|
assert self.result_tools, 'No result tools provided'
|
|
203
|
-
custom_result_args = self.result.
|
|
221
|
+
custom_result_args = self.result.value
|
|
204
222
|
result_tool = self.result_tools[self.seed % len(self.result_tools)]
|
|
205
223
|
if custom_result_args is not None:
|
|
206
224
|
return ModelResponse(
|
|
207
|
-
parts=[ToolCallPart
|
|
225
|
+
parts=[ToolCallPart(result_tool.name, custom_result_args)], model_name=self.model_name
|
|
208
226
|
)
|
|
209
227
|
else:
|
|
210
228
|
response_args = self.gen_tool_args(result_tool)
|
|
211
|
-
return ModelResponse(
|
|
212
|
-
parts=[ToolCallPart.from_raw_args(result_tool.name, response_args)], model_name=self.model_name
|
|
213
|
-
)
|
|
229
|
+
return ModelResponse(parts=[ToolCallPart(result_tool.name, response_args)], model_name=self.model_name)
|
|
214
230
|
|
|
215
231
|
|
|
216
232
|
@dataclass
|
|
@@ -241,9 +257,8 @@ class TestStreamedResponse(StreamedResponse):
|
|
|
241
257
|
self._usage += _get_string_usage(word)
|
|
242
258
|
yield self._parts_manager.handle_text_delta(vendor_part_id=i, content=word)
|
|
243
259
|
else:
|
|
244
|
-
args = part.args.args_json if isinstance(part.args, ArgsJson) else part.args.args_dict
|
|
245
260
|
yield self._parts_manager.handle_tool_call_part(
|
|
246
|
-
vendor_part_id=i, tool_name=part.tool_name, args=args, tool_call_id=part.tool_call_id
|
|
261
|
+
vendor_part_id=i, tool_name=part.tool_name, args=part.args, tool_call_id=part.tool_call_id
|
|
247
262
|
)
|
|
248
263
|
|
|
249
264
|
def timestamp(self) -> datetime:
|
pydantic_ai/result.py
CHANGED
|
@@ -46,7 +46,7 @@ A function that always takes and returns the same type of data (which is the res
|
|
|
46
46
|
* may or may not take [`RunContext`][pydantic_ai.tools.RunContext] as a first argument
|
|
47
47
|
* may or may not be async
|
|
48
48
|
|
|
49
|
-
Usage `ResultValidatorFunc[
|
|
49
|
+
Usage `ResultValidatorFunc[AgentDepsT, T]`.
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
52
|
_logfire = logfire_api.Logfire(otel_scope='pydantic-ai')
|
pydantic_ai/settings.py
CHANGED
|
@@ -80,11 +80,51 @@ class ModelSettings(TypedDict, total=False):
|
|
|
80
80
|
"""Whether to allow parallel tool calls.
|
|
81
81
|
|
|
82
82
|
Supported by:
|
|
83
|
-
* OpenAI
|
|
83
|
+
* OpenAI (some models, not o1)
|
|
84
84
|
* Groq
|
|
85
85
|
* Anthropic
|
|
86
86
|
"""
|
|
87
87
|
|
|
88
|
+
seed: int
|
|
89
|
+
"""The random seed to use for the model, theoretically allowing for deterministic results.
|
|
90
|
+
|
|
91
|
+
Supported by:
|
|
92
|
+
* OpenAI
|
|
93
|
+
* Groq
|
|
94
|
+
* Cohere
|
|
95
|
+
* Mistral
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
presence_penalty: float
|
|
99
|
+
"""Penalize new tokens based on whether they have appeared in the text so far.
|
|
100
|
+
|
|
101
|
+
Supported by:
|
|
102
|
+
* OpenAI
|
|
103
|
+
* Groq
|
|
104
|
+
* Cohere
|
|
105
|
+
* Gemini
|
|
106
|
+
* Mistral
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
frequency_penalty: float
|
|
110
|
+
"""Penalize new tokens based on their existing frequency in the text so far.
|
|
111
|
+
|
|
112
|
+
Supported by:
|
|
113
|
+
* OpenAI
|
|
114
|
+
* Groq
|
|
115
|
+
* Cohere
|
|
116
|
+
* Gemini
|
|
117
|
+
* Mistral
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
logit_bias: dict[str, int]
|
|
121
|
+
"""Modify the likelihood of specified tokens appearing in the completion.
|
|
122
|
+
|
|
123
|
+
Supported by:
|
|
124
|
+
* OpenAI
|
|
125
|
+
* Groq
|
|
126
|
+
"""
|
|
127
|
+
|
|
88
128
|
|
|
89
129
|
def merge_model_settings(base: ModelSettings | None, overrides: ModelSettings | None) -> ModelSettings | None:
|
|
90
130
|
"""Merge two sets of model settings, preferring the overrides.
|
pydantic_ai/tools.py
CHANGED
|
@@ -79,13 +79,13 @@ SystemPromptFunc = Union[
|
|
|
79
79
|
]
|
|
80
80
|
"""A function that may or maybe not take `RunContext` as an argument, and may or may not be async.
|
|
81
81
|
|
|
82
|
-
Usage `SystemPromptFunc[
|
|
82
|
+
Usage `SystemPromptFunc[AgentDepsT]`.
|
|
83
83
|
"""
|
|
84
84
|
|
|
85
85
|
ToolFuncContext = Callable[Concatenate[RunContext[AgentDepsT], ToolParams], Any]
|
|
86
86
|
"""A tool function that takes `RunContext` as the first argument.
|
|
87
87
|
|
|
88
|
-
Usage `ToolContextFunc[
|
|
88
|
+
Usage `ToolContextFunc[AgentDepsT, ToolParams]`.
|
|
89
89
|
"""
|
|
90
90
|
ToolFuncPlain = Callable[ToolParams, Any]
|
|
91
91
|
"""A tool function that does not take `RunContext` as the first argument.
|
|
@@ -98,7 +98,7 @@ ToolFuncEither = Union[ToolFuncContext[AgentDepsT, ToolParams], ToolFuncPlain[To
|
|
|
98
98
|
This is just a union of [`ToolFuncContext`][pydantic_ai.tools.ToolFuncContext] and
|
|
99
99
|
[`ToolFuncPlain`][pydantic_ai.tools.ToolFuncPlain].
|
|
100
100
|
|
|
101
|
-
Usage `ToolFuncEither[
|
|
101
|
+
Usage `ToolFuncEither[AgentDepsT, ToolParams]`.
|
|
102
102
|
"""
|
|
103
103
|
ToolPrepareFunc: TypeAlias = 'Callable[[RunContext[AgentDepsT], ToolDefinition], Awaitable[ToolDefinition | None]]'
|
|
104
104
|
"""Definition of a function that can prepare a tool definition at call time.
|
|
@@ -125,7 +125,7 @@ def hitchhiker(ctx: RunContext[int], answer: str) -> str:
|
|
|
125
125
|
hitchhiker = Tool(hitchhiker, prepare=only_if_42)
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Usage `ToolPrepareFunc[
|
|
128
|
+
Usage `ToolPrepareFunc[AgentDepsT]`.
|
|
129
129
|
"""
|
|
130
130
|
|
|
131
131
|
DocstringFormat = Literal['google', 'numpy', 'sphinx', 'auto']
|
|
@@ -158,6 +158,9 @@ class Tool(Generic[AgentDepsT]):
|
|
|
158
158
|
_var_positional_field: str | None = field(init=False)
|
|
159
159
|
_validator: SchemaValidator = field(init=False, repr=False)
|
|
160
160
|
_parameters_json_schema: ObjectJsonSchema = field(init=False)
|
|
161
|
+
|
|
162
|
+
# TODO: Move this state off the Tool class, which is otherwise stateless.
|
|
163
|
+
# This should be tracked inside a specific agent run, not the tool.
|
|
161
164
|
current_retry: int = field(default=0, init=False)
|
|
162
165
|
|
|
163
166
|
def __init__(
|
|
@@ -261,13 +264,13 @@ class Tool(Generic[AgentDepsT]):
|
|
|
261
264
|
|
|
262
265
|
async def run(
|
|
263
266
|
self, message: _messages.ToolCallPart, run_context: RunContext[AgentDepsT]
|
|
264
|
-
) -> _messages.
|
|
267
|
+
) -> _messages.ToolReturnPart | _messages.RetryPromptPart:
|
|
265
268
|
"""Run the tool function asynchronously."""
|
|
266
269
|
try:
|
|
267
|
-
if isinstance(message.args,
|
|
268
|
-
args_dict = self._validator.validate_json(message.args
|
|
270
|
+
if isinstance(message.args, str):
|
|
271
|
+
args_dict = self._validator.validate_json(message.args)
|
|
269
272
|
else:
|
|
270
|
-
args_dict = self._validator.validate_python(message.args
|
|
273
|
+
args_dict = self._validator.validate_python(message.args)
|
|
271
274
|
except ValidationError as e:
|
|
272
275
|
return self._on_error(e, message)
|
|
273
276
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-slim
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.21
|
|
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
|
|
@@ -34,7 +34,7 @@ Requires-Dist: anthropic>=0.40.0; extra == 'anthropic'
|
|
|
34
34
|
Provides-Extra: cohere
|
|
35
35
|
Requires-Dist: cohere>=5.13.11; extra == 'cohere'
|
|
36
36
|
Provides-Extra: graph
|
|
37
|
-
Requires-Dist: pydantic-graph==0.0.
|
|
37
|
+
Requires-Dist: pydantic-graph==0.0.21; extra == 'graph'
|
|
38
38
|
Provides-Extra: groq
|
|
39
39
|
Requires-Dist: groq>=0.12.0; extra == 'groq'
|
|
40
40
|
Provides-Extra: logfire
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
pydantic_ai/__init__.py,sha256=FbYetEgT6OO25u2KF5ZnFxKpz5DtnSpfckRXP4mjl8E,489
|
|
2
|
+
pydantic_ai/_griffe.py,sha256=RYRKiLbgG97QxnazbAwlnc74XxevGHLQet-FGfq9qls,3960
|
|
3
|
+
pydantic_ai/_parts_manager.py,sha256=ARfDQY1_5AIY5rNl_M2fAYHEFCe03ZxdhgjHf9qeIKw,11872
|
|
4
|
+
pydantic_ai/_pydantic.py,sha256=dROz3Hmfdi0C2exq88FhefDRVo_8S3rtkXnoUHzsz0c,8753
|
|
5
|
+
pydantic_ai/_result.py,sha256=tN1pVulf_EM4bkBvpNUWPnUXezLY-sBrJEVCFdy2nLU,10264
|
|
6
|
+
pydantic_ai/_system_prompt.py,sha256=602c2jyle2R_SesOrITBDETZqsLk4BZ8Cbo8yEhmx04,1120
|
|
7
|
+
pydantic_ai/_utils.py,sha256=zfuY3NiPPsSM5J1q2JElfbfIa8S1ONGOlC7M-iyBVso,9430
|
|
8
|
+
pydantic_ai/agent.py,sha256=7o7yfatFPBDkrpSi2t0A4xivX7lzlNbOhtIMEJQpLKc,63620
|
|
9
|
+
pydantic_ai/exceptions.py,sha256=eGDKX6bGhgVxXBzu81Sk3iiAkXr0GUtgT7bD5Rxlqpg,2028
|
|
10
|
+
pydantic_ai/format_as_xml.py,sha256=QE7eMlg5-YUMw1_2kcI3h0uKYPZZyGkgXFDtfZTMeeI,4480
|
|
11
|
+
pydantic_ai/messages.py,sha256=kzXn4ZjlX9Sy2KXgFHWYbbwPk7TzTPdztzOJLWEONwU,17101
|
|
12
|
+
pydantic_ai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
pydantic_ai/result.py,sha256=0beXiUfiSb2kVc68iqLeg2qFQW6-mnTC8TFtiQayPDQ,18394
|
|
14
|
+
pydantic_ai/settings.py,sha256=QSqs4_l_Gs2v4oixYNwKQhPiec_m9pn6XEAeUMFxt24,3054
|
|
15
|
+
pydantic_ai/tools.py,sha256=lhupwm815lPlFFS79B0P61AyhUYtepA62LbZOCJrPEY,13205
|
|
16
|
+
pydantic_ai/usage.py,sha256=60d9f6M7YEYuKMbqDGDogX4KsA73fhDtWyDXYXoIPaI,4948
|
|
17
|
+
pydantic_ai/models/__init__.py,sha256=XgZAhiSVVX0TbePHXSxVnDIbG38jQG9g3WRMlA_EHDY,13063
|
|
18
|
+
pydantic_ai/models/anthropic.py,sha256=v2m6zjaezLjtkHO2Rx67rmoN1iOqDeAp9fswJcqRMBA,16967
|
|
19
|
+
pydantic_ai/models/cohere.py,sha256=wyjtD2uwkYYbsXLKwr-flmXSng_Atd-0jqtVDxDie14,10611
|
|
20
|
+
pydantic_ai/models/function.py,sha256=jv2aw5K4KrMIRPFSTiGbBHcv16UZtGEe_1irjTudLg0,9826
|
|
21
|
+
pydantic_ai/models/gemini.py,sha256=espBJbEMZjdzT5fC_rKOHoo_5o5xH-Y1Ea-RZR4JaPs,28222
|
|
22
|
+
pydantic_ai/models/groq.py,sha256=W-uosi9PtvgXp8yoF6w8QZxPtrVjX1fmRQDjQQ10meE,13603
|
|
23
|
+
pydantic_ai/models/mistral.py,sha256=RuRlxTBPGXIpcwTdjX2596uN2tgHBvCDQCWieWa1A_Q,24793
|
|
24
|
+
pydantic_ai/models/openai.py,sha256=6ymsBzyu9WJVewbn3345jt_JoXpUpCLYOQERYJJlyRY,15228
|
|
25
|
+
pydantic_ai/models/test.py,sha256=D_wBpRtrPcikopd5LBYjdAp3q-1gvuB9WnuopBQiRME,16659
|
|
26
|
+
pydantic_ai/models/vertexai.py,sha256=bQZ5W8n4521AH3jTiyP1fOYxtNgCgkhjCbBeASv5Ap8,9388
|
|
27
|
+
pydantic_ai_slim-0.0.21.dist-info/METADATA,sha256=EeGz0ZJG_g_o7xKu-2XiXN2zZsBhGZLwL39QaQGZQdc,2879
|
|
28
|
+
pydantic_ai_slim-0.0.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
29
|
+
pydantic_ai_slim-0.0.21.dist-info/RECORD,,
|
pydantic_ai/models/ollama.py
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations as _annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Literal, Union
|
|
5
|
-
|
|
6
|
-
from httpx import AsyncClient as AsyncHTTPClient
|
|
7
|
-
|
|
8
|
-
from ..tools import ToolDefinition
|
|
9
|
-
from . import (
|
|
10
|
-
AgentModel,
|
|
11
|
-
Model,
|
|
12
|
-
cached_async_http_client,
|
|
13
|
-
check_allow_model_requests,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
from openai import AsyncOpenAI
|
|
18
|
-
except ImportError as e:
|
|
19
|
-
raise ImportError(
|
|
20
|
-
'Please install `openai` to use the OpenAI model, '
|
|
21
|
-
"you can use the `openai` optional group — `pip install 'pydantic-ai-slim[openai]'`"
|
|
22
|
-
) from e
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
from .openai import OpenAIModel
|
|
26
|
-
|
|
27
|
-
CommonOllamaModelNames = Literal[
|
|
28
|
-
'codellama',
|
|
29
|
-
'deepseek-r1',
|
|
30
|
-
'gemma',
|
|
31
|
-
'gemma2',
|
|
32
|
-
'llama3',
|
|
33
|
-
'llama3.1',
|
|
34
|
-
'llama3.2',
|
|
35
|
-
'llama3.2-vision',
|
|
36
|
-
'llama3.3',
|
|
37
|
-
'mistral',
|
|
38
|
-
'mistral-nemo',
|
|
39
|
-
'mixtral',
|
|
40
|
-
'phi3',
|
|
41
|
-
'phi4',
|
|
42
|
-
'qwq',
|
|
43
|
-
'qwen',
|
|
44
|
-
'qwen2',
|
|
45
|
-
'qwen2.5',
|
|
46
|
-
'starcoder2',
|
|
47
|
-
]
|
|
48
|
-
"""This contains just the most common ollama models.
|
|
49
|
-
|
|
50
|
-
For a full list see [ollama.com/library](https://ollama.com/library).
|
|
51
|
-
"""
|
|
52
|
-
OllamaModelName = Union[CommonOllamaModelNames, str]
|
|
53
|
-
"""Possible ollama models.
|
|
54
|
-
|
|
55
|
-
Since Ollama supports hundreds of models, we explicitly list the most models but
|
|
56
|
-
allow any name in the type hints.
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@dataclass(init=False)
|
|
61
|
-
class OllamaModel(Model):
|
|
62
|
-
"""A model that implements Ollama using the OpenAI API.
|
|
63
|
-
|
|
64
|
-
Internally, this uses the [OpenAI Python client](https://github.com/openai/openai-python) to interact with the Ollama server.
|
|
65
|
-
|
|
66
|
-
Apart from `__init__`, all methods are private or match those of the base class.
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
model_name: OllamaModelName
|
|
70
|
-
openai_model: OpenAIModel
|
|
71
|
-
|
|
72
|
-
def __init__(
|
|
73
|
-
self,
|
|
74
|
-
model_name: OllamaModelName,
|
|
75
|
-
*,
|
|
76
|
-
base_url: str | None = 'http://localhost:11434/v1/',
|
|
77
|
-
api_key: str = 'ollama',
|
|
78
|
-
openai_client: AsyncOpenAI | None = None,
|
|
79
|
-
http_client: AsyncHTTPClient | None = None,
|
|
80
|
-
):
|
|
81
|
-
"""Initialize an Ollama model.
|
|
82
|
-
|
|
83
|
-
Ollama has built-in compatability for the OpenAI chat completions API ([source](https://ollama.com/blog/openai-compatibility)), so we reuse the
|
|
84
|
-
[`OpenAIModel`][pydantic_ai.models.openai.OpenAIModel] here.
|
|
85
|
-
|
|
86
|
-
Args:
|
|
87
|
-
model_name: The name of the Ollama model to use. List of models available [here](https://ollama.com/library)
|
|
88
|
-
You must first download the model (`ollama pull <MODEL-NAME>`) in order to use the model
|
|
89
|
-
base_url: The base url for the ollama requests. The default value is the ollama default
|
|
90
|
-
api_key: The API key to use for authentication. Defaults to 'ollama' for local instances,
|
|
91
|
-
but can be customized for proxy setups that require authentication
|
|
92
|
-
openai_client: An existing
|
|
93
|
-
[`AsyncOpenAI`](https://github.com/openai/openai-python?tab=readme-ov-file#async-usage)
|
|
94
|
-
client to use, if provided, `base_url` and `http_client` must be `None`.
|
|
95
|
-
http_client: An existing `httpx.AsyncClient` to use for making HTTP requests.
|
|
96
|
-
"""
|
|
97
|
-
self.model_name = model_name
|
|
98
|
-
if openai_client is not None:
|
|
99
|
-
assert base_url is None, 'Cannot provide both `openai_client` and `base_url`'
|
|
100
|
-
assert http_client is None, 'Cannot provide both `openai_client` and `http_client`'
|
|
101
|
-
self.openai_model = OpenAIModel(model_name=model_name, openai_client=openai_client)
|
|
102
|
-
else:
|
|
103
|
-
# API key is not required for ollama but a value is required to create the client
|
|
104
|
-
http_client_ = http_client or cached_async_http_client()
|
|
105
|
-
oai_client = AsyncOpenAI(base_url=base_url, api_key=api_key, http_client=http_client_)
|
|
106
|
-
self.openai_model = OpenAIModel(model_name=model_name, openai_client=oai_client)
|
|
107
|
-
|
|
108
|
-
async def agent_model(
|
|
109
|
-
self,
|
|
110
|
-
*,
|
|
111
|
-
function_tools: list[ToolDefinition],
|
|
112
|
-
allow_text_result: bool,
|
|
113
|
-
result_tools: list[ToolDefinition],
|
|
114
|
-
) -> AgentModel:
|
|
115
|
-
check_allow_model_requests()
|
|
116
|
-
return await self.openai_model.agent_model(
|
|
117
|
-
function_tools=function_tools,
|
|
118
|
-
allow_text_result=allow_text_result,
|
|
119
|
-
result_tools=result_tools,
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
def name(self) -> str:
|
|
123
|
-
return f'ollama:{self.model_name}'
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
pydantic_ai/__init__.py,sha256=FbYetEgT6OO25u2KF5ZnFxKpz5DtnSpfckRXP4mjl8E,489
|
|
2
|
-
pydantic_ai/_griffe.py,sha256=RYRKiLbgG97QxnazbAwlnc74XxevGHLQet-FGfq9qls,3960
|
|
3
|
-
pydantic_ai/_parts_manager.py,sha256=pMDZs6BGC8EmaNa-73QvuptmxdG2MhBrBLIydCOl-gM,11886
|
|
4
|
-
pydantic_ai/_pydantic.py,sha256=dROz3Hmfdi0C2exq88FhefDRVo_8S3rtkXnoUHzsz0c,8753
|
|
5
|
-
pydantic_ai/_result.py,sha256=zlkI82g78DeLW4zTCP3OgWeMUUOqxeDdu0nxLKYsv9c,10381
|
|
6
|
-
pydantic_ai/_system_prompt.py,sha256=602c2jyle2R_SesOrITBDETZqsLk4BZ8Cbo8yEhmx04,1120
|
|
7
|
-
pydantic_ai/_utils.py,sha256=EHW866W6ZpGJLCWtoEAcwIPeWo9OQFhnD5el2DwVcwc,10949
|
|
8
|
-
pydantic_ai/agent.py,sha256=EwaH207k4LcU_M-DYom8ZFiKMVaHJ2ZobxU2WjjsrSk,63500
|
|
9
|
-
pydantic_ai/exceptions.py,sha256=eGDKX6bGhgVxXBzu81Sk3iiAkXr0GUtgT7bD5Rxlqpg,2028
|
|
10
|
-
pydantic_ai/format_as_xml.py,sha256=QE7eMlg5-YUMw1_2kcI3h0uKYPZZyGkgXFDtfZTMeeI,4480
|
|
11
|
-
pydantic_ai/messages.py,sha256=V6JwFuADF21wKfszqT1CNgiYUeSAuJzjsngD-BJo3Y4,17841
|
|
12
|
-
pydantic_ai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
pydantic_ai/result.py,sha256=uubCdc51fYeZwkGGy1E9x2H9WP8FKoeqNQDaL0vzD1s,18393
|
|
14
|
-
pydantic_ai/settings.py,sha256=Yn4cXoESeJouFktfWqY1o0Exlf6yHfsvf6Uw6iMkuZQ,2278
|
|
15
|
-
pydantic_ai/tools.py,sha256=IrFeIxYQcpRUCrIv9p_4-hqmpjmUNC3dVwvr0gXf-1w,13057
|
|
16
|
-
pydantic_ai/usage.py,sha256=60d9f6M7YEYuKMbqDGDogX4KsA73fhDtWyDXYXoIPaI,4948
|
|
17
|
-
pydantic_ai/models/__init__.py,sha256=-tsz2kKwqvLXhTXk2WvdxB-PoMcaA043sQhkhzM9OFU,11715
|
|
18
|
-
pydantic_ai/models/anthropic.py,sha256=xhTTSq7wniIf4IlTyIAIGSmXpuXUvVOF9I6TRJLfmeo,16645
|
|
19
|
-
pydantic_ai/models/cohere.py,sha256=fGuXNpHUXfhfQ9AyG-Bo-Zet2njuNhjcpELmsCjhsvo,9933
|
|
20
|
-
pydantic_ai/models/function.py,sha256=jv2aw5K4KrMIRPFSTiGbBHcv16UZtGEe_1irjTudLg0,9826
|
|
21
|
-
pydantic_ai/models/gemini.py,sha256=nixBvW4YEtzURAj1qQrVEHKabFN13SUV1QgA1lm_eWo,27595
|
|
22
|
-
pydantic_ai/models/groq.py,sha256=6V_b4Gj63Uask8CfZLO1RjCNdv2FYd8SVjcRtMLMvgo,13355
|
|
23
|
-
pydantic_ai/models/mistral.py,sha256=8kyZiHeAOaZdcJCwFF_xgS_dJkq_e9xwjFOv9IE3YPY,24766
|
|
24
|
-
pydantic_ai/models/ollama.py,sha256=CEgcMW6KliaS7h5Fakx80EmSgm4rDLNjofBOCwM15lM,4288
|
|
25
|
-
pydantic_ai/models/openai.py,sha256=MV7S6hxW6PTOAWNmKBLTZ-e6vkYMByQXT16t4KK54DA,14776
|
|
26
|
-
pydantic_ai/models/test.py,sha256=SKtWqfjc8cb-U2gXJD1U43POxQnHFj_bEx734tCMov0,16328
|
|
27
|
-
pydantic_ai/models/vertexai.py,sha256=bQZ5W8n4521AH3jTiyP1fOYxtNgCgkhjCbBeASv5Ap8,9388
|
|
28
|
-
pydantic_ai_slim-0.0.20.dist-info/METADATA,sha256=3Z-xQLFaAP-JStPOVeiZFwU8ZkIbXzUCkBh8TkLEbuQ,2879
|
|
29
|
-
pydantic_ai_slim-0.0.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
30
|
-
pydantic_ai_slim-0.0.20.dist-info/RECORD,,
|
|
File without changes
|