Repository navigation
Restore tool spans for failed argument validation - #6601
Conversation
There was a problem hiding this comment.
Review summary
Reviewed the diff for restoring the v1.94.0 behavior of recording a tool span for failed argument validation, while keeping wrap_tool_execute as the single wrapper around the full tool execution lifecycle.
What the PR does well
- Correct hook traversal —
_record_tool_validation_errorintool_manager.pycorrectly walksCombinedCapability→WrapperCapability→Instrumentation, respectsdefer_loading+available_capability_ids, and deduplicates viaseen: set[int]. Matches the existing_ctx_for_available_capstyle used elsewhere. - Targeted span —
Instrumentation._record_tool_validation_erroronly fires when validation actually failed (validated.args_valid is False), avoiding double spans for valid calls. - Doc updates —
abstract.pydocstring andcapabilities.mdtable/diagram now describe the newwrap_tool_executelifecycle accurately. The error-hooks section explicitly calls out tool execution as the exception to the general ordering. - Comprehensive tests —
tests/test_logfire.pycovers schema/validator/unknown failures,include_contenton/off,wrapped_instrumentationon/off, and the deferred-loading interaction.tests/test_capabilities.pyadds dedicated lifecycle ordering, onion-order preservation, and recovery tests. - Backward compatibility —
wrap_validation_errors=Falsecallers still get the raw exception path they expect; no behavior change for them.
Notes (not blocking)
The docstring of Instrumentation._record_tool_validation_error says "zero-width tool span" and the PR description uses "zero-width error span", but the implementation creates a regular start_as_current_span (with measurable duration). In the issue thread this was discussed as one of the alternatives to the full span; the author chose the full span. Either the docstring/PR description should be aligned with the chosen approach, or the implementation should actually be zero-width. Cosmetic, not behavioral.
The pre-existing wart that logfire.msg = "running tool: {tool_name}" is reused for validation-error spans (where no tool actually ran) is unchanged by this PR — it was the v1.94.0 behavior too, so restoring it is consistent.
Verdict
No HIGH or CRITICAL findings. Implementation is correct, tests are thorough, and the documented wrap_tool_execute lifecycle change matches the new code path.
There was a problem hiding this comment.
Clean fix for #6555. The new _instrument_tool_call closure on ToolManager correctly wraps the full validate+execute lifecycle, restoring the pre-v1.95 span boundary around validation failures. Verified: validation errors (schema and validator-rejected args) now produce an execute_tool span with status ERROR and the retry prompt as gen_ai.tool.call.result. Deferred Instrumentation (wrapped via WrapperCapability) is gated on ctx.available_capability_ids and only traces when loaded. User wrap_tool_execute still wraps the complete execute lifecycle (before, body, error, after); on_tool_execute_error still triggers on tool-body exceptions; control-flow exceptions still propagate. Instrumentation no longer overrides wrap_tool_execute, so the OTel span is the outermost wrapper. Tests cover all three scenarios and docs reflect the new semantics.
There was a problem hiding this comment.
Verified the fix restores the pre-v1.95 tool-span boundary: Instrumentation._wrap_tool_call now wraps the operation that either raises a stored validation error or executes the tool, and _execute_tool_call_impl is invoked inside the span. wrap_tool_execute semantics correctly expand to enclose before_tool_execute / on_tool_execute_error / after_tool_execute, matching the new docstring and the test_wrap_tool_execute_wraps_execute_lifecycle and test_tool_span_wraps_recovered_and_modified_lifecycle assertions. WrapperCapability and CombinedCapability delegate the new _wrap_tool_call hook symmetrically with the other lifecycle hooks. ToolRetryError raised from a failed validation is recorded as the tool-result attribute and the span is marked ERROR (handle_tool_control_flow=True), matching v1.94. No findings.
ApprovabilityVerdict: Approved d0d09dc This PR adds instrumentation spans for tool argument validation failures and refactors retry prompt creation into a centralized factory method. The changes are focused on observability/tracing without altering core execution behavior, with comprehensive test coverage. You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e10408b51d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughTool execution wrapping now covers both stored validation failures and validated execution. Capability hook contracts accept nullable tool definitions and arguments, while Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/hooks.md (1)
158-158: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winSame "all tool hooks" blanket statement conflicts with the new nullable
tool_defnote.See consolidated comment anchored on
docs/capabilities.md.Also applies to: 174-177
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/hooks.md` at line 158, Update the tool-hook documentation around the “All tool hooks receive” statement to account for nullable or absent tool_def values, aligning it with the nullable tool_def guidance in docs/capabilities.md. Apply the same clarification to the corresponding tool-hook parameter descriptions around the later referenced section.docs/capabilities.md (1)
1582-1582: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win"All tool hooks receive a
tool_defparameter" now contradicts the newwrap_tool_executenullability note a few lines down.See consolidated comment (anchored here) covering both this file and
docs/hooks.md.Also applies to: 1595-1610
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/capabilities.md` at line 1582, Update the tool-hook documentation around the ToolDefinition parameter and wrap_tool_execute nullability note so it no longer claims every hook always receives a non-null tool_def. Align the corresponding wording in docs/hooks.md, clearly documenting when tool_def may be absent while preserving the existing behavior for hooks that do receive a ToolDefinition.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@docs/capabilities.md`:
- Line 1582: Update the tool-hook documentation around the ToolDefinition
parameter and wrap_tool_execute nullability note so it no longer claims every
hook always receives a non-null tool_def. Align the corresponding wording in
docs/hooks.md, clearly documenting when tool_def may be absent while preserving
the existing behavior for hooks that do receive a ToolDefinition.
In `@docs/hooks.md`:
- Line 158: Update the tool-hook documentation around the “All tool hooks
receive” statement to account for nullable or absent tool_def values, aligning
it with the nullable tool_def guidance in docs/capabilities.md. Apply the same
clarification to the corresponding tool-hook parameter descriptions around the
later referenced section.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 530b436f-d28f-46ee-bf35-a09834202b6b
📒 Files selected for processing (10)
docs/capabilities.mddocs/hooks.mdpydantic_ai_slim/pydantic_ai/capabilities/abstract.pypydantic_ai_slim/pydantic_ai/capabilities/combined.pypydantic_ai_slim/pydantic_ai/capabilities/hooks.pypydantic_ai_slim/pydantic_ai/capabilities/instrumentation.pypydantic_ai_slim/pydantic_ai/capabilities/wrapper.pypydantic_ai_slim/pydantic_ai/tool_manager.pytests/test_capabilities.pytests/test_logfire.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
pydantic/logfire(manual)pydantic/pydantic-ai(manual)pydantic/pydantic(auto-detected)pydantic/unified-docs(auto-detected)
There was a problem hiding this comment.
Request changes — unresolved instrumentation/skip interaction
The prior UNRESOLVED review from chatgpt-codex-connector (commit-referenced diff on tool_manager.py) still applies to the current code: when Instrumentation is enabled (auto-prepended as the outermost capability — see pydantic_ai_slim/pydantic_ai/agent/__init__.py:1335) and an inner capability's wrap_tool_execute raises SkipToolExecution, the exception is caught by Instrumentation._run_tool_span's except BaseException block (pydantic_ai_slim/pydantic_ai/capabilities/instrumentation.py:381), which records the span with StatusCode.ERROR and re-raises. The same exception is then caught at tool_manager.py:517 and converted into a successful e.result. Net effect: a tool the agent deliberately skipped produces ERROR-status telemetry — the opposite of the PR's intent (#6555 was about restoring correct tool-span coverage for failed validation, not about regressing successful-skip telemetry).
To verify locally, run the new test_skip_tool_execution test (tests/test_capabilities.py:5647) with Instrumentation added to the agent's capabilities= list and assert logfire.level_num < 17 on the resulting tool span — it will fail under the current code.
The proposed fix is to special-case SkipToolExecution inside Instrumentation._run_tool_span (treating it as control flow, like the existing (CallDeferred, ApprovalRequired) branch on lines 354-372). The companion test (tests/test_logfire.py) should be extended to cover both phases (before and wrap) alongside Instrumentation so this can't regress.
The rest of the PR — type-signature change on AbstractCapability.wrap_tool_execute, removal of the private _instrument_tool_call boundary, decorator-style Hooks validation-failure filtering at hooks.py:1096, and the new tests/test_logfire.py validation-failure span tests — looks correct. The public-API compatibility note in the PR description adequately flags the breaking change for AbstractCapability.wrap_tool_execute overrides, so once the instrumentation/skip interaction is fixed this should be ready.
…-tool-execute # Conflicts: # docs/capabilities.md
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
docs/hooks.md (1)
177-179: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winClarify nullable arguments for
wrap_tool_execute.The preceding text says
argsis always a validated dictionary, butAbstractCapability.wrap_tool_executealso wraps stored validation failures wheretool_defandargsmay beNone. Scope the “always” statement to decorator execution hooks and document the nullable inputs for direct capability overrides.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/hooks.md` around lines 177 - 179, Update the documentation around AbstractCapability.wrap_tool_execute to limit the “args is always a validated dictionary” statement to tool_execute decorator hooks, and explicitly document that direct wrap_tool_execute overrides may receive None for tool_def and args when handling stored validation failures.docs/capabilities/custom.md (3)
630-630: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFix the unresolved output-tool reference.
[output tools][pydantic_ai.output.ToolOutput]has no defined reference and triggers MD052. Link directly to../output.md#tool-outputor add the canonical reference definition.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/capabilities/custom.md` at line 630, Update the output-tools link in the prepare_output_tools documentation entry to resolve correctly by linking directly to ../output.md#tool-output, or define and use the canonical reference for pydantic_ai.output.ToolOutput. Keep the surrounding lifecycle description unchanged.Sources: Coding guidelines, Linters/SAST tools
568-590: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winClarify the nullable
tool_defexception.“All tool hooks receive a
ToolDefinition” conflicts with the followingwrap_tool_executecontract, wheretool_defmay beNonefor unknown tools. State that all hooks receive the parameter, but only validation and non-wrapper execution hooks guarantee a non-null definition.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/capabilities/custom.md` around lines 568 - 590, Update the introductory statement and execution-hook documentation around AbstractCapability so they clarify that all hooks receive a tool_def parameter, but wrap_tool_execute may receive None for unknown tools. Explicitly state that validation hooks and non-wrapper execution hooks guarantee a non-null ToolDefinition, while preserving the existing nullable contract for wrap_tool_execute.
371-377: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winEscape union separators inside Markdown tables.
The literal
|characters are parsed as extra table columns, causing MD056 and malformed rendered tables. Escape them as\|(as already done forwrap_tool_executeon Line 589).Also applies to: 577-577, 612-612
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/capabilities/custom.md` around lines 371 - 377, Escape the literal union separators in the affected return-type cells of the capability method table, including the rows for get_toolset(), get_wrapper_toolset(), get_instructions(), get_model_settings(), get_model(), and resolve_model_id(), plus the additional referenced rows. Preserve the displayed type unions while formatting each pipe as \|, consistent with the existing wrap_tool_execute entry.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@docs/capabilities/custom.md`:
- Line 630: Update the output-tools link in the prepare_output_tools
documentation entry to resolve correctly by linking directly to
../output.md#tool-output, or define and use the canonical reference for
pydantic_ai.output.ToolOutput. Keep the surrounding lifecycle description
unchanged.
- Around line 568-590: Update the introductory statement and execution-hook
documentation around AbstractCapability so they clarify that all hooks receive a
tool_def parameter, but wrap_tool_execute may receive None for unknown tools.
Explicitly state that validation hooks and non-wrapper execution hooks guarantee
a non-null ToolDefinition, while preserving the existing nullable contract for
wrap_tool_execute.
- Around line 371-377: Escape the literal union separators in the affected
return-type cells of the capability method table, including the rows for
get_toolset(), get_wrapper_toolset(), get_instructions(), get_model_settings(),
get_model(), and resolve_model_id(), plus the additional referenced rows.
Preserve the displayed type unions while formatting each pipe as \|, consistent
with the existing wrap_tool_execute entry.
In `@docs/hooks.md`:
- Around line 177-179: Update the documentation around
AbstractCapability.wrap_tool_execute to limit the “args is always a validated
dictionary” statement to tool_execute decorator hooks, and explicitly document
that direct wrap_tool_execute overrides may receive None for tool_def and args
when handling stored validation failures.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ff6daa0-f71b-42a0-b57d-3f6c2481d5f7
📒 Files selected for processing (8)
docs/capabilities/custom.mddocs/hooks.mdpydantic_ai_slim/pydantic_ai/capabilities/abstract.pypydantic_ai_slim/pydantic_ai/capabilities/combined.pypydantic_ai_slim/pydantic_ai/capabilities/instrumentation.pypydantic_ai_slim/pydantic_ai/tool_manager.pytests/test_capabilities.pytests/test_logfire.py
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
pydantic/logfire(manual)pydantic/pydantic-ai(manual)pydantic/pydantic(auto-detected)pydantic/unified-docs(auto-detected)
🚧 Files skipped from review as they are similar to previous changes (6)
- pydantic_ai_slim/pydantic_ai/capabilities/instrumentation.py
- pydantic_ai_slim/pydantic_ai/capabilities/combined.py
- pydantic_ai_slim/pydantic_ai/capabilities/abstract.py
- pydantic_ai_slim/pydantic_ai/tool_manager.py
- tests/test_capabilities.py
- tests/test_logfire.py
There was a problem hiding this comment.
REQUEST_CHANGES — re-reviewing the diff against the previous unresolved thread.
The one substantive blocker (HIGH severity) is already flagged by chatgpt-codex-connector at pydantic_ai_slim/pydantic_ai/tool_manager.py:521: the new outer wrap_tool_execute boundary routes SkipToolExecution through Instrumentation._run_tool_span, where the except BaseException branch (instrumentation.py:387) marks the span ERROR and records the exception, even though execute_tool_call immediately converts that same exception into a successful replacement result. I traced the path end-to-end (the CombinedCapability chain places Instrumentation as the outermost cap per CapabilityOrdering(position=outermost)), and the bug reproduces as described — telemetry for skipped/denied tools reports error status and logs the SkipToolExecution as an escaped exception.
Per the review conventions I am not duplicating that finding inline; the existing thread is the right place for it. The PR remains blocked until SkipToolExecution (and by extension CallDeferred/ApprovalRequired already handled) is either special-cased in _run_tool_span so the span closes cleanly, or the wrap_tool_execute boundary is restructured to keep the skipped path outside the instrumented action.
The rest of the diff looks sound on a full-file re-read:
- AbstractCapability.wrap_tool_execute defaults to return await handler(args) — args=None correctly raises the stored validation_error via _execute_tool_call_impl.
- hooks.py short-circuits on tool_def is None or args is None, preserving the documented hooks.on.tool_execute valid-call-only contract.
- WrapperCapability and CombinedCapability correctly thread the optional types.
- No double-counting of ctx.usage.tool_calls: _execute_tool_call_impl catches SkipToolExecution from before_tool_execute/innermost handler; execute_tool_call only catches it from cap.wrap_tool_execute itself.
- New tests (test_tool_argument_validation_error_emits_span, test_wrapped_deferred_instrumentation_only_traces_when_loaded, test_tool_span_wraps_recovered_and_modified_lifecycle, test_wrap_tool_execute_wraps_execute_lifecycle, parametrized test_skip_tool_execution) correctly cover schema/validator/unknown failure sources, deferred loading, and lifecycle ordering.
One small doc nit (LOW): the VerboseLogging example in docs/capabilities/custom.md still does print(f" Tool call: {call.tool_name}({args})") against the new args: dict[str, Any] | None — when wrap_tool_execute is invoked for a stored validation failure this will print name(None). Worth a quick update alongside the rest of the docs to avoid surprising copy-paste users.
There was a problem hiding this comment.
Reviewed at 25a08edda9494e3cbd94d5666edc919ed12800a8.
No new findings — the surviving concerns from prior review threads (SkipToolExecution span handling, deferral scope, redaction asymmetry between validation and execution spans, exception.escaped bool/string alignment, from __future__ import annotations in the new helper, and the wrap_tool_validate signature) are all addressed at the current head. The implementation correctly restores the v1.94 tool-span behavior for failed argument validation, scopes the include_content=False redaction to the validation path with an explicit rationale comment, and shares retry-prompt construction so telemetry matches the prompt sent to the model. Tests cover both failure_source × include_content paths and the recovery-no-error-span contract for both capability orderings.
Generated by 🔎 CI Review
… and `pydantic_ai.tool.failure_stage` attribute
Dismissing prior approval to re-evaluate 4bd0e03
There was a problem hiding this comment.
Reviewed at 4bd0e0339cde7be99a7edaf9ec0bd1533af910e2.
The head commit is a small, additive polish on top of an already-thoroughly-reviewed change: it adds pydantic_ai.tool.failure_stage='validation' and the invalid tool call: <name> logfire.msg to the failed-validation span so backends can distinguish it from execution failures, with matching test assertions on both the failure span and the subsequent successful retry. No new behavior, no new public API, no risk to existing telemetry shape. Local pytest tests/test_logfire.py and pyright on the touched files are clean; the prior resolved threads (redaction under include_content=False, exception.escaped boolean alignment, from __future__ import annotations in _tool_retry.py) all still hold against this commit.
Generated by 🔎 CI Review
…n raw-mode dispatch behavior
Dismissing prior approval to re-evaluate fd063e9
Dismissing prior approval to re-evaluate 8a957f4
Dismissing prior approval to re-evaluate bc85385
There was a problem hiding this comment.
Reviewed at bc8538583def4827f36ca039e20d606a6bb305d5.
The PR restores the v1.94.0 failed-validation tool-span contract cleanly: shared retry-prompt construction (pydantic_ai/_tool_retry.py) keeps telemetry aligned with the prompt the model receives; recovery capabilities run before Instrumentation.on_tool_validate_error via CombinedCapability's reverse-order loop; and include_content=False redaction omits the rejected values. Tests cover both schema and validator failure sources, both capability orderings, and raw-mode dispatch. No new findings.
Generated by 🔎 CI Review
Dismissing prior approval to re-evaluate 61a11ea
There was a problem hiding this comment.
Reviewed at 61a11ea852512ee5c117f8c66912eb1cf57ecac8.
This is a well-scoped fix for the regression tracked as #6555. Key observations:
- The shared
retry_prompt_from_errorhelper in the new_retry_prompt.pymodule is now the single source of retry-prompt text used by_output.py,tool_manager.py, andcapabilities/instrumentation.py, so the span's recorded prompt and the message sent to the model cannot drift apart again. Instrumentation.on_tool_validate_errorcorrectly emits a zero-width ERROR span only when no recovery capability returns validated args; the recovered path produces no error span (test_recovered_tool_validation_emits_no_error_span).- The
include_content=Falsebranch recordsexception.typeonly (with a booleanexception.escapedand a comment explaining why the validation path differs from the execution path), and theassert 'private-invalid-value' not in str(...)line pins that redaction. - Both
ValidationError(schema) andModelRetry(validator) failure sources are parametrized intest_tool_argument_validation_failure_emits_span;test_raw_mode_validation_failure_emits_spancovershandle_call(wrap_validation_errors=False)from a sandboxed dispatcher.
The deliberate scope limit on the redaction asymmetry (validation redaction only, execution redaction deferred) is explicitly called out in the code comment, so future readers won't accidentally widen it without intent.
No new findings.
Generated by 🔎 CI Review
Dismissing prior approval to re-evaluate d0d09dc
Ports the tool-span construction #6601 added onto the retried `ToolReturnPart` this branch introduces: `_output.build_retried_tool_return` is now the single builder the agent loop and the validation-error span share, so the span keeps recording exactly what the model receives. `RetryPromptPart.from_error` stays as the constructor for user code answering a deferred call with a retry of its own.
This MR contains the following updates: | Package | Type | Update | Change | OpenSSF | |---|---|---|---|---| | [numpy](https://github.com/numpy/numpy) ([changelog](https://numpy.org/doc/stable/release)) | dependencies | patch | `2.5.2` → `2.5.3` | [](https://securityscorecards.dev/viewer/?uri=github.com/numpy/numpy) | | [openai](https://github.com/openai/openai-python) | dependencies | patch | `2.52.0` → `2.52.1` | [](https://securityscorecards.dev/viewer/?uri=github.com/openai/openai-python) | | [pydantic](https://github.com/pydantic/pydantic) ([changelog](https://docs.pydantic.dev/latest/changelog/)) | dependencies | patch | `2.13.4` → `2.13.5` | [](https://securityscorecards.dev/viewer/?uri=github.com/pydantic/pydantic) | | [pydantic-ai](https://github.com/pydantic/pydantic-ai) ([changelog](https://github.com/pydantic/pydantic-ai/releases)) | dependencies | patch | `2.27.0` → `2.27.1` | [](https://securityscorecards.dev/viewer/?uri=github.com/pydantic/pydantic-ai) | | [types-requests](https://github.com/python/typeshed) ([changelog](https://github.com/typeshed-internal/stub_uploader/blob/main/data/changelogs/requests.md)) | dependencies | patch | `2.33.0.20260712` → `2.33.0.20260906` | [](https://securityscorecards.dev/viewer/?uri=github.com/python/typeshed) | | [uvicorn](https://github.com/Kludex/uvicorn) ([changelog](https://uvicorn.dev/release-notes)) | dependencies | patch | `0.52.3` → `0.52.4` | [](https://securityscorecards.dev/viewer/?uri=github.com/Kludex/uvicorn) | --- ### Release Notes <details> <summary>numpy/numpy (numpy)</summary> ### [`v2.5.3`](https://github.com/numpy/numpy/releases/tag/v2.5.3): (Sep 6, 2026) [Compare Source](numpy/numpy@v2.5.2...v2.5.3) ### NumPy 2.5.3 Release Notes The NumPy 2.5.3 is a patch release that fixes bugs discovered after the 2.5.2 release. Apart from the usual bug and maintenance work, there are a number of StringDType related fixes for problems discovered during the ongoing string work in the main branch. This release supports Python versions 3.12-3.15 #### Changes - Casting a fixed-width byte string array (`np.bytes_`) to `StringDType` now raises `TypeError` when the bytes are not valid UTF-8. Previously the invalid bytes were stored as-is and later caused undefined behavior in string operations. ([gh-32296](numpy/numpy#32296)) - `MaskedArray._fill_value` would become stale when ufuncs that change dtype left the result holding a fill\_value typed for the old dtype. The mismatch was silent until something later called `_check_fill_value`, such as `.view()`, and then a `TypeError` would be raised. Now, when the copied fill\_value is no longer valid for the new dtype, fall back to the default fill\_value for that dtype instead of propagating the stale value. This may raise a `ComplexWarning` if the fill\_value is complex and the new dtype is real. ([gh-32423](numpy/numpy#32423)) #### Contributors A total of 9 people contributed to this release. People with a "+" by their names contributed a patch for the first time. - Charles Harris - Iason Krommydas - James Davies + - Joren Hammudoglu - Maanas Arora - Matti Picus - Nathan Goldbaum - Shikhar Goel + - Yeonho Kim + #### Pull requests merged A total of 27 pull requests were merged for this release. - [#​32235](numpy/numpy#32235): MAINT: Prepare 2.5.x for further development - [#​32289](numpy/numpy#32289): BUG: raise ValueError when reading into record array with references... - [#​32290](numpy/numpy#32290): BUG: avoid uninitialized memory access / NULL-pointer deref in... - [#​32291](numpy/numpy#32291): TYP: fix `np.random.{get,set}_bit_generator` implicit re-exports... - [#​32292](numpy/numpy#32292): BUG: don't assume strides are a multiple of itemsize in stringdtype... - [#​32293](numpy/numpy#32293): CI: fix ccache CC override, add CXX in mac Conda CI ([#​32285](numpy/numpy#32285)) - [#​32303](numpy/numpy#32303): BUG: Fix ref leak in \[convert\_from\_type]{#convert\_from\_type} for custom scalar types... - [#​32304](numpy/numpy#32304): BUG: fix a number of issues around iterators and StringDType... - [#​32326](numpy/numpy#32326): TST: avoid allocating huge tuple of arrays in concatenate test... - [#​32338](numpy/numpy#32338): BUG: avoid possible UB in 'safe' multiplication helpers ([#​32294](numpy/numpy#32294)) - [#​32339](numpy/numpy#32339): MAINT: use `PyObject_` functions instead of raw `PyArray_ ones` ([#​32331](numpy/numpy#32331)) - [#​32378](numpy/numpy#32378): BUG: validate UTF-8 and harden StringDType bounds handling ([#​32296](numpy/numpy#32296)) - [#​32380](numpy/numpy#32380): BUG: fix two error handling mistakes in stringdtype replace loop... - [#​32381](numpy/numpy#32381): BUG: fix visibility annotations for functions in StringDType... - [#​32384](numpy/numpy#32384): MAINT: Update ml\_dtypes pin to 8/21/2026. - [#​32385](numpy/numpy#32385): MAINT: Update numpy/\_core/src/umath/svml - [#​32410](numpy/numpy#32410): MAINT: skip failing cython limited API tests on Cython 3.3.0... - [#​32427](numpy/numpy#32427): BUG: close duplicated file descriptor if fdopen fails ([#​32386](numpy/numpy#32386)) - [#​32428](numpy/numpy#32428): MAINT: add missing space in warning and error messages ([#​32405](numpy/numpy#32405)) - [#​32430](numpy/numpy#32430): BUG: fix error handling in StringDType to fixed-width bytes case... - [#​32441](numpy/numpy#32441): MAINT: Only run nightly BLAS tests on main. - [#​32471](numpy/numpy#32471): BUG: fix memory leak in StringDType creation error path ([#​32470](numpy/numpy#32470)) - [#​32477](numpy/numpy#32477): BUG: fix stale fill\_value after ufuncs change MaskedArray dtype... - [#​32478](numpy/numpy#32478): MAINT: exit deadlock tests quickly on slow hardware ([#​32466](numpy/numpy#32466)) - [#​32481](numpy/numpy#32481): BUG: Backport StringDType byteorder fixes - [#​32506](numpy/numpy#32506): DOC: use static scipy doc site for intershpinx ([#​32503](numpy/numpy#32503)) - [#​32509](numpy/numpy#32509): BUG: fix crash in ufunc.resolve\_dtypes with a Python scalar type... </details> <details> <summary>openai/openai-python (openai)</summary> ### [`v2.52.1`](https://github.com/openai/openai-python/blob/HEAD/CHANGELOG.md#2521-2026-07-31) [Compare Source](openai/openai-python@v2.52.0...v2.52.1) Full Changelog: [v2.52.0...v2.52.1](openai/openai-python@v2.52.0...v2.52.1) ##### Chores - **ci:** pin setup-uv v5 to its underlying commit ([#​3560](openai/openai-python#3560)) ([cbdc98b](openai/openai-python@cbdc98b)) </details> <details> <summary>pydantic/pydantic (pydantic)</summary> ### [`v2.13.5`](https://github.com/pydantic/pydantic/releases/tag/v2.13.5) [Compare Source](pydantic/pydantic@v2.13.4...v2.13.5) #### v2.13.5 (2026-08-28) ##### What's Changed ##### Fixes - Allow reuse of validators when plugins are set by [@​Viicos](https://github.com/Viicos) in [#​13535](pydantic/pydantic#13535) - Fix missing GC traversal on some `pydantic-core` struct fields by [@​Viicos](https://github.com/Viicos) in [#​13624](pydantic/pydantic#13624) - Fix missing GC traversal in `pydantic-core` for `GeneralFieldsSerializer` by [@​Viicos](https://github.com/Viicos) in [#​13629](pydantic/pydantic#13629) - Count validated model fields once in smart unions by [@​tamird](https://github.com/tamird) in [#​13731](pydantic/pydantic#13731) </details> <details> <summary>pydantic/pydantic-ai (pydantic-ai)</summary> ### [`v2.27.1`](https://github.com/pydantic/pydantic-ai/releases/tag/v2.27.1): (2026-08-10) [Compare Source](pydantic/pydantic-ai@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](GHSA-3gh4-cghq-f8v4) (low). Fixed here in `2.27.1` ([#​7357](pydantic/pydantic-ai#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 [@​adtyavrdhn](https://github.com/adtyavrdhn) in [#​6601](pydantic/pydantic-ai#6601) - Fix `XaiStreamedResponse` finish\_reason mapping for streaming responses by [@​pydanty](https://github.com/pydanty)\[bot] in [#​6814](pydantic/pydantic-ai#6814) - Point offline web UI hosting at the self-contained chat UI build by [@​dsfaccini](https://github.com/dsfaccini) in [#​7349](pydantic/pydantic-ai#7349) - Allow adaptive thinking with Tool Output and forced tool choice on Anthropic by [@​pydanty](https://github.com/pydanty)\[bot] in [#​7200](pydantic/pydantic-ai#7200) - Gate `RetryPromptPart` OpenTelemetry content on `include_content` by [@​sean-kim05](https://github.com/sean-kim05) in [#​7357](pydantic/pydantic-ai#7357) **Full Changelog**: <pydantic/pydantic-ai@v2.27.0...v2.27.1> </details> <details> <summary>Kludex/uvicorn (uvicorn)</summary> ### [`v0.52.4`](https://github.com/Kludex/uvicorn/releases/tag/0.52.4): Version 0.52.4 [Compare Source](Kludex/uvicorn@0.52.3...0.52.4) ##### Fixed - Remove duplicate `Date` headers from accepted WebSocket handshakes with `websockets-sansio` ([#​3078](Kludex/uvicorn#3078)) **Full Changelog**: <Kludex/uvicorn@0.52.3...0.52.4> </details> --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zOS4yIiwidXBkYXRlZEluVmVyIjoiNDQuOTAuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiZGVwZW5kZW5jaWVzIiwicmVub3ZhdGUiXX0=--> See merge request swiss-armed-forces/cyber-command/cea/loom!769 Co-authored-by: Loom MR Pipeline Trigger <group_103951964_bot_9504bb8dead6d4e406ad817a607f24be@noreply.gitlab.com> Co-authored-by: shrewd-laidback palace <shrewd-laidback-palace-736-c41-2c1-e464fc974@swiss-armed-forces-open-source.ch>
Closes #6555
Summary
execute_toolspan when argument validation ultimately rejects a tool callinclude_content=FalseScope
The public validation and execution lifecycle is unchanged. The shared retry helper is internal.
Verification
Validation-error, recovery, retry, and redaction coverage passes with focused Logfire tests, lint, formatting, and type checking.
Checklist