Skip to content

fix: sanitize tool schemas for strict mode#5410

Merged
greysonlalonde merged 3 commits intomainfrom
fix/strict-tool-schema-sanitization
Apr 10, 2026
Merged

fix: sanitize tool schemas for strict mode#5410
greysonlalonde merged 3 commits intomainfrom
fix/strict-tool-schema-sanitization

Conversation

@greysonlalonde
Copy link
Copy Markdown
Contributor

@greysonlalonde greysonlalonde commented Apr 10, 2026

Summary

Pydantic schemas intermittently fail strict tool-use on openai, anthropic, and bedrock. All three reject nested objects missing additionalProperties: false, and anthropic also rejects minLength/maximum/top-level anyOf. Adds per-provider sanitizers wired into each provider's tool conversion.

Gemini and azure are follow-ups.

Verification

Ran the original bug-report schema against real APIs:

Provider Raw + strict Sanitized + strict
Bedrock Sonnet 4.5 additionalProperties must be explicitly set to false ok, all fields populated
Anthropic native same 400 ok, all fields populated
OpenAI gpt-4o same 400 ok, chat_id: null preserved

Test plan

  • Manual repro on real bedrock, anthropic, openai
  • Unit tests for the sanitizers

Note

Medium Risk
Changes tool schema generation in strict mode across three providers, which can affect tool-calling behavior and may surface new validation edge cases for existing tool definitions.

Overview
Fixes intermittent strict tool-use failures by sanitizing tool JSON schemas when strict is enabled for OpenAI, Anthropic, and Bedrock.

Adds provider-specific sanitizers in pydantic_schema_utils that inline refs, force additionalProperties: false, require all properties, and strip unsupported/metadata keys (plus Anthropic/Bedrock-specific removals like top-level anyOf and numeric/string constraints). Providers now apply these sanitizers during tool conversion instead of passing raw Pydantic schemas.

Reviewed by Cursor Bugbot for commit e3fb1b8. Bugbot is set up for automated code reviews on this repo. Configure here.

Pydantic schemas intermittently fail strict tool-use on openai, anthropic,
and bedrock. All three reject nested objects missing additionalProperties:
false, and anthropic also rejects keywords like minLength and top-level
anyOf. Adds per-provider sanitizers that inline refs, close objects, mark
every property required, preserve nullable unions, and strip keywords each
grammar compiler rejects. Verified against real bedrock, anthropic, and
openai.
Copy link
Copy Markdown
Contributor

@iris-clawd iris-clawd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the proper fix for the strict mode issue I flagged on #5388. Clean architecture:

Common pipeline (_common_strict_pipeline): resolve refs → strip $defs → oneOf→anyOf → ensure types → additionalProperties: false → require all properties → strip metadata — covers what all three providers need.

Per-provider sanitizers:

  • OpenAI: common + strip unsupported formats
  • Anthropic: common + lift_top_level_anyof (Claude rejects top-level unions) + strip Claude-specific keywords (numeric/string constraints, pattern, etc.)
  • Bedrock: delegates to Anthropic (same grammar compiler) — correct and DRY

Integration:

  • All three providers now conditionally sanitize only when strict is enabled — non-strict tools pass through unchanged
  • OpenAI's old force_additional_properties_false replaced with the fuller pipeline
  • Lazy imports moved to module-level (cleaner)

Verified against real Bedrock Sonnet 4.5, Anthropic, and OpenAI APIs. Unit tests noted as TODO — worth adding but not blocking.

LGTM 🚀 💬 221

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3fb1b8. Configure here.

@greysonlalonde greysonlalonde merged commit 8de4421 into main Apr 10, 2026
54 checks passed
@greysonlalonde greysonlalonde deleted the fix/strict-tool-schema-sanitization branch April 10, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants