fix(anthropic): stop mutating caller input_schema in tool translation

This commit is contained in:
Devin AI 2026-07-24 20:10:51 +00:00
parent 35dc982692
commit b0a77e26ae
2 changed files with 41 additions and 5 deletions

View file

@ -767,14 +767,18 @@ class LiteLLMAnthropicMessagesAdapter:
function_chunk = ChatCompletionToolParamFunctionChunk(
name=truncated_name,
)
if "input_schema" in tool:
function_chunk["parameters"] = tool["input_schema"] # type: ignore
extra_tool_params = {k: v for k, v in tool.items() if k not in mapped_tool_params}
input_schema = tool.get("input_schema")
if isinstance(input_schema, dict):
function_chunk["parameters"] = {
**copy.deepcopy(input_schema),
**extra_tool_params,
}
elif extra_tool_params:
function_chunk["parameters"] = dict(extra_tool_params)
if "description" in tool:
function_chunk["description"] = tool["description"] # type: ignore
for k, v in tool.items():
if k not in mapped_tool_params: # pass additional computer kwargs
function_chunk.setdefault("parameters", {}).update({k: v})
tool_param = ChatCompletionToolParam(type="function", function=function_chunk)
self._add_cache_control_if_applicable(tool, tool_param, model)
new_tools.append(tool_param) # type: ignore[arg-type]

View file

@ -1,3 +1,4 @@
import copy
import os
import sys
from typing import Any, cast
@ -3147,3 +3148,34 @@ def test_translate_anthropic_tools_to_openai_preserves_parameters_type():
params = new_tools[0]["function"]["parameters"]
assert params["type"] == "object"
assert new_tools[0]["type"] == "function"
def test_translate_anthropic_tools_to_openai_does_not_mutate_input_schema():
"""Regression for #34510: translation must not alias or mutate the caller's
input_schema; extra top-level tool keys must not leak back into it."""
adapter = LiteLLMAnthropicMessagesAdapter()
input_schema = {"type": "object", "properties": {"a": {"type": "string"}}}
tools = [
{
"type": "computer_20250124",
"name": "computer",
"input_schema": input_schema,
"display_width_px": 1024,
"display_height_px": 768,
}
]
original_tools = copy.deepcopy(tools)
new_tools, _ = adapter.translate_anthropic_tools_to_openai(tools=tools)
assert input_schema == {"type": "object", "properties": {"a": {"type": "string"}}}
assert tools == original_tools
params = new_tools[0]["function"]["parameters"]
assert params is not input_schema
assert params["display_width_px"] == 1024
assert params["display_height_px"] == 768
assert params["type"] == "object"
second_pass, _ = adapter.translate_anthropic_tools_to_openai(tools=tools)
assert second_pass == new_tools