Skip to content
Merged
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions py/src/braintrust/integrations/openai/test_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,39 @@ async def test_openai_async_parallel_requests(memory_logger):
assert_metrics_are_valid(span["metrics"])


@pytest.mark.vcr
@pytest.mark.skipif(
Version(openai.__version__) < Version("3.19.1"), reason="iterable tools are supported by OpenAI 3.19.1+"
)
def test_openai_chat_parse_generator_tools_are_logged_as_list(memory_logger):
assert not memory_logger.pop()

tools = [
{
"type": "function",
"function": {
"name": "lookup",
"description": "Look up a value",
"strict": True,
"parameters": {"type": "object", "properties": {}, "additionalProperties": False},
},
}
]
client = wrap_openai(openai.OpenAI())

response = client.chat.completions.parse(
model=TEST_MODEL,
messages=[{"role": "user", "content": "Say 24."}],
tools=(tool for tool in tools),
tool_choice="none",
)

assert response.choices[0].message.content
spans = memory_logger.pop()
assert len(spans) == 1
assert spans[0]["metadata"]["tools"] == tools


@pytest.mark.vcr
def test_openai_not_given_filtering(memory_logger):
"""Test that NOT_GIVEN values are filtered out of logged inputs but API call still works."""
Expand Down
5 changes: 4 additions & 1 deletion py/src/braintrust/integrations/openai/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import inspect
import json
import time
from collections.abc import Callable
from collections.abc import Callable, Iterable, Mapping
from typing import Any

from braintrust.integrations.utils import (
Expand Down Expand Up @@ -170,6 +170,9 @@ def _filter_metadata(params: dict[str, Any], allowlist: tuple[str, ...]) -> dict
value = params[key]
if _is_not_given(value):
continue
if key == "tools" and not isinstance(value, (list, str, bytes, Mapping)) and isinstance(value, Iterable):
value = list(value)
params[key] = value
if key in ("response_format", "text_format"):
value = _serialize_response_format(value)
metadata[key] = value
Expand Down
Loading