braintrust 0.3.11__tar.gz → 0.3.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {braintrust-0.3.11 → braintrust-0.3.12}/PKG-INFO +1 -1
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/auth.py +3 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/cors.py +1 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/server.py +6 -3
- braintrust-0.3.12/src/braintrust/version.py +4 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_openai.py +0 -32
- braintrust-0.3.12/src/braintrust/wrappers/test_openrouter.py +144 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust.egg-info/PKG-INFO +1 -1
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust.egg-info/SOURCES.txt +1 -0
- braintrust-0.3.11/src/braintrust/version.py +0 -4
- {braintrust-0.3.11 → braintrust-0.3.12}/README.md +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/setup.cfg +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/setup.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/_generated_types.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/audit.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/aws.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/bt_json.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/__main__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/eval.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/install/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/install/api.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/install/bump_versions.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/install/logs.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/install/redshift.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/install/run_migrations.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/cli/push.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/conftest.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/context.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/contrib/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/contrib/temporal/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/contrib/temporal/test_temporal.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/db_fields.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/dataset.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/eval_hooks.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/schemas.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/test_cached_login.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/test_lru_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/devserver/test_server_integration.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/framework.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/framework2.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/functions/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/functions/constants.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/functions/invoke.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/functions/stream.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/generated_types.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/git_fields.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/gitutil.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/graph_util.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/http_headers.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/id_gen.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/logger.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/merge_row_batch.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/oai.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/object.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/otel/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/otel/context.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/otel/test_distributed_tracing.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/otel/test_otel_bt_integration.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/parameters.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/disk_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/lru_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/prompt_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/test_disk_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/test_lru_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/prompt_cache/test_prompt_cache.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/py.typed +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/queue.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/resource_manager.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/score.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/serializable_data_class.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/span_identifier_v1.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/span_identifier_v2.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/span_identifier_v3.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/span_identifier_v4.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/span_types.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_framework.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_framework2.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_helpers.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_id_gen.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_logger.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_otel.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_queue.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_serializable_data_class.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_span_components.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_util.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/test_version.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/util.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/_anthropic_utils.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/agno/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/agno/agent.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/agno/function_call.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/agno/model.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/agno/team.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/agno/utils.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/anthropic.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/claude_agent_sdk/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/claude_agent_sdk/_wrapper.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/claude_agent_sdk/test_wrapper.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/dspy.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/google_genai/__init__.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/langchain.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/litellm.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/openai.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_agno.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_anthropic.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_dspy.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_google_genai.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_litellm.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_pydantic_ai.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/test_utils.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/xact_ids.py +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust.egg-info/dependency_links.txt +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust.egg-info/entry_points.txt +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust.egg-info/requires.txt +0 -0
- {braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust.egg-info/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ from ..logger import BraintrustState
|
|
|
10
10
|
ORIGIN_HEADER = "origin"
|
|
11
11
|
BRAINTRUST_AUTH_TOKEN_HEADER = "x-bt-auth-token"
|
|
12
12
|
BRAINTRUST_ORG_NAME_HEADER = "x-bt-org-name"
|
|
13
|
+
BRAINTRUST_PROJECT_ID_HEADER = "x-bt-project-id"
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@dataclass
|
|
@@ -17,6 +18,7 @@ class RequestContext:
|
|
|
17
18
|
app_origin: Optional[str]
|
|
18
19
|
token: Optional[str]
|
|
19
20
|
org_name: Optional[str]
|
|
21
|
+
project_id: Optional[str]
|
|
20
22
|
state: Optional[BraintrustState]
|
|
21
23
|
|
|
22
24
|
|
|
@@ -56,6 +58,7 @@ class AuthorizationMiddleware(BaseHTTPMiddleware):
|
|
|
56
58
|
app_origin=extract_allowed_origin(request.headers.get(ORIGIN_HEADER)),
|
|
57
59
|
token=None,
|
|
58
60
|
org_name=request.headers.get(BRAINTRUST_ORG_NAME_HEADER),
|
|
61
|
+
project_id=request.headers.get(BRAINTRUST_PROJECT_ID_HEADER),
|
|
59
62
|
state=None,
|
|
60
63
|
)
|
|
61
64
|
|
|
@@ -196,7 +196,7 @@ async def run_eval(request: Request) -> Union[JSONResponse, StreamingResponse]:
|
|
|
196
196
|
"state": state,
|
|
197
197
|
"scores": evaluator.scores
|
|
198
198
|
+ [
|
|
199
|
-
make_scorer(state, score["name"], score["function_id"])
|
|
199
|
+
make_scorer(state, score["name"], score["function_id"], ctx.project_id)
|
|
200
200
|
for score in eval_data.get("scores", [])
|
|
201
201
|
],
|
|
202
202
|
"stream": stream_fn,
|
|
@@ -305,7 +305,7 @@ def snake_to_camel(snake_str: str) -> str:
|
|
|
305
305
|
return components[0] + "".join(x.title() for x in components[1:]) if components else snake_str
|
|
306
306
|
|
|
307
307
|
|
|
308
|
-
def make_scorer(state: BraintrustState, name: str, score: FunctionId) -> EvalScorer[Any, Any]:
|
|
308
|
+
def make_scorer(state: BraintrustState, name: str, score: FunctionId, project_id: Optional[str] = None) -> EvalScorer[Any, Any]:
|
|
309
309
|
def scorer_fn(input, output, expected, metadata):
|
|
310
310
|
request = {
|
|
311
311
|
**score,
|
|
@@ -315,7 +315,10 @@ def make_scorer(state: BraintrustState, name: str, score: FunctionId) -> EvalSco
|
|
|
315
315
|
"mode": "auto",
|
|
316
316
|
"strict": True,
|
|
317
317
|
}
|
|
318
|
-
|
|
318
|
+
headers = {"Accept": "application/json"}
|
|
319
|
+
if project_id:
|
|
320
|
+
headers["x-bt-project-id"] = project_id
|
|
321
|
+
result = state.proxy_conn().post("function/invoke", json=request, headers=headers)
|
|
319
322
|
result.raise_for_status()
|
|
320
323
|
data = result.json()
|
|
321
324
|
return data
|
|
@@ -1690,35 +1690,3 @@ def test_braintrust_tracing_processor_trace_metadata_logging(memory_logger):
|
|
|
1690
1690
|
spans = memory_logger.pop()
|
|
1691
1691
|
root_span = spans[0]
|
|
1692
1692
|
assert root_span["metadata"]["conversation_id"] == "test-12345", "Should log trace metadata"
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
def test_parse_metrics_excludes_booleans():
|
|
1696
|
-
"""Test that boolean fields in usage objects are excluded from metrics.
|
|
1697
|
-
|
|
1698
|
-
Reproduces issue where OpenRouter returns is_byok (a boolean) in the usage
|
|
1699
|
-
object, which caused API validation errors: "Expected number, received boolean".
|
|
1700
|
-
|
|
1701
|
-
In Python, bool is a subclass of int, so isinstance(True, int) returns True.
|
|
1702
|
-
The fix ensures _is_numeric explicitly excludes booleans.
|
|
1703
|
-
"""
|
|
1704
|
-
from braintrust.oai import _parse_metrics_from_usage
|
|
1705
|
-
|
|
1706
|
-
# Simulate OpenRouter's usage object with boolean field
|
|
1707
|
-
usage = {
|
|
1708
|
-
"completion_tokens": 11,
|
|
1709
|
-
"prompt_tokens": 8,
|
|
1710
|
-
"total_tokens": 19,
|
|
1711
|
-
"cost": 0.000104,
|
|
1712
|
-
"is_byok": False, # This boolean should be filtered out
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
metrics = _parse_metrics_from_usage(usage)
|
|
1716
|
-
|
|
1717
|
-
# Numeric fields should be included
|
|
1718
|
-
assert metrics["completion_tokens"] == 11
|
|
1719
|
-
assert metrics["prompt_tokens"] == 8
|
|
1720
|
-
assert metrics["tokens"] == 19 # total_tokens gets renamed
|
|
1721
|
-
assert metrics["cost"] == 0.000104
|
|
1722
|
-
|
|
1723
|
-
# Boolean field should NOT be in metrics (this was the bug)
|
|
1724
|
-
assert "is_byok" not in metrics
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests to ensure wrap_openai works correctly with OpenRouter.
|
|
3
|
+
|
|
4
|
+
OpenRouter is a popular API gateway that provides access to multiple LLM providers
|
|
5
|
+
through an OpenAI-compatible interface. This test validates that our wrapper handles
|
|
6
|
+
OpenRouter-specific response fields correctly (e.g., boolean `is_byok` in usage).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from braintrust import logger, wrap_openai
|
|
14
|
+
from braintrust.test_helpers import init_test_logger
|
|
15
|
+
from braintrust.wrappers.test_utils import assert_metrics_are_valid
|
|
16
|
+
from openai import AsyncOpenAI, OpenAI
|
|
17
|
+
|
|
18
|
+
PROJECT_NAME = "test-openrouter"
|
|
19
|
+
TEST_MODEL = "openai/gpt-4o-mini"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture(scope="module")
|
|
23
|
+
def vcr_config():
|
|
24
|
+
return {
|
|
25
|
+
"filter_headers": [
|
|
26
|
+
"authorization",
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def memory_logger():
|
|
33
|
+
init_test_logger(PROJECT_NAME)
|
|
34
|
+
with logger._internal_with_memory_background_logger() as bgl:
|
|
35
|
+
yield bgl
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _get_client():
|
|
39
|
+
return OpenAI(
|
|
40
|
+
base_url="https://openrouter.ai/api/v1",
|
|
41
|
+
api_key=os.environ.get("OPENROUTER_API_KEY"),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _get_async_client():
|
|
46
|
+
return AsyncOpenAI(
|
|
47
|
+
base_url="https://openrouter.ai/api/v1",
|
|
48
|
+
api_key=os.environ.get("OPENROUTER_API_KEY"),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.mark.vcr
|
|
53
|
+
def test_openrouter_chat_completion_sync(memory_logger):
|
|
54
|
+
assert not memory_logger.pop()
|
|
55
|
+
|
|
56
|
+
client = wrap_openai(_get_client())
|
|
57
|
+
|
|
58
|
+
start = time.time()
|
|
59
|
+
response = client.chat.completions.create(
|
|
60
|
+
model=TEST_MODEL,
|
|
61
|
+
messages=[{"role": "user", "content": "What is 2+2? Reply with just the number."}],
|
|
62
|
+
max_tokens=10,
|
|
63
|
+
)
|
|
64
|
+
end = time.time()
|
|
65
|
+
|
|
66
|
+
assert response
|
|
67
|
+
assert response.choices[0].message.content
|
|
68
|
+
assert "4" in response.choices[0].message.content
|
|
69
|
+
|
|
70
|
+
spans = memory_logger.pop()
|
|
71
|
+
assert len(spans) == 1
|
|
72
|
+
span = spans[0]
|
|
73
|
+
|
|
74
|
+
metrics = span["metrics"]
|
|
75
|
+
assert_metrics_are_valid(metrics, start, end)
|
|
76
|
+
|
|
77
|
+
# Ensure no boolean values in metrics (the original bug with is_byok)
|
|
78
|
+
for key, value in metrics.items():
|
|
79
|
+
assert not isinstance(value, bool), f"Metric {key} should not be a boolean"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@pytest.mark.vcr
|
|
83
|
+
@pytest.mark.asyncio
|
|
84
|
+
async def test_openrouter_chat_completion_async(memory_logger):
|
|
85
|
+
"""Test that wrap_openai works with OpenRouter's async client."""
|
|
86
|
+
assert not memory_logger.pop()
|
|
87
|
+
|
|
88
|
+
client = wrap_openai(_get_async_client())
|
|
89
|
+
|
|
90
|
+
start = time.time()
|
|
91
|
+
response = await client.chat.completions.create(
|
|
92
|
+
model=TEST_MODEL,
|
|
93
|
+
messages=[{"role": "user", "content": "What is 3+3? Reply with just the number."}],
|
|
94
|
+
max_tokens=10,
|
|
95
|
+
)
|
|
96
|
+
end = time.time()
|
|
97
|
+
|
|
98
|
+
assert response
|
|
99
|
+
assert response.choices[0].message.content
|
|
100
|
+
assert "6" in response.choices[0].message.content
|
|
101
|
+
|
|
102
|
+
spans = memory_logger.pop()
|
|
103
|
+
assert len(spans) == 1
|
|
104
|
+
span = spans[0]
|
|
105
|
+
|
|
106
|
+
metrics = span["metrics"]
|
|
107
|
+
assert_metrics_are_valid(metrics, start, end)
|
|
108
|
+
|
|
109
|
+
for key, value in metrics.items():
|
|
110
|
+
assert not isinstance(value, bool), f"Metric {key} should not be a boolean"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@pytest.mark.vcr
|
|
114
|
+
def test_openrouter_streaming_sync(memory_logger):
|
|
115
|
+
"""Test that wrap_openai works with OpenRouter's streaming responses."""
|
|
116
|
+
assert not memory_logger.pop()
|
|
117
|
+
|
|
118
|
+
client = wrap_openai(_get_client())
|
|
119
|
+
|
|
120
|
+
start = time.time()
|
|
121
|
+
chunks = []
|
|
122
|
+
stream = client.chat.completions.create(
|
|
123
|
+
model=TEST_MODEL,
|
|
124
|
+
messages=[{"role": "user", "content": "What is 5+5? Reply with just the number."}],
|
|
125
|
+
max_tokens=10,
|
|
126
|
+
stream=True,
|
|
127
|
+
)
|
|
128
|
+
for chunk in stream:
|
|
129
|
+
chunks.append(chunk)
|
|
130
|
+
end = time.time()
|
|
131
|
+
|
|
132
|
+
assert chunks
|
|
133
|
+
content = "".join(c.choices[0].delta.content or "" for c in chunks if c.choices)
|
|
134
|
+
assert "10" in content
|
|
135
|
+
|
|
136
|
+
spans = memory_logger.pop()
|
|
137
|
+
assert len(spans) == 1
|
|
138
|
+
span = spans[0]
|
|
139
|
+
|
|
140
|
+
metrics = span["metrics"]
|
|
141
|
+
assert_metrics_are_valid(metrics, start, end)
|
|
142
|
+
|
|
143
|
+
for key, value in metrics.items():
|
|
144
|
+
assert not isinstance(value, bool), f"Metric {key} should not be a boolean"
|
|
@@ -104,6 +104,7 @@ src/braintrust/wrappers/test_dspy.py
|
|
|
104
104
|
src/braintrust/wrappers/test_google_genai.py
|
|
105
105
|
src/braintrust/wrappers/test_litellm.py
|
|
106
106
|
src/braintrust/wrappers/test_openai.py
|
|
107
|
+
src/braintrust/wrappers/test_openrouter.py
|
|
107
108
|
src/braintrust/wrappers/test_pydantic_ai.py
|
|
108
109
|
src/braintrust/wrappers/test_utils.py
|
|
109
110
|
src/braintrust/wrappers/agno/__init__.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/claude_agent_sdk/__init__.py
RENAMED
|
File without changes
|
{braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/claude_agent_sdk/_wrapper.py
RENAMED
|
File without changes
|
{braintrust-0.3.11 → braintrust-0.3.12}/src/braintrust/wrappers/claude_agent_sdk/test_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|