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
11 changes: 11 additions & 0 deletions py/noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
# CLI bundling started in 0.1.10 - older versions require external Claude Code installation
CLAUDE_AGENT_SDK_VERSIONS = (LATEST, "0.1.10")
AGNO_VERSIONS = (LATEST, "2.1.0")
OPENAI_AGENTS_VERSIONS = (LATEST, "0.8.0", "0.7.0")
# pydantic_ai 1.x requires Python >= 3.10
# Two test suites with different version requirements:
# 1. wrap_openai approach: works with older versions (0.1.9+)
Expand Down Expand Up @@ -156,6 +157,16 @@ def test_openai(session, version):
_run_core_tests(session)


@nox.session()
@nox.parametrize("version", OPENAI_AGENTS_VERSIONS, ids=OPENAI_AGENTS_VERSIONS)
def test_openai_agents(session, version):
_install_test_deps(session)
_install(session, "openai")
_install(session, "openai-agents", version)
_run_tests(session, f"{WRAPPER_DIR}/test_openai.py")
_run_core_tests(session)


@nox.session()
def test_openrouter(session):
"""Test wrap_openai with OpenRouter. Requires OPENROUTER_API_KEY env var."""
Expand Down
20 changes: 11 additions & 9 deletions py/src/braintrust/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,12 @@ def default_get_api_conn():
self._id_generator = None

# For unit-testing, tests may wish to temporarily override the global
# logger with a custom one. We allow this but keep the override variable
# thread-local to prevent the possibility that tests running on
# different threads unintentionally use the same override.
self._override_bg_logger = threading.local()
# logger with a custom one. We use a ContextVar so that the override
# propagates across thread boundaries (e.g. asyncio.to_thread) while
# still being isolated per-context (preventing test cross-talk).
self._override_bg_logger: contextvars.ContextVar[_BackgroundLogger | None] = contextvars.ContextVar(
"_override_bg_logger", default=None
)

self.reset_login_info()

Expand Down Expand Up @@ -587,7 +589,7 @@ def user_info(self) -> Mapping[str, Any]:
return self._user_info

def global_bg_logger(self) -> "_BackgroundLogger":
return getattr(self._override_bg_logger, "logger", None) or self._global_bg_logger.get()
return self._override_bg_logger.get() or self._global_bg_logger.get()

# Should only be called by the login function.
def login_replace_api_conn(self, api_conn: "HTTPConnection"):
Expand Down Expand Up @@ -1436,21 +1438,21 @@ def _internal_get_global_state() -> BraintrustState:
@contextlib.contextmanager
def _internal_with_custom_background_logger():
custom_logger = _HTTPBackgroundLogger(LazyValue(lambda: _state.api_conn(), use_mutex=True))
_state._override_bg_logger.logger = custom_logger
token = _state._override_bg_logger.set(custom_logger)
try:
yield custom_logger
finally:
_state._override_bg_logger.logger = None
_state._override_bg_logger.reset(token)


@contextlib.contextmanager
def _internal_with_memory_background_logger():
memory_logger = _MemoryBackgroundLogger()
_state._override_bg_logger.logger = memory_logger
token = _state._override_bg_logger.set(memory_logger)
try:
yield memory_logger
finally:
_state._override_bg_logger.logger = None
_state._override_bg_logger.reset(token)


@dataclasses.dataclass
Expand Down
2 changes: 2 additions & 0 deletions py/src/braintrust/wrappers/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import braintrust
from agents import tracing
from braintrust.logger import NOOP_SPAN
from braintrust.wrappers.threads import setup_threads


def _span_type(span: tracing.Span[Any]) -> braintrust.SpanTypeAttribute:
Expand Down Expand Up @@ -62,6 +63,7 @@ class BraintrustTracingProcessor(tracing.TracingProcessor):
"""

def __init__(self, logger: braintrust.Span | braintrust.Experiment | braintrust.Logger | None = None):
setup_threads() # Propagate ContextVars across worker threads (agents SDK >= 0.8)
self._logger = logger
self._spans: dict[str, braintrust.Span] = {}
self._first_input: dict[str, Any] = {}
Expand Down
Loading