Skip to content

fix(bedrock): sanitize tool names to meet Bedrock API constraints#1784

Closed
AnantKumar17 wants to merge 1 commit intokagent-dev:mainfrom
AnantKumar17:fix/bedrock-sanitize-tool-names
Closed

fix(bedrock): sanitize tool names to meet Bedrock API constraints#1784
AnantKumar17 wants to merge 1 commit intokagent-dev:mainfrom
AnantKumar17:fix/bedrock-sanitize-tool-names

Conversation

@AnantKumar17
Copy link
Copy Markdown

What this does

MCP servers can produce tool names containing dots, spaces, or other characters that Bedrock rejects. The Converse API requires tool names to match [a-zA-Z0-9_-]+, but the previous code passed names through unchanged, which caused ValidationException errors at runtime.

This PR adds _sanitize_tool_name, which replaces invalid characters with underscores and falls back to a generated name for empty inputs. A name_map is shared across _convert_tools_to_converse and _convert_content_to_converse_messages so the same original name always maps to the same sanitized name within a single request. A reverse_name_map is built from it and used to restore original names in Bedrock responses, so the rest of the agent runtime sees the names it registered.

A WARNING log is emitted whenever a name is sanitized to help with debugging.

Closes #1473

Changes

  • python/packages/kagent-adk/src/kagent/adk/models/_bedrock.py

    • Added _BEDROCK_TOOL_NAME_VALID and _BEDROCK_TOOL_NAME_INVALID regex constants
    • Added _sanitize_tool_name function (follows the same pattern as the existing _sanitize_tool_id)
    • Updated _convert_content_to_converse_messages to sanitize function_call.name in history
    • Updated _convert_tools_to_converse to sanitize tool declaration names
    • In generate_content_async, built a shared name_map/name_counter and a reverse_name_map to restore names in both streaming and non-streaming responses
  • python/packages/kagent-adk/tests/unittests/models/test_bedrock.py

    • Added TestSanitizeToolName: unit tests for the new function
    • Added TestConvertToolsToConverse: verifies dotted names are sanitized in the tool spec
    • Added TestBedrockToolNameRoundTrip: integration tests confirming original names are restored in both non-streaming and streaming responses

Testing

All 264 existing unit tests continue to pass. 12 new tests cover the added behaviour.

uv run pytest tests/unittests/ --ignore=tests/unittests/models/test_tls_e2e.py
264 passed, 27 warnings

MCP servers can produce tool names containing dots, spaces, or other
characters that Bedrock rejects. The Converse API requires tool names
to match [a-zA-Z0-9_-]+ but the previous code passed names through
unchanged, causing ValidationException errors at runtime.

This change adds _sanitize_tool_name, which replaces any invalid
character with an underscore and falls back to a generated name when
the input is empty. A name_map shared across both _convert_tools_to_converse
and _convert_content_to_converse_messages ensures the same original name
always maps to the same sanitized name within a single request. A
reverse_name_map is then used to restore original names in Bedrock
responses before they are returned to the ADK framework, so the rest
of the agent runtime sees the names it originally registered.

A warning is logged whenever a name is sanitized to aid debugging.

Fixes kagent-dev#1473

Signed-off-by: AnantKumar17 <anant.kumar17@example.com>
Copilot AI review requested due to automatic review settings April 30, 2026 17:13
@github-actions github-actions Bot added the bug Something isn't working label Apr 30, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Bedrock Converse adapter to sanitize MCP tool names into Bedrock-compatible identifiers and to round-trip tool names by restoring the original names in Bedrock responses.

Changes:

  • Add regexes + _sanitize_tool_name to enforce Bedrock tool name constraints ([a-zA-Z0-9_-]+).
  • Sanitize tool names in both outgoing tool declarations and message history (function calls).
  • Track a shared name mapping per request and restore original tool names in both streaming and non-streaming Bedrock responses.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
python/packages/kagent-adk/src/kagent/adk/models/_bedrock.py Introduces tool-name sanitization and response name restoration via shared per-request maps.
python/packages/kagent-adk/tests/unittests/models/test_bedrock.py Adds unit + integration coverage for tool name sanitization and round-trip restoration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

sanitized = _BEDROCK_TOOL_NAME_INVALID.sub("_", name)
if not sanitized or not _BEDROCK_TOOL_NAME_VALID.match(sanitized):
counter[0] += 1
sanitized = f"unknown_tool_{counter[0]}"
Comment on lines +60 to +76
def _sanitize_tool_name(name: str, name_map: dict[str, str], counter: list[int]) -> str:
"""Return a valid Bedrock tool name.

Bedrock requires tool names to match [a-zA-Z0-9_-]+ and be non-empty.
name_map caches original->sanitized so the same tool name is consistently
mapped throughout a single request. counter is a single-element list used
as a mutable integer for generating unique fallback names.

See https://github.com/kagent-dev/kagent/issues/1473
"""
if name in name_map:
return name_map[name]
sanitized = _BEDROCK_TOOL_NAME_INVALID.sub("_", name)
if not sanitized or not _BEDROCK_TOOL_NAME_VALID.match(sanitized):
counter[0] += 1
sanitized = f"unknown_tool_{counter[0]}"
return sanitized
Comment on lines +145 to +148
result = _sanitize_tool_name("", name_map, counter)
assert result == "unknown_tool_1"
assert counter[0] == 1

Copy link
Copy Markdown
Contributor

@supreme-gg-gg supreme-gg-gg left a comment

Choose a reason for hiding this comment

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

Duplicate of #1730

@AnantKumar17
Copy link
Copy Markdown
Author

Closing this in favour of #1730, which I noticed is already in review and covers the same ground.

@AnantKumar17 AnantKumar17 deleted the fix/bedrock-sanitize-tool-names branch April 30, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(bedrock): sanitize tool names for Bedrock API constraints

3 participants