Skip to content

feat(bedrock): add strict_tools config with auto-inject of additional…#2213

Merged
zastrowm merged 2 commits intostrands-agents:mainfrom
kaghatim:feat/strict-tools-config
Apr 29, 2026
Merged

feat(bedrock): add strict_tools config with auto-inject of additional…#2213
zastrowm merged 2 commits intostrands-agents:mainfrom
kaghatim:feat/strict-tools-config

Conversation

@kaghatim
Copy link
Copy Markdown
Contributor

@kaghatim kaghatim commented Apr 27, 2026

Description

Motivation

Bedrock's Converse API supports a strict field on ToolSpecification that enables constrained decoding on tool names and inputs, preventing the model from hallucinating tool names or generating inputs that don't match the defined schema. Currently there is no way to enable this through the SDK because _format_request only forwards name, description, and inputSchema from each tool spec.

A key challenge with strict mode is that Bedrock requires "additionalProperties": false on every object type in the tool's input schema, validated recursively including nested objects. The Strands @tool decorator does not include this field in generated schemas, and in fact actively strips it in _clean_pydantic_schema. This means simply injecting strict: true into the request is not enough: every @tool-decorated function would fail with a ValidationException.

This PR adds a strict_tools config option to BedrockModel that both injects strict: true and automatically adds "additionalProperties": false to all object types in tool input schemas, making strict mode work out of the box with @tool-decorated functions. The schema transformation operates on a deep copy so original tool specs are never mutated. This follows the same pattern as OpenAI's Python SDK (_ensure_strict_json_schema).

Resolves #2210

Public API Changes

BedrockConfig now accepts an optional strict_tools boolean parameter:

# Before: no way to enable strict schema validation on tools
model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-6")

# After: blanket toggle for all tool specs
model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-6",
    strict_tools=True,
)

When strict_tools=True, every toolSpec in the formatted request includes "strict": true and all object types in tool input schemas have "additionalProperties": false injected. When unset, None, or False, tool specs remain unchanged.

Use Cases

  • Preventing tool name hallucination: Eliminates garbled tool names in production (e.g. store-case-syummary-tool instead of store-case-summary-tool), avoiding wasted cycles and tokens on self-correction
  • Input schema enforcement: Ensures model-generated tool inputs always conform to the defined schema, preventing extra or misspelled parameters

Related Issues

#2210

Type of Change

New feature

Testing

Verified with live Bedrock calls against us.anthropic.claude-sonnet-4-6:

Configuration Result
strict_tools=True with @tool decorated function Works (previously failed with ValidationException)
strict_tools=True with manually defined schema Works
strict_tools unset / False / None Works, no regression
  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 88.23529% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/strands/models/_strict_schema.py 87.87% 2 Missing and 6 partials ⚠️

📢 Thoughts on this report? Let us know!

Comment thread src/strands/models/bedrock.py Outdated
Comment thread tests/strands/models/test_bedrock.py Outdated
Comment thread src/strands/models/bedrock.py
Comment thread tests/strands/models/test_bedrock.py Outdated
@github-actions
Copy link
Copy Markdown

Assessment: Comment

Clean implementation of strict_tools with good schema-safety patterns (deep copy, recursive transformation). Two items need attention before merge: a missing oneOf traversal in the schema walker and the citations incompatibility warning specified in issue #2210.

Review Categories
  • Completeness: _close_object_types doesn't traverse oneOf branches, despite oneOf being a recognized composition keyword in this codebase. The citations warning from the issue acceptance criteria is also not implemented.
  • Test Coverage: Tests cover the happy path well, but lack coverage for array items, anyOf/allOf/$defs traversal paths, and the case where additionalProperties: True is explicitly set and should be preserved.

Well-structured PR with thorough documentation and a thoughtful approach to the schema transformation.

Comment thread tests/strands/models/test_bedrock.py Outdated
Comment thread tests/strands/models/test_bedrock.py Outdated
Comment thread tests/strands/models/test_bedrock.py Outdated
Comment thread tests/strands/models/test_bedrock.py Outdated
Comment thread tests/strands/models/test_strict_schema.py Outdated
Comment thread tests/strands/models/test_bedrock.py
Comment thread src/strands/models/_strict_schema.py Outdated
Comment thread src/strands/models/_strict_schema.py
@github-actions
Copy link
Copy Markdown

