Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ Pydantic AI is still pre-version 1, so breaking changes will occur, however:

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

This release was meant to clean some old deprecated code, so we can get a step closer to V1.

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.

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.

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.

See [#2443](https://github.com/pydantic/pydantic-ai/pull/2443) - The `data` property was removed from the `FinalResult` class. Use `output` instead.

See [#2445](https://github.com/pydantic/pydantic-ai/pull/2445) - The `get_data` and `validate_structured_result` methods were removed from the
Expand Down
2 changes: 1 addition & 1 deletion examples/pydantic_ai_examples/flight_booking.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Failed(BaseModel):
# This agent is responsible for extracting the user's seat selection
seat_preference_agent = Agent[None, SeatPreference | Failed](
'openai:gpt-4o',
output_type=SeatPreference | Failed, # type: ignore
output_type=SeatPreference | Failed,
system_prompt=(
"Extract the user's seat preference. "
'Seats A and F are window seats. '
Expand Down
180 changes: 6 additions & 174 deletions pydantic_ai_slim/pydantic_ai/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
_instrument_default: ClassVar[InstrumentationSettings | bool] = False

_deps_type: type[AgentDepsT] = dataclasses.field(repr=False)
_deprecated_result_tool_name: str | None = dataclasses.field(repr=False)
_deprecated_result_tool_description: str | None = dataclasses.field(repr=False)
_output_schema: _output.BaseOutputSchema[OutputDataT] = dataclasses.field(repr=False)
_output_validators: list[_output.OutputValidator[AgentDepsT, OutputDataT]] = dataclasses.field(repr=False)
_instructions: str | None = dataclasses.field(repr=False)
Expand Down Expand Up @@ -199,44 +197,13 @@ def __init__(
history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
) -> None: ...

@overload
@deprecated(
'`result_type`, `result_tool_name` & `result_tool_description` are deprecated, use `output_type` instead. `result_retries` is deprecated, use `output_retries` instead.'
)
def __init__(
self,
model: models.Model | models.KnownModelName | str | None = None,
*,
result_type: type[OutputDataT] = str,
instructions: str
| _system_prompt.SystemPromptFunc[AgentDepsT]
| Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
| None = None,
system_prompt: str | Sequence[str] = (),
deps_type: type[AgentDepsT] = NoneType,
name: str | None = None,
model_settings: ModelSettings | None = None,
retries: int = 1,
result_tool_name: str = _output.DEFAULT_OUTPUT_TOOL_NAME,
result_tool_description: str | None = None,
result_retries: int | None = None,
tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (),
prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
defer_model_check: bool = False,
end_strategy: EndStrategy = 'early',
instrument: InstrumentationSettings | bool | None = None,
history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
) -> None: ...

@overload
@deprecated('`mcp_servers` is deprecated, use `toolsets` instead.')
def __init__(
self,
model: models.Model | models.KnownModelName | str | None = None,
*,
result_type: type[OutputDataT] = str,
output_type: OutputSpec[OutputDataT] = str,
instructions: str
| _system_prompt.SystemPromptFunc[AgentDepsT]
| Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
Expand All @@ -246,9 +213,7 @@ def __init__(
name: str | None = None,
model_settings: ModelSettings | None = None,
retries: int = 1,
result_tool_name: str = _output.DEFAULT_OUTPUT_TOOL_NAME,
result_tool_description: str | None = None,
result_retries: int | None = None,
Comment on lines -249 to -251
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those were wrong.

output_retries: int | None = None,
tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = (),
prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
Expand All @@ -263,8 +228,7 @@ def __init__(
self,
model: models.Model | models.KnownModelName | str | None = None,
*,
# TODO change this back to `output_type: _output.OutputType[OutputDataT] = str,` when we remove the overloads
output_type: Any = str,
output_type: OutputSpec[OutputDataT] = str,
instructions: str
| _system_prompt.SystemPromptFunc[AgentDepsT]
| Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
Expand Down Expand Up @@ -341,42 +305,10 @@ def __init__(
self.name = name
self.model_settings = model_settings

if 'result_type' in _deprecated_kwargs:
if output_type is not str: # pragma: no cover
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
warnings.warn('`result_type` is deprecated, use `output_type` instead', DeprecationWarning, stacklevel=2)
output_type = _deprecated_kwargs.pop('result_type')

self.output_type = output_type

self.instrument = instrument

self._deps_type = deps_type

self._deprecated_result_tool_name = _deprecated_kwargs.pop('result_tool_name', None)
if self._deprecated_result_tool_name is not None:
warnings.warn(
'`result_tool_name` is deprecated, use `output_type` with `ToolOutput` instead',
DeprecationWarning,
stacklevel=2,
)

self._deprecated_result_tool_description = _deprecated_kwargs.pop('result_tool_description', None)
if self._deprecated_result_tool_description is not None:
warnings.warn(
'`result_tool_description` is deprecated, use `output_type` with `ToolOutput` instead',
DeprecationWarning,
stacklevel=2,
)
result_retries = _deprecated_kwargs.pop('result_retries', None)
if result_retries is not None:
if output_retries is not None: # pragma: no cover
raise TypeError('`output_retries` and `result_retries` cannot be set at the same time.')
warnings.warn(
'`result_retries` is deprecated, use `max_result_retries` instead', DeprecationWarning, stacklevel=2
)
output_retries = result_retries

if mcp_servers := _deprecated_kwargs.pop('mcp_servers', None):
if toolsets is not None: # pragma: no cover
raise TypeError('`mcp_servers` and `toolsets` cannot be set at the same time.')
Expand All @@ -389,12 +321,7 @@ def __init__(
self.model.profile.default_structured_output_mode if isinstance(self.model, models.Model) else None
)

self._output_schema = _output.OutputSchema[OutputDataT].build(
output_type,
default_mode=default_output_mode,
name=self._deprecated_result_tool_name,
description=self._deprecated_result_tool_description,
)
self._output_schema = _output.OutputSchema[OutputDataT].build(output_type, default_mode=default_output_mode)
self._output_validators = []

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

@overload
@deprecated('`result_type` is deprecated, use `output_type` instead.')
async def run(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
*,
result_type: type[RunOutputDataT],
message_history: list[_messages.ModelMessage] | None = None,
model: models.Model | models.KnownModelName | str | None = None,
deps: AgentDepsT = None,
model_settings: ModelSettings | None = None,
usage_limits: _usage.UsageLimits | None = None,
usage: _usage.Usage | None = None,
infer_name: bool = True,
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
) -> AgentRunResult[RunOutputDataT]: ...

async def run(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
Expand Down Expand Up @@ -540,12 +450,6 @@ async def main():
if infer_name and self.name is None:
self._infer_name(inspect.currentframe())

if 'result_type' in _deprecated_kwargs: # pragma: no cover
if output_type is not str:
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
output_type = _deprecated_kwargs.pop('result_type')

_utils.validate_empty_kwargs(_deprecated_kwargs)

async with self.iter(
Expand Down Expand Up @@ -599,23 +503,6 @@ def iter(
**_deprecated_kwargs: Never,
) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, RunOutputDataT]]: ...

@overload
@deprecated('`result_type` is deprecated, use `output_type` instead.')
def iter(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
*,
result_type: type[RunOutputDataT],
message_history: list[_messages.ModelMessage] | None = None,
model: models.Model | models.KnownModelName | str | None = None,
deps: AgentDepsT = None,
model_settings: ModelSettings | None = None,
usage_limits: _usage.UsageLimits | None = None,
usage: _usage.Usage | None = None,
infer_name: bool = True,
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, Any]]: ...

@asynccontextmanager
async def iter(
self,
Expand Down Expand Up @@ -714,12 +601,6 @@ async def main():
model_used = self._get_model(model)
del model

if 'result_type' in _deprecated_kwargs: # pragma: no cover
if output_type is not str:
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
output_type = _deprecated_kwargs.pop('result_type')

_utils.validate_empty_kwargs(_deprecated_kwargs)

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

@overload
@deprecated('`result_type` is deprecated, use `output_type` instead.')
def run_sync(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
*,
result_type: type[RunOutputDataT],
message_history: list[_messages.ModelMessage] | None = None,
model: models.Model | models.KnownModelName | str | None = None,
deps: AgentDepsT = None,
model_settings: ModelSettings | None = None,
usage_limits: _usage.UsageLimits | None = None,
usage: _usage.Usage | None = None,
infer_name: bool = True,
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
) -> AgentRunResult[RunOutputDataT]: ...

def run_sync(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
Expand Down Expand Up @@ -977,12 +841,6 @@ def run_sync(
if infer_name and self.name is None:
self._infer_name(inspect.currentframe())

if 'result_type' in _deprecated_kwargs: # pragma: no cover
if output_type is not str:
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
output_type = _deprecated_kwargs.pop('result_type')

_utils.validate_empty_kwargs(_deprecated_kwargs)

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

@overload
@deprecated('`result_type` is deprecated, use `output_type` instead.')
def run_stream(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
*,
result_type: type[RunOutputDataT],
message_history: list[_messages.ModelMessage] | None = None,
model: models.Model | models.KnownModelName | str | None = None,
deps: AgentDepsT = None,
model_settings: ModelSettings | None = None,
usage_limits: _usage.UsageLimits | None = None,
usage: _usage.Usage | None = None,
infer_name: bool = True,
toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
) -> AbstractAsyncContextManager[result.StreamedRunResult[AgentDepsT, RunOutputDataT]]: ...

@asynccontextmanager
async def run_stream( # noqa C901
async def run_stream(
self,
user_prompt: str | Sequence[_messages.UserContent] | None = None,
*,
Expand Down Expand Up @@ -1101,12 +942,6 @@ async def main():
if frame := inspect.currentframe(): # pragma: no branch
self._infer_name(frame.f_back)

if 'result_type' in _deprecated_kwargs: # pragma: no cover
if output_type is not str:
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
output_type = _deprecated_kwargs.pop('result_type')

_utils.validate_empty_kwargs(_deprecated_kwargs)

yielded = False
Expand Down Expand Up @@ -1732,10 +1567,7 @@ def _prepare_output_schema(
if self._output_validators:
raise exceptions.UserError('Cannot set a custom run `output_type` when the agent has output validators')
schema = _output.OutputSchema[RunOutputDataT].build(
output_type,
name=self._deprecated_result_tool_name,
description=self._deprecated_result_tool_description,
default_mode=model_profile.default_structured_output_mode,
output_type, default_mode=model_profile.default_structured_output_mode
)
else:
schema = self._output_schema.with_default_mode(model_profile.default_structured_output_mode)
Expand Down
50 changes: 1 addition & 49 deletions tests/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3638,68 +3638,20 @@ def test_deprecated_kwargs_still_work():
"""Test that valid deprecated kwargs still work with warnings."""
import warnings

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

agent = Agent('test', result_type=str) # type: ignore[call-arg]
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert '`result_type` is deprecated' in str(w[0].message)
assert agent.output_type is str

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

agent = Agent('test', result_tool_name='test_tool') # type: ignore[call-arg]
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert '`result_tool_name` is deprecated' in str(w[0].message)

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

agent = Agent('test', result_tool_description='test description') # type: ignore[call-arg]
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert '`result_tool_description` is deprecated' in str(w[0].message)

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

agent = Agent('test', result_retries=3) # type: ignore[call-arg]
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert '`result_retries` is deprecated' in str(w[0].message)

try:
from pydantic_ai.mcp import MCPServerStdio

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

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


def test_deprecated_kwargs_mixed_valid_invalid():
"""Test that mix of valid deprecated and invalid kwargs raises error for invalid ones."""
import warnings

with pytest.raises(UserError, match='Unknown keyword arguments: `usage_limits`'):
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning) # Ignore the deprecation warning for result_type
Agent('test', result_type=str, usage_limits='invalid') # type: ignore[call-arg]

with pytest.raises(UserError, match='Unknown keyword arguments: `foo`, `bar`'):
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning) # Ignore the deprecation warning for result_tool_name
Agent('test', result_tool_name='test', foo='value1', bar='value2') # type: ignore[call-arg]


def test_override_toolsets():
foo_toolset = FunctionToolset()

Expand Down
2 changes: 1 addition & 1 deletion tests/test_streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ async def test_stream_iter_structured_validator() -> None:
class NotOutputType(BaseModel):
not_value: str

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

@agent.output_validator
def output_validator(data: OutputType | NotOutputType) -> OutputType | NotOutputType:
Expand Down
Loading