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
5 changes: 5 additions & 0 deletions py/src/braintrust/btx/span_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ def _is_non_negative_number(value: Any) -> bool:
return isinstance(value, (int, float)) and not isinstance(value, bool) and value >= 0


def _is_positive_number(value: Any) -> bool:
return isinstance(value, (int, float)) and not isinstance(value, bool) and value > 0


def _is_non_empty_string(value: Any) -> bool:
return isinstance(value, str) and len(value) > 0

Expand All @@ -58,6 +62,7 @@ def _is_reasoning_message(value: Any) -> bool:

_NAMED_MATCHERS: dict[str, Any] = {
"is_non_negative_number": _is_non_negative_number,
"is_positive_number": _is_positive_number,
"is_non_empty_string": _is_non_empty_string,
"is_reasoning_message": _is_reasoning_message,
}
Expand Down
2 changes: 1 addition & 1 deletion py/src/braintrust/btx/spec-ref.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.0.1
v0.0.10
Original file line number Diff line number Diff line change
@@ -1,155 +1,83 @@
interactions:
- request:
body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What
color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}'
body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"Briefly
describe these attachments"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}},{"type":"file","file":{"filename":"blank.pdf","file_data":"data:application/pdf;base64,JVBERi0xLjAKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUl0gL0NvdW50IDEgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA2MTIgNzkyXSA+PgplbmRvYmoKeHJlZgowIDQKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDA5IDAwMDAwIG4gCjAwMDAwMDAwNTggMDAwMDAgbiAKMDAwMDAwMDExNSAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDQgL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjE5MAolJUVPRgo="}}]}],"model":"gpt-4o","temperature":0.0}'
headers:
Accept:
accept:
- application/json
Accept-Encoding:
accept-encoding:
- gzip, deflate
Connection:
connection:
- keep-alive
Content-Length:
- '353'
Content-Type:
content-length:
- '888'
content-type:
- application/json
Host:
host:
- api.openai.com
method: POST
uri: https://api.openai.com/v1/chat/completions
response:
body:
string: "{\n \"id\": \"chatcmpl-DYJCnaJpluKcRLAhJ6IFEPYlb25km\",\n \"object\":
\"chat.completion\",\n \"created\": 1777069349,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n
string: "{\n \"id\": \"chatcmpl-ECrtQIzXCewzHrgripHO0lB2egzRQ\",\n \"object\":
\"chat.completion\",\n \"created\": 1786735808,\n \"model\": \"gpt-4o-2024-08-06\",\n
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
\"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\":
null,\n \"annotations\": []\n },\n \"logprobs\": null,\n
\ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\":
8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\":
{\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\":
\"assistant\",\n \"content\": \"The first attachment is a solid red
square, likely an image file with no additional content or context.\\n\\nThe
second attachment, \\\"blank.pdf,\\\" appears to be a PDF document with no
readable content or visible images.\",\n \"refusal\": null,\n \"annotations\":
[]\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n
\ }\n ],\n \"usage\": {\n \"prompt_tokens\": 495,\n \"completion_tokens\":
42,\n \"total_tokens\": 537,\n \"prompt_tokens_details\": {\n \"cached_tokens\":
0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\":
{\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\":
0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\":
\"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n"
\"default\",\n \"system_fingerprint\": \"fp_684acb85fd\"\n}\n"
headers:
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Fri, 24 Apr 2026 22:22:29 GMT
Server:
- cloudflare
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
Transfer-Encoding:
- chunked
X-Content-Type-Options:
- nosniff
access-control-expose-headers:
- X-Request-ID
- CF-Ray
- CF-Ray
connection:
- keep-alive
content-length:
- '827'
- '1021'
content-type:
- application/json
date:
- Fri, 14 Aug 2026 19:30:09 GMT
openai-processing-ms:
- '374'
- '1020'
openai-version:
- '2020-10-01'
x-openai-proxy-wasm:
- v0.1
x-ratelimit-limit-input-images:
- '50000'
x-ratelimit-limit-requests:
- '30000'
x-ratelimit-limit-tokens:
- '150000000'
x-ratelimit-remaining-input-images:
- '49999'
x-ratelimit-remaining-requests:
- '29999'
x-ratelimit-remaining-tokens:
- '149999220'
x-ratelimit-reset-input-images:
- 1ms
x-ratelimit-reset-requests:
- 2ms
x-ratelimit-reset-tokens:
- 0s
status:
code: 200
message: OK
- request:
body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What
color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '353'
Content-Type:
- application/json
Host:
- api.openai.com
method: POST
uri: https://api.openai.com/v1/chat/completions
response:
body:
string: "{\n \"id\": \"chatcmpl-DYJIoOeeAgj8TR5Pa2eURAXaOgFj1\",\n \"object\":
\"chat.completion\",\n \"created\": 1777069722,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
\"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\":
null,\n \"annotations\": []\n },\n \"logprobs\": null,\n
\ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\":
8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\":
{\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\":
{\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\":
0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\":
\"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n"
headers:
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Fri, 24 Apr 2026 22:28:42 GMT
Server:
server:
- cloudflare
Strict-Transport-Security:
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
Transfer-Encoding:
transfer-encoding:
- chunked
X-Content-Type-Options:
x-content-type-options:
- nosniff
access-control-expose-headers:
- X-Request-ID
content-length:
- '827'
openai-processing-ms:
- '395'
openai-version:
- '2020-10-01'
x-openai-proxy-wasm:
- v0.1
x-ratelimit-limit-input-images:
- '50000'
- '250000'
x-ratelimit-limit-requests:
- '30000'
- '10000'
x-ratelimit-limit-tokens:
- '150000000'
- '30000000'
x-ratelimit-remaining-input-images:
- '49999'
- '249999'
x-ratelimit-remaining-requests:
- '29999'
- '9999'
x-ratelimit-remaining-tokens:
- '149999217'
- '29998451'
x-ratelimit-reset-input-images:
- 1ms
- 0s
x-ratelimit-reset-requests:
- 2ms
- 6ms
x-ratelimit-reset-tokens:
- 0s
- 3ms
status:
code: 200
message: OK
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
interactions:
- request:
body: '{"messages":[{"role":"user","content":"Look at this sequence: 2, 6, 12,
20, 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning_effort":"medium"}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate
connection:
- keep-alive
content-length:
- '199'
content-type:
- application/json
host:
- api.openai.com
method: POST
uri: https://api.openai.com/v1/chat/completions
response:
body:
string: "{\n \"id\": \"chatcmpl-ECrtSDJsX8y8zz1RLupVS9AJ6Kbq7\",\n \"object\":
\"chat.completion\",\n \"created\": 1786735810,\n \"model\": \"o4-mini-2025-04-16\",\n
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
\"assistant\",\n \"content\": \"The five terms are \\r\\n 2, 6, 12,
20, 30 \\r\\nTheir successive differences are \\r\\n 6\u22122=4, 12\u22126=6,
20\u221212=8, 30\u221220=10 \\r\\nso the differences go up by 2 each time.
\ Hence it\u2019s a quadratic sequence. In fact one checks \\r\\n \\r\\n
a\u2099 = n\xB2 + n \\r\\n \\r\\ngives \\r\\n a\u2081 = 1 + 1 = 2 \\r\\n
a\u2082 = 4 + 2 = 6 \\r\\n a\u2083 = 9 + 3 = 12 \\r\\n a\u2084 = 16 + 4
= 20 \\r\\n a\u2085 = 25 + 5 = 30 \\r\\n \\r\\nEquivalently, these are
the \u201Cpronic\u201D numbers n(n + 1).\",\n \"refusal\": null,\n
\ \"annotations\": []\n },\n \"finish_reason\": \"stop\"\n
\ }\n ],\n \"usage\": {\n \"prompt_tokens\": 41,\n \"completion_tokens\":
642,\n \"total_tokens\": 683,\n \"prompt_tokens_details\": {\n \"cached_tokens\":
0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\":
{\n \"reasoning_tokens\": 448,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\":
0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\":
\"default\",\n \"system_fingerprint\": null\n}\n"
headers:
access-control-expose-headers:
- X-Request-ID
- CF-Ray
- CF-Ray
connection:
- keep-alive
content-length:
- '1234'
content-type:
- application/json
date:
- Fri, 14 Aug 2026 19:30:16 GMT
openai-processing-ms:
- '5857'
openai-version:
- '2020-10-01'
server:
- cloudflare
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
transfer-encoding:
- chunked
x-content-type-options:
- nosniff
x-openai-proxy-wasm:
- v0.1
x-ratelimit-limit-requests:
- '30000'
x-ratelimit-limit-tokens:
- '150000000'
x-ratelimit-remaining-requests:
- '29999'
x-ratelimit-remaining-tokens:
- '149999970'
x-ratelimit-reset-requests:
- 2ms
x-ratelimit-reset-tokens:
- 0s
status:
code: 200
message: OK
version: 1
Loading