[Test] add request-body mock test for bedrock gpt-oss tool schema

Complements the stubbed-out live integration test by verifying the
outgoing Bedrock Converse request body for GPT-OSS is well-formed when
the caller supplies a tool schema with OpenAI-style metadata
($id, $schema, additionalProperties, strict):
- correct converse URL for bedrock/converse/openai.gpt-oss-20b-1:0
- toolConfig.tools[0].toolSpec has the expected name/description
- inputSchema.json keeps type/properties/required and strips fields
  Bedrock does not accept
This commit is contained in:
Yuneng Jiang
2026-04-15 09:52:24 -07:00
committed by Ishaan Jaffer
parent c8a94ff1ec
commit 1e50925d9b
+93 -2
View File
@@ -1,14 +1,16 @@
from base_llm_unit_tests import BaseLLMChatTest
import json
import pytest
import sys
import os
from unittest.mock import patch, MagicMock
from unittest.mock import patch, Mock, MagicMock
sys.path.insert(
0, os.path.abspath("../..")
) # Adds the parent directory to the system path
import litellm
from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConfig
from litellm.llms.custom_httpx.http_handler import HTTPHandler
class TestBedrockGPTOSS(BaseLLMChatTest):
@@ -22,9 +24,98 @@ class TestBedrockGPTOSS(BaseLLMChatTest):
pass
def test_function_calling_with_tool_response(self):
"""Bedrock GPT-OSS intermittently emits truncated toolUse.input deltas; the underlying code path is already covered by the Claude, Nova, and Llama Converse suites in test_bedrock_completion.py / test_bedrock_llama.py."""
"""Bedrock GPT-OSS intermittently emits truncated toolUse.input deltas on
the live endpoint, which makes the inherited live integration test flaky.
The accumulation side is covered deterministically by
tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py::test_transform_tool_calls_index;
the GPT-OSS-specific request-body transformation is covered by
test_function_calling_request_body_gpt_oss below.
"""
pass
def test_function_calling_request_body_gpt_oss(self):
"""Verify the Bedrock Converse request body is well-formed for GPT-OSS when the
caller supplies a tool schema with OpenAI-style metadata ($id, $schema,
additionalProperties, strict). Bedrock only accepts a trimmed JSON Schema in
toolSpec.inputSchema.json, so the extra fields must be stripped and the
required shape preserved.
"""
client = HTTPHandler()
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the weather in a city",
"parameters": {
"$id": "https://some/internal/name",
"$schema": "https://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to get the weather for",
}
},
"required": ["city"],
"additionalProperties": False,
},
"strict": True,
},
}
]
with patch.object(client, "post", new=Mock()) as mock_post:
try:
litellm.completion(
model="bedrock/converse/openai.gpt-oss-20b-1:0",
messages=[
{"role": "user", "content": "How is the weather in Mumbai?"}
],
tools=tools,
aws_region_name="us-west-2",
client=client,
)
except Exception:
# We only care about the outgoing request; the mocked post returns
# a Mock that can't be parsed as a real Converse response.
pass
mock_post.assert_called_once()
call_kwargs = mock_post.call_args.kwargs
assert call_kwargs["url"].endswith(
"/model/openai.gpt-oss-20b-1%3A0/converse"
), call_kwargs["url"]
request_body = json.loads(call_kwargs["data"])
assert "toolConfig" in request_body
tool_specs = request_body["toolConfig"]["tools"]
assert len(tool_specs) == 1
tool_spec = tool_specs[0]["toolSpec"]
assert tool_spec["name"] == "get_weather"
assert tool_spec["description"] == "Get the weather in a city"
input_schema = tool_spec["inputSchema"]["json"]
assert input_schema["type"] == "object"
assert input_schema["required"] == ["city"]
assert input_schema["properties"]["city"]["type"] == "string"
# Bedrock's toolSpec.inputSchema.json only accepts type/properties/required;
# the OpenAI-style metadata must not leak through.
for stripped_field in ("$id", "$schema", "additionalProperties", "strict"):
assert (
stripped_field not in input_schema
), f"{stripped_field} should be stripped before hitting Bedrock"
assert request_body["messages"][0]["role"] == "user"
assert (
request_body["messages"][0]["content"][0]["text"]
== "How is the weather in Mumbai?"
)
def test_prompt_caching(self):
"""
Remove override once we have access to Bedrock prompt caching