fix(anthropic): sanitize tool_use/tool_result IDs to API pattern

The Anthropic Messages API rejects tool IDs that don't match
`^[a-zA-Z0-9_-]+$` with a 400 error. Tool IDs originating from other
providers or restored multi-turn sessions can contain invalid
characters (pipes, dots). Add a deterministic _sanitize_tool_id() and
apply it to both the tool_use id and the matching tool_result
tool_use_id so the pair stays consistent.
This commit is contained in:
comadreja
2026-06-18 00:03:08 +08:00
committed by Xubin Ren
parent 0023f6d998
commit 4d7c2074e6
+18 -2
View File
@@ -24,6 +24,22 @@ def _gen_tool_id() -> str:
return "toolu_" + "".join(secrets.choice(_ALNUM) for _ in range(22))
_VALID_TOOL_ID = re.compile(r"^[a-zA-Z0-9_-]+$")
def _sanitize_tool_id(tid: str) -> str:
"""Ensure tool_use/tool_result IDs match Anthropic's required pattern.
The Anthropic API rejects tool IDs that don't match ``^[a-zA-Z0-9_-]+$``
with a 400 ("String should match pattern") error. IDs coming from other
providers or restored sessions can contain pipes, dots or other invalid
characters, so coerce them to the allowed charset.
"""
if not tid or _VALID_TOOL_ID.match(tid):
return tid
return re.sub(r"[^a-zA-Z0-9_-]", "_", tid)
class AnthropicProvider(LLMProvider):
"""LLM provider using the native Anthropic SDK for Claude models.
@@ -176,7 +192,7 @@ class AnthropicProvider(LLMProvider):
content = msg.get("content")
block: dict[str, Any] = {
"type": "tool_result",
"tool_use_id": msg.get("tool_call_id", ""),
"tool_use_id": _sanitize_tool_id(msg.get("tool_call_id", "")),
}
if isinstance(content, list):
block["content"] = AnthropicProvider._convert_user_content(content)
@@ -212,7 +228,7 @@ class AnthropicProvider(LLMProvider):
args = func.get("arguments", "{}")
blocks.append({
"type": "tool_use",
"id": tc.get("id") or _gen_tool_id(),
"id": _sanitize_tool_id(tc.get("id") or _gen_tool_id()),
"name": func.get("name", ""),
"input": tool_arguments_object_for_replay(args),
})