mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
Merge ef770eec0b into 02f61c9c42
This commit is contained in:
commit
472c54d95a
3 changed files with 59 additions and 5 deletions
|
|
@ -529,6 +529,9 @@ NON_LLM_CONNECTION_TIMEOUT: Final = int(
|
|||
MAX_EXCEPTION_MESSAGE_LENGTH: Final = int(os.getenv("MAX_EXCEPTION_MESSAGE_LENGTH", 2000))
|
||||
MAX_STRING_LENGTH_PROMPT_IN_DB: Final = int(os.getenv("MAX_STRING_LENGTH_PROMPT_IN_DB", 2048))
|
||||
BEDROCK_MAX_POLICY_SIZE: Final = int(os.getenv("BEDROCK_MAX_POLICY_SIZE", 75))
|
||||
# Bedrock Runtime hard-limits tool names to 64 characters; this is a fixed AWS API
|
||||
# constraint, not a tunable, so it is a plain constant rather than an env var.
|
||||
BEDROCK_MAX_TOOL_NAME_LENGTH: Final = 64
|
||||
# One entry per distinct AWS credential-argument set. Per-user cost attribution passes the attributed
|
||||
# identity as aws_session_name, so this bounds how many attributed identities keep a cached STS session.
|
||||
BEDROCK_IAM_CACHE_MAX_ENTRIES: Final = 1000
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import litellm.types
|
|||
import litellm.types.llms
|
||||
from litellm import verbose_logger
|
||||
from litellm._uuid import uuid
|
||||
from litellm.constants import REDACTED_BY_LITELLM
|
||||
from litellm.constants import BEDROCK_MAX_TOOL_NAME_LENGTH, REDACTED_BY_LITELLM
|
||||
from litellm.litellm_core_utils.prompt_templates.mid_conversation_system import anthropic_system_messages
|
||||
from litellm.litellm_core_utils.url_utils import async_safe_get, safe_get
|
||||
from litellm.llms.custom_httpx.http_handler import HTTPHandler, get_async_httpx_client
|
||||
|
|
@ -4968,7 +4968,11 @@ def _bedrock_converse_messages_pt(
|
|||
|
||||
|
||||
def make_valid_bedrock_tool_name(input_tool_name: str) -> str:
|
||||
"""Normalize tool names to Bedrock pattern [a-zA-Z][a-zA-Z0-9_-]*."""
|
||||
"""Normalize tool names to Bedrock pattern [a-zA-Z][a-zA-Z0-9_-]* within the 64-char limit.
|
||||
|
||||
Note: scoped to Amazon Bedrock Runtime (the Converse / InvokeModel tool path).
|
||||
Only Bedrock tool names are normalized here; other providers are unaffected.
|
||||
"""
|
||||
|
||||
def replace_invalid(char):
|
||||
if char.isalnum() or char in ("_", "-"):
|
||||
|
|
@ -4986,12 +4990,22 @@ def make_valid_bedrock_tool_name(input_tool_name: str) -> str:
|
|||
# Replace any invalid characters with underscores
|
||||
valid_string: Final = "".join(replace_invalid(char) for char in bedrock_tool_name)
|
||||
|
||||
if input_tool_name != valid_string:
|
||||
# Enforce Bedrock's max tool-name length. Truncate and append a short
|
||||
# deterministic hash so distinct long names don't collide and the same
|
||||
# input always maps to the same output (so toolSpec and toolUse match).
|
||||
if len(valid_string) > BEDROCK_MAX_TOOL_NAME_LENGTH:
|
||||
name_hash = hashlib.sha256(valid_string.encode()).hexdigest()[:8]
|
||||
prefix_length = BEDROCK_MAX_TOOL_NAME_LENGTH - len(name_hash) - 1
|
||||
final_name = f"{valid_string[:prefix_length]}_{name_hash}"
|
||||
else:
|
||||
final_name = valid_string
|
||||
|
||||
if input_tool_name != final_name:
|
||||
# passed tool name was formatted to become valid
|
||||
# store it internally so we can use for the response
|
||||
litellm.bedrock_tool_name_mappings.set_cache(key=valid_string, value=input_tool_name)
|
||||
litellm.bedrock_tool_name_mappings.set_cache(key=final_name, value=input_tool_name)
|
||||
|
||||
return valid_string
|
||||
return final_name
|
||||
|
||||
|
||||
def add_cache_point_tool_block(tool: dict, model: str | None = None) -> BedrockToolBlock | None:
|
||||
|
|
|
|||
|
|
@ -2462,6 +2462,43 @@ def test_make_valid_bedrock_tool_name_preserves_hyphens():
|
|||
)
|
||||
|
||||
|
||||
def test_make_valid_bedrock_tool_name_truncates_and_restores_long_name():
|
||||
"""Names over Bedrock's 64-char limit are truncated and mapped back on response."""
|
||||
import litellm
|
||||
|
||||
raw_name = "mcp__codex_apps__atlassian_rovo___getAccessibleAtlassianResources"
|
||||
assert len(raw_name) > 64
|
||||
|
||||
valid = make_valid_bedrock_tool_name(raw_name)
|
||||
assert len(valid) == 64
|
||||
assert re.match(r"^[a-zA-Z][a-zA-Z0-9_-]*$", valid)
|
||||
# the original name is recoverable on the response path
|
||||
assert litellm.bedrock_tool_name_mappings.get_cache(key=valid) == raw_name
|
||||
|
||||
|
||||
def test_make_valid_bedrock_tool_name_is_deterministic():
|
||||
"""Same input always yields the same sanitized name (toolSpec == toolUse)."""
|
||||
raw_name = "a" * 80
|
||||
assert make_valid_bedrock_tool_name(raw_name) == make_valid_bedrock_tool_name(
|
||||
raw_name
|
||||
)
|
||||
|
||||
|
||||
def test_make_valid_bedrock_tool_name_avoids_collision_on_shared_prefix():
|
||||
"""Two long names sharing a >64-char prefix must not collapse to the same value."""
|
||||
name_a = "shared_prefix_" + "a" * 60 + "_alpha"
|
||||
name_b = "shared_prefix_" + "a" * 60 + "_beta"
|
||||
assert len(name_a) > 64 and len(name_b) > 64
|
||||
assert make_valid_bedrock_tool_name(name_a) != make_valid_bedrock_tool_name(name_b)
|
||||
|
||||
|
||||
def test_make_valid_bedrock_tool_name_boundary_64_unchanged():
|
||||
"""A valid name of exactly 64 chars is passed through untouched."""
|
||||
name = "a" + "b" * 63
|
||||
assert len(name) == 64
|
||||
assert make_valid_bedrock_tool_name(name) == name
|
||||
|
||||
|
||||
def test_bedrock_tool_name_sanitized_consistently_in_tools_and_tool_use():
|
||||
"""toolSpec and toolUse names must match after sanitization (issue #5007)."""
|
||||
raw_name = "foo@bar"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue