← Back to PRs

#21873: fix: sanitize Bedrock toolUse.name in conversation history

by shan-lvr open 2026-02-20 13:41 View on GitHub →
size: XS
## Problem The Bedrock Converse API requires `toolUse.name` to match `[a-zA-Z0-9_-]+` (max 64 chars). The provider already sanitizes `toolUseId` via `normalizeToolCallId()`, but the tool name (`c.name`) in `convertMessages()` is passed to `toolUse.name` as-is: ```js // amazon-bedrock.js — current case "toolCall": contentBlocks.push({ toolUse: { toolUseId: c.id, name: c.name, input: c.arguments }, }); ``` When a model generates a tool call with an invalid name — e.g. Kimi K2.5 on Bedrock occasionally hallucinates names like `browser.navigate` (dot is forbidden) — that name gets stored in the conversation history. The **next** API call replays that history to Bedrock, which rejects it with: ``` 2 validation errors detected: Value at 'messages.N.member.content.1.member.toolUse.name' failed to satisfy constraint: Member must have length less than or equal to 64 Value at 'messages.N.member.content.1.member.toolUse.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+ ``` This poisons all subsequent messages in the conversation — the user sees the raw Bedrock validation error on every reply until they start a fresh session. ## Fix Add `normalizeToolName()` (same logic as `normalizeToolCallId()`) and apply it to `c.name` when building `toolUse` content blocks. Invalid characters are replaced with `_`; names > 64 chars are truncated. ```js // After fix function normalizeToolName(name) { const sanitized = (name || "unknown_tool").replace(/[^a-zA-Z0-9_-]/g, "_"); return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized; } // … toolUse: { toolUseId: c.id, name: normalizeToolName(c.name), input: c.arguments } ``` Delivered as a pnpm patch to `@mariozechner/pi-ai@0.54.0` since there's no separate public repo for that package. ## Repro Configure Kimi K2.5 (`amazon-bedrock/moonshotai.kimi-k2.5`) as the agent model in a channel with browser tools enabled, then ask it to open a browser. After the first browser call it may hallucinate a follow-up tool name containing a dot. All subsequent messages in that session will return the Bedrock validation error. <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds `normalizeToolName()` function to sanitize tool names before sending them to AWS Bedrock Converse API, preventing validation errors when models hallucinate invalid tool names (e.g., `browser.navigate` with forbidden dots). The sanitization replaces invalid characters with underscores and truncates names exceeding 64 characters, matching Bedrock's `[a-zA-Z0-9_-]+` pattern requirement. This fix prevents conversation history from being poisoned by a single invalid tool call, which would otherwise cause all subsequent messages to fail validation until the session is reset. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The fix is a simple, defensive sanitization that addresses a real production issue. It follows the existing pattern (`normalizeToolCallId`), handles edge cases properly (null names, truncation), and only affects the Bedrock provider's API boundary without changing internal behavior or breaking tool name matching - No files require special attention <sub>Last reviewed commit: 1a59daa</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs