refactor(vertex_ai): build the tool chunk in one shot instead of mutating

Construct the function chunk from a merged dict rather than assigning
`parameters` into it after the fact, per the repo's no-mutation convention.

This also removes a latent crash. Reading `parameters` off the already-built
chunk meant an explicit `"parameters": null` alongside `input_schema` relied on
post-hoc assignment to fix up; the merge form handles it directly. Added a test
for that shape, which fails against the pre-fix implementation.
This commit is contained in:
Mohammad Ali Farhan 2026-08-08 13:22:32 +05:30
parent bcfe5b7de6
commit 8ef6f755c9
2 changed files with 27 additions and 10 deletions

View file

@ -604,14 +604,13 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
openai_function_object = _openai_function_object
elif "name" in tool: # functions list
_named_function_object = ChatCompletionToolParamFunctionChunk(**tool)
if _named_function_object.get("parameters") is None:
_input_schema = tool.get("input_schema")
if isinstance(_input_schema, dict):
_named_function_object["parameters"] = _build_vertex_schema(_input_schema)
openai_function_object = _named_function_object
_input_schema = tool.get("input_schema") if tool.get("parameters") is None else None
_named_tool = (
{**tool, "parameters": _build_vertex_schema(_input_schema)}
if isinstance(_input_schema, dict)
else tool
)
openai_function_object = ChatCompletionToolParamFunctionChunk(**_named_tool)
if "type" in tool and tool["type"] == "computer_use":
computer_use_config = {k: v for k, v in tool.items() if k != "type"}

View file

@ -1254,14 +1254,32 @@ def test_vertex_ai_map_tool_input_schema_gets_vertex_schema_conversion():
def test_vertex_ai_map_tool_explicit_parameters_wins_over_input_schema():
"""A tool carrying both keys must keep `parameters` — `input_schema` is only a fallback."""
tool = _anthropic_shaped_tool({"type": "object", "properties": {"ignored": {"type": "string"}}})
tool["parameters"] = {"type": "object", "properties": {"location": {"type": "string"}}}
tool = {
**_anthropic_shaped_tool({"type": "object", "properties": {"ignored": {"type": "string"}}}),
"parameters": {"type": "object", "properties": {"location": {"type": "string"}}},
}
declaration = _declaration_for(tool)
assert declaration["parameters"]["properties"] == {"location": {"type": "string"}}
def test_vertex_ai_map_tool_null_parameters_falls_back_to_input_schema():
"""A JSON `"parameters": null` alongside `input_schema` must take the fallback, not
send a null schema upstream."""
tool = {
**_anthropic_shaped_tool({"type": "object", "properties": {"location": {"type": "string"}}}),
"parameters": None,
}
declaration = _declaration_for(tool)
assert declaration["parameters"] == {
"type": "object",
"properties": {"location": {"type": "string"}},
}
def test_vertex_ai_map_tool_without_any_schema_is_unchanged():
"""A named tool with no schema at all must still map, without inventing parameters."""
declaration = _declaration_for({"name": "ping", "description": "no args"})