v2.53.0

pydantic/pydantic-aiv2.53.0Oct 2, 2026by dsfaccini

Upgrading?

AI Summary

This release prioritizes security by fixing a critical concurrency issue in `ConcurrencyLimitedModel`. It adds new capabilities like `ToolCallJudge` and `SystemOneModel`, extends harness durability options, and improves JSON schema support.

Key Highlights

  • Fixed high-severity concurrency security vulnerability (GHSA-6fqq-452j-qhrp).
  • Added `ToolCallJudge` to assess tool calls before execution.
  • Added `SystemOneModel` for running decision models over the `/v1/systemone` API.
  • Added `AbsurdDurability` to the harness as a replacement for `pydantic-ai-absurd`.
  • Added `oneOf` schema support to `TestModel`'s generated data.

Breaking Changes

  • `ConcurrencyLimiter.acquire()` now takes a slot on every call, even on the same task.
  • `ConcurrencyLimiter` now raises `UserError` when sharing a limiter with the agent or enclosing wrapper.

New Features

  • `ToolCallJudge`
  • `SystemOneModel`
  • `AbsurdDurability`
  • `AskUser` deferral to host and timeout support
  • Exposed message-history repair pipeline as `repair_messages`

Full Release Notes

<!-- Release notes generated using configuration in .github/release.yml at main -->

### 🛡️ Security

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

- **[GHSA-6fqq-452j-qhrp](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-6fqq-452j-qhrp)** (high): a streamed request through `ConcurrencyLimitedModel` or `limit_model_concurrency` could keep its concurrency slot when the slot was released on a different task than the one that acquired it: after an early exit (the consumer stopped iterating, raised, or was cancelled), and also after fully consuming `stream_text()` with its default debouncing. Repeated streams could then block every request sharing the limiter. Agent-level `max_concurrency` and non-streaming requests are not affected. Reported by @lche511. (#9478)

The fix also changes how limiters are shared: a model wrapper now raises `UserError` when it shares a limiter with the agent making the request or with an enclosing model wrapper, `ConcurrencyLimiter.acquire()` takes a slot on every call, even on the same task, and a custom `AbstractConcurrencyLimiter` must allow `release()` from another task.

Patched in `2.53.0`. v1 is not affected.

## What's Changed
### ⚠️ Compatibility Notes
* Add `oneOf` schema support to `TestModel`'s generated data by [@pydanty](https://github.com/apps/pydanty) in https://github.com/pydantic/pydantic-ai/pull/8783
* Deprecate `pydantic_ai_harness.step_persistence.naming` by @mpfaffenberger in https://github.com/pydantic/pydantic-ai/pull/9499
### 🚀 Features
* Count Google grounding web search queries in `usage` by [@pydanty](https://github.com/apps/pydanty) in https://github.com/pydantic/pydantic-ai/pull/8891
* Add `AbsurdDurability` to the harness as a replacement for `pydantic-ai-absurd` by @adtyavrdhn in https://github.com/pydantic/pydantic-ai/pull/8946
* Let `AskUser` defer questions to the host and time out a slow answerer by @mpfaffenberger in https://github.com/pydantic/pydantic-ai/pull/9509
* Add `SystemOneModel` to run decision models such as CLM and Laya over the `/v1/systemone` API by @mpfaffenberger in https://github.com/pydantic/pydantic-ai/pull/8942
* Add `ToolCallJudge` to assess tool calls before execution by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9041
* Send images and documents from GPT-Live tool results to the delegated backend by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9048
* Expose the message-history repair pipeline as `repair_messages` by @DouweM in https://github.com/pydantic/pydantic-ai/pull/8370
### 🐛 Bug Fixes
* Kill the process group when a `LocalWorkspaceBackend.run` timeout fires during process startup by @dsfaccini in https://github.com/pydantic/pydantic-ai/pull/9358
* Avoid invalid-escape warning floods during `CodeMode` analysis by @mpfaffenberger in https://github.com/pydantic/pydantic-ai/pull/9475
* Keep the registered `Memory` toolset across runs so durable execution accepts it by @mpfaffenberger in https://github.com/pydantic/pydantic-ai/pull/9489
* Keep the registered `Planning` toolset across runs so durable execution accepts it by @mpfaffenberger in https://github.com/pydantic/pydantic-ai/pull/9507
* Keep planted files from escaping `BubblewrapSandbox` on the next launch by @dsfaccini in https://github.com/pydantic/pydantic-ai/pull/9457
* Render non-finite eval metrics as `inf`/`-inf`/`nan` by [@pydanty](https://github.com/apps/pydanty) in https://github.com/pydantic/pydantic-ai/pull/8852
* Snap `gemini-3.1-flash-image` thinking efforts to `minimal` and `high` on the Gemini API by @dsfaccini in https://github.com/pydantic/pydantic-ai/pull/9515
* Raise `UnexpectedModelBehavior` instead of running the wrong tool when function tool calls share a `tool_call_id` by [@pydanty](https://github.com/apps/pydanty) in https://github.com/pydantic/pydantic-ai/pull/8782
* Build one streamed `XaiModel` thinking part per output, matching the non-streamed response by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9416
* Leave image generation calls out of the `OpenAIResponsesModel` replay when `openai_store=False` by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9388
* Build the same `ModelResponse` from streamed and complete `OpenAIChatModel` and `OpenRouterModel` responses by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9418
* Make `OpenAIResponsesModel` build the same `ModelResponse` from a stream as from a complete response by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9417
* Make xAI push-to-talk reply only when asked: `commit_audio()` alone no longer triggers a reply, and `create_response()` is always answered by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9070
* Tolerate OpenAI realtime `status`, `status_details` and session values the SDK does not know yet by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9392
* Stop `SubAgents` from forcing `thinking` on disk agents by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9384
* Restore `DynamicWorkflow` reveal announcements after compaction or history loss by @DouweM in https://github.com/pydantic/pydantic-ai/pull/9371
* Make Logfire Temporal spans replay-safe by @DouweM in https://github.com/pydantic/pydantic-ai/pull/7006
* Allow unschemable types in the derived Temporal `ActivityConfig` schema by [@pydanty](https://github.com/apps/pydanty) in https://github.com/pydantic/pydantic-ai/pull/9577
* Let `GoogleRealtimeModel` declare tools whose `dict` values are recursive models by @dsfaccini in https://github.com/pydantic/pydantic-ai/pull/9607

## New Contributors
* @Poojita060926 made their first contribution in https://github.com/pydantic/pydantic-ai/pull/8900

**Full Changelog**: https://github.com/pydantic/pydantic-ai/compare/v2.52.0...v2.53.0


Related Repositories