Assessment: Comment

The refactoring into a dedicated _strict_schema.py module is a nice improvement — it addresses the oneOf, $defs, and additionalProperties: True preservation issues from the previous review. Two new items to consider on the schema transformation, plus the citations warning from the previous review remains outstanding.

Review Details
  • $ref inlining safety: The shallow merge when resolving $ref creates shared nested dict references. Low-risk since output is JSON-serialized, but using deepcopy(resolved) would make the function's immutability guarantees more robust.
  • Test coverage: The "definitions" keyword path (older JSON Schema draft format) is handled in code but untested, contributing to the coverage gap.
  • Previous review items still open: The citations incompatibility warning from issue [FEATURE] Support strict: true on tool definitions in BedrockModel #2210 acceptance criteria is still not implemented. Zastrowm's feedback on full-object assertions and test structure also remains.

Good evolution of the implementation — the module separation and comprehensive schema handling are solid.

@kaghatim
Copy link
Copy Markdown
Contributor Author

I intentionally omitted the citations warning after testing against Bedrock. Citations in the Converse API are configured per-document inside message content blocks (DocumentBlock.citations), not as a model-level or request level config. There is no citations field in additional_request_fields that we could check against. The only way to detect it would be scanning every message for document blocks with citations enabled on every request, which felt like the wrong abstraction for a config-time warning. Bedrock returns a clear error if the incompatibility is actually hit at runtime.

BV-Venky and others added 2 commits April 29, 2026 16:22
Add ensure_strict_json_schema utility that recursively injects
additionalProperties: false on all object types in tool input schemas.
Handles $defs, definitions, anyOf, allOf, oneOf, items, and $ref
resolution with deep copy safety. Includes require_all_properties
flag for OpenAI support.

From PR strands-agents#1862

Co-authored-by: Hatim Kagalwala <kaghatim@amazon.com>
Add strict_tools boolean option to BedrockConfig that injects strict: true
into each toolSpec and uses ensure_strict_json_schema from _strict_schema
to automatically add additionalProperties: false to all object types in
tool input schemas. This makes strict mode work out of the box with @tool
decorated functions.

Resolves strands-agents#2210
@kaghatim kaghatim force-pushed the feat/strict-tools-config branch from 7f66b49 to 30f3e2f Compare April 29, 2026 16:22
@github-actions github-actions Bot added size/l and removed size/m labels Apr 29, 2026
@kaghatim kaghatim temporarily deployed to manual-approval April 29, 2026 16:22 — with GitHub Actions Inactive
@kaghatim
Copy link
Copy Markdown
Contributor Author

@zastrowm Thanks for the review! I have addressed the feedback:

  • Flattened tests to top-level functions (no more class)
  • Added additionalProperties: True preservation test
  • Rewrote test_strict_schema.py with full-object assertions
  • Added integration test with a complex schema (list[str] params, multiple tools)
  • Also fixed $ref inlining to use deepcopy and added definitions/oneOf coverage

Let me know if there's anything else you'd like adjusted or changed.

@github-actions
Copy link
Copy Markdown

Assessment: Approve

All previous review feedback has been thoroughly addressed. The refactored _strict_schema.py module is clean, well-tested (302 lines of unit tests + integration test), and handles all JSON Schema composition keywords correctly. The $ref deepcopy fix, full-object assertions, and flattened test structure all look great.

Minor Item
  • AGENTS.md: The directory structure listing should include the new _strict_schema.py file per the repo's own guidelines.

The author's explanation for omitting the citations warning is reasonable — citations are configured per-document in content blocks rather than at request level, making a config-time check infeasible.

@kaghatim
Copy link
Copy Markdown
Contributor Author

it seems like the integration tests failure are unrelated to this change, but happy to take a look if anything needs to be changed.

@zastrowm zastrowm enabled auto-merge (squash) April 29, 2026 21:15
@zastrowm zastrowm merged commit 6e208a8 into strands-agents:main Apr 29, 2026
30 of 37 checks passed
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.

[FEATURE] Support strict: true on tool definitions in BedrockModel

3 participants