Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,17 @@ class NvidiaChatPromptExecutionSettings(NvidiaPromptExecutionSettings):
nvext: dict[str, Any] | None = None

def prepare_settings_dict(self, **kwargs) -> dict[str, Any]:
"""Override only for embeddings to exclude input_type and truncate."""
return self.model_dump(
exclude={"service_id", "extension_data", "structured_json_response", "response_format"},
"""Prepare the settings dict, moving nvext into extra_body.

The OpenAI client only sends nvext as part of extra_body. Keys already in extra_body["nvext"],
such as the guided_json set from response_format, take precedence over the same keys in nvext.
"""
settings_dict = self.model_dump(
exclude={"service_id", "extension_data", "structured_json_response", "response_format", "nvext"},
exclude_none=True,
by_alias=True,
)
if self.nvext:
extra_body = settings_dict.setdefault("extra_body", {})
extra_body["nvext"] = self.nvext | extra_body.get("nvext", {})
return settings_dict
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@ async def _send_chat_completion_request(
"""Send a request to the NVIDIA chat completion endpoint."""
try:
settings_dict = settings.prepare_settings_dict()

# Handle structured output if nvext is present in extra_body
if settings.extra_body and "nvext" in settings.extra_body:
if "extra_body" not in settings_dict:
settings_dict["extra_body"] = {}
settings_dict["extra_body"]["nvext"] = settings.extra_body["nvext"]

response = await self.client.chat.completions.create(**settings_dict)
self.store_usage(response)
return response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,46 @@ class TestModel(BaseModel):
assert "nvext" in call_args["extra_body"]
assert "guided_json" in call_args["extra_body"]["nvext"]

@pytest.mark.asyncio
@patch.object(AsyncCompletions, "create", new_callable=AsyncMock)
async def test_nvext_is_sent_in_extra_body(self, mock_create, nvidia_unit_test_env):
"""Test that the nvext setting is sent in extra_body, not as a create() argument."""
mock_create.return_value = _create_mock_chat_completion()

service = NvidiaChatCompletion()
chat_history = ChatHistory()
chat_history.add_user_message("Hello")
settings = NvidiaChatPromptExecutionSettings(nvext={"guided_choice": ["yes", "no"]})

await service.get_chat_message_contents(chat_history, settings)

call_args = mock_create.call_args[1]
assert "nvext" not in call_args
assert call_args["extra_body"]["nvext"] == {"guided_choice": ["yes", "no"]}

@pytest.mark.asyncio
@patch.object(AsyncCompletions, "create", new_callable=AsyncMock)
async def test_nvext_is_merged_with_structured_output(self, mock_create, nvidia_unit_test_env):
"""Test that nvext keys are kept next to the guided_json set from response_format."""

class TestModel(BaseModel):
name: str

mock_create.return_value = _create_mock_chat_completion('{"name": "test"}')

service = NvidiaChatCompletion()
chat_history = ChatHistory()
chat_history.add_user_message("Give me structured data")
settings = NvidiaChatPromptExecutionSettings(nvext={"repetition_penalty": 1.1}, response_format=TestModel)

await service.get_chat_message_contents(chat_history, settings)

call_args = mock_create.call_args[1]
assert call_args["extra_body"]["nvext"] == {
"repetition_penalty": 1.1,
"guided_json": TestModel.model_json_schema(),
}

@pytest.mark.asyncio
@patch.object(AsyncCompletions, "create", new_callable=AsyncMock)
async def test_error_handling(self, mock_create, nvidia_unit_test_env):
Expand Down
Loading