Skip to content

Commit d51906b

Browse files
authored
BREAKING CHANGE: Remove result_type parameter and similar from Agent (#2441)
1 parent a822df9 commit d51906b

File tree

6 files changed

+16
-225
lines changed

6 files changed

+16
-225
lines changed

docs/changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,14 @@ Pydantic AI is still pre-version 1, so breaking changes will occur, however:
1414

1515
### v0.6.0 (2025-08-06)
1616

17+
This release was meant to clean some old deprecated code, so we can get a step closer to V1.
18+
1719
See [#2440](https://github.com/pydantic/pydantic-ai/pull/2440) - The `next` method was removed from the `Graph` class. Use `async with graph.iter(...) as run: run.next()` instead.
1820

21+
See [#2441](https://github.com/pydantic/pydantic-ai/pull/2441) - The `result_type`, `result_tool_name` and `result_tool_description` arguments were removed from the `Agent` class. Use `output_type` instead.
22+
23+
See [#2441](https://github.com/pydantic/pydantic-ai/pull/2441) - The `result_retries` argument was also removed from the `Agent` class. Use `output_retries` instead.
24+
1925
See [#2443](https://github.com/pydantic/pydantic-ai/pull/2443) - The `data` property was removed from the `FinalResult` class. Use `output` instead.
2026

2127
See [#2445](https://github.com/pydantic/pydantic-ai/pull/2445) - The `get_data` and `validate_structured_result` methods were removed from the

examples/pydantic_ai_examples/flight_booking.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class Failed(BaseModel):
108108
# This agent is responsible for extracting the user's seat selection
109109
seat_preference_agent = Agent[None, SeatPreference | Failed](
110110
'openai:gpt-4o',
111-
output_type=SeatPreference | Failed, # type: ignore
111+
output_type=SeatPreference | Failed,
112112
system_prompt=(
113113
"Extract the user's seat preference. "
114114
'Seats A and F are window seats. '

pydantic_ai_slim/pydantic_ai/agent.py

Lines changed: 6 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
151151
_instrument_default: ClassVar[InstrumentationSettings | bool] = False
152152

153153
_deps_type: type[AgentDepsT] = dataclasses.field(repr=False)
154-
_deprecated_result_tool_name: str | None = dataclasses.field(repr=False)
155-
_deprecated_result_tool_description: str | None = dataclasses.field(repr=False)
156154
_output_schema: _output.BaseOutputSchema[OutputDataT] = dataclasses.field(repr=False)
157155
_output_validators: list[_output.OutputValidator[AgentDepsT, OutputDataT]] = dataclasses.field(repr=False)
158156
_instructions: str | None = dataclasses.field(repr=False)
@@ -199,44 +197,13 @@ def __init__(
199197
history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
200198
) -> None: ...
201199

202-
@overload
203-
@deprecated(
204-
'`result_type`, `result_tool_name` & `result_tool_description` are deprecated, use `output_type` instead. `result_retries` is deprecated, use `output_retries` instead.'
205-
)
206-
def __init__(
207-
self,
208-
model: models.Model | models.KnownModelName | str | None = None,
209-
*,
210-
result_type: type[OutputDataT] = str,
211-
instructions: str
212-
| _system_prompt.SystemPromptFunc[AgentDepsT]
213-
| Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
214-
| None = None,
215-
system_prompt: str | Sequence[str] = (),
216-
deps_type: type[AgentDepsT] = NoneType,
217-
name: str | None = None,
218-
model_settings: ModelSettings | None = None,
219-
retries: int = 1,
220-
result_tool_name: str = _output.DEFAULT_OUTPUT_TOOL_NAME,
221-
result_tool_description: str | None = None,
222-
result_retries: int | None = None,
223-
tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (),
224-
prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
225-
prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
226-
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
227-
defer_model_check: bool = False,
228-
end_strategy: EndStrategy = 'early',
229-
instrument: InstrumentationSettings | bool | None = None,
230-
history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
231-
) -> None: ...
232-
233200
@overload
234201
@deprecated('`mcp_servers` is deprecated, use `toolsets` instead.')
235202
def __init__(
236203
self,
237204
model: models.Model | models.KnownModelName | str | None = None,
238205
*,
239-
result_type: type[OutputDataT] = str,
206+
output_type: OutputSpec[OutputDataT] = str,
240207
instructions: str
241208
| _system_prompt.SystemPromptFunc[AgentDepsT]
242209
| Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
@@ -246,9 +213,7 @@ def __init__(
246213
name: str | None = None,
247214
model_settings: ModelSettings | None = None,
248215
retries: int = 1,
249-
result_tool_name: str = _output.DEFAULT_OUTPUT_TOOL_NAME,
250-
result_tool_description: str | None = None,
251-
result_retries: int | None = None,
216+
output_retries: int | None = None,
252217
tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (),
253218
prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
254219
prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
@@ -263,8 +228,7 @@ def __init__(
263228
self,
264229
model: models.Model | models.KnownModelName | str | None = None,
265230
*,
266-
# TODO change this back to `output_type: _output.OutputType[OutputDataT] = str,` when we remove the overloads
267-
output_type: Any = str,
231+
output_type: OutputSpec[OutputDataT] = str,
268232
instructions: str
269233
| _system_prompt.SystemPromptFunc[AgentDepsT]
270234
| Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
@@ -341,42 +305,10 @@ def __init__(
341305
self.name = name
342306
self.model_settings = model_settings
343307

344-
if 'result_type' in _deprecated_kwargs:
345-
if output_type is not str: # pragma: no cover
346-
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
347-
warnings.warn('`result_type` is deprecated, use `output_type` instead', DeprecationWarning, stacklevel=2)
348-
output_type = _deprecated_kwargs.pop('result_type')
349-
350308
self.output_type = output_type
351-
352309
self.instrument = instrument
353-
354310
self._deps_type = deps_type
355311

356-
self._deprecated_result_tool_name = _deprecated_kwargs.pop('result_tool_name', None)
357-
if self._deprecated_result_tool_name is not None:
358-
warnings.warn(
359-
'`result_tool_name` is deprecated, use `output_type` with `ToolOutput` instead',
360-
DeprecationWarning,
361-
stacklevel=2,
362-
)
363-
364-
self._deprecated_result_tool_description = _deprecated_kwargs.pop('result_tool_description', None)
365-
if self._deprecated_result_tool_description is not None:
366-
warnings.warn(
367-
'`result_tool_description` is deprecated, use `output_type` with `ToolOutput` instead',
368-
DeprecationWarning,
369-
stacklevel=2,
370-
)
371-
result_retries = _deprecated_kwargs.pop('result_retries', None)
372-
if result_retries is not None:
373-
if output_retries is not None: # pragma: no cover
374-
raise TypeError('`output_retries` and `result_retries` cannot be set at the same time.')
375-
warnings.warn(
376-
'`result_retries` is deprecated, use `max_result_retries` instead', DeprecationWarning, stacklevel=2
377-
)
378-
output_retries = result_retries
379-
380312
if mcp_servers := _deprecated_kwargs.pop('mcp_servers', None):
381313
if toolsets is not None: # pragma: no cover
382314
raise TypeError('`mcp_servers` and `toolsets` cannot be set at the same time.')
@@ -389,12 +321,7 @@ def __init__(
389321
self.model.profile.default_structured_output_mode if isinstance(self.model, models.Model) else None
390322
)
391323

392-
self._output_schema = _output.OutputSchema[OutputDataT].build(
393-
output_type,
394-
default_mode=default_output_mode,
395-
name=self._deprecated_result_tool_name,
396-
description=self._deprecated_result_tool_description,
397-
)
324+
self._output_schema = _output.OutputSchema[OutputDataT].build(output_type, default_mode=default_output_mode)
398325
self._output_validators = []
399326

400327
self._instructions = ''
@@ -472,23 +399,6 @@ async def run(
472399
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
473400
) -> AgentRunResult[RunOutputDataT]: ...
474401

475-
@overload
476-
@deprecated('`result_type` is deprecated, use `output_type` instead.')
477-
async def run(
478-
self,
479-
user_prompt: str | Sequence[_messages.UserContent] | None = None,
480-
*,
481-
result_type: type[RunOutputDataT],
482-
message_history: list[_messages.ModelMessage] | None = None,
483-
model: models.Model | models.KnownModelName | str | None = None,
484-
deps: AgentDepsT = None,
485-
model_settings: ModelSettings | None = None,
486-
usage_limits: _usage.UsageLimits | None = None,
487-
usage: _usage.Usage | None = None,
488-
infer_name: bool = True,
489-
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
490-
) -> AgentRunResult[RunOutputDataT]: ...
491-
492402
async def run(
493403
self,
494404
user_prompt: str | Sequence[_messages.UserContent] | None = None,
@@ -540,12 +450,6 @@ async def main():
540450
if infer_name and self.name is None:
541451
self._infer_name(inspect.currentframe())
542452

543-
if 'result_type' in _deprecated_kwargs: # pragma: no cover
544-
if output_type is not str:
545-
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
546-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
547-
output_type = _deprecated_kwargs.pop('result_type')
548-
549453
_utils.validate_empty_kwargs(_deprecated_kwargs)
550454

551455
async with self.iter(
@@ -599,23 +503,6 @@ def iter(
599503
**_deprecated_kwargs: Never,
600504
) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, RunOutputDataT]]: ...
601505

602-
@overload
603-
@deprecated('`result_type` is deprecated, use `output_type` instead.')
604-
def iter(
605-
self,
606-
user_prompt: str | Sequence[_messages.UserContent] | None = None,
607-
*,
608-
result_type: type[RunOutputDataT],
609-
message_history: list[_messages.ModelMessage] | None = None,
610-
model: models.Model | models.KnownModelName | str | None = None,
611-
deps: AgentDepsT = None,
612-
model_settings: ModelSettings | None = None,
613-
usage_limits: _usage.UsageLimits | None = None,
614-
usage: _usage.Usage | None = None,
615-
infer_name: bool = True,
616-
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
617-
) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, Any]]: ...
618-
619506
@asynccontextmanager
620507
async def iter(
621508
self,
@@ -714,12 +601,6 @@ async def main():
714601
model_used = self._get_model(model)
715602
del model
716603

717-
if 'result_type' in _deprecated_kwargs: # pragma: no cover
718-
if output_type is not str:
719-
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
720-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
721-
output_type = _deprecated_kwargs.pop('result_type')
722-
723604
_utils.validate_empty_kwargs(_deprecated_kwargs)
724605

725606
deps = self._get_deps(deps)
@@ -910,23 +791,6 @@ def run_sync(
910791
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
911792
) -> AgentRunResult[RunOutputDataT]: ...
912793

913-
@overload
914-
@deprecated('`result_type` is deprecated, use `output_type` instead.')
915-
def run_sync(
916-
self,
917-
user_prompt: str | Sequence[_messages.UserContent] | None = None,
918-
*,
919-
result_type: type[RunOutputDataT],
920-
message_history: list[_messages.ModelMessage] | None = None,
921-
model: models.Model | models.KnownModelName | str | None = None,
922-
deps: AgentDepsT = None,
923-
model_settings: ModelSettings | None = None,
924-
usage_limits: _usage.UsageLimits | None = None,
925-
usage: _usage.Usage | None = None,
926-
infer_name: bool = True,
927-
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
928-
) -> AgentRunResult[RunOutputDataT]: ...
929-
930794
def run_sync(
931795
self,
932796
user_prompt: str | Sequence[_messages.UserContent] | None = None,
@@ -977,12 +841,6 @@ def run_sync(
977841
if infer_name and self.name is None:
978842
self._infer_name(inspect.currentframe())
979843

980-
if 'result_type' in _deprecated_kwargs: # pragma: no cover
981-
if output_type is not str:
982-
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
983-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
984-
output_type = _deprecated_kwargs.pop('result_type')
985-
986844
_utils.validate_empty_kwargs(_deprecated_kwargs)
987845

988846
return get_event_loop().run_until_complete(
@@ -1031,25 +889,8 @@ def run_stream(
1031889
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
1032890
) -> AbstractAsyncContextManager[result.StreamedRunResult[AgentDepsT, RunOutputDataT]]: ...
1033891

1034-
@overload
1035-
@deprecated('`result_type` is deprecated, use `output_type` instead.')
1036-
def run_stream(
1037-
self,
1038-
user_prompt: str | Sequence[_messages.UserContent] | None = None,
1039-
*,
1040-
result_type: type[RunOutputDataT],
1041-
message_history: list[_messages.ModelMessage] | None = None,
1042-
model: models.Model | models.KnownModelName | str | None = None,
1043-
deps: AgentDepsT = None,
1044-
model_settings: ModelSettings | None = None,
1045-
usage_limits: _usage.UsageLimits | None = None,
1046-
usage: _usage.Usage | None = None,
1047-
infer_name: bool = True,
1048-
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
1049-
) -> AbstractAsyncContextManager[result.StreamedRunResult[AgentDepsT, RunOutputDataT]]: ...
1050-
1051892
@asynccontextmanager
1052-
async def run_stream( # noqa C901
893+
async def run_stream(
1053894
self,
1054895
user_prompt: str | Sequence[_messages.UserContent] | None = None,
1055896
*,
@@ -1101,12 +942,6 @@ async def main():
1101942
if frame := inspect.currentframe(): # pragma: no branch
1102943
self._infer_name(frame.f_back)
1103944

1104-
if 'result_type' in _deprecated_kwargs: # pragma: no cover
1105-
if output_type is not str:
1106-
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
1107-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
1108-
output_type = _deprecated_kwargs.pop('result_type')
1109-
1110945
_utils.validate_empty_kwargs(_deprecated_kwargs)
1111946

1112947
yielded = False
@@ -1732,10 +1567,7 @@ def _prepare_output_schema(
17321567
if self._output_validators:
17331568
raise exceptions.UserError('Cannot set a custom run `output_type` when the agent has output validators')
17341569
schema = _output.OutputSchema[RunOutputDataT].build(
1735-
output_type,
1736-
name=self._deprecated_result_tool_name,
1737-
description=self._deprecated_result_tool_description,
1738-
default_mode=model_profile.default_structured_output_mode,
1570+
output_type, default_mode=model_profile.default_structured_output_mode
17391571
)
17401572
else:
17411573
schema = self._output_schema.with_default_mode(model_profile.default_structured_output_mode)

tests/test_agent.py

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3638,68 +3638,20 @@ def test_deprecated_kwargs_still_work():
36383638
"""Test that valid deprecated kwargs still work with warnings."""
36393639
import warnings
36403640

3641-
with warnings.catch_warnings(record=True) as w:
3642-
warnings.simplefilter('always')
3643-
3644-
agent = Agent('test', result_type=str) # type: ignore[call-arg]
3645-
assert len(w) == 1
3646-
assert issubclass(w[0].category, DeprecationWarning)
3647-
assert '`result_type` is deprecated' in str(w[0].message)
3648-
assert agent.output_type is str
3649-
3650-
with warnings.catch_warnings(record=True) as w:
3651-
warnings.simplefilter('always')
3652-
3653-
agent = Agent('test', result_tool_name='test_tool') # type: ignore[call-arg]
3654-
assert len(w) == 1
3655-
assert issubclass(w[0].category, DeprecationWarning)
3656-
assert '`result_tool_name` is deprecated' in str(w[0].message)
3657-
3658-
with warnings.catch_warnings(record=True) as w:
3659-
warnings.simplefilter('always')
3660-
3661-
agent = Agent('test', result_tool_description='test description') # type: ignore[call-arg]
3662-
assert len(w) == 1
3663-
assert issubclass(w[0].category, DeprecationWarning)
3664-
assert '`result_tool_description` is deprecated' in str(w[0].message)
3665-
3666-
with warnings.catch_warnings(record=True) as w:
3667-
warnings.simplefilter('always')
3668-
3669-
agent = Agent('test', result_retries=3) # type: ignore[call-arg]
3670-
assert len(w) == 1
3671-
assert issubclass(w[0].category, DeprecationWarning)
3672-
assert '`result_retries` is deprecated' in str(w[0].message)
3673-
36743641
try:
36753642
from pydantic_ai.mcp import MCPServerStdio
36763643

36773644
with warnings.catch_warnings(record=True) as w:
36783645
warnings.simplefilter('always')
36793646

3680-
agent = Agent('test', mcp_servers=[MCPServerStdio('python', ['-m', 'tests.mcp_server'])]) # type: ignore[call-arg]
3647+
Agent('test', mcp_servers=[MCPServerStdio('python', ['-m', 'tests.mcp_server'])]) # type: ignore[call-arg]
36813648
assert len(w) == 1
36823649
assert issubclass(w[0].category, DeprecationWarning)
36833650
assert '`mcp_servers` is deprecated' in str(w[0].message)
36843651
except ImportError:
36853652
pass
36863653

36873654

3688-
def test_deprecated_kwargs_mixed_valid_invalid():
3689-
"""Test that mix of valid deprecated and invalid kwargs raises error for invalid ones."""
3690-
import warnings
3691-
3692-
with pytest.raises(UserError, match='Unknown keyword arguments: `usage_limits`'):
3693-
with warnings.catch_warnings():
3694-
warnings.simplefilter('ignore', DeprecationWarning) # Ignore the deprecation warning for result_type
3695-
Agent('test', result_type=str, usage_limits='invalid') # type: ignore[call-arg]
3696-
3697-
with pytest.raises(UserError, match='Unknown keyword arguments: `foo`, `bar`'):
3698-
with warnings.catch_warnings():
3699-
warnings.simplefilter('ignore', DeprecationWarning) # Ignore the deprecation warning for result_tool_name
3700-
Agent('test', result_tool_name='test', foo='value1', bar='value2') # type: ignore[call-arg]
3701-
3702-
37033655
def test_override_toolsets():
37043656
foo_toolset = FunctionToolset()
37053657

tests/test_streaming.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ async def test_stream_iter_structured_validator() -> None:
926926
class NotOutputType(BaseModel):
927927
not_value: str
928928

929-
agent = Agent[None, Union[OutputType, NotOutputType]]('test', output_type=Union[OutputType, NotOutputType]) # pyright: ignore[reportArgumentType]
929+
agent = Agent[None, Union[OutputType, NotOutputType]]('test', output_type=Union[OutputType, NotOutputType])
930930

931931
@agent.output_validator
932932
def output_validator(data: OutputType | NotOutputType) -> OutputType | NotOutputType:

0 commit comments

Comments
 (0)