Keep approval-required and external tools native under `CodeMode(tools='all')`
CodeMode() previously folded statically deferred tools into run_code, where they could not complete without an inline handler. This implements option 1 from #9364: keep approval-required and external tools native under tools='all'. Handler detection is not used because handlers can resolve only selected calls, as ExaAgent does. Douwe's sign-off on option 1 and a Harness minor release is still required before merge.
[!WARNING]
Compatibility impact: Agents using default CodeMode() with a HandleDeferredToolCalls handler previously could call requires_approval=True and external tools from snippets. Those tools now remain native; the handler still resolves their direct calls.
Why this can ship in a minor release: This changes Harness behavior, not Pydantic AI core. The Harness 0.x version policy permits changed defaults between minor releases, with migration guidance. This is not a claim that the formerly documented inline-handler behavior qualifies for core's undocumented-behavior bug-fix exception.
Migration: To preserve sandbox placement, use an explicit selector, for example CodeMode(tools=lambda ctx, td: True), with the inline handler.
New public surface: None.
User-visible behavior:
| Example configuration | Before | After |
|---|---|---|
Default CodeMode() with a requires_approval=True or external tool | Tool is callable through run_code and needs an inline handler | Tool is called directly, preserving DeferredToolRequests and inline-handler resolution |
- Explicit name, callable, and metadata selectors can still sandbox these tools.
- Tool Search discovery follows that same partition. Search descriptions and discovery announcements direct the model to use
run_codeonly for catalog entries and call separately exposed tools directly. - Tools raising
ApprovalRequiredorCallDeferredfrom their bodies, including throughApprovalRequiredToolset, remain sandboxed as before and still need an inline handler.
Verification:
- Default partition, explicit-selector handler, and native approval tests.
- Eight discovery and pause/resume regressions: approval-required/external tools, local/provider-native search, and dynamic/static catalogs.
- 228 targeted tests passed across those files and CLAI2 speculative mode; targeted Ruff/Pyright and pre-commit passed. CI is green: 83 checks passed and 23 skipped.
What changes for existing users: Statically deferred tools become native under default CodeMode(); users without those tools or with explicit selectors retain their tool placement.
No public signatures changed, so no deterministic API-check waiver was needed.
- Fixes #9364
Checklist
- No breaking changes in accordance with the version policy.
- Any permitted compatibility impact has a label, warning, migration, release note, and exact API-check waiver.
- PR title is fit for the release changelog.