chore(deps): update dependency pydantic-ai to v2.53.0 [security] #9

Open
renovate-forgejo wants to merge 1 commit from renovate/pypi-pydantic-ai-vulnerability into main
Collaborator

This PR contains the following updates:

Package Type Update Change
pydantic-ai (changelog) dependency-groups minor 2.24.0 → 2.53.0

Pydantic AI OpenTelemetry instrumentation: retry prompt content is not redacted when include_content=False

CVE-2026-107293 / GHSA-3gh4-cghq-f8v4

More information

Details

Summary

Pydantic AI's OpenTelemetry instrumentation supports InstrumentationSettings(include_content=False) to exclude message content — user prompts, model completions, tool call arguments and responses — from exported telemetry, so that agents can be monitored without sending sensitive content to the observability backend.

Retry prompts — the feedback messages Pydantic AI sends back to the model when its output fails validation or an output validator raises ModelRetry — were not covered by this setting when they were not associated with a tool call, as with structured output modes that don't use tool calls (e.g. NativeOutput or PromptedOutput) and output validators applied to text output. Their full content was recorded on model request spans even with include_content=False. Since validation feedback can quote invalid values from the model's response, message content that the setting was configured to withhold could reach the telemetry backend.

Details

Retry prompts without an associated tool call were serialized into span message attributes (such as gen_ai.input.messages and pydantic_ai.all_messages) as regular text parts, and this path did not apply the include_content check that every other message part applies. Retry prompts tied to a tool call, and all other message content, were redacted correctly.

Impact

This does not grant an attacker any new access to the agent or its data: the content is only visible to whoever can read the exported telemetry. The exposure matters when traces are exported to a destination whose audience is broader or less trusted than the agent's own data — a third-party observability vendor or a shared backend — which is the scenario include_content=False exists for. The disclosed content is limited to retry feedback: validation error details, which can quote invalid values from the model's output, or output-validator ModelRetry messages.

Who Is Affected

You are affected if you enabled instrumentation with include_content=False and your agent can produce retry prompts outside of tool calls: it uses a structured output mode that doesn't rely on tool calls (such as NativeOutput or PromptedOutput), or output validators on text output. You are not affected if you don't set include_content=False, or if all of your agent's retries come from tool calls (including the default tool-based structured output mode), which were redacted correctly.

Remediation

Upgrade to a patched version; retry prompt content now honors include_content=False like all other message content. If you rely on this setting, consider reviewing previously exported traces for retry prompt content that should not have been recorded.

Workaround for Unpatched Versions

If you cannot upgrade, scrub or drop the message attributes (gen_ai.input.messages, gen_ai.output.messages, pydantic_ai.all_messages) in your telemetry pipeline (for example with an OpenTelemetry Collector processor), or use tool-based structured output modes, whose retry feedback honors include_content=False.

Credits

Reported privately by the University of Sydney Security Research Team (Liyi Zhou, Ziyue Wang, Strick, Maurice, Chenchen Yu), and later independently discovered and reported publicly, with a fix, by @​sean-kim05.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI Web chat UI (Agent.to_web(), clai web): a website visited by the developer can trigger agent runs and server-side tool execution on the local chat endpoint

CVE-2026-107295 / GHSA-h4xc-3qfq-jf93

More information

Details

Summary

The Pydantic AI development web chat UI (Agent.to_web(), clai web) did not check the content type of requests to its chat endpoint. This allowed a website visited by a developer to submit a request to a chat UI running on that developer's machine, causing the served agent to run and to execute its tools with the privileges and credentials of the local process.

Binding the web UI to localhost — the default — does not prevent this, because a page open in the developer's browser can reach the loopback address.

Impact

Applications and developers serving an agent through Agent.to_web() or clai web. The consequences depend on the tools the served agent exposes, and can include data disclosure as well as unwanted tool side effects. Tools marked requires_approval=True were not protected either, because the endpoint trusts approval decisions relayed by the client.

Mitigation

Upgrade to a patched version. The chat endpoint now requires Content-Type: application/json and rejects other requests before the request body is parsed and before the agent runs. The bundled chat UI already sends this header; scripts and other non-browser clients that call the endpoint directly may need to be updated to send it.

If you cannot upgrade, don't run the web UI while browsing untrusted sites, stop it when you aren't using it, and don't serve an agent with side-effecting tools through it.

Credits
  • Thai Son Dinh from VinSOC Labs (R&D)

Severity

  • CVSS Score: 7.6 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI Web chat UI (Agent.to_web(), clai web): the local chat endpoint does not validate the Host header

CVE-2026-107292 / GHSA-q2xc-rrxj-58x9

More information

Details

Summary

The Pydantic AI development web chat UI (Agent.to_web(), clai web) does not validate the Host header of incoming requests. A website a developer visits can use DNS rebinding to make requests to a chat UI running on that developer's machine appear same-origin to the browser, causing the served agent to run and to execute its tools with the privileges and credentials of the local process.

Details

Once a name the attacker controls resolves to the loopback address, the browser treats the request as same-origin, so neither an Origin check nor a CSRF token constrains it — a same-origin page can read the served UI and any token in it.

Binding the web UI to localhost — the default — does not prevent this.

Impact

Applications and developers serving an agent through Agent.to_web() or clai web. The consequences depend on the tools the served agent exposes, and can include data disclosure as well as unwanted tool side effects.

Current browser protections reduce but do not remove this exposure: Chromium's Local Network Access gates loopback subresource requests, but does not cover top-level navigations, and Safari does not implement it.

Mitigation

Upgrade to pydantic-ai/pydantic-ai-slim >= 2.30.0, or >= 1.107.5 on the v1 maintenance line.

The fix validates the Host header and rejects anything other than localhost, a loopback/LAN IP address, or an explicitly allowed host, responding 421 Misdirected Request otherwise. If you serve the web chat UI under a real hostname — behind a reverse proxy, tunnel, or similar — name it explicitly:

app = agent.to_web(allowed_hosts=['ui.example.com'])

Severity

  • CVSS Score: 6.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:H/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI OpenTelemetry instrumentation: exception events on tool and agent run spans include content when include_content=False

CVE-2026-107291 / GHSA-4x9p-g9wm-8q7f

More information

Details

Summary

Pydantic AI's OpenTelemetry instrumentation supports InstrumentationSettings(include_content=False) to exclude message content — user prompts, model completions, tool call arguments and responses, and any other message content — from exported telemetry, so that agents can be monitored without sending sensitive content to the observability backend.

The message attributes honoured the setting. Several other parts of the same spans did not, and exported content regardless of it:

  • Exceptions. Recorded as OpenTelemetry exception events, with their message and stack trace, on tool, agent run, model request, embedding and image generation spans, and on realtime session spans. The message of the exception carrying a tool's ModelRetry or ToolFailed feedback is the text sent back to the model, which can quote tool arguments and results. When a tool ran out of retries, the error that ended the run was chained from the last retry, so its stack trace repeated that text on the run span. Exceptions raised by tool code were recorded with their full message, as were failures of a model request, embedding or image generation, whose messages carry the provider's error response body.
  • The error status description. The OpenTelemetry SDK describes a span's ERROR status with the exception's type and message, so the message reached the backend a second time even where the event itself was redacted.
  • Instructions and the prompted-output template. The model_request_parameters attribute serialized the request's instruction parts in full, exporting the agent's instructions — both static and those built from dependencies at request time — along with the template used to prompt for structured output.
Details

Content reaches these places because of what they carry rather than through any single missing check, which is why the setting was applied correctly to the message attributes (gen_ai.input.messages, gen_ai.tool.call.arguments, gen_ai.tool.call.result, and so on) while these paths were not: the exception recording and the status description came from the OpenTelemetry SDK's defaults, and the instructions and output template were serialized as part of the request's parameters rather than treated as content.

Impact

This does not grant an attacker any new access to the agent or its data: the content is only visible to whoever can read the exported telemetry. The exposure matters when traces are exported to a destination whose audience is broader or less trusted than the agent's own data — a third-party observability vendor or a shared backend — which is the scenario include_content=False exists for.

Who Is Affected

You are affected if you enabled instrumentation with include_content=False. Instructions are exported on every successful run, so no failure is needed to be affected; the exception paths additionally require a tool to raise, or a model, embedding or image generation request to fail. Realtime sessions are affected the same way, through the errors their provider connections report. GHSA-3gh4-cghq-f8v4 stated that retries coming from tool calls were redacted correctly; that was true of the retry prompt in the message attributes but not of the exception event on the tool span. You are not affected if you don't set include_content=False.

Remediation

Upgrade to a patched version. With include_content=False, exception events now record only the exception type, error statuses carry no description, and model_request_parameters is exported without its instruction content or output template. If you rely on this setting, consider reviewing previously exported traces for exception events, for error status descriptions, and for model_request_parameters.

Workaround for Unpatched Versions

If you cannot upgrade, scrub the exception.message and exception.stacktrace event attributes, the error status description, and the instruction parts and prompted_output_template within model_request_parameters, on spans emitted by Pydantic AI in your telemetry pipeline (for example with an OpenTelemetry Collector processor). Setting include_model_request_parameters=False alongside include_content=False removes both, at the cost of the rest of that attribute.

Credits

Reported privately by @​BrianWillows, whose report covered the exception events on tool and agent run spans. The remaining paths were found while fixing it, by a test that drives content through every channel at once and checks the whole exported trace.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI: Event loop blocked by quadratic title extraction in web_fetch

CVE-2026-107290 / GHSA-fpf4-vwcp-v4hp

More information

Details

Summary

