github pydantic/pydantic-ai v2.52.0
v2.52.0 (2026-09-29)

latest release: v1.107.7
2 hours ago

🛡️ Security

This release fixes one security issue in web_fetch. See the advisory for full details and affected versions.

  • GHSA-v36g-jcw9-x7cw (moderate): converting attacker-controlled HTML with deeply nested elements in the local web_fetch tool could consume excessive CPU and memory. Provider-native web fetching is not affected. Reported by @SounLabs. (#8984)

Patched in 2.52.0 (v2) and 1.107.7 (v1).

📦 Harness and CLAI 2

pydantic-ai-harness now lives in this repository and ships with every Pydantic AI release, so it jumps from 0.36.0 to 0.52.0. pydantic-clai2 0.52.0 is its first release: uvx pydantic-clai2.

What's Changed

⚠️ Compatibility Notes

  • Run harness capabilities in any workspace: Coder, FileSystem, Shell and the rest work through ctx.workspace, locally or in a sandbox by @adtyavrdhn in #8866
  • Replace ModalSandbox's own tools with a Modal workspace, so Coder, Shell and FileSystem run in the sandbox; ModalSandboxBackend replaces ModalSandboxSession by @adtyavrdhn in #8867
  • Raise AnthropicModel's default max_tokens from 4096 to 16384 on Claude Sonnet 4.5 and later by @DouweM in #9025
  • Keep the prompt as a DecisionModel's judged text after a retry by @dsfaccini in #8967
  • Stop SubAgents loading agent files by default, and deprecate inherit_tools by @DouweM in #9023
  • Default AnthropicModel's max_tokens to the model's maximum output, streaming such requests behind the scenes by @DouweM in #9298

🚀 Features

  • Add workspaces: ctx.workspace gives tools one API for files and commands, on your machine or in a sandbox, with durable execution support by @adtyavrdhn in #6492
  • Add SpritesSandbox: a workspace that runs Coder, Shell, FileSystem and every other harness capability in a Fly.io Sprite by @adtyavrdhn in #8869
  • Add E2BSandbox: a workspace that runs Coder, Shell, FileSystem and every other harness capability in an E2B sandbox by @adtyavrdhn in #8868
  • Give Coder file tools a retry budget of 5 and keep scratch files out of the project by @mpfaffenberger in #8970
  • Add a typesafe extra to pydantic-clai2 and reject models with a missing provider SDK at /model time by @mpfaffenberger in #8962
  • Add Claude Sonnet 5.5 (claude-sonnet-5-5) support by @dsfaccini in #8974
  • Model realtime async tool calls as a profile async_tool_call_mode with a shared async_tool_calls setting by @DouweM in #8813
  • Show tool-call arguments in pydantic-clai2 tool headers, clipped by display.tool_arg_chars by @mpfaffenberger in #9100
  • Open a clai2 plugin's settings menu when it is turned on, and end every settings menu with Save & close by @mpfaffenberger in #9102
  • Add _process_provider_details hook to OpenAIResponsesModel by @pydanty in #9094
  • Add clai2 --agent MODULE:ATTR to chat with an existing Agent with plugins off by @mpfaffenberger in #9291
  • Add a built-in github plugin to clai2 with a settings menu and its token in /keys by @mpfaffenberger in #8904
  • Add a built-in pylon plugin to CLAI2 with a settings menu and a named /keys entry by @mpfaffenberger in #8953
  • Seed retained user audio on Gemini gemini-3.1-flash-live-preview and gemini-3.8-live by @DouweM in #9047
  • Support browser WebRTC on OpenAI GPT-Live with answer_webrtc_offer and a sideband session by @DouweM in #9059
  • Add SSHWorkspace and BubblewrapSandbox harness capabilities by @mpfaffenberger in #8956
  • Add a pydantic-clai2 console script so uvx pydantic-clai2 runs CLAI by @mpfaffenberger in #9304
  • Add azure_voice_live_voice to choose an Azure voice for Azure AI Voice Live sessions by @DouweM in #9044
  • Add google_workspace as a built-in clai2 plugin backed by harness GoogleWorkspace by @mpfaffenberger in #8907
  • Apply thinking, openai_turn_detection, openai_input_noise_reduction and a new azure_voice_live_temperature on Azure AI Voice Live by @DouweM in #9051
  • Seed tool calls and results as native function parts on Gemini gemini-3.8-live by @DouweM in #9058
  • Emit identified response, turn, and input lifecycle events from the OpenAI-protocol realtime connection by @DouweM in #9064
  • Add a built-in day_ai plugin to clai2 with a settings menu and /keys or browser sign-in by @mpfaffenberger in #8940
  • Warn on unexpected RequestUsage.extract() failures by @adtyavrdhn in #8564
  • Add a built-in ordinal plugin to clai2 with token or keyring-backed browser sign-in by @mpfaffenberger in #8941
  • feat(profiles): default_cache_retention + prompt_cache_outlook() cold-window helper; rename resolve_prompt_cache_retention() to resolve_cache_retention() by @DouweM in #6337
  • Add a built-in notion plugin to clai2 with a settings menu and its key in /keys by @mpfaffenberger in #8944
  • Deliver images and text files returned from tools on Gemini 3.x Live by @DouweM in #9065
  • Map the shared thinking and parallel_tool_calls settings to the GPT-Live backend model by @DouweM in #9040
  • Accept mxfp4, nvfp4, and mxfp8 OpenRouter quantizations and the exacto sort value by @harimaruthachalam in #8888
  • Add a built-in slack plugin to pydantic-clai2 with a settings menu, /keys user token, or browser sign-in by @mpfaffenberger in #8908
  • Add a logfire_mcp built-in plugin to clai2 with /keys, LOGFIRE_API_KEY, and keyring-backed OAuth by @mpfaffenberger in #8903
  • Add OpenAI gpt-6.1-sol model support and allow image output on gpt-6-astra by @dsfaccini in #9305

🐛 Bug Fixes

  • Record realtime user turns in speaking order under push-to-talk, barge-in, and with input transcription off by @DouweM in #8764
  • Stop tool docstring parsing from changing the root logger level by @adtyavrdhn in #8872
  • Treat application/toml as text-like for inline model inputs by @JoeyTan21 in #8848
  • Ask for one answer per batch of parallel realtime tool results, and stop wait_for_reply() hanging on merged or failed replies by @DouweM in #8765
  • Move tool-forcing and thinking-default profile flags to ModelProfile so they apply on every provider route by @DouweM in #8808
  • Stop Gemini Live tool rounds reporting RealtimeTurnCompleteEvent before the spoken answer by @DouweM in #8766
  • Don't force output tools on Anthropic requests that think, so Claude keeps thinking with a structured output_type by @DouweM in #8812
  • Truncate the provider's copy of a realtime reply the user cut off after it finished generating by @DouweM in #8757
  • Leave room for the extended thinking budget in Anthropic's default max_tokens by @DouweM in #8986
  • Settle Gemini tool calls and 2.5 typed turns a resumed realtime session lost, and stop OpenAI-protocol reconnects re-requesting a failed response.create by @DouweM in #8763
  • Keep a realtime microphone task alive across a reconnect by dropping audio sent while the link is re-dialed by @DouweM in #8806
  • Raise UserError instead of ModelRetry for Macroscope setup failures by @DouweM in #8999
  • Give the first stage of a Playwright operation its full configured budget by @DouweM in #9029
  • Make workspace concurrency deadlines robust under load by @DouweM in #9043
  • Report OpenAI native web searches in RequestUsage.details and price them in cost by @dltsum in #8310
  • Stop blank lines and "settings unchanged" notices after closing clai2 menus by @mpfaffenberger in #9101
  • Terminate !command shell descendants on cancellation in clai2 by @dafyy321-pixel in #9092
  • Quiet missing plugin modules and UserWarnings in clai2, and group CodeMode missing-return-schema warnings by @mpfaffenberger in #9099
  • Handle Ctrl-C during clai2 shell process startup by @DouweM in #9104
  • Apply model concurrency limits to compact_messages() by @yang0228 in #8241
  • Keep Up/Down on prompt history when clai2 recalls a slash command by @mpfaffenberger in #9297
  • Allow azure_voice_live=True for gpt-realtime-2 models on AzureRealtimeModel by @DouweM in #9050
  • Bound the Gemini Live handshake with handshake_timeout by @DouweM in #9042
  • Allow text output on Vertex gemini-live-2.5-flash and remove a stale Gemini Live docs claim by @DouweM in #9069
  • Emit DeferredToolRequestsEvent in realtime sessions before the HandleDeferredToolCalls handler runs by @DouweM in #9057
  • Map OpenAI response JSON decode errors to ModelAPIError by @pydanty in #8846
  • Map in-stream error objects to ModelAPIError in OpenAIChatModel, GroqModel and HuggingFaceModel by @DouweM in #9313
  • Raise ModelAPIError instead of ValidationError when an OpenRouterModel stream drops mid-response by @DouweM in #9312
  • Read the capabilities docs topic from capabilities/overview.md in PydanticAIDocs by @DouweM in #9011
  • Apply FileSystem default read_only_patterns to nested .env and .git/ paths by @DouweM in #9021
  • Restore CodeMode discovery announcements after compaction or history loss by @DouweM in #9045
  • Keep the original request in the TrajectoryJudge window when the transcript is clamped by @DouweM in #9012
  • Raise ContentFilterError for a thinking-only response refused by the content filter, instead of retrying by @DouweM in #9355
  • Sandbox file methods and block sockets without network in BubblewrapSandbox by @mpfaffenberger in #9349
  • Give the current time to the hour in LogfireMCP instructions so they stop busting the prompt cache by @mpfaffenberger in #9319
  • Raise ModelAPIError when the OpenAI Responses API reports a failed response or an error stream event by @DouweM in #9321
  • Map every MistralError from the Mistral SDK to ModelHTTPError or ModelAPIError by @DouweM in #9307
  • Map provider errors from GoogleModel.count_tokens and XaiModel file uploads by @DouweM in #9308
  • Fix capability audit findings in ClampOversizedMessages, SubAgents, and StepPersistence by @DouweM in #9026
  • Root union output member data validation errors under result.data so retry feedback keeps the failing input by @pydanty in #8669
  • Read a shell job log deleted mid-read as empty instead of failing the call by @dsfaccini in #9322
  • Record Gemini Live turn_complete_reason as the realtime response's finish_reason by @DouweM in #9390
  • Remove the default ACP request_limit by @DouweM in #9380
  • Report a realtime session's own usage on its span, not a carried total by @DouweM in #9389
  • Count separately budgeted SubAgent usage toward parent budgets by @DouweM in #9374

📦 Dependencies

  • Bump the python-packages group across 1 directory with 14 updates by @dependabot[bot] in #9076

New Contributors

Full Changelog: v2.51.0...v2.52.0

Don't miss a new pydantic-ai release

NewReleases is sending notifications on new releases.