The local web-fetch tool (web_fetch_tool, also used as the WebFetch capability's local fallback) processed responses with several steps whose running time grows quadratically with the size of certain server-controlled inputs, and ran them on the event loop: decoding the body with whichever charset the server declared, extracting the page title with a backtracking regular expression, and converting the HTML to markdown. An application that exposes this tool to untrusted prompts can be steered to fetch an attacker-controlled page of a megabyte or two that blocks the event loop for minutes, stalling every other coroutine in the process — other agent runs, other requests being served — for the duration.

This is an availability issue only. SSRF protections and the download size limit introduced in GHSA-v2xh-2vp8-57h8 are unaffected; that limit bounds how much is downloaded, not how long the response takes to process.

Details

Title extraction used a backtracking pattern over the raw response body, so a body made of repeated unterminated tag openings cost time proportional to the square of its size. The HTML-to-markdown conversion had the same shape in three of its steps: normalizing whitespace, stripping preformatted blocks, and numbering ordered lists all took time proportional to the square of a run of spaces or a list's length. All of it ran on the event loop, and the regex steps hold the interpreter lock even when moved off it, so the whole process paid for the size of a server-controlled response.

The response body was also decoded on the event loop with the codec named by the charset parameter of the response's Content-Type, looked up in Python's codec registry. That registry includes punycode, whose decoder takes time proportional to the square of its input: a response of about one megabyte labelled charset=punycode blocked the event loop for roughly half a minute, with no HTML required. The registry also includes codecs that aren't text encodings at all, such as rot_13 and base64_codec; a response labelled with one of those raised an unexpected exception out of the tool, aborting the agent run that fetched it.

Separately, the HTML-to-markdown conversion recursed once per nested element, so a page nested a few hundred elements deep raised a RecursionError out of the tool, aborting the agent run that fetched it. A JSON response nested deeper than the interpreter allows did the same. These only affect that one run.

Who Is Affected

You are affected if your application registers the local web-fetch tool (or relies on the WebFetch capability's local fallback) and exposes the agent to untrusted prompts. allowed_domains narrows the exposure to pages on those domains but does not remove it. Applications that only fetch developer-controlled URLs are not exposed to the model-chosen attack path.

Remediation

Upgrade to a patched version. The title is now found with a single linear scan, the conversion steps above run in linear time, and decoding, title extraction and conversion all run in a worker thread. A charset naming a codec that isn't a text encoding, and a page too deeply nested to convert, are reported back to the model as a failed fetch instead of aborting the run; a JSON body too deeply nested to parse is returned as plain text.

Credits

Reported privately by @​BrianWillows, whose report covered the quadratic title extraction. The response decoding, the codecs that are not text encodings, and the quadratic steps in the HTML-to-markdown conversion were found while fixing it.

Severity

  • CVSS Score: 6.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv6 zone identifiers

CVE-2026-107289 / GHSA-vmxc-h2x2-jmf3

More information

Details

Summary

When an application using Pydantic AI opts a URL into local network access — either a FileUrl with force_download='allow-local', or web_fetch_tool(allow_local_urls=True) — the cloud-metadata blocklist could be bypassed by appending an IPv6 zone identifier to a metadata address (for example fd00:ec2::254%251). The host ignores the zone identifier on a destination that is not link-local and delivers the request to the metadata endpoint anyway, exposing cloud IAM short-term credentials.

This is an incomplete fix of GHSA-cqp8-fcvh-x7r3 / CVE-2026-46678 and GHSA-cg7w-rg45-pc59 / CVE-2026-48782, themselves follow-ups to CVE-2026-25580. The parent advisory's remediation guaranteed that cloud metadata endpoints are always blocked, even with local access allowed. That guarantee did not hold for zone-scoped spellings of the IPv6 metadata endpoints.

Details

The cloud-metadata guard compared IPv6 addresses against its blocklist by set membership. Python includes the zone identifier in IPv6Address equality and hashing, so a zone-scoped spelling of a blocked address did not match, while the network stack ignores the zone identifier for a destination that is not link-local. The private-range checks, and the IPv4 and transition-form metadata checks, were already unaffected, because they compare by network containment and by packed bytes respectively.

Only the IPv6 cloud metadata endpoints were reachable this way, so the issue requires an IPv6-enabled environment — for example AWS EC2 or EKS with IPv6, GCP IPv6-only instances, or Scaleway.

Who Is Affected

You are affected only if your application opts a URL that is, or could be, influenced by untrusted input into local network access, through either:

  • a FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) with force_download='allow-local'; or
  • web_fetch_tool(allow_local_urls=True), where the model chooses the URL.

Both are off by default.

You are not affected through the FileUrl path if you use any of the bundled integrations to ingest user input, because they do not propagate force_download from external data:

  • Agent.to_web / clai web
  • VercelAIAdapter
  • AGUIAdapter / Agent.to_ag_ui

web_fetch_tool is configured by your own application, so a client cannot turn on allow_local_urls.

Applications that only download from developer-controlled URLs are not affected.

Remediation

Upgrade to a patched version. The cloud-metadata and private-IP checks now drop an IPv6 zone identifier before evaluating the address, so every blocklist comparison is made on the address itself. A zone identifier is still carried on the connection, so legitimate link-local fetches under local network access continue to work.

Workaround for Unpatched Versions

Avoid opting into local network access — force_download='allow-local' or web_fetch_tool(allow_local_urls=True) — on any URL that could be influenced by untrusted input. If you must, reject URL hosts containing % before constructing the FileUrl or configuring the tool.

Credits

Reported by @​euriconicacio.

Severity

  • CVSS Score: 6.8 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI: Excessive resource use when local web fetching converts nested HTML

CVE-2026-107287 / GHSA-v36g-jcw9-x7cw

More information

Details

Summary

Applications using Pydantic AI's local web-fetch tool can experience excessive CPU and memory use when it converts attacker-controlled HTML. An agent must fetch the affected page; provider-native web fetching is not affected.

Details

Nested block elements cause HTML-to-Markdown conversion to reprocess accumulated text at each level and can greatly expand the intermediate output. The response-body limit bounds downloaded bytes, while the returned-content limit is applied only after conversion. On current releases, conversion runs in a worker thread but can still consume substantial resources and delay other work in the process. Older releases performed conversion on the event loop.

Mitigation

Upgrade to a patched release of pydantic-ai or pydantic-ai-slim. If you cannot upgrade yet, avoid using local web fetching for attacker-controlled HTML.

Severity

  • CVSS Score: 6.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Pydantic AI: Concurrency-limited models can keep their slot when a streamed request ends early

CVE-2026-107286 / GHSA-6fqq-452j-qhrp

More information

Details

This issue was posted by Codex Desktop using gpt-6.1-sol on behalf of David.

Summary

Applications that wrap a model with ConcurrencyLimitedModel or limit_model_concurrency can permanently lose shared concurrency capacity when a streamed request releases its slot from a different task than the one that acquired it. This can happen when a stream ends early, and also when a stream is fully consumed using the default stream_text() debouncing.

In an application that exposes an affected streaming endpoint to network clients and shares a long-lived model limiter across requests, a client can repeatedly start a stream and disconnect. The completed requests retain their slots, eventually preventing subsequent requests that share the limiter from proceeding.

Agent-level max_concurrency and non-streaming model requests are not affected by this defect.

Details

The built-in limiter uses anyio.CapacityLimiter, which associates each acquired slot with its borrowing task. Pydantic AI's streaming lifecycle can acquire the slot on the task consuming the stream and run cleanup on another internal task. The limiter rejects that release, so the slot remains occupied even after the request has ended. Cleanup can raise a RuntimeError; a later request on the borrowing task can also fail because that task still holds a slot.

Early termination includes stopping iteration, a consumer exception, and cancellation. Fully consuming stream_text() with its default debounce_by=0.1 can also reach the cross-task release path. Fully consumed streams must therefore not be assumed safe.

Mitigation

Upgrade to a patched release of pydantic-ai or pydantic-ai-slim. If you cannot upgrade yet, use the agent-level max_concurrency setting instead of a concurrency-limited model, or avoid streaming runs through a concurrency-limited model.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Release Notes

pydantic/pydantic-ai (pydantic-ai)

v2.53.0: (2026-10-01)

Compare Source

🛡️ Security

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

  • 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
🚀 Features
🐛 Bug Fixes
  • Kill the process group when a LocalWorkspaceBackend.run timeout fires during process startup by @​dsfaccini in #​9358
  • Ask for CLAI2 keychain access once per session by encrypting credentials with one keyring-held key by @​mpfaffenberger in #​9465
  • Name CLAI2 worktree branches clai-NAME and reopen existing worktrees with --worktree NAME by @​mpfaffenberger in #​9462
  • Avoid invalid-escape warning floods during CodeMode analysis by @​mpfaffenberger in #​9475
  • Group clai2 resume sessions by repository identity by @​mpfaffenberger in #​9482
  • Create the CLAI2 plugins folder at startup by @​mpfaffenberger in #​9484
  • Keep the registered Memory toolset across runs so durable execution accepts it by @​mpfaffenberger in #​9489
  • Keep the registered Planning toolset across runs so durable execution accepts it by @​mpfaffenberger in #​9507
  • Keep planted files from escaping BubblewrapSandbox on the next launch by @​dsfaccini in #​9457
  • Render non-finite eval metrics as inf/-inf/nan by @​pydanty in #​8852
  • Snap gemini-3.1-flash-image thinking efforts to minimal and high on the Gemini API by @​dsfaccini in #​9515
  • Raise UnexpectedModelBehavior instead of running the wrong tool when function tool calls share a tool_call_id by @​pydanty in #​8782
  • Explain that CLAI2 needs a restart when /reload hits a stale Harness import by @​mpfaffenberger in #​9571
  • Build one streamed XaiModel thinking part per output, matching the non-streamed response by @​DouweM in #​9416
  • Leave image generation calls out of the OpenAIResponsesModel replay when openai_store=False by @​DouweM in #​9388
  • Build the same ModelResponse from streamed and complete OpenAIChatModel and OpenRouterModel responses by @​DouweM in #​9418
  • Make OpenAIResponsesModel build the same ModelResponse from a stream as from a complete response by @​DouweM in #​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 #​9070
  • Tolerate OpenAI realtime status, status_details and session values the SDK does not know yet by @​DouweM in #​9392
  • Stop SubAgents from forcing thinking on disk agents by @​DouweM in #​9384
  • Restore DynamicWorkflow reveal announcements after compaction or history loss by @​DouweM in #​9371
  • Preserve free-text focus in CLAI2 /compact by @​mpfaffenberger in #​9587
  • Make Logfire Temporal spans replay-safe by @​DouweM in #​7006
  • Keep the launch-directory workspace in clai2 when capability functions supply none, and expose unrestricted_filesystem in /plugins configure coder by @​mpfaffenberger in #​9593
  • Allow unschemable types in the derived Temporal ActivityConfig schema by @​pydanty in #​9577
  • Let GoogleRealtimeModel declare tools whose dict values are recursive models by @​dsfaccini in #​9607
📦 Dependencies

New Contributors

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

v2.52.0: (2026-09-29)

Compare Source

🛡️ 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

New Contributors

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

v2.51.0: (2026-09-25)

Compare Source

What's Changed

⚠️ Compatibility Notes
  • Match dated gemini-3.8-live ids, reject google_affective_dialog on Gemini 3.1 Flash Live and 3.8 Live at connect, and raise RealtimeError for Gemini Live close codes by @​DouweM in #​8761
  • Raise a UserError for a realtime tool_choice that forces a tool call on OpenAI, Azure OpenAI, and xAI by @​DouweM in #​8755
🚀 Features
  • Add OpenAI GPT-Live support with OpenAILiveModel by @​DouweM in #​8390
  • Expose context_window_used on realtime sessions, from GPT-Live's reported ratio or response usage by @​DouweM in #​8803
🐛 Bug Fixes
  • Reduce RunContext copying overhead in capability hooks by @​Kludex in #​8775
  • Keep provider_details on OpenAI Realtime tool-call responses and the response id on replies cut off by a drop or close() by @​DouweM in #​8762
  • Buffer text deltas in CompletedStreamedResponse replay by @​Kludex in #​8799
  • Resend a recent image with a typed Gemini Live turn, which doesn't see video frames by @​DouweM in #​8756
  • Cache the agent graph instead of rebuilding it on every Agent.run() by @​Kludex in #​8658
  • Stop spawning a task group when a toolset or capability fan-out has a single child by @​Kludex in #​8774

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.50.0...v2.51.0

v2.50.0: (2026-09-24)

Compare Source

What's Changed

⚠️ Compatibility Notes
  • Ask a DecisionModel which route to take by name, with one label per route by @​DouweM in #​8733
  • Make ModelSelectionContext.messages end with the request being routed, and add ModelSelectionContext.prompt by @​DouweM in #​8737
  • Replace the decision model's tool-call lean with an opt-in decision_route_threshold by @​DouweM in #​8739
🚀 Features
  • Expose OpenAI service_tier in provider details by @​pydanty in #​7945
  • Add DecisionModel, a base for Decisions-protocol models, and make TypeSafeModel one by @​DouweM in #​8696
  • Add RunContext.in_durable_context so hooks can tell they run in durable workflow code by @​mpfaffenberger in #​8723
  • Add gemini-3.8-live and gemini-3.8-live-extended-thinking realtime support by @​DouweM in #​8393
  • Ask a DecisionModel's route fields with the route question under a route premise, with nested-field context and a done state after tool calls by @​DouweM in #​8749
  • Emit a decide span for every request a DecisionModel sends by @​DouweM in #​8698
🐛 Bug Fixes
  • Keep the type variable of a generic OutputSpec[T] passed to Agent.run under mypy by @​DouweM in #​8730
  • Send ThinkingParts in the history decision models judge by @​DouweM in #​8738
  • Price Anthropic one-hour cache writes at the one-hour rate instead of the five-minute rate by @​kazmer97 in #​8666
  • Price realtime image input at the image rate by @​DouweM in #​8741
  • Add RequestUsage.audio_seconds so duration-billed voice models are priced by @​DouweM in #​8427
  • Offer a decision model's unfillable output_type as a route beside other routes, and rename ToolCallProposed to UnfillableRoute under a DecisionHandOff base by @​DouweM in #​8744
  • Keep realtime user turns whole when the microphone streams continuously on providers without input item IDs by @​DouweM in #​8746
  • Roll back a realtime send the provider refuses, so wait_for_reply() no longer hangs on it by @​DouweM in #​8747
  • Turn reasoning off for thinking=False on OpenAI Realtime by sending reasoning.effort: 'none' by @​DouweM in #​8753
  • Take Jev's context_window from genai-prices and document compacting a Jev conversation by @​DouweM in #​8740
  • Buffer five minutes of audio per stream_audio() view so speaker-paced playback gets whole replies by @​DouweM in #​8750
  • Stop Google Search from crashing Gemini 2.5 native-audio realtime sessions by @​DouweM in #​8751
  • Keep user speech out of Gemini 3.x realtime history when input transcription is off by @​DouweM in #​8754
  • Surface a failed OpenAI realtime response's error as a RealtimeSessionErrorEvent by @​DouweM in #​8752

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.49.0...v2.50.0

v2.49.0: (2026-09-23)

Compare Source

What's Changed

🚀 Features
  • Add GitHubCopilotOAuthFlow for device authorization by @​Kludex in #​8618
  • Add BoolCriteria to say what a bool field's yes and no mean, and let a True/False Enum do the same by @​DouweM in #​8586
  • Use what the user wrote about None as the "none of these" option in TypeSafeModel by @​DouweM in #​8684
  • Offer whole numbers that are not a rubric as a Choice in TypeSafeModel by @​DouweM in #​8686
  • Add RealtimeSession.wait_for_reply() by @​DouweM in #​8514
🐛 Bug Fixes
  • Keep all streamed OpenAIChatModel logprobs in provider_details['logprobs'] by @​adtyavrdhn in #​8653
  • Allow gpt-6-sol, gpt-6-luna, and gpt-6-astra on Bedrock Converse by @​sevakva in #​8656
  • fix: preserve fanned producer contributions in graph joins by @​FIITAY in #​8385
  • Surface @GraphBuilder.stream node errors in-context during graph.iter() by @​pydanty in #​8304
  • Forward Cloud Storage gs:// references as fileData in GoogleImageGenerationModel on Vertex AI by @​dorukgezici in #​8225
  • Preserve output tool names and descriptions for Annotated model types by @​ikriv in #​8608
  • Type None in a list of output types as | None so output_type=[Foo, Bar, None] passes pyright by @​DouweM in #​8641
  • Fix google_proactive_audio, which no Gemini Live session could ever connect with by @​DouweM in #​8394
  • Drop temperature and top_p for OpenAI GPT-5.6 and GPT-6 on Bedrock Converse instead of failing with a 400 by @​kimnamu in #​8668
  • Let a field's default apply when TypeSafeModel answers "None of these" for an optional field by @​DouweM in #​8685
  • Surface realtime receive-side failures to every consumer shape, and end send_audio(iterable) cleanly on close by @​DouweM in #​8138
  • Keep Annotated metadata on the members of an X | Y output_type by @​DouweM in #​8687
  • Keep an uninstrumented delegate's usage off its caller's agent run span by @​DouweM in #​8689
  • Let a nested model's default apply when TypeSafeModel answers "None of these" for every field under it by @​DouweM in #​8697
  • Accept Annotated, Literal and union output_types as PEP 747 TypeForms, and bump pyright to 1.1.414 by @​DouweM in #​8690
  • Make RunContext.tracer, trace_include_content and instrumentation_version follow an explicit Instrumentation capability by @​DouweM in #​8706
  • Send deferred tools with native tool search on OpenAICodexModel instead of failing with a 400 by @​aweis89 in #​8693

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.48.0...v2.49.0

v2.48.0: (2026-09-22)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes
📦 Dependencies

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.47.0...v2.48.0

v2.47.0: (2026-09-21)

Compare Source

What's Changed

⚠️ Compatibility Notes
  • Name a None output route None rather than NoneType by @​DouweM in #​8590
  • Raise when UserPromptPart.content is not a str or a sequence, instead of silently sending a dict's keys by @​DouweM in #​8595
🚀 Features
🐛 Bug Fixes
📦 Dependencies

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.46.0...v2.47.0

v2.46.0: (2026-09-18)

Compare Source

What's Changed

🚀 Features
  • Let TypeSafeModel fill a tool's arguments when Jev can express them by @​DouweM in #​8501
  • Add RealtimeSession.wait_for_playback() and let the docs examples finish the reply before closing by @​DouweM in #​8141
  • Add supports_text_output to ModelProfile, and run LLMJudge and GEval on a model without it by @​DouweM in #​8480
  • Add typesafe_boolean_threshold for what a yes/no has to be before it is True by @​DouweM in #​8505
  • Let TypeSafeModel fill a union of output types by choosing the type first by @​DouweM in #​8481
  • Add event_stream_topic to TemporalDurability to stream agent events via Workflow Streams by @​brianstrauch in #​6639
  • Describe an Enum's options by its member docstrings when it mixes in UseEnumMemberDocstrings by @​DouweM in #​8479
  • Add a Choices helper for a set of described options built at run time by @​DouweM in #​8530
🐛 Bug Fixes
  • Refuse more options than Jev can pick from in TypeSafeModel by @​DouweM in #​8484
  • Record a failed ToolReturnPart when a realtime tool raises, and keep a tool call and its speech in one ModelResponse by @​DouweM in #​8135
  • Dispatch tool calls with the live ToolDefinition in CombinedToolset and FunctionToolset by @​adtyavrdhn in #​8082
  • Allow adaptive thinking with tool output and forced tool choice on Bedrock by @​pydanty in #​7967
  • Fix gateway IDs being misclassified as OpenAI o-series models by @​DouweM in #​8512
  • Keep late realtime input transcripts attached to the user turn they belong to by @​DouweM in #​8139
  • Lay the first-run banner out for the terminal's actual width by @​DouweM in #​8517
  • Raise ModelRetry when web_fetch_tool gets a URL httpx2 rejects as invalid by @​DouweM in #​8521
  • Price realtime responses so usage.cost and UsageLimits.cost_limit work in a session by @​DouweM in #​8136
  • Re-arm coverage for code already seen when the dataclass walk resumes it by @​DouweM in #​8438

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.45.0...v2.46.0

v2.45.0: (2026-09-17)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes
  • Pass xhigh effort through on Bedrock when the model profile supports it by @​willfrey in #​8392
  • Allow gpt-5.6-sol, gpt-5.6-luna, and gpt-5.6-terra on Bedrock Converse by @​pydanty in #​7825
  • Resolve a DynamicToolset once per durable run instead of inside every durable unit by @​DouweM in #​8455
  • Hold one MCP server session per durable run instead of one per durable unit by @​DouweM in #​8463
  • Preserve tool history in MCPSamplingModel by @​DouweM in #​8466
  • Stop importing legacy httpx in pydantic_ai.mcp, which a FastMCP 4 install does not ship by @​DouweM in #​8461
  • Report each agent run's own usage on its span by @​DouweM in #​8456

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.44.0...v2.45.0

v2.44.0: (2026-09-16)

Compare Source

🛡️ Security

This release fixes four security issues, all of them reached through web_fetch_tool or OpenTelemetry instrumentation. See each advisory for full details and affected versions.

  • GHSA-vmxc-h2x2-jmf3 (moderate): the cloud-metadata and private-IP blocklists could be bypassed with an IPv6 zone identifier on a URL opted into local network access, via FileUrl(force_download='allow-local') or web_fetch_tool(allow_local_urls=True). Both are off by default. Reported by @​euriconicacio. (#​8401)
  • GHSA-fpf4-vwcp-v4hp (moderate): web_fetch processed responses in superlinear time on the event loop, in both the HTML conversion and the charset decode, so a single attacker-chosen page could stall every agent in the process. Reported by @​BrianWillows. (#​8397, #​8418, #​8433)
  • GHSA-22h6-qm39-v87j (low): web_fetch_tool's domain lists were compared as written rather than in the form the resolver uses, so a blocked domain could be reached under another spelling. (#​8407, #​8421)
  • GHSA-4x9p-g9wm-8q7f (low): with InstrumentationSettings(include_content=False), spans still carried exceptions, error statuses, instructions and the output template. Reported by @​BrianWillows. (#​8403, #​8408, #​8419, #​8428)

Patched in 2.44.0 (v2) and 1.107.6 (v1).

What's Changed

⚠️ Compatibility Notes
  • Make RunContext.enqueue() safe from worker threads by @​adtyavrdhn in #​7758
  • Require a JSON Content-Type on UI adapter requests by @​DouweM in #​8396
  • Dispatch a capability @durable_operation called from a per-request hook, instead of silently running it inline by @​DouweM in #​8395
🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.43.0...v2.44.0

v2.43.0: (2026-09-11)

Compare Source

What's Changed

🚀 Features
  • Add a first-run banner describing the run, and open clai sessions with it by @​DouweM in #​7447
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.42.0...v2.43.0

v2.42.0: (2026-09-08)

Compare Source

What's Changed

⚠️ Compatibility Notes
🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.41.0...v2.42.0

v2.41.0: (2026-09-07)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.40.0...v2.41.0

v2.40.0: (2026-09-04)

Compare Source

What's Changed

🚀 Features
  • Add pydantic_ai.prices.update_in_background() by @​adtyavrdhn in #​4841
  • Handle barge-in in the session: handle_barge_in=True, interrupt(played_bytes=...), and played_audio_bytes by @​DouweM in #​7870
  • Add provider_factory to infer_realtime_model by @​DouweM in #​8106
  • Add @agent.on_event for registering event listeners on an Agent by @​DouweM in #​8101
  • Add respond= to RealtimeSession.send() and document that a text turn solicits a reply by @​DouweM in #​8110
  • Add RealtimeSession.enqueue() for out-of-band prompts from code driving the session by @​DouweM in #​8109
🐛 Bug Fixes
  • Map finish_reason on OpenAI Responses stream terminal events by @​pydanty in #​7916
  • Fix defer_loading reveal synthesis splitting a parallel batch's tool_result from its tool_use by @​pydanty in #​7879
  • fix(realtime): roll back user-turn state when an audio chunk is not bytes-like by @​simpleqt in #​7905
  • Let a capability cache derived state again, and refuse a collection the merge cannot rebuild by @​DouweM in #​8099
  • Make a capability's auto-assigned registry key look like the run-local handle it is by @​DouweM in #​8119
  • Stop sending reasoning to the dated gpt-realtime-2025-08-28 snapshot by @​DouweM in #​8103
  • Subscribe stream_audio() and stream_transcripts() views when they are called, not on first iteration by @​DouweM in #​8107
  • End the realtime audio and transcript views when a tool fails and nobody is iterating by @​DouweM in #​8108
  • Let a realtime tool hang up with ctx.realtime_session.close() instead of wedging itself by @​DouweM in #​8105
  • Fix the realtime "Speaking first" and relay examples, the interrupt(played_ms=) cancel race, and two provider tables by @​DouweM in #​8132

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.39.0...v2.40.0

v2.39.0: (2026-09-03)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes
  • Fix the context_subtree() exporter cache and its span-processor leaks by @​dsfaccini in #​7667
  • Restore the Instrumentation spec option include_model_request_parameters and sharpen the undeclared-attribute merge error by @​DouweM in #​8046
  • Detect Azure content-filter errors for AzureProvider and for AsyncAzureOpenAI clients on OpenAIProvider by @​quinnarnold in #​7922
  • Emit speech finalized by a tool call on stream_transcripts() by @​DouweM in #​8062
  • Attribute tool-returned media to its originating tool call when it can't ride the tool result by @​dsfaccini in #​7830
  • Restore capability composition invariants by @​dsfaccini in #​8047

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.38.0...v2.39.0

v2.38.0: (2026-09-03)

Compare Source

What's Changed

⚠️ Compatibility Notes
🚀 Features
🐛 Bug Fixes
  • Support CancellationToken in UI adapter run methods by @​dsfaccini in #​7743
  • Stop pytest tests/durable_exec/temporal from crashing when the suite's requirements are missing by @​dsfaccini in #​7898
  • Fix DeepSeek and Together forced tool_choice handling and support NativeOutput on DeepSeek's Responses API by @​dsfaccini in #​7450
  • Restore raw tool-call IDs when replaying Bedrock Mantle Responses history by @​dsfaccini in #​7962
  • Keep a run cancelled during its first tool call resumable by @​DouweM in #​7993
  • Fix CodeExecutionTool uploads never reaching a fresh Anthropic container on a multi-turn history by @​dsfaccini in #​7864
  • Prevent synthetic reasoning IDs from reaching OpenAI Responses by @​dsfaccini in #​8020
  • Emit REASONING_* events from ag-ui-protocol 0.1.11 instead of 0.1.13 by @​dsfaccini in #​7226
  • Accept the environment-key call pattern in GoogleProvider's overload by @​dsfaccini in #​8030
  • Fix XaiModel streamed text after a native tool call being merged into the ended pre-call part by @​pydanty[bot] in #​7925
  • Persist Anthropic stale thinking-block recovery across turns by @​dsfaccini in #​8037
  • Preserve dynamic native factory config in XSearch and ImageGeneration fallback subagents by @​CoralGarden52 in #​7541
📦 Dependencies

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.37.0...v2.38.0

v2.37.0: (2026-08-31)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.36.0...v2.37.0

v2.36.0: (2026-08-28)

Compare Source

What's Changed

⚠️ Compatibility Notes
🚀 Features
  • Add @durable_operation for capabilities and a public backend API for third-party durable execution engines by @​DouweM in #​6696
  • Give instruction parts a stable InstructionPart.id by @​DouweM in #​6887
  • Accept async iterables in RealtimeSession.send_audio() and move the voice example to listentome by @​DouweM in #​7860
  • Require an explicit operation name on @durable_operation by @​DouweM in #​7868
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.35.3...v2.36.0

v2.35.3: (2026-08-27)

Compare Source

What's Changed

🐛 Bug Fixes

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.35.1...v2.35.3

v2.35.1: (2026-08-26)

Compare Source

What's Changed

🐛 Bug Fixes
  • Carry Bedrock guardrail trace in ModelResponse.provider_details by @​pydanty in #​7562
  • Honor provider_factory when cancelling Temporal responses by @​DouweM in #​7000
  • Cap dbos below 2.31.0 to avoid a missing opentelemetry-instrumentation-logging import by @​dsfaccini in #​7804

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.35.0...v2.35.1

v2.35.0: (2026-08-25)

Compare Source

What's Changed

⚠️ Compatibility Notes
  • Deprecate RunContext.capability_loaded and available_capability_ids in favor of capability_active and active_capability_ids by @​DouweM in #​7454
  • Make inclusive integer maximum reachable in TestModel by @​pydanty in #​7697
🚀 Features
🐛 Bug Fixes

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.34.0...v2.35.0

v2.34.0: (2026-08-24)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.33.0...v2.34.0

v2.33.0: (2026-08-20)

Compare Source

⚠️ If Anthropic stopped working for you in the last day

anthropic 1.0.0 — rebuilt on httpx2, with legacy httpx support removed — reached PyPI on August 20. Every earlier pydantic-ai release, including v2.32.2 cut a few hours before this one, allowed that version without supporting it: a fresh or unpinned install of pydantic-ai[anthropic] could resolve anthropic 1.0.0 and then fail at runtime when using an Anthropic model. Apologies for the breakage window.

  • Fix: upgrade to pydantic-ai v2.33.0, which requires and supports anthropic>=1.0.0.
  • If you need to stay on an older pydantic-ai: pin anthropic<1.

If you pass your own http_client to AnthropicProvider, it must now be an httpx2.AsyncClient — the 1.x SDK rejects legacy httpx clients at construction.

What's Changed

⚠️ Compatibility Notes

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.32.2...v2.33.0

v2.32.2: (2026-08-20)

Compare Source

What's Changed

🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.32.1...v2.32.2

v2.32.1: (2026-08-19)

Compare Source

What's Changed

🐛 Bug Fixes

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.32.0...v2.32.1

v2.32.0: (2026-08-18)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes
  • Run sync hooks in a thread pool and enforce timeout= for blocking sync tools and hooks by @​adtyavrdhn in #​7557
  • Record RunContext.cancel() from setup-phase for_run hooks instead of raising UserError by @​adtyavrdhn in #​7567
  • Treat a response containing only empty text parts as having no text output by @​adtyavrdhn in #​7568
  • Only list available tools in the unknown-tool retry message by @​adtyavrdhn in #​7572
  • Sort tool results ahead of tool availability announcements so Bedrock accepts turns revealing multiple tools by @​adtyavrdhn in #​7571
  • Drop native tool calls the replayed payload has no result block for by @​dsfaccini in #​7504
📦 Dependencies

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.31.1...v2.32.0

v2.31.1: (2026-08-17)

Compare Source

What's Changed

🐛 Bug Fixes
  • Deny native structured output for Claude Sonnet 5 and Fable 5 on Bedrock by @​pydanty[bot] in #​7374
  • Fall back to thinking_level='LOW' for Gemini models that reject MINIMAL by @​pydanty[bot] in #​7469

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.31.0...v2.31.1

v2.31.0: (2026-08-14)

Compare Source

What's Changed

🚀 Features
  • Allow a UIEventStream to be built without a run_input, and give AGUIEventStream its own thread_id/run_id by @​dsfaccini in #​7292
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.30.0...v2.31.0

v2.30.0: (2026-08-13)

Compare Source

What's Changed

🛡️ Security
  • GHSA-q2xc-rrxj-58x9: the local dev web chat UI (Agent.to_web(), clai web) didn't validate the Host header, so DNS rebinding from a website you visit could reach it and run the served agent with your local process's tools and credentials. Fixed in pydantic-ai/pydantic-ai-slim 2.30.0 by validating Host against localhost/loopback/LAN addresses by default; deployments reached under a real hostname must opt in with the new allowed_hosts setting.
🚀 Features
🐛 Bug Fixes
  • Resolve deferred openai resource imports and genai-prices data loading at Model construction time by @​adtyavrdhn in #​7408
  • Fall back to ASCII in EvaluationReport.print() on non-UTF-8 consoles by @​dsfaccini in #​7290
  • Lowercase model name before profile lookup in SambaNova, Heroku, and Fireworks providers by @​pydanty[bot] in #​6818
  • Update LatestCerebrasModelNames to current model catalog by @​pydanty[bot] in #​6838
  • Require a deferred tool to be revealed, and its capability loaded, before it can be called by @​DouweM in #​7271
  • Anchor the tool-callability evidence window to the response's serving provider by @​DouweM in #​7442

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.29.0...v2.30.0

v2.29.0: (2026-08-12)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.28.0...v2.29.0

v2.28.0: (2026-08-11)

Compare Source

🛡️ Security

Fixes a high-severity vulnerability in the development web chat UI (Agent.to_web(), clai web): the chat endpoint didn't check the request's content type, so a plain cross-origin request from a website open in the developer's browser could reach the endpoint without a CORS preflight and trigger the served agent to run and execute its tools with the local process's privileges and credentials. The endpoint now requires Content-Type: application/json and rejects other requests before the body is parsed and before the agent runs. See GHSA-h4xc-3qfq-jf93. Patched in 2.28.0 (v2) and 1.107.4 (v1).

What's Changed

🚀 Features
🐛 Bug Fixes
📦 Dependencies

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.27.1...v2.28.0

v2.27.1: (2026-08-10)

Compare Source

🛡️ Security

This release fixed an information-disclosure issue: retry-prompt content (validation feedback sent back to the model, which can quote invalid values from its output) was not redacted by InstrumentationSettings(include_content=False) when the retry was not tied to a tool call. Now disclosed as GHSA-3gh4-cghq-f8v4 (low). Fixed here in 2.27.1 (#​7357); v1 users should upgrade to 1.107.4 or later.

What's Changed

🐛 Bug Fixes

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.27.0...v2.27.1

v2.27.0: (2026-08-07)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes
  • Honor include_binary_content=False in every OTel serialization sink by @​dsfaccini in #​7131
  • Keep ToolReturn.tools in the redacted OTel shape by @​DouweM in #​7273
  • Fix SpanQuery has_attributes matching for JSON-serialized dict and list values by @​pydanty[bot] in #​5905
  • Skip re-sending the standing prompt where the OpenAI Responses compaction item retains it by @​DouweM in #​7264
  • Round-trip Anthropic compaction encrypted_content verbatim by @​DouweM in #​7286
  • Strip the compaction provenance stamp in sanitize_messages by @​DouweM in #​7285
  • Point at the cause when a tool return or model response exceeds Temporal's payload size limit by @​dsfaccini in #​7157

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.26.0...v2.27.0

v2.26.0: (2026-08-06)

Compare Source

What's Changed

🚀 Features
  • Support hiding function tools until revealed — via tool search, load_capability, or ToolReturn.tools — using each provider's native deferral/addition channel by @​DouweM in #​7104
  • Add first-party run cancellation: AgentRun.cancel(), RunContext.cancel(), RunCancelled by @​DouweM in #​6497
  • Add Model.resolve_prompt_cache_retention() to resolve effective prompt-cache retention from model settings by @​DouweM in #​7254
  • Promote run_stream_events() iterator to public AgentRunEvents handle with cancel() and run-state access by @​DouweM in #​6498
  • Cover and document DeepSeek V4 Flash via OpenAIResponsesModel + DeepSeekProvider by @​dsfaccini in #​7202
🐛 Bug Fixes
  • Forward model_id through WrapperModel and resolve it against the active model in TemporalModel by @​dsfaccini in #​7181
  • Map streamed OpenRouter reasoning details by their index by @​VictorPeralta in #​7214
  • Gate OpenRouter off native mid-conversation system messages with supports_inline_system_prompts=False by @​DouweM in #​7253
  • Restore the released legacy profile-key shim and fix two reveal-state edges (is_tool_available, TestModel native additions) by @​DouweM in #​7260
  • Keep deferred tools searchable after discovery and reset reveal state at CompactionPart boundaries by @​DouweM in #​7225
  • Forward events from UIEventStream callbacks that return an async iterator without being an async generator function by @​DouweM in #​7256
  • Send only the compacted window: drop history before the latest same-provider CompactionPart by @​DouweM in #​7228

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.25.0...v2.26.0

v2.25.0: (2026-08-05)

Compare Source

What's Changed

🚀 Features
🐛 Bug Fixes

New Contributors

Full Changelog: https://github.com/pydantic/pydantic-ai/compare/v2.24.0...v2.25.0


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [pydantic-ai](https://github.com/pydantic/pydantic-ai) ([changelog](https://github.com/pydantic/pydantic-ai/releases)) | dependency-groups | minor | `2.24.0` → `2.53.0` | --- ### Pydantic AI OpenTelemetry instrumentation: retry prompt content is not redacted when `include_content=False` [CVE-2026-107293](https://nvd.nist.gov/vuln/detail/CVE-2026-107293) / [GHSA-3gh4-cghq-f8v4](https://github.com/advisories/GHSA-3gh4-cghq-f8v4) <details> <summary>More information</summary> #### Details ##### Summary Pydantic AI's OpenTelemetry instrumentation supports `InstrumentationSettings(include_content=False)` to exclude message content — user prompts, model completions, tool call arguments and responses — from exported telemetry, so that agents can be monitored without sending sensitive content to the observability backend. Retry prompts — the feedback messages Pydantic AI sends back to the model when its output fails validation or an output validator raises `ModelRetry` — were not covered by this setting when they were not associated with a tool call, as with structured output modes that don't use tool calls (e.g. `NativeOutput` or `PromptedOutput`) and output validators applied to text output. Their full content was recorded on model request spans even with `include_content=False`. Since validation feedback can quote invalid values from the model's response, message content that the setting was configured to withhold could reach the telemetry backend. ##### Details Retry prompts without an associated tool call were serialized into span message attributes (such as `gen_ai.input.messages` and `pydantic_ai.all_messages`) as regular text parts, and this path did not apply the `include_content` check that every other message part applies. Retry prompts tied to a tool call, and all other message content, were redacted correctly. ##### Impact This does not grant an attacker any new access to the agent or its data: the content is only visible to whoever can read the exported telemetry. The exposure matters when traces are exported to a destination whose audience is broader or less trusted than the agent's own data — a third-party observability vendor or a shared backend — which is the scenario `include_content=False` exists for. The disclosed content is limited to retry feedback: validation error details, which can quote invalid values from the model's output, or output-validator `ModelRetry` messages. ##### Who Is Affected You are affected if you enabled instrumentation with `include_content=False` and your agent can produce retry prompts outside of tool calls: it uses a structured output mode that doesn't rely on tool calls (such as `NativeOutput` or `PromptedOutput`), or output validators on text output. You are not affected if you don't set `include_content=False`, or if all of your agent's retries come from tool calls (including the default tool-based structured output mode), which were redacted correctly. ##### Remediation Upgrade to a patched version; retry prompt content now honors `include_content=False` like all other message content. If you rely on this setting, consider reviewing previously exported traces for retry prompt content that should not have been recorded. ##### Workaround for Unpatched Versions If you cannot upgrade, scrub or drop the message attributes (`gen_ai.input.messages`, `gen_ai.output.messages`, `pydantic_ai.all_messages`) in your telemetry pipeline (for example with an OpenTelemetry Collector processor), or use tool-based structured output modes, whose retry feedback honors `include_content=False`. ##### Credits Reported privately by the University of Sydney Security Research Team (Liyi Zhou, Ziyue Wang, Strick, Maurice, Chenchen Yu), and later independently discovered and reported publicly, with a fix, by @&#8203;sean-kim05. #### Severity - CVSS Score: 2.3 / 10 (Low) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-3gh4-cghq-f8v4](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-3gh4-cghq-f8v4) - [https://github.com/pydantic/pydantic-ai/pull/7357](https://github.com/pydantic/pydantic-ai/pull/7357) - [https://github.com/pydantic/pydantic-ai/commit/fe9dbed7b7ccf7e7128b5786886e4441f6f5594f](https://github.com/pydantic/pydantic-ai/commit/fe9dbed7b7ccf7e7128b5786886e4441f6f5594f) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.27.1](https://github.com/pydantic/pydantic-ai/releases/tag/v2.27.1) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-3gh4-cghq-f8v4) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI Web chat UI (`Agent.to_web()`, `clai web`): a website visited by the developer can trigger agent runs and server-side tool execution on the local chat endpoint [CVE-2026-107295](https://nvd.nist.gov/vuln/detail/CVE-2026-107295) / [GHSA-h4xc-3qfq-jf93](https://github.com/advisories/GHSA-h4xc-3qfq-jf93) <details> <summary>More information</summary> #### Details ##### Summary The Pydantic AI development web chat UI (`Agent.to_web()`, `clai web`) did not check the content type of requests to its chat endpoint. This allowed a website visited by a developer to submit a request to a chat UI running on that developer's machine, causing the served agent to run and to execute its tools with the privileges and credentials of the local process. Binding the web UI to localhost — the default — does not prevent this, because a page open in the developer's browser can reach the loopback address. ##### Impact Applications and developers serving an agent through `Agent.to_web()` or `clai web`. The consequences depend on the tools the served agent exposes, and can include data disclosure as well as unwanted tool side effects. Tools marked `requires_approval=True` were not protected either, because the endpoint trusts approval decisions relayed by the client. ##### Mitigation Upgrade to a patched version. The chat endpoint now requires `Content-Type: application/json` and rejects other requests before the request body is parsed and before the agent runs. The bundled chat UI already sends this header; scripts and other non-browser clients that call the endpoint directly may need to be updated to send it. If you cannot upgrade, don't run the web UI while browsing untrusted sites, stop it when you aren't using it, and don't serve an agent with side-effecting tools through it. ##### Credits - Thai Son Dinh from VinSOC Labs (R&D) #### Severity - CVSS Score: 7.6 / 10 (High) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:L` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-h4xc-3qfq-jf93](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-h4xc-3qfq-jf93) - [https://github.com/pydantic/pydantic-ai/pull/7382](https://github.com/pydantic/pydantic-ai/pull/7382) - [https://github.com/pydantic/pydantic-ai/pull/7383](https://github.com/pydantic/pydantic-ai/pull/7383) - [https://github.com/pydantic/pydantic-ai/commit/d2690201a1834005d382dbf5c47e0ed94ef8bf46](https://github.com/pydantic/pydantic-ai/commit/d2690201a1834005d382dbf5c47e0ed94ef8bf46) - [https://github.com/pydantic/pydantic-ai/commit/dd2abbdfa029c9ad138e7cc0edd2eaeaf9ed69c0](https://github.com/pydantic/pydantic-ai/commit/dd2abbdfa029c9ad138e7cc0edd2eaeaf9ed69c0) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.4](https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.4) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.28.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.28.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-h4xc-3qfq-jf93) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI Web chat UI (`Agent.to_web()`, `clai web`): the local chat endpoint does not validate the `Host` header [CVE-2026-107292](https://nvd.nist.gov/vuln/detail/CVE-2026-107292) / [GHSA-q2xc-rrxj-58x9](https://github.com/advisories/GHSA-q2xc-rrxj-58x9) <details> <summary>More information</summary> #### Details ##### Summary The Pydantic AI development web chat UI (`Agent.to_web()`, `clai web`) does not validate the `Host` header of incoming requests. A website a developer visits can use DNS rebinding to make requests to a chat UI running on that developer's machine appear same-origin to the browser, causing the served agent to run and to execute its tools with the privileges and credentials of the local process. ##### Details Once a name the attacker controls resolves to the loopback address, the browser treats the request as same-origin, so neither an `Origin` check nor a CSRF token constrains it — a same-origin page can read the served UI and any token in it. Binding the web UI to localhost — the default — does not prevent this. ##### Impact Applications and developers serving an agent through `Agent.to_web()` or `clai web`. The consequences depend on the tools the served agent exposes, and can include data disclosure as well as unwanted tool side effects. Current browser protections reduce but do not remove this exposure: Chromium's Local Network Access gates loopback subresource requests, but does not cover top-level navigations, and Safari does not implement it. ##### Mitigation Upgrade to `pydantic-ai`/`pydantic-ai-slim` >= 2.30.0, or >= 1.107.5 on the v1 maintenance line. The fix validates the `Host` header and rejects anything other than localhost, a loopback/LAN IP address, or an explicitly allowed host, responding `421 Misdirected Request` otherwise. If you serve the web chat UI under a real hostname — behind a reverse proxy, tunnel, or similar — name it explicitly: ```python app = agent.to_web(allowed_hosts=['ui.example.com']) ``` #### Severity - CVSS Score: 6.4 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:H/A:L` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-q2xc-rrxj-58x9](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-q2xc-rrxj-58x9) - [https://github.com/pydantic/pydantic-ai/pull/7437](https://github.com/pydantic/pydantic-ai/pull/7437) - [https://github.com/pydantic/pydantic-ai/pull/7438](https://github.com/pydantic/pydantic-ai/pull/7438) - [https://github.com/pydantic/pydantic-ai/commit/394cc1d31656620704a703a2daed752afa5135fe](https://github.com/pydantic/pydantic-ai/commit/394cc1d31656620704a703a2daed752afa5135fe) - [https://github.com/pydantic/pydantic-ai/commit/871c7aeec5dfed2138655ccbccbf15c6d763bae7](https://github.com/pydantic/pydantic-ai/commit/871c7aeec5dfed2138655ccbccbf15c6d763bae7) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.5](https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.5) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.30.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.30.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-q2xc-rrxj-58x9) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI OpenTelemetry instrumentation: exception events on tool and agent run spans include content when `include_content=False` [CVE-2026-107291](https://nvd.nist.gov/vuln/detail/CVE-2026-107291) / [GHSA-4x9p-g9wm-8q7f](https://github.com/advisories/GHSA-4x9p-g9wm-8q7f) <details> <summary>More information</summary> #### Details ##### Summary Pydantic AI's OpenTelemetry instrumentation supports `InstrumentationSettings(include_content=False)` to exclude message content — user prompts, model completions, tool call arguments and responses, and any other message content — from exported telemetry, so that agents can be monitored without sending sensitive content to the observability backend. The message attributes honoured the setting. Several other parts of the same spans did not, and exported content regardless of it: - **Exceptions.** Recorded as OpenTelemetry exception events, with their message and stack trace, on tool, agent run, model request, embedding and image generation spans, and on realtime session spans. The message of the exception carrying a tool's `ModelRetry` or `ToolFailed` feedback is the text sent back to the model, which can quote tool arguments and results. When a tool ran out of retries, the error that ended the run was chained from the last retry, so its stack trace repeated that text on the run span. Exceptions raised by tool code were recorded with their full message, as were failures of a model request, embedding or image generation, whose messages carry the provider's error response body. - **The error status description.** The OpenTelemetry SDK describes a span's ERROR status with the exception's type and message, so the message reached the backend a second time even where the event itself was redacted. - **Instructions and the prompted-output template.** The `model_request_parameters` attribute serialized the request's instruction parts in full, exporting the agent's instructions — both static and those built from dependencies at request time — along with the template used to prompt for structured output. ##### Details Content reaches these places because of what they carry rather than through any single missing check, which is why the setting was applied correctly to the message attributes (`gen_ai.input.messages`, `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result`, and so on) while these paths were not: the exception recording and the status description came from the OpenTelemetry SDK's defaults, and the instructions and output template were serialized as part of the request's parameters rather than treated as content. ##### Impact This does not grant an attacker any new access to the agent or its data: the content is only visible to whoever can read the exported telemetry. The exposure matters when traces are exported to a destination whose audience is broader or less trusted than the agent's own data — a third-party observability vendor or a shared backend — which is the scenario `include_content=False` exists for. ##### Who Is Affected You are affected if you enabled instrumentation with `include_content=False`. Instructions are exported on every successful run, so no failure is needed to be affected; the exception paths additionally require a tool to raise, or a model, embedding or image generation request to fail. Realtime sessions are affected the same way, through the errors their provider connections report. GHSA-3gh4-cghq-f8v4 stated that retries coming from tool calls were redacted correctly; that was true of the retry prompt in the message attributes but not of the exception event on the tool span. You are not affected if you don't set `include_content=False`. ##### Remediation Upgrade to a patched version. With `include_content=False`, exception events now record only the exception type, error statuses carry no description, and `model_request_parameters` is exported without its instruction content or output template. If you rely on this setting, consider reviewing previously exported traces for exception events, for error status descriptions, and for `model_request_parameters`. ##### Workaround for Unpatched Versions If you cannot upgrade, scrub the `exception.message` and `exception.stacktrace` event attributes, the error status description, and the instruction parts and `prompted_output_template` within `model_request_parameters`, on spans emitted by Pydantic AI in your telemetry pipeline (for example with an OpenTelemetry Collector processor). Setting `include_model_request_parameters=False` alongside `include_content=False` removes both, at the cost of the rest of that attribute. ##### Credits Reported privately by @&#8203;BrianWillows, whose report covered the exception events on tool and agent run spans. The remaining paths were found while fixing it, by a test that drives content through every channel at once and checks the whole exported trace. #### Severity - CVSS Score: 2.3 / 10 (Low) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-4x9p-g9wm-8q7f](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-4x9p-g9wm-8q7f) - [https://github.com/pydantic/pydantic-ai/pull/8403](https://github.com/pydantic/pydantic-ai/pull/8403) - [https://github.com/pydantic/pydantic-ai/pull/8404](https://github.com/pydantic/pydantic-ai/pull/8404) - [https://github.com/pydantic/pydantic-ai/pull/8408](https://github.com/pydantic/pydantic-ai/pull/8408) - [https://github.com/pydantic/pydantic-ai/pull/8428](https://github.com/pydantic/pydantic-ai/pull/8428) - [https://github.com/pydantic/pydantic-ai/pull/8429](https://github.com/pydantic/pydantic-ai/pull/8429) - [https://github.com/pydantic/pydantic-ai/commit/4e013c51a50659aba2adf7853bfb22bb77f6a518](https://github.com/pydantic/pydantic-ai/commit/4e013c51a50659aba2adf7853bfb22bb77f6a518) - [https://github.com/pydantic/pydantic-ai/commit/6b14c74cb281f899a2ae4fae5327111e33f60771](https://github.com/pydantic/pydantic-ai/commit/6b14c74cb281f899a2ae4fae5327111e33f60771) - [https://github.com/pydantic/pydantic-ai/commit/7ee27e38ab2e525ca60ff1a25d16413ff989fd79](https://github.com/pydantic/pydantic-ai/commit/7ee27e38ab2e525ca60ff1a25d16413ff989fd79) - [https://github.com/pydantic/pydantic-ai/commit/963dec5f70d6f558997fc259356c0090cc5ea487](https://github.com/pydantic/pydantic-ai/commit/963dec5f70d6f558997fc259356c0090cc5ea487) - [https://github.com/pydantic/pydantic-ai/commit/de4e61515327bd80a19cd8552001c30933e6acc3](https://github.com/pydantic/pydantic-ai/commit/de4e61515327bd80a19cd8552001c30933e6acc3) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6](https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-4x9p-g9wm-8q7f) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI: Event loop blocked by quadratic title extraction in `web_fetch` [CVE-2026-107290](https://nvd.nist.gov/vuln/detail/CVE-2026-107290) / [GHSA-fpf4-vwcp-v4hp](https://github.com/advisories/GHSA-fpf4-vwcp-v4hp) <details> <summary>More information</summary> #### Details ##### Summary The local web-fetch tool (`web_fetch_tool`, also used as the `WebFetch` capability's local fallback) processed responses with several steps whose running time grows quadratically with the size of certain server-controlled inputs, and ran them on the event loop: decoding the body with whichever charset the server declared, extracting the page title with a backtracking regular expression, and converting the HTML to markdown. An application that exposes this tool to untrusted prompts can be steered to fetch an attacker-controlled page of a megabyte or two that blocks the event loop for minutes, stalling every other coroutine in the process — other agent runs, other requests being served — for the duration. This is an **availability** issue only. SSRF protections and the download size limit introduced in GHSA-v2xh-2vp8-57h8 are unaffected; that limit bounds how much is downloaded, not how long the response takes to process. ##### Details Title extraction used a backtracking pattern over the raw response body, so a body made of repeated unterminated tag openings cost time proportional to the square of its size. The HTML-to-markdown conversion had the same shape in three of its steps: normalizing whitespace, stripping preformatted blocks, and numbering ordered lists all took time proportional to the square of a run of spaces or a list's length. All of it ran on the event loop, and the regex steps hold the interpreter lock even when moved off it, so the whole process paid for the size of a server-controlled response. The response body was also decoded on the event loop with the codec named by the `charset` parameter of the response's `Content-Type`, looked up in Python's codec registry. That registry includes `punycode`, whose decoder takes time proportional to the square of its input: a response of about one megabyte labelled `charset=punycode` blocked the event loop for roughly half a minute, with no HTML required. The registry also includes codecs that aren't text encodings at all, such as `rot_13` and `base64_codec`; a response labelled with one of those raised an unexpected exception out of the tool, aborting the agent run that fetched it. Separately, the HTML-to-markdown conversion recursed once per nested element, so a page nested a few hundred elements deep raised a `RecursionError` out of the tool, aborting the agent run that fetched it. A JSON response nested deeper than the interpreter allows did the same. These only affect that one run. ##### Who Is Affected You are affected if your application registers the local web-fetch tool (or relies on the `WebFetch` capability's local fallback) and exposes the agent to untrusted prompts. `allowed_domains` narrows the exposure to pages on those domains but does not remove it. Applications that only fetch developer-controlled URLs are not exposed to the model-chosen attack path. ##### Remediation Upgrade to a patched version. The title is now found with a single linear scan, the conversion steps above run in linear time, and decoding, title extraction and conversion all run in a worker thread. A charset naming a codec that isn't a text encoding, and a page too deeply nested to convert, are reported back to the model as a failed fetch instead of aborting the run; a JSON body too deeply nested to parse is returned as plain text. ##### Credits Reported privately by @&#8203;BrianWillows, whose report covered the quadratic title extraction. The response decoding, the codecs that are not text encodings, and the quadratic steps in the HTML-to-markdown conversion were found while fixing it. #### Severity - CVSS Score: 6.5 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-fpf4-vwcp-v4hp](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-fpf4-vwcp-v4hp) - [https://github.com/pydantic/pydantic-ai/pull/8397](https://github.com/pydantic/pydantic-ai/pull/8397) - [https://github.com/pydantic/pydantic-ai/pull/8399](https://github.com/pydantic/pydantic-ai/pull/8399) - [https://github.com/pydantic/pydantic-ai/pull/8418](https://github.com/pydantic/pydantic-ai/pull/8418) - [https://github.com/pydantic/pydantic-ai/pull/8433](https://github.com/pydantic/pydantic-ai/pull/8433) - [https://github.com/pydantic/pydantic-ai/pull/8434](https://github.com/pydantic/pydantic-ai/pull/8434) - [https://github.com/pydantic/pydantic-ai/commit/2faa6181d8a17d83bc9516d035c5270db8730fa0](https://github.com/pydantic/pydantic-ai/commit/2faa6181d8a17d83bc9516d035c5270db8730fa0) - [https://github.com/pydantic/pydantic-ai/commit/9cdc952e4c3319e85a3e04f2de49fbbb765bd38b](https://github.com/pydantic/pydantic-ai/commit/9cdc952e4c3319e85a3e04f2de49fbbb765bd38b) - [https://github.com/pydantic/pydantic-ai/commit/a93ea5226be1e93ae13131ae3f22287190411389](https://github.com/pydantic/pydantic-ai/commit/a93ea5226be1e93ae13131ae3f22287190411389) - [https://github.com/pydantic/pydantic-ai/commit/c3fd1cc1f15fdbf750d78e4e3ec1e8b4d6a3d920](https://github.com/pydantic/pydantic-ai/commit/c3fd1cc1f15fdbf750d78e4e3ec1e8b4d6a3d920) - [https://github.com/pydantic/pydantic-ai/commit/fb92ccfc3ca2735dab877e2ed73856681bf72ad1](https://github.com/pydantic/pydantic-ai/commit/fb92ccfc3ca2735dab877e2ed73856681bf72ad1) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6](https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv6 zone identifiers [CVE-2026-107289](https://nvd.nist.gov/vuln/detail/CVE-2026-107289) / [GHSA-vmxc-h2x2-jmf3](https://github.com/advisories/GHSA-vmxc-h2x2-jmf3) <details> <summary>More information</summary> #### Details ##### Summary When an application using Pydantic AI opts a URL into local network access — either a `FileUrl` with `force_download='allow-local'`, or `web_fetch_tool(allow_local_urls=True)` — the cloud-metadata blocklist could be bypassed by appending an IPv6 zone identifier to a metadata address (for example `fd00:ec2::254%251`). The host ignores the zone identifier on a destination that is not link-local and delivers the request to the metadata endpoint anyway, exposing cloud IAM short-term credentials. This is an incomplete fix of [GHSA-cqp8-fcvh-x7r3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cqp8-fcvh-x7r3) / [CVE-2026-46678](https://nvd.nist.gov/vuln/detail/CVE-2026-46678) and [GHSA-cg7w-rg45-pc59](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cg7w-rg45-pc59) / [CVE-2026-48782](https://nvd.nist.gov/vuln/detail/CVE-2026-48782), themselves follow-ups to [CVE-2026-25580](https://nvd.nist.gov/vuln/detail/CVE-2026-25580). The parent advisory's remediation guaranteed that cloud metadata endpoints are always blocked, even with local access allowed. That guarantee did not hold for zone-scoped spellings of the IPv6 metadata endpoints. ##### Details The cloud-metadata guard compared IPv6 addresses against its blocklist by set membership. Python includes the zone identifier in `IPv6Address` equality and hashing, so a zone-scoped spelling of a blocked address did not match, while the network stack ignores the zone identifier for a destination that is not link-local. The private-range checks, and the IPv4 and transition-form metadata checks, were already unaffected, because they compare by network containment and by packed bytes respectively. Only the IPv6 cloud metadata endpoints were reachable this way, so the issue requires an IPv6-enabled environment — for example AWS EC2 or EKS with IPv6, GCP IPv6-only instances, or Scaleway. ##### Who Is Affected You are affected **only if** your application opts a URL that is, or could be, influenced by untrusted input into local network access, through either: - a `FileUrl` (`ImageUrl`, `AudioUrl`, `VideoUrl`, `DocumentUrl`) with `force_download='allow-local'`; or - `web_fetch_tool(allow_local_urls=True)`, where the model chooses the URL. Both are off by default. You are **not** affected through the `FileUrl` path if you use any of the bundled integrations to ingest user input, because they do not propagate `force_download` from external data: - `Agent.to_web` / `clai web` - `VercelAIAdapter` - `AGUIAdapter` / `Agent.to_ag_ui` `web_fetch_tool` is configured by your own application, so a client cannot turn on `allow_local_urls`. Applications that only download from developer-controlled URLs are not affected. ##### Remediation Upgrade to a patched version. The cloud-metadata and private-IP checks now drop an IPv6 zone identifier before evaluating the address, so every blocklist comparison is made on the address itself. A zone identifier is still carried on the connection, so legitimate link-local fetches under local network access continue to work. ##### Workaround for Unpatched Versions Avoid opting into local network access — `force_download='allow-local'` or `web_fetch_tool(allow_local_urls=True)` — on any URL that could be influenced by untrusted input. If you must, reject URL hosts containing `%` before constructing the `FileUrl` or configuring the tool. ##### Credits Reported by [@&#8203;euriconicacio](https://github.com/euriconicacio). #### Severity - CVSS Score: 6.8 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-vmxc-h2x2-jmf3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-vmxc-h2x2-jmf3) - [https://github.com/pydantic/pydantic-ai/pull/8401](https://github.com/pydantic/pydantic-ai/pull/8401) - [https://github.com/pydantic/pydantic-ai/pull/8402](https://github.com/pydantic/pydantic-ai/pull/8402) - [https://github.com/pydantic/pydantic-ai/commit/02157e1b87bd45d3f2e111ce07afdf89f9fb0e5b](https://github.com/pydantic/pydantic-ai/commit/02157e1b87bd45d3f2e111ce07afdf89f9fb0e5b) - [https://github.com/pydantic/pydantic-ai/commit/4da70591460f51a8c4f128eaeef70a33340dbd55](https://github.com/pydantic/pydantic-ai/commit/4da70591460f51a8c4f128eaeef70a33340dbd55) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6](https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-vmxc-h2x2-jmf3) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI: Excessive resource use when local web fetching converts nested HTML [CVE-2026-107287](https://nvd.nist.gov/vuln/detail/CVE-2026-107287) / [GHSA-v36g-jcw9-x7cw](https://github.com/advisories/GHSA-v36g-jcw9-x7cw) <details> <summary>More information</summary> #### Details ##### Summary Applications using Pydantic AI's local web-fetch tool can experience excessive CPU and memory use when it converts attacker-controlled HTML. An agent must fetch the affected page; provider-native web fetching is not affected. ##### Details Nested block elements cause HTML-to-Markdown conversion to reprocess accumulated text at each level and can greatly expand the intermediate output. The response-body limit bounds downloaded bytes, while the returned-content limit is applied only after conversion. On current releases, conversion runs in a worker thread but can still consume substantial resources and delay other work in the process. Older releases performed conversion on the event loop. ##### Mitigation Upgrade to a patched release of `pydantic-ai` or `pydantic-ai-slim`. If you cannot upgrade yet, avoid using local web fetching for attacker-controlled HTML. #### Severity - CVSS Score: 6.5 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-v36g-jcw9-x7cw](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-v36g-jcw9-x7cw) - [https://github.com/pydantic/pydantic-ai/pull/8984](https://github.com/pydantic/pydantic-ai/pull/8984) - [https://github.com/pydantic/pydantic-ai/pull/8985](https://github.com/pydantic/pydantic-ai/pull/8985) - [https://github.com/pydantic/pydantic-ai/commit/2b247add4950bef61d352e7ca8aefbd20539180c](https://github.com/pydantic/pydantic-ai/commit/2b247add4950bef61d352e7ca8aefbd20539180c) - [https://github.com/pydantic/pydantic-ai/commit/2fd38792693da00a3ca5412aeffb436787af3545](https://github.com/pydantic/pydantic-ai/commit/2fd38792693da00a3ca5412aeffb436787af3545) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.7](https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.7) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.52.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.52.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-v36g-jcw9-x7cw) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Pydantic AI: Concurrency-limited models can keep their slot when a streamed request ends early [CVE-2026-107286](https://nvd.nist.gov/vuln/detail/CVE-2026-107286) / [GHSA-6fqq-452j-qhrp](https://github.com/advisories/GHSA-6fqq-452j-qhrp) <details> <summary>More information</summary> #### Details > This issue was posted by Codex Desktop using gpt-6.1-sol on behalf of David. ##### Summary Applications that wrap a model with `ConcurrencyLimitedModel` or `limit_model_concurrency` can permanently lose shared concurrency capacity when a streamed request releases its slot from a different task than the one that acquired it. This can happen when a stream ends early, and also when a stream is fully consumed using the default `stream_text()` debouncing. In an application that exposes an affected streaming endpoint to network clients and shares a long-lived model limiter across requests, a client can repeatedly start a stream and disconnect. The completed requests retain their slots, eventually preventing subsequent requests that share the limiter from proceeding. Agent-level `max_concurrency` and non-streaming model requests are not affected by this defect. ##### Details The built-in limiter uses `anyio.CapacityLimiter`, which associates each acquired slot with its borrowing task. Pydantic AI's streaming lifecycle can acquire the slot on the task consuming the stream and run cleanup on another internal task. The limiter rejects that release, so the slot remains occupied even after the request has ended. Cleanup can raise a `RuntimeError`; a later request on the borrowing task can also fail because that task still holds a slot. Early termination includes stopping iteration, a consumer exception, and cancellation. Fully consuming `stream_text()` with its default `debounce_by=0.1` can also reach the cross-task release path. Fully consumed streams must therefore not be assumed safe. ##### Mitigation Upgrade to a patched release of `pydantic-ai` or `pydantic-ai-slim`. If you cannot upgrade yet, use the agent-level `max_concurrency` setting instead of a concurrency-limited model, or avoid streaming runs through a concurrency-limited model. #### Severity - CVSS Score: 7.5 / 10 (High) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` #### References - [https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-6fqq-452j-qhrp](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-6fqq-452j-qhrp) - [https://nvd.nist.gov/vuln/detail/CVE-2026-107286](https://nvd.nist.gov/vuln/detail/CVE-2026-107286) - [https://github.com/pydantic/pydantic-ai/pull/9478](https://github.com/pydantic/pydantic-ai/pull/9478) - [https://github.com/pydantic/pydantic-ai/commit/453f19feeb7ab1d789f9393b1723c6a73b3d77b2](https://github.com/pydantic/pydantic-ai/commit/453f19feeb7ab1d789f9393b1723c6a73b3d77b2) - [https://github.com/pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) - [https://github.com/pydantic/pydantic-ai/releases/tag/v2.53.0](https://github.com/pydantic/pydantic-ai/releases/tag/v2.53.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-6fqq-452j-qhrp) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>pydantic/pydantic-ai (pydantic-ai)</summary> ### [`v2.53.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.53.0): (2026-10-01) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.52.0...v2.53.0) <!-- 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 [@&#8203;lche511](https://github.com/lche511). ([#&#8203;9478](https://github.com/pydantic/pydantic-ai/issues/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 [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8783](https://github.com/pydantic/pydantic-ai/pull/8783) - Make `clai2` plugins declarative `Plugin` subclasses, modeled on `AbstractCapability` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9493](https://github.com/pydantic/pydantic-ai/pull/9493) - Move session naming into `clai2` and deprecate `pydantic_ai_harness.step_persistence.naming` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9499](https://github.com/pydantic/pydantic-ai/pull/9499) ##### 🚀 Features - Add a built-in `posthog` plugin to `pydantic-clai2` with `/keys` or browser sign-in by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8901](https://github.com/pydantic/pydantic-ai/pull/8901) - Add a built-in `grain` plugin to `clai2` with a keyring-backed Grain sign-in by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8905](https://github.com/pydantic/pydantic-ai/pull/8905) - Add a built-in `linear` plugin to `clai2` with a settings menu and `/keys` credentials by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8949](https://github.com/pydantic/pydantic-ai/pull/8949) - Count Google grounding web search queries in `usage` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8891](https://github.com/pydantic/pydantic-ai/pull/8891) - Add `AbsurdDurability` to the harness as a replacement for `pydantic-ai-absurd` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8946](https://github.com/pydantic/pydantic-ai/pull/8946) - Let CLAI2 plugins run models under their own prefix with `host.model_provider` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9468](https://github.com/pydantic/pydantic-ai/pull/9468) - Apply theme-aware accents to the `clai2` status row by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9473](https://github.com/pydantic/pydantic-ai/pull/9473) - Add opt-in Logfire UI telemetry and a Logfire setup menu (region, sign-in, project) to `pydantic-clai2` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9467](https://github.com/pydantic/pydantic-ai/pull/9467) - Add an opt-in herdr plugin for `clai2` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9480](https://github.com/pydantic/pydantic-ai/pull/9480) - Let `AskUser` defer questions to the host and time out a slow answerer by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9509](https://github.com/pydantic/pydantic-ai/pull/9509) - Add a Codex-only `/fast` command to CLAI2 by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9518](https://github.com/pydantic/pydantic-ai/pull/9518) - Let /login take a provider name, and let plugins add their own sign-ins by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9485](https://github.com/pydantic/pydantic-ai/pull/9485) - Add `SystemOneModel` to run decision models such as CLM and Laya over the `/v1/systemone` API by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8942](https://github.com/pydantic/pydantic-ai/pull/8942) - CLAI2: plugin logins add their models; plugin models can use a provider's /model_settings controls by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9558](https://github.com/pydantic/pydantic-ai/pull/9558) - Rename the CLAI `logfire` plugin to `observability` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9566](https://github.com/pydantic/pydantic-ai/pull/9566) - Add `ToolCallJudge` to assess tool calls before execution by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9041](https://github.com/pydantic/pydantic-ai/pull/9041) - Add managed subagents to CLAI2, with Claude and Codex agent definitions in Harness by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9573](https://github.com/pydantic/pydantic-ai/pull/9573) - Add a settings menu to CLAI2's built-in `observability` (Logfire) plugin by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9306](https://github.com/pydantic/pydantic-ai/pull/9306) - CLAI2: `/update` with stable (PyPI) and bleeding (`main`) channels by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9576](https://github.com/pydantic/pydantic-ai/pull/9576) - Make the CLAI2 `/plugins` menu themed and readable, with plugin descriptions by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9570](https://github.com/pydantic/pydantic-ai/pull/9570) - Send images and documents from GPT-Live tool results to the delegated backend by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9048](https://github.com/pydantic/pydantic-ai/pull/9048) - Tag `clai2` plugin settings with the features they need, and skip a plugin capability that rejects its settings at run setup by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9569](https://github.com/pydantic/pydantic-ai/pull/9569) - Show compact used/max context in the CLAI2 status line by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9583](https://github.com/pydantic/pydantic-ai/pull/9583) - Expose the message-history repair pipeline as `repair_messages` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8370](https://github.com/pydantic/pydantic-ai/pull/8370) ##### 🐛 Bug Fixes - Kill the process group when a `LocalWorkspaceBackend.run` timeout fires during process startup by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;9358](https://github.com/pydantic/pydantic-ai/pull/9358) - Ask for CLAI2 keychain access once per session by encrypting credentials with one keyring-held key by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9465](https://github.com/pydantic/pydantic-ai/pull/9465) - Name CLAI2 worktree branches `clai-NAME` and reopen existing worktrees with `--worktree NAME` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9462](https://github.com/pydantic/pydantic-ai/pull/9462) - Avoid invalid-escape warning floods during `CodeMode` analysis by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9475](https://github.com/pydantic/pydantic-ai/pull/9475) - Group `clai2` resume sessions by repository identity by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9482](https://github.com/pydantic/pydantic-ai/pull/9482) - Create the CLAI2 plugins folder at startup by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9484](https://github.com/pydantic/pydantic-ai/pull/9484) - Keep the registered `Memory` toolset across runs so durable execution accepts it by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9489](https://github.com/pydantic/pydantic-ai/pull/9489) - Keep the registered `Planning` toolset across runs so durable execution accepts it by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9507](https://github.com/pydantic/pydantic-ai/pull/9507) - Keep planted files from escaping `BubblewrapSandbox` on the next launch by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;9457](https://github.com/pydantic/pydantic-ai/pull/9457) - Render non-finite eval metrics as `inf`/`-inf`/`nan` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8852](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 [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;9515](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 [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8782](https://github.com/pydantic/pydantic-ai/pull/8782) - Explain that CLAI2 needs a restart when `/reload` hits a stale Harness import by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9571](https://github.com/pydantic/pydantic-ai/pull/9571) - Build one streamed `XaiModel` thinking part per output, matching the non-streamed response by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9416](https://github.com/pydantic/pydantic-ai/pull/9416) - Leave image generation calls out of the `OpenAIResponsesModel` replay when `openai_store=False` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9388](https://github.com/pydantic/pydantic-ai/pull/9388) - Build the same `ModelResponse` from streamed and complete `OpenAIChatModel` and `OpenRouterModel` responses by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9418](https://github.com/pydantic/pydantic-ai/pull/9418) - Make `OpenAIResponsesModel` build the same `ModelResponse` from a stream as from a complete response by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9417](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 [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9070](https://github.com/pydantic/pydantic-ai/pull/9070) - Tolerate OpenAI realtime `status`, `status_details` and session values the SDK does not know yet by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9392](https://github.com/pydantic/pydantic-ai/pull/9392) - Stop `SubAgents` from forcing `thinking` on disk agents by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9384](https://github.com/pydantic/pydantic-ai/pull/9384) - Restore `DynamicWorkflow` reveal announcements after compaction or history loss by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9371](https://github.com/pydantic/pydantic-ai/pull/9371) - Preserve free-text focus in CLAI2 `/compact` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9587](https://github.com/pydantic/pydantic-ai/pull/9587) - Make Logfire Temporal spans replay-safe by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7006](https://github.com/pydantic/pydantic-ai/pull/7006) - Keep the launch-directory workspace in `clai2` when capability functions supply none, and expose `unrestricted_filesystem` in `/plugins configure coder` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9593](https://github.com/pydantic/pydantic-ai/pull/9593) - Allow unschemable types in the derived Temporal `ActivityConfig` schema by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;9577](https://github.com/pydantic/pydantic-ai/pull/9577) - Let `GoogleRealtimeModel` declare tools whose `dict` values are recursive models by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;9607](https://github.com/pydantic/pydantic-ai/pull/9607) ##### 📦 Dependencies - Bump CLAI2 to `termflow-md` 0.11.0 by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9483](https://github.com/pydantic/pydantic-ai/pull/9483) #### New Contributors - [@&#8203;Poojita060926](https://github.com/Poojita060926) made their first contribution in [#&#8203;8900](https://github.com/pydantic/pydantic-ai/pull/8900) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.52.0...v2.53.0> ### [`v2.52.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.52.0): (2026-09-29) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.51.0...v2.52.0) ##### 🛡️ Security This release fixes one security issue in `web_fetch`. See the advisory for full details and affected versions. - **[GHSA-v36g-jcw9-x7cw](https://github.com/pydantic/pydantic-ai/security/advisories/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 [@&#8203;SounLabs](https://github.com/SounLabs). ([#&#8203;8984](https://github.com/pydantic/pydantic-ai/issues/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 [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8866](https://github.com/pydantic/pydantic-ai/pull/8866) - Replace `ModalSandbox`'s own tools with a Modal workspace, so `Coder`, `Shell` and `FileSystem` run in the sandbox; `ModalSandboxBackend` replaces `ModalSandboxSession` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8867](https://github.com/pydantic/pydantic-ai/pull/8867) - Raise `AnthropicModel`'s default `max_tokens` from 4096 to 16384 on Claude Sonnet 4.5 and later by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9025](https://github.com/pydantic/pydantic-ai/pull/9025) - Keep the prompt as a `DecisionModel`'s judged `text` after a retry by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8967](https://github.com/pydantic/pydantic-ai/pull/8967) - Stop `SubAgents` loading agent files by default, and deprecate `inherit_tools` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9023](https://github.com/pydantic/pydantic-ai/pull/9023) - Default `AnthropicModel`'s `max_tokens` to the model's maximum output, streaming such requests behind the scenes by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9298](https://github.com/pydantic/pydantic-ai/pull/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 [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;6492](https://github.com/pydantic/pydantic-ai/pull/6492) - Add `SpritesSandbox`: a workspace that runs `Coder`, `Shell`, `FileSystem` and every other harness capability in a Fly.io Sprite by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8869](https://github.com/pydantic/pydantic-ai/pull/8869) - Add `E2BSandbox`: a workspace that runs `Coder`, `Shell`, `FileSystem` and every other harness capability in an E2B sandbox by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8868](https://github.com/pydantic/pydantic-ai/pull/8868) - Give `Coder` file tools a retry budget of 5 and keep scratch files out of the project by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8970](https://github.com/pydantic/pydantic-ai/pull/8970) - Add a `typesafe` extra to `pydantic-clai2` and reject models with a missing provider SDK at `/model` time by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8962](https://github.com/pydantic/pydantic-ai/pull/8962) - Add Claude Sonnet 5.5 (`claude-sonnet-5-5`) support by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8974](https://github.com/pydantic/pydantic-ai/pull/8974) - Model realtime async tool calls as a profile `async_tool_call_mode` with a shared `async_tool_calls` setting by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8813](https://github.com/pydantic/pydantic-ai/pull/8813) - Show tool-call arguments in `pydantic-clai2` tool headers, clipped by `display.tool_arg_chars` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9100](https://github.com/pydantic/pydantic-ai/pull/9100) - Open a `clai2` plugin's settings menu when it is turned on, and end every settings menu with Save & close by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9102](https://github.com/pydantic/pydantic-ai/pull/9102) - Add `_process_provider_details` hook to `OpenAIResponsesModel` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;9094](https://github.com/pydantic/pydantic-ai/pull/9094) - Add `clai2 --agent MODULE:ATTR` to chat with an existing `Agent` with plugins off by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9291](https://github.com/pydantic/pydantic-ai/pull/9291) - Add a built-in `github` plugin to `clai2` with a settings menu and its token in `/keys` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8904](https://github.com/pydantic/pydantic-ai/pull/8904) - Add a built-in `pylon` plugin to CLAI2 with a settings menu and a named `/keys` entry by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8953](https://github.com/pydantic/pydantic-ai/pull/8953) - Seed retained user audio on Gemini `gemini-3.1-flash-live-preview` and `gemini-3.8-live` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9047](https://github.com/pydantic/pydantic-ai/pull/9047) - Support browser WebRTC on OpenAI GPT-Live with `answer_webrtc_offer` and a sideband session by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9059](https://github.com/pydantic/pydantic-ai/pull/9059) - Add `SSHWorkspace` and `BubblewrapSandbox` harness capabilities by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8956](https://github.com/pydantic/pydantic-ai/pull/8956) - Add a `pydantic-clai2` console script so `uvx pydantic-clai2` runs CLAI by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9304](https://github.com/pydantic/pydantic-ai/pull/9304) - Add `azure_voice_live_voice` to choose an Azure voice for Azure AI Voice Live sessions by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9044](https://github.com/pydantic/pydantic-ai/pull/9044) - Add `google_workspace` as a built-in `clai2` plugin backed by harness `GoogleWorkspace` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8907](https://github.com/pydantic/pydantic-ai/pull/8907) - Apply `thinking`, `openai_turn_detection`, `openai_input_noise_reduction` and a new `azure_voice_live_temperature` on Azure AI Voice Live by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9051](https://github.com/pydantic/pydantic-ai/pull/9051) - Seed tool calls and results as native function parts on Gemini `gemini-3.8-live` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9058](https://github.com/pydantic/pydantic-ai/pull/9058) - Emit identified response, turn, and input lifecycle events from the OpenAI-protocol realtime connection by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9064](https://github.com/pydantic/pydantic-ai/pull/9064) - Add a built-in `day_ai` plugin to `clai2` with a settings menu and `/keys` or browser sign-in by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8940](https://github.com/pydantic/pydantic-ai/pull/8940) - Warn on unexpected `RequestUsage.extract()` failures by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8564](https://github.com/pydantic/pydantic-ai/pull/8564) - Add a built-in `ordinal` plugin to `clai2` with token or keyring-backed browser sign-in by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8941](https://github.com/pydantic/pydantic-ai/pull/8941) - feat(profiles): `default_cache_retention` + `prompt_cache_outlook()` cold-window helper; rename `resolve_prompt_cache_retention()` to `resolve_cache_retention()` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6337](https://github.com/pydantic/pydantic-ai/pull/6337) - Add a built-in `notion` plugin to `clai2` with a settings menu and its key in `/keys` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8944](https://github.com/pydantic/pydantic-ai/pull/8944) - Deliver images and text files returned from tools on Gemini 3.x Live by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9065](https://github.com/pydantic/pydantic-ai/pull/9065) - Map the shared `thinking` and `parallel_tool_calls` settings to the GPT-Live backend model by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9040](https://github.com/pydantic/pydantic-ai/pull/9040) - Accept `mxfp4`, `nvfp4`, and `mxfp8` OpenRouter `quantizations` and the `exacto` `sort` value by [@&#8203;harimaruthachalam](https://github.com/harimaruthachalam) in [#&#8203;8888](https://github.com/pydantic/pydantic-ai/pull/8888) - Add a built-in `slack` plugin to `pydantic-clai2` with a settings menu, `/keys` user token, or browser sign-in by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8908](https://github.com/pydantic/pydantic-ai/pull/8908) - Add a `logfire_mcp` built-in plugin to `clai2` with `/keys`, `LOGFIRE_API_KEY`, and keyring-backed OAuth by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8903](https://github.com/pydantic/pydantic-ai/pull/8903) - Add OpenAI `gpt-6.1-sol` model support and allow image output on `gpt-6-astra` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;9305](https://github.com/pydantic/pydantic-ai/pull/9305) ##### 🐛 Bug Fixes - Record realtime user turns in speaking order under push-to-talk, barge-in, and with input transcription off by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8764](https://github.com/pydantic/pydantic-ai/pull/8764) - Stop tool docstring parsing from changing the root logger level by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8872](https://github.com/pydantic/pydantic-ai/pull/8872) - Treat `application/toml` as text-like for inline model inputs by [@&#8203;JoeyTan21](https://github.com/JoeyTan21) in [#&#8203;8848](https://github.com/pydantic/pydantic-ai/pull/8848) - Ask for one answer per batch of parallel realtime tool results, and stop `wait_for_reply()` hanging on merged or failed replies by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8765](https://github.com/pydantic/pydantic-ai/pull/8765) - Move tool-forcing and thinking-default profile flags to `ModelProfile` so they apply on every provider route by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8808](https://github.com/pydantic/pydantic-ai/pull/8808) - Stop Gemini Live tool rounds reporting `RealtimeTurnCompleteEvent` before the spoken answer by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8766](https://github.com/pydantic/pydantic-ai/pull/8766) - Don't force output tools on Anthropic requests that think, so Claude keeps thinking with a structured `output_type` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8812](https://github.com/pydantic/pydantic-ai/pull/8812) - Truncate the provider's copy of a realtime reply the user cut off after it finished generating by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8757](https://github.com/pydantic/pydantic-ai/pull/8757) - Leave room for the extended thinking budget in Anthropic's default `max_tokens` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8986](https://github.com/pydantic/pydantic-ai/pull/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 [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8763](https://github.com/pydantic/pydantic-ai/pull/8763) - Keep a realtime microphone task alive across a reconnect by dropping audio sent while the link is re-dialed by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8806](https://github.com/pydantic/pydantic-ai/pull/8806) - Raise `UserError` instead of `ModelRetry` for `Macroscope` setup failures by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8999](https://github.com/pydantic/pydantic-ai/pull/8999) - Give the first stage of a Playwright operation its full configured budget by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9029](https://github.com/pydantic/pydantic-ai/pull/9029) - Make workspace concurrency deadlines robust under load by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9043](https://github.com/pydantic/pydantic-ai/pull/9043) - Report OpenAI native web searches in `RequestUsage.details` and price them in `cost` by [@&#8203;dltsum](https://github.com/dltsum) in [#&#8203;8310](https://github.com/pydantic/pydantic-ai/pull/8310) - Stop blank lines and "settings unchanged" notices after closing `clai2` menus by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9101](https://github.com/pydantic/pydantic-ai/pull/9101) - Terminate `!command` shell descendants on cancellation in `clai2` by [@&#8203;dafyy321-pixel](https://github.com/dafyy321-pixel) in [#&#8203;9092](https://github.com/pydantic/pydantic-ai/pull/9092) - Quiet missing plugin modules and `UserWarning`s in `clai2`, and group `CodeMode` missing-return-schema warnings by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9099](https://github.com/pydantic/pydantic-ai/pull/9099) - Handle Ctrl-C during `clai2` shell process startup by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9104](https://github.com/pydantic/pydantic-ai/pull/9104) - Apply model concurrency limits to `compact_messages()` by [@&#8203;yang0228](https://github.com/yang0228) in [#&#8203;8241](https://github.com/pydantic/pydantic-ai/pull/8241) - Keep Up/Down on prompt history when `clai2` recalls a slash command by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9297](https://github.com/pydantic/pydantic-ai/pull/9297) - Allow `azure_voice_live=True` for `gpt-realtime-2` models on `AzureRealtimeModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9050](https://github.com/pydantic/pydantic-ai/pull/9050) - Bound the Gemini Live handshake with `handshake_timeout` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9042](https://github.com/pydantic/pydantic-ai/pull/9042) - Allow text output on Vertex `gemini-live-2.5-flash` and remove a stale Gemini Live docs claim by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9069](https://github.com/pydantic/pydantic-ai/pull/9069) - Emit `DeferredToolRequestsEvent` in realtime sessions before the `HandleDeferredToolCalls` handler runs by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9057](https://github.com/pydantic/pydantic-ai/pull/9057) - Map OpenAI response JSON decode errors to `ModelAPIError` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8846](https://github.com/pydantic/pydantic-ai/pull/8846) - Map in-stream error objects to `ModelAPIError` in `OpenAIChatModel`, `GroqModel` and `HuggingFaceModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9313](https://github.com/pydantic/pydantic-ai/pull/9313) - Raise `ModelAPIError` instead of `ValidationError` when an `OpenRouterModel` stream drops mid-response by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9312](https://github.com/pydantic/pydantic-ai/pull/9312) - Read the `capabilities` docs topic from `capabilities/overview.md` in `PydanticAIDocs` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9011](https://github.com/pydantic/pydantic-ai/pull/9011) - Apply `FileSystem` default `read_only_patterns` to nested `.env` and `.git/` paths by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9021](https://github.com/pydantic/pydantic-ai/pull/9021) - Restore `CodeMode` discovery announcements after compaction or history loss by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9045](https://github.com/pydantic/pydantic-ai/pull/9045) - Keep the original request in the `TrajectoryJudge` window when the transcript is clamped by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9012](https://github.com/pydantic/pydantic-ai/pull/9012) - Raise `ContentFilterError` for a thinking-only response refused by the content filter, instead of retrying by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9355](https://github.com/pydantic/pydantic-ai/pull/9355) - Sandbox file methods and block sockets without network in `BubblewrapSandbox` by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9349](https://github.com/pydantic/pydantic-ai/pull/9349) - Give the current time to the hour in `LogfireMCP` instructions so they stop busting the prompt cache by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;9319](https://github.com/pydantic/pydantic-ai/pull/9319) - Raise `ModelAPIError` when the OpenAI Responses API reports a failed response or an `error` stream event by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9321](https://github.com/pydantic/pydantic-ai/pull/9321) - Map every `MistralError` from the Mistral SDK to `ModelHTTPError` or `ModelAPIError` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9307](https://github.com/pydantic/pydantic-ai/pull/9307) - Map provider errors from `GoogleModel.count_tokens` and `XaiModel` file uploads by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9308](https://github.com/pydantic/pydantic-ai/pull/9308) - Fix capability audit findings in `ClampOversizedMessages`, `SubAgents`, and `StepPersistence` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9026](https://github.com/pydantic/pydantic-ai/pull/9026) - Root union output member `data` validation errors under `result.data` so retry feedback keeps the failing input by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8669](https://github.com/pydantic/pydantic-ai/pull/8669) - Read a `shell` job log deleted mid-read as empty instead of failing the call by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;9322](https://github.com/pydantic/pydantic-ai/pull/9322) - Record Gemini Live `turn_complete_reason` as the realtime response's `finish_reason` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9390](https://github.com/pydantic/pydantic-ai/pull/9390) - Remove the default ACP `request_limit` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9380](https://github.com/pydantic/pydantic-ai/pull/9380) - Report a realtime session's own usage on its span, not a carried total by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9389](https://github.com/pydantic/pydantic-ai/pull/9389) - Count separately budgeted `SubAgent` usage toward parent budgets by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;9374](https://github.com/pydantic/pydantic-ai/pull/9374) ##### 📦 Dependencies - Bump the python-packages group across 1 directory with 14 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;9076](https://github.com/pydantic/pydantic-ai/pull/9076) #### New Contributors - [@&#8203;JoeyTan21](https://github.com/JoeyTan21) made their first contribution in [#&#8203;8848](https://github.com/pydantic/pydantic-ai/pull/8848) - [@&#8203;dltsum](https://github.com/dltsum) made their first contribution in [#&#8203;8310](https://github.com/pydantic/pydantic-ai/pull/8310) - [@&#8203;Jinzhengxu](https://github.com/Jinzhengxu) made their first contribution in [#&#8203;8567](https://github.com/pydantic/pydantic-ai/pull/8567) - [@&#8203;dafyy321-pixel](https://github.com/dafyy321-pixel) made their first contribution in [#&#8203;9092](https://github.com/pydantic/pydantic-ai/pull/9092) - [@&#8203;yang0228](https://github.com/yang0228) made their first contribution in [#&#8203;8241](https://github.com/pydantic/pydantic-ai/pull/8241) - [@&#8203;harimaruthachalam](https://github.com/harimaruthachalam) made their first contribution in [#&#8203;8888](https://github.com/pydantic/pydantic-ai/pull/8888) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.51.0...v2.52.0> ### [`v2.51.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.51.0): (2026-09-25) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.50.0...v2.51.0) <!-- Release notes generated using configuration in .github/release.yml at 39328d5b0d4cce94d513b6afcd2b3191bd5708d5 --> #### What's Changed ##### ⚠️ Compatibility Notes - Match dated `gemini-3.8-live` ids, reject `google_affective_dialog` on Gemini 3.1 Flash Live and 3.8 Live at connect, and raise `RealtimeError` for Gemini Live close codes by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8761](https://github.com/pydantic/pydantic-ai/pull/8761) - Raise a `UserError` for a realtime `tool_choice` that forces a tool call on OpenAI, Azure OpenAI, and xAI by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8755](https://github.com/pydantic/pydantic-ai/pull/8755) ##### 🚀 Features - Add OpenAI GPT-Live support with `OpenAILiveModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8390](https://github.com/pydantic/pydantic-ai/pull/8390) - Expose `context_window_used` on realtime sessions, from GPT-Live's reported ratio or response usage by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8803](https://github.com/pydantic/pydantic-ai/pull/8803) ##### 🐛 Bug Fixes - Reduce `RunContext` copying overhead in capability hooks by [@&#8203;Kludex](https://github.com/Kludex) in [#&#8203;8775](https://github.com/pydantic/pydantic-ai/pull/8775) - Keep `provider_details` on OpenAI Realtime tool-call responses and the response id on replies cut off by a drop or `close()` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8762](https://github.com/pydantic/pydantic-ai/pull/8762) - Buffer text deltas in `CompletedStreamedResponse` replay by [@&#8203;Kludex](https://github.com/Kludex) in [#&#8203;8799](https://github.com/pydantic/pydantic-ai/pull/8799) - Resend a recent image with a typed Gemini Live turn, which doesn't see video frames by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8756](https://github.com/pydantic/pydantic-ai/pull/8756) - Cache the agent graph instead of rebuilding it on every `Agent.run()` by [@&#8203;Kludex](https://github.com/Kludex) in [#&#8203;8658](https://github.com/pydantic/pydantic-ai/pull/8658) - Stop spawning a task group when a toolset or capability fan-out has a single child by [@&#8203;Kludex](https://github.com/Kludex) in [#&#8203;8774](https://github.com/pydantic/pydantic-ai/pull/8774) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.50.0...v2.51.0> ### [`v2.50.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.50.0): (2026-09-24) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.49.0...v2.50.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### ⚠️ Compatibility Notes - Ask a `DecisionModel` which route to take by name, with one label per route by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8733](https://github.com/pydantic/pydantic-ai/pull/8733) - Make `ModelSelectionContext.messages` end with the request being routed, and add `ModelSelectionContext.prompt` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8737](https://github.com/pydantic/pydantic-ai/pull/8737) - Replace the decision model's tool-call lean with an opt-in `decision_route_threshold` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8739](https://github.com/pydantic/pydantic-ai/pull/8739) ##### 🚀 Features - Expose OpenAI `service_tier` in provider details by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7945](https://github.com/pydantic/pydantic-ai/pull/7945) - Add `DecisionModel`, a base for Decisions-protocol models, and make `TypeSafeModel` one by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8696](https://github.com/pydantic/pydantic-ai/pull/8696) - Add `RunContext.in_durable_context` so hooks can tell they run in durable workflow code by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;8723](https://github.com/pydantic/pydantic-ai/pull/8723) - Add `gemini-3.8-live` and `gemini-3.8-live-extended-thinking` realtime support by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8393](https://github.com/pydantic/pydantic-ai/pull/8393) - Ask a `DecisionModel`'s route fields with the route question under a route premise, with nested-field `context` and a `done` state after tool calls by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8749](https://github.com/pydantic/pydantic-ai/pull/8749) - Emit a `decide` span for every request a `DecisionModel` sends by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8698](https://github.com/pydantic/pydantic-ai/pull/8698) ##### 🐛 Bug Fixes - Keep the type variable of a generic `OutputSpec[T]` passed to `Agent.run` under mypy by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8730](https://github.com/pydantic/pydantic-ai/pull/8730) - Send `ThinkingPart`s in the history decision models judge by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8738](https://github.com/pydantic/pydantic-ai/pull/8738) - Price Anthropic one-hour cache writes at the one-hour rate instead of the five-minute rate by [@&#8203;kazmer97](https://github.com/kazmer97) in [#&#8203;8666](https://github.com/pydantic/pydantic-ai/pull/8666) - Price realtime image input at the image rate by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8741](https://github.com/pydantic/pydantic-ai/pull/8741) - Add `RequestUsage.audio_seconds` so duration-billed voice models are priced by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8427](https://github.com/pydantic/pydantic-ai/pull/8427) - Offer a decision model's unfillable `output_type` as a route beside other routes, and rename `ToolCallProposed` to `UnfillableRoute` under a `DecisionHandOff` base by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8744](https://github.com/pydantic/pydantic-ai/pull/8744) - Keep realtime user turns whole when the microphone streams continuously on providers without input item IDs by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8746](https://github.com/pydantic/pydantic-ai/pull/8746) - Roll back a realtime send the provider refuses, so `wait_for_reply()` no longer hangs on it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8747](https://github.com/pydantic/pydantic-ai/pull/8747) - Turn reasoning off for `thinking=False` on OpenAI Realtime by sending `reasoning.effort: 'none'` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8753](https://github.com/pydantic/pydantic-ai/pull/8753) - Take Jev's `context_window` from genai-prices and document compacting a Jev conversation by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8740](https://github.com/pydantic/pydantic-ai/pull/8740) - Buffer five minutes of audio per `stream_audio()` view so speaker-paced playback gets whole replies by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8750](https://github.com/pydantic/pydantic-ai/pull/8750) - Stop Google Search from crashing Gemini 2.5 native-audio realtime sessions by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8751](https://github.com/pydantic/pydantic-ai/pull/8751) - Keep user speech out of Gemini 3.x realtime history when input transcription is off by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8754](https://github.com/pydantic/pydantic-ai/pull/8754) - Surface a failed OpenAI realtime response's error as a `RealtimeSessionErrorEvent` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8752](https://github.com/pydantic/pydantic-ai/pull/8752) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.49.0...v2.50.0> ### [`v2.49.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.49.0): (2026-09-23) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.48.0...v2.49.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add `GitHubCopilotOAuthFlow` for device authorization by [@&#8203;Kludex](https://github.com/Kludex) in [#&#8203;8618](https://github.com/pydantic/pydantic-ai/pull/8618) - Add `BoolCriteria` to say what a `bool` field's yes and no mean, and let a `True`/`False` `Enum` do the same by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8586](https://github.com/pydantic/pydantic-ai/pull/8586) - Use what the user wrote about `None` as the "none of these" option in `TypeSafeModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8684](https://github.com/pydantic/pydantic-ai/pull/8684) - Offer whole numbers that are not a rubric as a `Choice` in `TypeSafeModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8686](https://github.com/pydantic/pydantic-ai/pull/8686) - Add `RealtimeSession.wait_for_reply()` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8514](https://github.com/pydantic/pydantic-ai/pull/8514) ##### 🐛 Bug Fixes - Keep all streamed `OpenAIChatModel` logprobs in `provider_details['logprobs']` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8653](https://github.com/pydantic/pydantic-ai/pull/8653) - Allow `gpt-6-sol`, `gpt-6-luna`, and `gpt-6-astra` on Bedrock Converse by [@&#8203;sevakva](https://github.com/sevakva) in [#&#8203;8656](https://github.com/pydantic/pydantic-ai/pull/8656) - fix: preserve fanned producer contributions in graph joins by [@&#8203;FIITAY](https://github.com/FIITAY) in [#&#8203;8385](https://github.com/pydantic/pydantic-ai/pull/8385) - Surface `@GraphBuilder.stream` node errors in-context during `graph.iter()` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8304](https://github.com/pydantic/pydantic-ai/pull/8304) - Forward Cloud Storage `gs://` references as `fileData` in `GoogleImageGenerationModel` on Vertex AI by [@&#8203;dorukgezici](https://github.com/dorukgezici) in [#&#8203;8225](https://github.com/pydantic/pydantic-ai/pull/8225) - Preserve output tool names and descriptions for `Annotated` model types by [@&#8203;ikriv](https://github.com/ikriv) in [#&#8203;8608](https://github.com/pydantic/pydantic-ai/pull/8608) - Type `None` in a list of output types as `| None` so `output_type=[Foo, Bar, None]` passes pyright by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8641](https://github.com/pydantic/pydantic-ai/pull/8641) - Fix `google_proactive_audio`, which no Gemini Live session could ever connect with by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8394](https://github.com/pydantic/pydantic-ai/pull/8394) - Drop `temperature` and `top_p` for OpenAI GPT-5.6 and GPT-6 on Bedrock Converse instead of failing with a 400 by [@&#8203;kimnamu](https://github.com/kimnamu) in [#&#8203;8668](https://github.com/pydantic/pydantic-ai/pull/8668) - Let a field's default apply when `TypeSafeModel` answers "None of these" for an optional field by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8685](https://github.com/pydantic/pydantic-ai/pull/8685) - Surface realtime receive-side failures to every consumer shape, and end `send_audio(iterable)` cleanly on close by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8138](https://github.com/pydantic/pydantic-ai/pull/8138) - Keep `Annotated` metadata on the members of an `X | Y` `output_type` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8687](https://github.com/pydantic/pydantic-ai/pull/8687) - Keep an uninstrumented delegate's usage off its caller's agent run span by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8689](https://github.com/pydantic/pydantic-ai/pull/8689) - Let a nested model's default apply when `TypeSafeModel` answers "None of these" for every field under it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8697](https://github.com/pydantic/pydantic-ai/pull/8697) - Accept `Annotated`, `Literal` and union `output_type`s as PEP 747 `TypeForm`s, and bump pyright to 1.1.414 by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8690](https://github.com/pydantic/pydantic-ai/pull/8690) - Make `RunContext.tracer`, `trace_include_content` and `instrumentation_version` follow an explicit `Instrumentation` capability by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8706](https://github.com/pydantic/pydantic-ai/pull/8706) - Send deferred tools with native tool search on `OpenAICodexModel` instead of failing with a 400 by [@&#8203;aweis89](https://github.com/aweis89) in [#&#8203;8693](https://github.com/pydantic/pydantic-ai/pull/8693) #### New Contributors - [@&#8203;FIITAY](https://github.com/FIITAY) made their first contribution in [#&#8203;8385](https://github.com/pydantic/pydantic-ai/pull/8385) - [@&#8203;ikriv](https://github.com/ikriv) made their first contribution in [#&#8203;8608](https://github.com/pydantic/pydantic-ai/pull/8608) - [@&#8203;aweis89](https://github.com/aweis89) made their first contribution in [#&#8203;8693](https://github.com/pydantic/pydantic-ai/pull/8693) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.48.0...v2.49.0> ### [`v2.48.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.48.0): (2026-09-22) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.47.0...v2.48.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Support `genai-prices` 0.1.7 and new OpenAI audio models by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8617](https://github.com/pydantic/pydantic-ai/pull/8617) - Add OpenAI `gpt-6-sol` and `gpt-6-luna` model support by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8635](https://github.com/pydantic/pydantic-ai/pull/8635) - Add Claude Opus 5.5 (`claude-opus-5-5`) support by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8637](https://github.com/pydantic/pydantic-ai/pull/8637) ##### 🐛 Bug Fixes - Preserve `UIMessage.id` across Vercel AI `load_messages` and `dump_messages` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8623](https://github.com/pydantic/pydantic-ai/pull/8623) - Preserve AG-UI `Message.id` across `AGUIAdapter.load_messages` and `dump_messages` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8632](https://github.com/pydantic/pydantic-ai/pull/8632) ##### 📦 Dependencies - Bump `genai-prices` to 0.1.8 by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8648](https://github.com/pydantic/pydantic-ai/pull/8648) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.47.0...v2.48.0> ### [`v2.47.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.47.0): (2026-09-21) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.46.0...v2.47.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### ⚠️ Compatibility Notes - Name a `None` output route `None` rather than `NoneType` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8590](https://github.com/pydantic/pydantic-ai/pull/8590) - Raise when `UserPromptPart.content` is not a `str` or a sequence, instead of silently sending a `dict`'s keys by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8595](https://github.com/pydantic/pydantic-ai/pull/8595) ##### 🚀 Features - Ask three more field types `TypeSafeModel` can already answer by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8544](https://github.com/pydantic/pydantic-ai/pull/8544) ##### 🐛 Bug Fixes - Refuse a `tuple` output field and a self-contained model instead of crashing by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8537](https://github.com/pydantic/pydantic-ai/pull/8537) - Refuse a rubric with more levels than Jev scores against by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8583](https://github.com/pydantic/pydantic-ai/pull/8583) - Let `None` be a route `TypeSafeModel` can pick by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8540](https://github.com/pydantic/pydantic-ai/pull/8540) - Let a `Choices` set describe itself as a `TypeSafeModel` route by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8541](https://github.com/pydantic/pydantic-ai/pull/8541) - Recognise a `None` route and a `None` option that carry a description by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8598](https://github.com/pydantic/pydantic-ai/pull/8598) - Name the picked route in the `TypeSafeModel` request that fills it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8589](https://github.com/pydantic/pydantic-ai/pull/8589) ##### 📦 Dependencies - Pin `ag-ui-protocol` to `<1` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8579](https://github.com/pydantic/pydantic-ai/pull/8579) #### New Contributors - [@&#8203;huynguyengl99](https://github.com/huynguyengl99) made their first contribution in [#&#8203;8554](https://github.com/pydantic/pydantic-ai/pull/8554) - [@&#8203;xyi74976-del](https://github.com/xyi74976-del) made their first contribution in [#&#8203;8560](https://github.com/pydantic/pydantic-ai/pull/8560) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.46.0...v2.47.0> ### [`v2.46.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.46.0): (2026-09-18) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.45.0...v2.46.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Let `TypeSafeModel` fill a tool's arguments when Jev can express them by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8501](https://github.com/pydantic/pydantic-ai/pull/8501) - Add `RealtimeSession.wait_for_playback()` and let the docs examples finish the reply before closing by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8141](https://github.com/pydantic/pydantic-ai/pull/8141) - Add `supports_text_output` to `ModelProfile`, and run `LLMJudge` and `GEval` on a model without it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8480](https://github.com/pydantic/pydantic-ai/pull/8480) - Add `typesafe_boolean_threshold` for what a yes/no has to be before it is `True` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8505](https://github.com/pydantic/pydantic-ai/pull/8505) - Let `TypeSafeModel` fill a union of output types by choosing the type first by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8481](https://github.com/pydantic/pydantic-ai/pull/8481) - Add `event_stream_topic` to `TemporalDurability` to stream agent events via Workflow Streams by [@&#8203;brianstrauch](https://github.com/brianstrauch) in [#&#8203;6639](https://github.com/pydantic/pydantic-ai/pull/6639) - Describe an `Enum`'s options by its member docstrings when it mixes in `UseEnumMemberDocstrings` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8479](https://github.com/pydantic/pydantic-ai/pull/8479) - Add a `Choices` helper for a set of described options built at run time by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8530](https://github.com/pydantic/pydantic-ai/pull/8530) ##### 🐛 Bug Fixes - Refuse more options than Jev can pick from in `TypeSafeModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8484](https://github.com/pydantic/pydantic-ai/pull/8484) - Record a failed `ToolReturnPart` when a realtime tool raises, and keep a tool call and its speech in one `ModelResponse` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8135](https://github.com/pydantic/pydantic-ai/pull/8135) - Dispatch tool calls with the live `ToolDefinition` in `CombinedToolset` and `FunctionToolset` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8082](https://github.com/pydantic/pydantic-ai/pull/8082) - Allow adaptive thinking with tool output and forced tool choice on Bedrock by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7967](https://github.com/pydantic/pydantic-ai/pull/7967) - Fix gateway IDs being misclassified as OpenAI o-series models by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8512](https://github.com/pydantic/pydantic-ai/pull/8512) - Keep late realtime input transcripts attached to the user turn they belong to by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8139](https://github.com/pydantic/pydantic-ai/pull/8139) - Lay the first-run banner out for the terminal's actual width by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8517](https://github.com/pydantic/pydantic-ai/pull/8517) - Raise `ModelRetry` when `web_fetch_tool` gets a URL `httpx2` rejects as invalid by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8521](https://github.com/pydantic/pydantic-ai/pull/8521) - Price realtime responses so `usage.cost` and `UsageLimits.cost_limit` work in a session by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8136](https://github.com/pydantic/pydantic-ai/pull/8136) - Re-arm coverage for code already seen when the dataclass walk resumes it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8438](https://github.com/pydantic/pydantic-ai/pull/8438) #### New Contributors - [@&#8203;brianstrauch](https://github.com/brianstrauch) made their first contribution in [#&#8203;6639](https://github.com/pydantic/pydantic-ai/pull/6639) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.45.0...v2.46.0> ### [`v2.45.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.45.0): (2026-09-17) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.44.0...v2.45.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add `TypeSafeModel` for TypeSafe's Jev by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8450](https://github.com/pydantic/pydantic-ai/pull/8450) ##### 🐛 Bug Fixes - Pass `xhigh` effort through on Bedrock when the model profile supports it by [@&#8203;willfrey](https://github.com/willfrey) in [#&#8203;8392](https://github.com/pydantic/pydantic-ai/pull/8392) - Allow `gpt-5.6-sol`, `gpt-5.6-luna`, and `gpt-5.6-terra` on Bedrock Converse by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7825](https://github.com/pydantic/pydantic-ai/pull/7825) - Resolve a `DynamicToolset` once per durable run instead of inside every durable unit by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8455](https://github.com/pydantic/pydantic-ai/pull/8455) - Hold one MCP server session per durable run instead of one per durable unit by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8463](https://github.com/pydantic/pydantic-ai/pull/8463) - Preserve tool history in `MCPSamplingModel` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8466](https://github.com/pydantic/pydantic-ai/pull/8466) - Stop importing legacy `httpx` in `pydantic_ai.mcp`, which a FastMCP 4 install does not ship by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8461](https://github.com/pydantic/pydantic-ai/pull/8461) - Report each agent run's own usage on its span by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8456](https://github.com/pydantic/pydantic-ai/pull/8456) #### New Contributors - [@&#8203;willfrey](https://github.com/willfrey) made their first contribution in [#&#8203;8392](https://github.com/pydantic/pydantic-ai/pull/8392) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.44.0...v2.45.0> ### [`v2.44.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0): (2026-09-16) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.43.0...v2.44.0) ##### 🛡️ Security This release fixes four security issues, all of them reached through `web_fetch_tool` or OpenTelemetry instrumentation. See each advisory for full details and affected versions. - **[GHSA-vmxc-h2x2-jmf3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-vmxc-h2x2-jmf3)** (moderate): the cloud-metadata and private-IP blocklists could be bypassed with an IPv6 zone identifier on a URL opted into local network access, via `FileUrl(force_download='allow-local')` or `web_fetch_tool(allow_local_urls=True)`. Both are off by default. Reported by [@&#8203;euriconicacio](https://github.com/euriconicacio). ([#&#8203;8401](https://github.com/pydantic/pydantic-ai/issues/8401)) - **[GHSA-fpf4-vwcp-v4hp](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-fpf4-vwcp-v4hp)** (moderate): `web_fetch` processed responses in superlinear time on the event loop, in both the HTML conversion and the charset decode, so a single attacker-chosen page could stall every agent in the process. Reported by [@&#8203;BrianWillows](https://github.com/BrianWillows). ([#&#8203;8397](https://github.com/pydantic/pydantic-ai/issues/8397), [#&#8203;8418](https://github.com/pydantic/pydantic-ai/issues/8418), [#&#8203;8433](https://github.com/pydantic/pydantic-ai/issues/8433)) - **[GHSA-22h6-qm39-v87j](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-22h6-qm39-v87j)** (low): `web_fetch_tool`'s domain lists were compared as written rather than in the form the resolver uses, so a blocked domain could be reached under another spelling. ([#&#8203;8407](https://github.com/pydantic/pydantic-ai/issues/8407), [#&#8203;8421](https://github.com/pydantic/pydantic-ai/issues/8421)) - **[GHSA-4x9p-g9wm-8q7f](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-4x9p-g9wm-8q7f)** (low): with `InstrumentationSettings(include_content=False)`, spans still carried exceptions, error statuses, instructions and the output template. Reported by [@&#8203;BrianWillows](https://github.com/BrianWillows). ([#&#8203;8403](https://github.com/pydantic/pydantic-ai/issues/8403), [#&#8203;8408](https://github.com/pydantic/pydantic-ai/issues/8408), [#&#8203;8419](https://github.com/pydantic/pydantic-ai/issues/8419), [#&#8203;8428](https://github.com/pydantic/pydantic-ai/issues/8428)) Patched in `2.44.0` (v2) and `1.107.6` (v1). #### What's Changed ##### ⚠️ Compatibility Notes - Make `RunContext.enqueue()` safe from worker threads by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7758](https://github.com/pydantic/pydantic-ai/pull/7758) - Require a JSON `Content-Type` on UI adapter requests by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8396](https://github.com/pydantic/pydantic-ai/pull/8396) - Dispatch a capability `@durable_operation` called from a per-request hook, instead of silently running it inline by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8395](https://github.com/pydantic/pydantic-ai/pull/8395) ##### 🚀 Features - Add a Vercel AI SDK and Eve migration skill by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8357](https://github.com/pydantic/pydantic-ai/pull/8357) - Give `AgentRunResult` a stable serialized shape, and settle a finished stream into one by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8269](https://github.com/pydantic/pydantic-ai/pull/8269) - Add a `Storage` page so persistence is findable by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8336](https://github.com/pydantic/pydantic-ai/pull/8336) - Emit `EnqueuedMessagesEvent` when a realtime session delivers enqueued content by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8134](https://github.com/pydantic/pydantic-ai/pull/8134) ##### 🐛 Bug Fixes - Forward `blocked_domains` to OpenAI web search by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8323](https://github.com/pydantic/pydantic-ai/pull/8323) - Fix OpenAI hosted `tool_search` pairing in AG-UI by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8313](https://github.com/pydantic/pydantic-ai/pull/8313) - Let `Agent.from_spec()` construct without a model, deferring the requirement to run time by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8339](https://github.com/pydantic/pydantic-ai/pull/8339) - Let `RealtimeSession.close()` finish its teardown when the closing task is cancelled by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8142](https://github.com/pydantic/pydantic-ai/pull/8142) - Run a capability's `prepare_tools` over every tool the availability gate admits by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8071](https://github.com/pydantic/pydantic-ai/pull/8071) - Bound the realtime session event queue while nothing is iterating it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8133](https://github.com/pydantic/pydantic-ai/pull/8133) - Report a run's own usage on its span, not the conversation total by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8417](https://github.com/pydantic/pydantic-ai/pull/8417) #### New Contributors - [@&#8203;mrchatam](https://github.com/mrchatam) made their first contribution in [#&#8203;8286](https://github.com/pydantic/pydantic-ai/pull/8286) - [@&#8203;vedjaw](https://github.com/vedjaw) made their first contribution in [#&#8203;7028](https://github.com/pydantic/pydantic-ai/pull/7028) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.43.0...v2.44.0> ### [`v2.43.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.43.0): (2026-09-11) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.42.0...v2.43.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add a first-run banner describing the run, and open `clai` sessions with it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7447](https://github.com/pydantic/pydantic-ai/pull/7447) ##### 🐛 Bug Fixes - Preserve text part boundaries after tool calls in `OpenAIChatModel` by [@&#8203;KaranJayakumar](https://github.com/KaranJayakumar) in [#&#8203;8235](https://github.com/pydantic/pydantic-ai/pull/8235) - fix(temporal): key tool opt-out checks on operation kind, not an MCP import by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8257](https://github.com/pydantic/pydantic-ai/pull/8257) #### New Contributors - [@&#8203;KaranJayakumar](https://github.com/KaranJayakumar) made their first contribution in [#&#8203;8235](https://github.com/pydantic/pydantic-ai/pull/8235) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.42.0...v2.43.0> ### [`v2.42.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.42.0): (2026-09-08) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.41.0...v2.42.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### ⚠️ Compatibility Notes - Reject invalid `DeferredToolResults.approvals` values by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8081](https://github.com/pydantic/pydantic-ai/pull/8081) ##### 🚀 Features - Add a `GitHubCopilotProvider` for GitHub Copilot's OpenAI-compatible API by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8059](https://github.com/pydantic/pydantic-ai/pull/8059) ##### 🐛 Bug Fixes - Honor `anthropic_disallows_sampling_settings` in `BedrockConverseModel` by [@&#8203;rscholz98](https://github.com/rscholz98) in [#&#8203;7961](https://github.com/pydantic/pydantic-ai/pull/7961) - Resolve non-object `$ref` definitions inline in code-mode function signatures by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;8056](https://github.com/pydantic/pydantic-ai/pull/8056) - Validate `ToolReturnContent` without a Python call per JSON node by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7823](https://github.com/pydantic/pydantic-ai/pull/7823) - Preserve Anthropic recovery across normalized history by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8040](https://github.com/pydantic/pydantic-ai/pull/8040) #### New Contributors - [@&#8203;StarsExpress](https://github.com/StarsExpress) made their first contribution in [#&#8203;8155](https://github.com/pydantic/pydantic-ai/pull/8155) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.41.0...v2.42.0> ### [`v2.41.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.41.0): (2026-09-07) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.40.0...v2.41.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Deprecate `fallback_model` in favor of `fallback_subagent_model` on `ImageGeneration` and `XSearch` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8077](https://github.com/pydantic/pydantic-ai/pull/8077) - Add `openai-codex` provider for ChatGPT/Codex subscription authentication by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;7769](https://github.com/pydantic/pydantic-ai/pull/7769) - Add a direct image generation API with `ImageGenerator` by [@&#8203;EgonFerri](https://github.com/EgonFerri) in [#&#8203;5357](https://github.com/pydantic/pydantic-ai/pull/5357) ##### 🐛 Bug Fixes - Report Anthropic native web searches in `RequestUsage.details` and price them in `cost` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8169](https://github.com/pydantic/pydantic-ai/pull/8169) - Wrap botocore transport errors in `ModelAPIError` in `BedrockConverseModel` by [@&#8203;kimnamu](https://github.com/kimnamu) in [#&#8203;8131](https://github.com/pydantic/pydantic-ai/pull/8131) - Snap Gemini thinking levels to the nearest supported level by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8165](https://github.com/pydantic/pydantic-ai/pull/8165) #### New Contributors - [@&#8203;kimnamu](https://github.com/kimnamu) made their first contribution in [#&#8203;8131](https://github.com/pydantic/pydantic-ai/pull/8131) - [@&#8203;EgonFerri](https://github.com/EgonFerri) made their first contribution in [#&#8203;5357](https://github.com/pydantic/pydantic-ai/pull/5357) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.40.0...v2.41.0> ### [`v2.40.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.40.0): (2026-09-04) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.39.0...v2.40.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add `pydantic_ai.prices.update_in_background()` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;4841](https://github.com/pydantic/pydantic-ai/pull/4841) - Handle barge-in in the session: `handle_barge_in=True`, `interrupt(played_bytes=...)`, and `played_audio_bytes` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7870](https://github.com/pydantic/pydantic-ai/pull/7870) - Add `provider_factory` to `infer_realtime_model` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8106](https://github.com/pydantic/pydantic-ai/pull/8106) - Add `@agent.on_event` for registering event listeners on an `Agent` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8101](https://github.com/pydantic/pydantic-ai/pull/8101) - Add `respond=` to `RealtimeSession.send()` and document that a text turn solicits a reply by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8110](https://github.com/pydantic/pydantic-ai/pull/8110) - Add `RealtimeSession.enqueue()` for out-of-band prompts from code driving the session by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8109](https://github.com/pydantic/pydantic-ai/pull/8109) ##### 🐛 Bug Fixes - Map `finish_reason` on OpenAI Responses stream terminal events by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7916](https://github.com/pydantic/pydantic-ai/pull/7916) - Fix `defer_loading` reveal synthesis splitting a parallel batch's `tool_result` from its `tool_use` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7879](https://github.com/pydantic/pydantic-ai/pull/7879) - fix(realtime): roll back user-turn state when an audio chunk is not bytes-like by [@&#8203;simpleqt](https://github.com/simpleqt) in [#&#8203;7905](https://github.com/pydantic/pydantic-ai/pull/7905) - Let a capability cache derived state again, and refuse a collection the merge cannot rebuild by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8099](https://github.com/pydantic/pydantic-ai/pull/8099) - Make a capability's auto-assigned registry key look like the run-local handle it is by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8119](https://github.com/pydantic/pydantic-ai/pull/8119) - Stop sending `reasoning` to the dated `gpt-realtime-2025-08-28` snapshot by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8103](https://github.com/pydantic/pydantic-ai/pull/8103) - Subscribe `stream_audio()` and `stream_transcripts()` views when they are called, not on first iteration by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8107](https://github.com/pydantic/pydantic-ai/pull/8107) - End the realtime audio and transcript views when a tool fails and nobody is iterating by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8108](https://github.com/pydantic/pydantic-ai/pull/8108) - Let a realtime tool hang up with `ctx.realtime_session.close()` instead of wedging itself by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8105](https://github.com/pydantic/pydantic-ai/pull/8105) - Fix the realtime "Speaking first" and relay examples, the `interrupt(played_ms=)` cancel race, and two provider tables by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8132](https://github.com/pydantic/pydantic-ai/pull/8132) #### New Contributors - [@&#8203;simpleqt](https://github.com/simpleqt) made their first contribution in [#&#8203;7905](https://github.com/pydantic/pydantic-ai/pull/7905) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.39.0...v2.40.0> ### [`v2.39.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.39.0): (2026-09-03) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.38.0...v2.39.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add OpenAI `gpt-6-astra` model support by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8055](https://github.com/pydantic/pydantic-ai/pull/8055) ##### 🐛 Bug Fixes - Fix the `context_subtree()` exporter cache and its span-processor leaks by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7667](https://github.com/pydantic/pydantic-ai/pull/7667) - Restore the `Instrumentation` spec option `include_model_request_parameters` and sharpen the undeclared-attribute merge error by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8046](https://github.com/pydantic/pydantic-ai/pull/8046) - Detect Azure content-filter errors for `AzureProvider` and for `AsyncAzureOpenAI` clients on `OpenAIProvider` by [@&#8203;quinnarnold](https://github.com/quinnarnold) in [#&#8203;7922](https://github.com/pydantic/pydantic-ai/pull/7922) - Emit speech finalized by a tool call on `stream_transcripts()` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;8062](https://github.com/pydantic/pydantic-ai/pull/8062) - Attribute tool-returned media to its originating tool call when it can't ride the tool result by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7830](https://github.com/pydantic/pydantic-ai/pull/7830) - Restore capability composition invariants by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8047](https://github.com/pydantic/pydantic-ai/pull/8047) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.38.0...v2.39.0> ### [`v2.38.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.38.0): (2026-09-03) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.37.0...v2.38.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### ⚠️ Compatibility Notes - Give one-off capabilities a default `id` and a `combine` rule for repeats by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7248](https://github.com/pydantic/pydantic-ai/pull/7248) ##### 🚀 Features - Add `context_window` to `ModelProfile` and `context_window_used` to `RunContext` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;4611](https://github.com/pydantic/pydantic-ai/pull/4611) - Add profile flag to reject streams without `finish_reason` by [@&#8203;jonashaag](https://github.com/jonashaag) in [#&#8203;7096](https://github.com/pydantic/pydantic-ai/pull/7096) - Add `gemini-3.8-flash` model by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8021](https://github.com/pydantic/pydantic-ai/pull/8021) - Let application code and capabilities emit typed `CustomEvent`s and `CapabilityEvent`s into the run event stream and subscribe with `@on_event` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6258](https://github.com/pydantic/pydantic-ai/pull/6258) - Add Claude Fable 5.1 (`claude-fable-5-1`) and Claude Mythos 5.1 (`claude-mythos-5-1`) support by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7989](https://github.com/pydantic/pydantic-ai/pull/7989) - Add `VLLMProvider` for vLLM servers by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;6153](https://github.com/pydantic/pydantic-ai/pull/6153) ##### 🐛 Bug Fixes - Support `CancellationToken` in UI adapter run methods by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7743](https://github.com/pydantic/pydantic-ai/pull/7743) - Stop `pytest tests/durable_exec/temporal` from crashing when the suite's requirements are missing by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7898](https://github.com/pydantic/pydantic-ai/pull/7898) - Fix DeepSeek and Together forced `tool_choice` handling and support `NativeOutput` on DeepSeek's Responses API by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7450](https://github.com/pydantic/pydantic-ai/pull/7450) - Restore raw tool-call IDs when replaying Bedrock Mantle Responses history by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7962](https://github.com/pydantic/pydantic-ai/pull/7962) - Keep a run cancelled during its first tool call resumable by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7993](https://github.com/pydantic/pydantic-ai/pull/7993) - Fix `CodeExecutionTool` uploads never reaching a fresh Anthropic container on a multi-turn history by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7864](https://github.com/pydantic/pydantic-ai/pull/7864) - Prevent synthetic reasoning IDs from reaching OpenAI Responses by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8020](https://github.com/pydantic/pydantic-ai/pull/8020) - Emit `REASONING_*` events from `ag-ui-protocol` 0.1.11 instead of 0.1.13 by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7226](https://github.com/pydantic/pydantic-ai/pull/7226) - Accept the environment-key call pattern in `GoogleProvider`'s overload by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8030](https://github.com/pydantic/pydantic-ai/pull/8030) - Fix `XaiModel` streamed text after a native tool call being merged into the ended pre-call part by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7925](https://github.com/pydantic/pydantic-ai/pull/7925) - Persist Anthropic stale thinking-block recovery across turns by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;8037](https://github.com/pydantic/pydantic-ai/pull/8037) - Preserve dynamic `native` factory config in `XSearch` and `ImageGeneration` fallback subagents by [@&#8203;CoralGarden52](https://github.com/CoralGarden52) in [#&#8203;7541](https://github.com/pydantic/pydantic-ai/pull/7541) ##### 📦 Dependencies - Bump `genai-prices` to 0.1.6 by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;8019](https://github.com/pydantic/pydantic-ai/pull/8019) #### New Contributors - [@&#8203;piomeer](https://github.com/piomeer) made their first contribution in [#&#8203;7952](https://github.com/pydantic/pydantic-ai/pull/7952) - [@&#8203;jonashaag](https://github.com/jonashaag) made their first contribution in [#&#8203;7096](https://github.com/pydantic/pydantic-ai/pull/7096) - [@&#8203;CoralGarden52](https://github.com/CoralGarden52) made their first contribution in [#&#8203;7541](https://github.com/pydantic/pydantic-ai/pull/7541) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.37.0...v2.38.0> ### [`v2.37.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.37.0): (2026-08-31) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.36.0...v2.37.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add `glm-5.3-flash` and rework the Z.AI test suite onto cassettes by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7887](https://github.com/pydantic/pydantic-ai/pull/7887) ##### 🐛 Bug Fixes - fix: preserve all conditions in pruned span queries by [@&#8203;mikemikimike](https://github.com/mikemikimike) in [#&#8203;7499](https://github.com/pydantic/pydantic-ai/pull/7499) - Accept and map Z.AI's non-standard `finish_reason` values by [@&#8203;zhj12395](https://github.com/zhj12395) in [#&#8203;7685](https://github.com/pydantic/pydantic-ai/pull/7685) - Emit an AG-UI `TEXT_MESSAGE_START` for the assistant message that owns a response's tool calls by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7699](https://github.com/pydantic/pydantic-ai/pull/7699) - Route Vertex-vs-Gemini API branches in `GoogleModel` by client transport instead of provider name by [@&#8203;thejamesgore](https://github.com/thejamesgore) in [#&#8203;7280](https://github.com/pydantic/pydantic-ai/pull/7280) - Skip inactive capability hooks in agent tracebacks by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7328](https://github.com/pydantic/pydantic-ai/pull/7328) - Context-manage models rebuilt inside durable operations by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7954](https://github.com/pydantic/pydantic-ai/pull/7954) - Reject per-run `capabilities=` on DBOS, matching Temporal by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6955](https://github.com/pydantic/pydantic-ai/pull/6955) - Journal Prefect tool discovery in tasks by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6966](https://github.com/pydantic/pydantic-ai/pull/6966) - Stop rebuilding unmanaged models in durable capability operations by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7972](https://github.com/pydantic/pydantic-ai/pull/7972) #### New Contributors - [@&#8203;zhj12395](https://github.com/zhj12395) made their first contribution in [#&#8203;7685](https://github.com/pydantic/pydantic-ai/pull/7685) - [@&#8203;thejamesgore](https://github.com/thejamesgore) made their first contribution in [#&#8203;7280](https://github.com/pydantic/pydantic-ai/pull/7280) - [@&#8203;pcbeingused333](https://github.com/pcbeingused333) made their first contribution in [#&#8203;7936](https://github.com/pydantic/pydantic-ai/pull/7936) - [@&#8203;quinnarnold](https://github.com/quinnarnold) made their first contribution in [#&#8203;7921](https://github.com/pydantic/pydantic-ai/pull/7921) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.36.0...v2.37.0> ### [`v2.36.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.36.0): (2026-08-28) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.35.3...v2.36.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### ⚠️ Compatibility Notes - Add `--mcp-config` support and tool-call streaming to `clai` by [@&#8203;Kludex](https://github.com/Kludex) in [#&#8203;1374](https://github.com/pydantic/pydantic-ai/pull/1374) ##### 🚀 Features - Add `@durable_operation` for capabilities and a public backend API for third-party durable execution engines by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6696](https://github.com/pydantic/pydantic-ai/pull/6696) - Give instruction parts a stable `InstructionPart.id` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6887](https://github.com/pydantic/pydantic-ai/pull/6887) - Accept async iterables in `RealtimeSession.send_audio()` and move the voice example to `listentome` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7860](https://github.com/pydantic/pydantic-ai/pull/7860) - Require an explicit operation name on `@durable_operation` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7868](https://github.com/pydantic/pydantic-ai/pull/7868) ##### 🐛 Bug Fixes - Fix `TestModel` generation for narrow exclusive numeric bounds by [@&#8203;Terminator666666](https://github.com/Terminator666666) in [#&#8203;7800](https://github.com/pydantic/pydantic-ai/pull/7800) - Project a bare `ToolDefinition` into Prefect cache keys by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7872](https://github.com/pydantic/pydantic-ai/pull/7872) #### New Contributors - [@&#8203;Terminator666666](https://github.com/Terminator666666) made their first contribution in [#&#8203;7800](https://github.com/pydantic/pydantic-ai/pull/7800) - [@&#8203;mme](https://github.com/mme) made their first contribution in [#&#8203;7432](https://github.com/pydantic/pydantic-ai/pull/7432) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.35.3...v2.36.0> ### [`v2.35.3`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.35.3): (2026-08-27) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.35.1...v2.35.3) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🐛 Bug Fixes - Route Heroku GLM models through `zai_model_profile` by [@&#8203;LHMQ878](https://github.com/LHMQ878) in [#&#8203;6837](https://github.com/pydantic/pydantic-ai/pull/6837) - Scope `safe_download` cookies to original hostnames by [@&#8203;Diwak4r](https://github.com/Diwak4r) in [#&#8203;7077](https://github.com/pydantic/pydantic-ai/pull/7077) - Fix `DeferredToolRequests.remaining` resolving cross-category result IDs by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7626](https://github.com/pydantic/pydantic-ai/pull/7626) - Identify rejected runtime toolsets in durable execution errors by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;6784](https://github.com/pydantic/pydantic-ai/pull/6784) - Un-cap the `dbos` extra; add `opentelemetry-instrumentation-logging` as a test dependency instead by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7820](https://github.com/pydantic/pydantic-ai/pull/7820) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.35.1...v2.35.3> ### [`v2.35.1`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.35.1): (2026-08-26) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.35.0...v2.35.1) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🐛 Bug Fixes - Carry Bedrock guardrail `trace` in `ModelResponse.provider_details` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7562](https://github.com/pydantic/pydantic-ai/pull/7562) - Honor `provider_factory` when cancelling Temporal responses by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7000](https://github.com/pydantic/pydantic-ai/pull/7000) - Cap `dbos` below 2.31.0 to avoid a missing `opentelemetry-instrumentation-logging` import by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7804](https://github.com/pydantic/pydantic-ai/pull/7804) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.35.0...v2.35.1> ### [`v2.35.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.35.0): (2026-08-25) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.34.0...v2.35.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### ⚠️ Compatibility Notes - Deprecate `RunContext.capability_loaded` and `available_capability_ids` in favor of `capability_active` and `active_capability_ids` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7454](https://github.com/pydantic/pydantic-ai/pull/7454) - Make inclusive integer `maximum` reachable in `TestModel` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7697](https://github.com/pydantic/pydantic-ai/pull/7697) ##### 🚀 Features - Reduce the default Temporal metric export frequency by [@&#8203;dmontagu](https://github.com/dmontagu) in [#&#8203;7768](https://github.com/pydantic/pydantic-ai/pull/7768) ##### 🐛 Bug Fixes - Preserve explicit empty `Tool` description instead of falling back to the function docstring by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;7759](https://github.com/pydantic/pydantic-ai/pull/7759) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.34.0...v2.35.0> ### [`v2.34.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.34.0): (2026-08-24) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.33.0...v2.34.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add a LangChain migration skill by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7679](https://github.com/pydantic/pydantic-ai/pull/7679) - Add GLM-5.3 support to `ZaiModel` by [@&#8203;aisk](https://github.com/aisk) in [#&#8203;7600](https://github.com/pydantic/pydantic-ai/pull/7600) ##### 🐛 Bug Fixes - Fix `TestModel` generation for equal inclusive bounds by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7642](https://github.com/pydantic/pydantic-ai/pull/7642) - Render enum $refs as `Literal` in `FunctionSignature` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7579](https://github.com/pydantic/pydantic-ai/pull/7579) - Fix `TestModel` generation of falsy JSON Schema `const` values by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7630](https://github.com/pydantic/pydantic-ai/pull/7630) - Fix stale `UIEventStream` part state on cancellation by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7675](https://github.com/pydantic/pydantic-ai/pull/7675) - Only strip `logit_bias` from Cerebras model settings by [@&#8203;ryanl-cerebras](https://github.com/ryanl-cerebras) in [#&#8203;7653](https://github.com/pydantic/pydantic-ai/pull/7653) - Fix `VercelAIAdapter` rejecting reasoning part `id` in run input by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7706](https://github.com/pydantic/pydantic-ai/pull/7706) - Fix dropped zero-argument tool calls in `CohereModel` by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7720](https://github.com/pydantic/pydantic-ai/pull/7720) - Fix `VercelProvider` dropping the Groq profile for `groq/`-prefixed models by [@&#8203;pydanty](https://github.com/apps/pydanty) in [#&#8203;7551](https://github.com/pydantic/pydantic-ai/pull/7551) - fix(evals): honor zero-valued `SpanQuery` maximums by [@&#8203;lntutor](https://github.com/lntutor) in [#&#8203;6934](https://github.com/pydantic/pydantic-ai/pull/6934) - Handle asctime-form `Retry-After` dates in `wait_retry_after()` by [@&#8203;parveshsaini](https://github.com/parveshsaini) in [#&#8203;7711](https://github.com/pydantic/pydantic-ai/pull/7711) - Honor agent tool retry budget for `load_capability` by [@&#8203;lntutor](https://github.com/lntutor) in [#&#8203;6937](https://github.com/pydantic/pydantic-ai/pull/6937) - Recognize Bedrock’s `r1` alias in `deepseek_model_profile()` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7723](https://github.com/pydantic/pydantic-ai/pull/7723) #### New Contributors - [@&#8203;brianosaurus](https://github.com/brianosaurus) made their first contribution in [#&#8203;7522](https://github.com/pydantic/pydantic-ai/pull/7522) - [@&#8203;junqi410-create](https://github.com/junqi410-create) made their first contribution in [#&#8203;7669](https://github.com/pydantic/pydantic-ai/pull/7669) - [@&#8203;aisk](https://github.com/aisk) made their first contribution in [#&#8203;7600](https://github.com/pydantic/pydantic-ai/pull/7600) - [@&#8203;ryanl-cerebras](https://github.com/ryanl-cerebras) made their first contribution in [#&#8203;7653](https://github.com/pydantic/pydantic-ai/pull/7653) - [@&#8203;parveshsaini](https://github.com/parveshsaini) made their first contribution in [#&#8203;7711](https://github.com/pydantic/pydantic-ai/pull/7711) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.33.0...v2.34.0> ### [`v2.33.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.33.0): (2026-08-20) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.32.2...v2.33.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### ⚠️ If Anthropic stopped working for you in the last day `anthropic` 1.0.0 — rebuilt on `httpx2`, with legacy `httpx` support removed — reached PyPI on August 20. Every earlier pydantic-ai release, including v2.32.2 cut a few hours before this one, allowed that version without supporting it: a fresh or unpinned install of `pydantic-ai[anthropic]` could resolve `anthropic` 1.0.0 and then fail at runtime when using an Anthropic model. Apologies for the breakage window. - **Fix**: upgrade to `pydantic-ai` v2.33.0, which requires and supports `anthropic>=1.0.0`. - **If you need to stay on an older pydantic-ai**: pin `anthropic<1`. If you pass your own `http_client` to `AnthropicProvider`, it must now be an `httpx2.AsyncClient` — the 1.x SDK rejects legacy `httpx` clients at construction. #### What's Changed ##### ⚠️ Compatibility Notes - Use `httpx2` for Anthropic clients by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7657](https://github.com/pydantic/pydantic-ai/pull/7657) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.32.2...v2.33.0> ### [`v2.32.2`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.32.2): (2026-08-20) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.32.1...v2.32.2) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🐛 Bug Fixes - Await async callable instances in `pydantic_evals` tasks and the `evaluate` decorator by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7535](https://github.com/pydantic/pydantic-ai/pull/7535) - Fix `RunContext.cancel()` in realtime sessions by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7528](https://github.com/pydantic/pydantic-ai/pull/7528) - Recognize `m.youtube.com` URLs in `VideoUrl` by [@&#8203;uczltw6](https://github.com/uczltw6) in [#&#8203;7592](https://github.com/pydantic/pydantic-ai/pull/7592) - Normalize DeepSeek Responses function-call replay by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7448](https://github.com/pydantic/pydantic-ai/pull/7448) - Fail the workflow on `UnexpectedModelBehavior` and `FallbackExceptionGroup` under the deprecated `TemporalAgent` by [@&#8203;aviseth](https://github.com/aviseth) in [#&#8203;7465](https://github.com/pydantic/pydantic-ai/pull/7465) #### New Contributors - [@&#8203;uczltw6](https://github.com/uczltw6) made their first contribution in [#&#8203;7592](https://github.com/pydantic/pydantic-ai/pull/7592) - [@&#8203;aviseth](https://github.com/aviseth) made their first contribution in [#&#8203;7465](https://github.com/pydantic/pydantic-ai/pull/7465) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.32.1...v2.32.2> ### [`v2.32.1`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.32.1): (2026-08-19) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.32.0...v2.32.1) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🐛 Bug Fixes - Reject `Agent.run_sync()` from synchronous callbacks inside agent runs by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7277](https://github.com/pydantic/pydantic-ai/pull/7277) - Don't send Anthropic `thinking` blocks with an empty signature by [@&#8203;mpfaffenberger](https://github.com/mpfaffenberger) in [#&#8203;7601](https://github.com/pydantic/pydantic-ai/pull/7601) - Accept any callable as a `FunctionModel` `function` or `stream_function` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7589](https://github.com/pydantic/pydantic-ai/pull/7589) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.32.0...v2.32.1> ### [`v2.32.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.32.0): (2026-08-18) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.31.1...v2.32.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Suggest known model names for invalid identifiers by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7325](https://github.com/pydantic/pydantic-ai/pull/7325) - Support xAI attachment search lifecycle by [@&#8203;colesmcintosh](https://github.com/colesmcintosh) in [#&#8203;7156](https://github.com/pydantic/pydantic-ai/pull/7156) - Surface OpenRouter web-search sources in `provider_details["annotations"]` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7458](https://github.com/pydantic/pydantic-ai/pull/7458) - Add instrumentation version 6, emitting tool results under `role: 'tool'` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7582](https://github.com/pydantic/pydantic-ai/pull/7582) ##### 🐛 Bug Fixes - Run sync hooks in a thread pool and enforce `timeout=` for blocking sync tools and hooks by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7557](https://github.com/pydantic/pydantic-ai/pull/7557) - Record `RunContext.cancel()` from setup-phase `for_run` hooks instead of raising `UserError` by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7567](https://github.com/pydantic/pydantic-ai/pull/7567) - Treat a response containing only empty text parts as having no text output by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7568](https://github.com/pydantic/pydantic-ai/pull/7568) - Only list available tools in the unknown-tool retry message by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7572](https://github.com/pydantic/pydantic-ai/pull/7572) - Sort tool results ahead of tool availability announcements so Bedrock accepts turns revealing multiple tools by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7571](https://github.com/pydantic/pydantic-ai/pull/7571) - Drop native tool calls the replayed payload has no result block for by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7504](https://github.com/pydantic/pydantic-ai/pull/7504) ##### 📦 Dependencies - Use `httpx2` for compatible HTTP clients by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7351](https://github.com/pydantic/pydantic-ai/pull/7351) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.31.1...v2.32.0> ### [`v2.31.1`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.31.1): (2026-08-17) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.31.0...v2.31.1) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🐛 Bug Fixes - Deny native structured output for Claude Sonnet 5 and Fable 5 on Bedrock by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7374](https://github.com/pydantic/pydantic-ai/pull/7374) - Fall back to `thinking_level='LOW'` for Gemini models that reject `MINIMAL` by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7469](https://github.com/pydantic/pydantic-ai/pull/7469) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.31.0...v2.31.1> ### [`v2.31.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.31.0): (2026-08-14) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.30.0...v2.31.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Allow a `UIEventStream` to be built without a `run_input`, and give `AGUIEventStream` its own `thread_id`/`run_id` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7292](https://github.com/pydantic/pydantic-ai/pull/7292) ##### 🐛 Bug Fixes - Attribute failed `FallbackModel` spans to the failing model, not the `fallback:` wrapper by [@&#8203;strawgate](https://github.com/strawgate) in [#&#8203;7018](https://github.com/pydantic/pydantic-ai/pull/7018) - Pass `openai` through Temporal workflow sandboxes by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7464](https://github.com/pydantic/pydantic-ai/pull/7464) #### New Contributors - [@&#8203;echoVic](https://github.com/echoVic) made their first contribution in [#&#8203;4636](https://github.com/pydantic/pydantic-ai/pull/4636) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.30.0...v2.31.0> ### [`v2.30.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.30.0): (2026-08-13) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.29.0...v2.30.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🛡️ Security - [GHSA-q2xc-rrxj-58x9](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-q2xc-rrxj-58x9): the local dev web chat UI (`Agent.to_web()`, `clai web`) didn't validate the `Host` header, so DNS rebinding from a website you visit could reach it and run the served agent with your local process's tools and credentials. Fixed in `pydantic-ai`/`pydantic-ai-slim` 2.30.0 by validating `Host` against localhost/loopback/LAN addresses by default; deployments reached under a real hostname must opt in with the new `allowed_hosts` setting. ##### 🚀 Features - Use `openrouter:web_search` for web search by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7378](https://github.com/pydantic/pydantic-ai/pull/7378) - Add `gemini-3.7-flash` model by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7445](https://github.com/pydantic/pydantic-ai/pull/7445) - Expose gRPC `metadata` on `XaiProvider` by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7423](https://github.com/pydantic/pydantic-ai/pull/7423) - Add `allowed_hosts` to `Agent.to_web()` and `clai web` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7437](https://github.com/pydantic/pydantic-ai/pull/7437) ##### 🐛 Bug Fixes - Resolve deferred `openai` resource imports and genai-prices data loading at `Model` construction time by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;7408](https://github.com/pydantic/pydantic-ai/pull/7408) - Fall back to ASCII in `EvaluationReport.print()` on non-UTF-8 consoles by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7290](https://github.com/pydantic/pydantic-ai/pull/7290) - Lowercase model name before profile lookup in SambaNova, Heroku, and Fireworks providers by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;6818](https://github.com/pydantic/pydantic-ai/pull/6818) - Update LatestCerebrasModelNames to current model catalog by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;6838](https://github.com/pydantic/pydantic-ai/pull/6838) - Require a deferred tool to be revealed, and its capability loaded, before it can be called by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7271](https://github.com/pydantic/pydantic-ai/pull/7271) - Anchor the tool-callability evidence window to the response's serving provider by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7442](https://github.com/pydantic/pydantic-ai/pull/7442) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.29.0...v2.30.0> ### [`v2.29.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.29.0): (2026-08-12) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.28.0...v2.29.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Support FastMCP 4 and MCP SDK v2 in `MCPToolset` alongside FastMCP 3 by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;6738](https://github.com/pydantic/pydantic-ai/pull/6738) - Add Azure AI Voice Live via the `azure_voice_live` setting by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6642](https://github.com/pydantic/pydantic-ai/pull/6642) ##### 🐛 Bug Fixes - Fix silent truncation of gzip response bodies by [@&#8203;ChaoGlenXu](https://github.com/ChaoGlenXu) in [#&#8203;7388](https://github.com/pydantic/pydantic-ai/pull/7388) - Include parameter descriptions in rendered tool signatures by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;6487](https://github.com/pydantic/pydantic-ai/pull/6487) - Fix inherited realtime WebRTC and Azure `for_realtime` bugs from `#6676` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7412](https://github.com/pydantic/pydantic-ai/pull/7412) - Fix concurrent provider stream shutdown by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7375](https://github.com/pydantic/pydantic-ai/pull/7375) #### New Contributors - [@&#8203;ChaoGlenXu](https://github.com/ChaoGlenXu) made their first contribution in [#&#8203;7388](https://github.com/pydantic/pydantic-ai/pull/7388) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.28.0...v2.29.0> ### [`v2.28.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.28.0): (2026-08-11) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.27.1...v2.28.0) ##### 🛡️ Security Fixes a high-severity vulnerability in the development web chat UI (`Agent.to_web()`, `clai web`): the chat endpoint didn't check the request's content type, so a plain cross-origin request from a website open in the developer's browser could reach the endpoint without a CORS preflight and trigger the served agent to run and execute its tools with the local process's privileges and credentials. The endpoint now requires `Content-Type: application/json` and rejects other requests before the body is parsed and before the agent runs. See [GHSA-h4xc-3qfq-jf93](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-h4xc-3qfq-jf93). Patched in `2.28.0` (v2) and `1.107.4` (v1). #### What's Changed ##### 🚀 Features - Add realtime speech-to-speech support with `Agent.realtime()` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6324](https://github.com/pydantic/pydantic-ai/pull/6324) - Add Crusoe provider by [@&#8203;acheamponge](https://github.com/acheamponge) in [#&#8203;6457](https://github.com/pydantic/pydantic-ai/pull/6457) - Add browser WebRTC + server sideband support for realtime speech-to-speech by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6676](https://github.com/pydantic/pydantic-ai/pull/6676) ##### 🐛 Bug Fixes - fix(bedrock): attach a leading `CachePoint` to the preceding user message instead of raising by [@&#8203;Diwak4r](https://github.com/Diwak4r) in [#&#8203;7071](https://github.com/pydantic/pydantic-ai/pull/7071) - Test cancellation of concurrent `PeekableAsyncStream` pulls by [@&#8203;mikemikimike](https://github.com/mikemikimike) in [#&#8203;7023](https://github.com/pydantic/pydantic-ai/pull/7023) - Settle in-flight state and report `state_restored` honestly on realtime reconnect by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7379](https://github.com/pydantic/pydantic-ai/pull/7379) - Only accept JSON request bodies on the web UI chat endpoint by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7382](https://github.com/pydantic/pydantic-ai/pull/7382) - Await callback results uniformly via a shared `await_maybe` helper by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7265](https://github.com/pydantic/pydantic-ai/pull/7265) - Fix `safe_download` Host header dropping non-default port by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7348](https://github.com/pydantic/pydantic-ai/pull/7348) - Serialize AG-UI dict tool-call deltas with Pydantic Core by [@&#8203;bferanmi806-sketch](https://github.com/bferanmi806-sketch) in [#&#8203;7221](https://github.com/pydantic/pydantic-ai/pull/7221) ##### 📦 Dependencies - Add the `cerebras` optional dependency group by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7387](https://github.com/pydantic/pydantic-ai/pull/7387) #### New Contributors - [@&#8203;Diwak4r](https://github.com/Diwak4r) made their first contribution in [#&#8203;7071](https://github.com/pydantic/pydantic-ai/pull/7071) - [@&#8203;mikemikimike](https://github.com/mikemikimike) made their first contribution in [#&#8203;7023](https://github.com/pydantic/pydantic-ai/pull/7023) - [@&#8203;acheamponge](https://github.com/acheamponge) made their first contribution in [#&#8203;6457](https://github.com/pydantic/pydantic-ai/pull/6457) - [@&#8203;bferanmi806-sketch](https://github.com/bferanmi806-sketch) made their first contribution in [#&#8203;7221](https://github.com/pydantic/pydantic-ai/pull/7221) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.27.1...v2.28.0> ### [`v2.27.1`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.27.1): (2026-08-10) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.27.0...v2.27.1) ##### 🛡️ Security This release fixed an information-disclosure issue: retry-prompt content (validation feedback sent back to the model, which can quote invalid values from its output) was not redacted by `InstrumentationSettings(include_content=False)` when the retry was not tied to a tool call. Now disclosed as [GHSA-3gh4-cghq-f8v4](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-3gh4-cghq-f8v4) (low). Fixed here in `2.27.1` ([#&#8203;7357](https://github.com/pydantic/pydantic-ai/pull/7357)); v1 users should upgrade to `1.107.4` or later. <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🐛 Bug Fixes - Restore tool spans for failed argument validation by [@&#8203;adtyavrdhn](https://github.com/adtyavrdhn) in [#&#8203;6601](https://github.com/pydantic/pydantic-ai/pull/6601) - Fix `XaiStreamedResponse` finish_reason mapping for streaming responses by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;6814](https://github.com/pydantic/pydantic-ai/pull/6814) - Point offline web UI hosting at the self-contained chat UI build by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7349](https://github.com/pydantic/pydantic-ai/pull/7349) - Allow adaptive thinking with Tool Output and forced tool choice on Anthropic by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7200](https://github.com/pydantic/pydantic-ai/pull/7200) - Gate `RetryPromptPart` OpenTelemetry content on `include_content` by [@&#8203;sean-kim05](https://github.com/sean-kim05) in [#&#8203;7357](https://github.com/pydantic/pydantic-ai/pull/7357) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.27.0...v2.27.1> ### [`v2.27.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.27.0): (2026-08-07) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.26.0...v2.27.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Add `xai_agent_count` to `XaiModelSettings` by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7155](https://github.com/pydantic/pydantic-ai/pull/7155) - Round-trip `CompactionPart` through the Vercel AI and AG-UI adapters by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7287](https://github.com/pydantic/pydantic-ai/pull/7287) - Add `SnowflakeModel` and `SnowflakeProvider` for Snowflake Cortex by [@&#8203;ayirpown](https://github.com/ayirpown) in [#&#8203;6150](https://github.com/pydantic/pydantic-ai/pull/6150) ##### 🐛 Bug Fixes - Honor `include_binary_content=False` in every OTel serialization sink by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7131](https://github.com/pydantic/pydantic-ai/pull/7131) - Keep `ToolReturn.tools` in the redacted OTel shape by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7273](https://github.com/pydantic/pydantic-ai/pull/7273) - Fix `SpanQuery` `has_attributes` matching for JSON-serialized dict and list values by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;5905](https://github.com/pydantic/pydantic-ai/pull/5905) - Skip re-sending the standing prompt where the OpenAI Responses compaction item retains it by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7264](https://github.com/pydantic/pydantic-ai/pull/7264) - Round-trip Anthropic compaction `encrypted_content` verbatim by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7286](https://github.com/pydantic/pydantic-ai/pull/7286) - Strip the compaction provenance stamp in `sanitize_messages` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7285](https://github.com/pydantic/pydantic-ai/pull/7285) - Point at the cause when a tool return or model response exceeds Temporal's payload size limit by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7157](https://github.com/pydantic/pydantic-ai/pull/7157) #### New Contributors - [@&#8203;ayirpown](https://github.com/ayirpown) made their first contribution in [#&#8203;6150](https://github.com/pydantic/pydantic-ai/pull/6150) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.26.0...v2.27.0> ### [`v2.26.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.26.0): (2026-08-06) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.25.0...v2.26.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Support hiding function tools until revealed — via tool search, `load_capability`, or `ToolReturn.tools` — using each provider's native deferral/addition channel by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7104](https://github.com/pydantic/pydantic-ai/pull/7104) - Add first-party run cancellation: `AgentRun.cancel()`, `RunContext.cancel()`, `RunCancelled` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6497](https://github.com/pydantic/pydantic-ai/pull/6497) - Add `Model.resolve_prompt_cache_retention()` to resolve effective prompt-cache retention from model settings by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7254](https://github.com/pydantic/pydantic-ai/pull/7254) - Promote `run_stream_events()` iterator to public `AgentRunEvents` handle with `cancel()` and run-state access by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;6498](https://github.com/pydantic/pydantic-ai/pull/6498) - Cover and document DeepSeek V4 Flash via `OpenAIResponsesModel` + `DeepSeekProvider` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7202](https://github.com/pydantic/pydantic-ai/pull/7202) ##### 🐛 Bug Fixes - Forward `model_id` through `WrapperModel` and resolve it against the active model in `TemporalModel` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7181](https://github.com/pydantic/pydantic-ai/pull/7181) - Map streamed OpenRouter reasoning details by their index by [@&#8203;VictorPeralta](https://github.com/VictorPeralta) in [#&#8203;7214](https://github.com/pydantic/pydantic-ai/pull/7214) - Gate OpenRouter off native mid-conversation system messages with `supports_inline_system_prompts=False` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7253](https://github.com/pydantic/pydantic-ai/pull/7253) - Restore the released legacy profile-key shim and fix two reveal-state edges (`is_tool_available`, `TestModel` native additions) by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7260](https://github.com/pydantic/pydantic-ai/pull/7260) - Keep deferred tools searchable after discovery and reset reveal state at `CompactionPart` boundaries by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7225](https://github.com/pydantic/pydantic-ai/pull/7225) - Forward events from `UIEventStream` callbacks that return an async iterator without being an async generator function by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7256](https://github.com/pydantic/pydantic-ai/pull/7256) - Send only the compacted window: drop history before the latest same-provider `CompactionPart` by [@&#8203;DouweM](https://github.com/DouweM) in [#&#8203;7228](https://github.com/pydantic/pydantic-ai/pull/7228) #### New Contributors - [@&#8203;VictorPeralta](https://github.com/VictorPeralta) made their first contribution in [#&#8203;7214](https://github.com/pydantic/pydantic-ai/pull/7214) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.25.0...v2.26.0> ### [`v2.25.0`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.25.0): (2026-08-05) [Compare Source](https://github.com/pydantic/pydantic-ai/compare/v2.24.0...v2.25.0) <!-- Release notes generated using configuration in .github/release.yml at main --> #### What's Changed ##### 🚀 Features - Forward xAI `FileSearchTool` collections search options by [@&#8203;pydanty](https://github.com/pydanty)\[bot] in [#&#8203;7154](https://github.com/pydantic/pydantic-ai/pull/7154) ##### 🐛 Bug Fixes - fix(azure): send `max_tokens` for Mistral models, not `max_completion_tokens` by [@&#8203;feiiiiii5](https://github.com/feiiiiii5) in [#&#8203;6929](https://github.com/pydantic/pydantic-ai/pull/6929) - Omit server attributes for a malformed `base_url` port and forward `base_url` through `WrapperModel` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7136](https://github.com/pydantic/pydantic-ai/pull/7136) - Fix `thinking="minimal"` for GPT-5.6 models by [@&#8203;daikeren](https://github.com/daikeren) in [#&#8203;7082](https://github.com/pydantic/pydantic-ai/pull/7082) - Degrade malformed tool-call args in `ToolCallPart.args_as_json_str()` by [@&#8203;dsfaccini](https://github.com/dsfaccini) in [#&#8203;7092](https://github.com/pydantic/pydantic-ai/pull/7092) #### New Contributors - [@&#8203;feiiiiii5](https://github.com/feiiiiii5) made their first contribution in [#&#8203;6929](https://github.com/pydantic/pydantic-ai/pull/6929) - [@&#8203;daikeren](https://github.com/daikeren) made their first contribution in [#&#8203;7082](https://github.com/pydantic/pydantic-ai/pull/7082) **Full Changelog**: <https://github.com/pydantic/pydantic-ai/compare/v2.24.0...v2.25.0> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNDguNiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0OC42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin renovate/pypi-pydantic-ai-vulnerability:renovate/pypi-pydantic-ai-vulnerability
git switch renovate/pypi-pydantic-ai-vulnerability

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff renovate/pypi-pydantic-ai-vulnerability
git switch renovate/pypi-pydantic-ai-vulnerability
git rebase main
git switch main
git merge --ff-only renovate/pypi-pydantic-ai-vulnerability
git switch renovate/pypi-pydantic-ai-vulnerability
git rebase main
git switch main
git merge --no-ff renovate/pypi-pydantic-ai-vulnerability
git switch main
git merge --squash renovate/pypi-pydantic-ai-vulnerability
git switch main
git merge --ff-only renovate/pypi-pydantic-ai-vulnerability
git switch main
git merge renovate/pypi-pydantic-ai-vulnerability
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
finkregh/paste-to-tidal-playlist!9
No description provided.