From 478d6b1990aeb50398f27fd89f9d589ad8342bd1 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Tue, 1 Sep 2026 13:41:55 -0400 Subject: [PATCH] feat(trace): add advanced span filters Add `filters` to `Trace.get_spans()` so callers can select spans by type, name, error state, partial metadata, and duration without fetching the whole trace and filtering it themselves. ```python spans = await trace.get_spans( filters={ "span_type": ["tool"], "name": ["search", "lookup"], "has_error": True, "metadata": {"model": "gpt-5"}, "duration": {"min": 0.5, "max": 10}, } ) ``` Combine filter dimensions with AND and match any value within each name or span-type list. Duration bounds are inclusive and measured in seconds. Keep the existing top-level `span_type` argument supported. Apply consistent filtering to buffered spans, complete trace caches, and BTQL queries. Check returned metadata candidates locally to handle backend type coercion differences, and avoid caching partial filtered results as complete traces. Keep client-side validation limited to supported keys and input shapes. --- .../test_span_filters_backend_parity.yaml | 4850 +++++++++++++++++ py/src/braintrust/logger.py | 3 + py/src/braintrust/span_cache.py | 49 +- py/src/braintrust/test_span_cache.py | 7 + py/src/braintrust/test_trace.py | 495 +- py/src/braintrust/trace.py | 397 +- py/src/braintrust/type_tests/test_trace.py | 8 + 7 files changed, 5433 insertions(+), 376 deletions(-) create mode 100644 py/src/braintrust/cassettes/test_span_filters_backend_parity.yaml create mode 100644 py/src/braintrust/type_tests/test_trace.py diff --git a/py/src/braintrust/cassettes/test_span_filters_backend_parity.yaml b/py/src/braintrust/cassettes/test_span_filters_backend_parity.yaml new file mode 100644 index 000000000..40c5f99b1 --- /dev/null +++ b/py/src/braintrust/cassettes/test_span_filters_backend_parity.yaml @@ -0,0 +1,4850 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, zstd + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://www.braintrust.dev/api/apikey/login + response: + body: + string: '{"org_info":[{"id":"5abfae3a-7aa7-4653-a9c8-b3efcb18f584","name":"Braintrust + SDKs","api_url":"https://api.braintrust.dev","git_metadata":{"collect":"some","fields":["commit","branch","tag","dirty","author_name","author_email","commit_message","commit_time"]},"is_universal_api":null,"proxy_url":"https://api.braintrust.dev","realtime_url":"wss://realtime.braintrustapi.com"}]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, + Content-Type, Date, X-Api-Version + Access-Control-Allow-Methods: + - GET,OPTIONS,PATCH,DELETE,POST,PUT + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - public, max-age=0, must-revalidate + Content-Length: + - '376' + Content-Security-Policy: + - 'script-src ''self'' ''unsafe-eval'' ''wasm-unsafe-eval'' ''strict-dynamic'' + ''nonce-NzNiODRhNzctMzY2NS00OTNmLThhYWMtODNkOWU1NmU3YjZi'' *.js.stripe.com + js.stripe.com maps.googleapis.com ; style-src ''self'' ''unsafe-inline'' *.braintrust.dev + btcm6qilbbhv4yi1.public.blob.vercel-storage.com fonts.googleapis.com www.gstatic.com + d4tuoctqmanu0.cloudfront.net; font-src ''self'' data: fonts.gstatic.com btcm6qilbbhv4yi1.public.blob.vercel-storage.com + cdn.jsdelivr.net d4tuoctqmanu0.cloudfront.net fonts.googleapis.com mintlify-assets.b-cdn.net + fonts.cdnfonts.com; object-src ''none''; base-uri ''self''; form-action ''self'' + https://www.facebook.com; frame-ancestors ''self''; worker-src ''self'' blob:; + report-uri https://o4507221741076480.ingest.us.sentry.io/api/4507221754380288/security/?sentry_key=27fa5ac907cf7c6ce4a1ab2a03f805b4&sentry_environment=production&sentry_release=16; + report-to csp-endpoint-0' + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 10 Sep 2026 14:13:26 GMT + Etag: + - '"13vsc5ye8flag"' + Reporting-Endpoints: + - csp-endpoint-0="https://o4507221741076480.ingest.us.sentry.io/api/4507221754380288/security/?sentry_key=27fa5ac907cf7c6ce4a1ab2a03f805b4&sentry_environment=production&sentry_release=16" + Server: + - Vercel + Strict-Transport-Security: + - max-age=63072000 + X-Clerk-Auth-Message: + - Invalid JWT form. A JWT consists of three parts separated by dots. (reason=token-invalid, + token-carrier=header) + X-Clerk-Auth-Reason: + - token-invalid + X-Clerk-Auth-Status: + - signed-out + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Matched-Path: + - /api/apikey/login + X-Nonce: + - NzNiODRhNzctMzY2NS00OTNmLThhYWMtODNkOWU1NmU3YjZi + X-Vercel-Cache: + - MISS + X-Vercel-Id: + - yul1::iad1::hm628-1789049606407-c0db5ad4ac68 + status: + code: 200 + message: OK +- request: + body: '{"name": "python-sdk-vcr-tests", "org_name": "Braintrust SDKs"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, zstd + Connection: + - keep-alive + Content-Length: + - '63' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/v1/project + response: + body: + string: '{"id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","org_id":"5abfae3a-7aa7-4653-a9c8-b3efcb18f584","name":"python-sdk-vcr-tests","description":null,"created":"2026-09-10T14:02:15.249Z","deleted_at":null,"user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","settings":null}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - no-store, no-cache, must-revalidate, proxy-revalidate + Connection: + - keep-alive + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 10 Sep 2026 14:13:26 GMT + ETag: + - W/"106-k/eIki4AkL3hlx7nKmFl6U7L9DM" + Expires: + - '0' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Surrogate-Control: + - no-store + Transfer-Encoding: + - chunked + Vary: + - Origin, Accept-Encoding + Via: + - 1.1 70fd8dd903406754b301439f9111e256.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - 6x_XBXXV6-glFOiijxvjLEOHt33QayJ_-BWYWz-_eUfZYpFP9buVkA== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '262' + x-bt-found-existing: + - 'true' + status: + code: 200 + message: OK +- request: + body: '{"project_id": "2f3bb2d1-8360-47ec-89a9-7c7e10e22cff", "ensure_new": false, + "name": "span-filters-backend-parity-v2", "public": false}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, zstd + Connection: + - keep-alive + Content-Length: + - '134' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/v1/experiment + response: + body: + string: '{"id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","name":"span-filters-backend-parity-v2","description":null,"created":"2026-09-10T14:13:29.070Z","repo_info":null,"commit":null,"base_exp_id":null,"deleted_at":null,"dataset_id":null,"dataset_version":null,"internal_metadata":null,"parameters_id":null,"parameters_version":null,"public":false,"user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","metadata":null,"tags":null}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - no-store, no-cache, must-revalidate, proxy-revalidate + Connection: + - keep-alive + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 10 Sep 2026 14:13:29 GMT + ETag: + - W/"1d2-kV4K5ubZZrgID7MG1llw6j++oIo" + Expires: + - '0' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Surrogate-Control: + - no-store + Transfer-Encoding: + - chunked + Vary: + - Origin, Accept-Encoding + Via: + - 1.1 6589108eb8812ce79de8a8eef3f72bee.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - yuwvOnN003Lgj6ceVzy52H-uNZ91KuBw3pjvZN3TycC9cwRj58pPsg== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '466' + status: + code: 200 + message: OK +- request: + body: '{"rows": [{"span_id": "span-filters-root", "span_attributes": {"name": + "root", "type": "task"}, "id": "span-filters-root", "root_span_id": "span-filters-root", + "experiment_id": "ced0d1a7-b4aa-4694-9301-8d9a075bec90", "span_parents": []}, + {"metadata": {"request": {"region": "us", "model": null}, "flag": true}, "metrics": + {"start": 100, "end": 102}, "span_id": "search", "span_attributes": {"name": + "search", "type": "tool"}, "id": "search", "root_span_id": "span-filters-root", + "experiment_id": "ced0d1a7-b4aa-4694-9301-8d9a075bec90", "span_parents": ["span-filters-root"]}, + {"metadata": {"request": {"region": "eu", "model": "test"}, "flag": 1}, "error": + "failed", "metrics": {"start": 100, "end": 105}, "span_id": "failed", "span_attributes": + {"name": "search", "type": "tool"}, "id": "failed", "root_span_id": "span-filters-root", + "experiment_id": "ced0d1a7-b4aa-4694-9301-8d9a075bec90", "span_parents": ["span-filters-root"]}, + {"metadata": {"request": {}}, "error": "", "metrics": {"start": 100, "end": + 100.5}, "span_id": "lookup", "span_attributes": {"name": "lookup", "type": "llm"}, + "id": "lookup", "root_span_id": "span-filters-root", "experiment_id": "ced0d1a7-b4aa-4694-9301-8d9a075bec90", + "span_parents": ["span-filters-root"]}, {"metrics": {"start": 100}, "span_id": + "open", "span_attributes": {"name": "open", "type": "tool"}, "id": "open", "root_span_id": + "span-filters-root", "experiment_id": "ced0d1a7-b4aa-4694-9301-8d9a075bec90", + "span_parents": ["span-filters-root"]}, {"metrics": {"start": 100, "end": 102}, + "span_id": "scorer", "span_attributes": {"name": "search", "type": "score", + "purpose": "scorer"}, "id": "scorer", "root_span_id": "span-filters-root", "experiment_id": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90", "span_parents": ["span-filters-root"]}], + "api_version": 2}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, zstd + Connection: + - keep-alive + Content-Length: + - '1795' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/logs3 + response: + body: + string: '{"ids":["span-filters-root","search","failed","lookup","open","scorer"],"xact_id":"1000197839408140331"}' + headers: + Connection: + - keep-alive + Content-Type: + - application/json; charset=utf-8 + Date: + - Thu, 10 Sep 2026 14:13:29 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Via: + - 1.1 829010acd0fdda0ad4dee0ccb1db7af4.cloudfront.net (CloudFront), 1.1 019b4503d2ffede0ae900992ff140770.cloudfront.net + (CloudFront) + X-Amz-Cf-Id: + - 6yk1djfOObzum0xCPZh3-xlj8K75FGnfSuHNnoc-vPNGf0irMrMyYA== + X-Amz-Cf-Pop: + - YTO53-P2 + - YTO50-P2 + X-Amzn-Trace-Id: + - Root=1-6aa2bb09-789eb1f409e6b80039d2da3e;Parent=4b24a1f6ae441d67;Sampled=0;Lineage=1:24be3d11:0 + X-Cache: + - Miss from cloudfront + access-control-allow-credentials: + - 'true' + access-control-expose-headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + cache-control: + - no-store, no-cache, must-revalidate, proxy-revalidate + content-length: + - '104' + etag: + - W/"68-0OFIdCk/cIeM24wmIPleioeKu38" + expires: + - '0' + surrogate-control: + - no-store + vary: + - Origin, Accept-Encoding + x-amz-apigw-id: + - DfIpjEZ3IAMErlw= + x-amzn-RequestId: + - 138c01ec-058f-45e9-be40-2a6503132ce1 + x-bt-internal-trace-id: + - 6aa2bb090000000078c90314f94ae2e1 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "in", "left": {"op": + "ident", "name": ["span_attributes", "type"]}, "right": {"op": "literal", "value": + ["tool"]}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '854' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":null,"last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:30 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 50d743941b822ae5fa30db69233863a6.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - NLyojlC-XK4NYWQ1nxSxkn6l3dSHVMla00FaavhvbS95-kd2ljt0lw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '10414' + x-bt-api-duration-ms: + - '726' + x-bt-brainstore-duration-ms: + - '113' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - 61534bb53be2b2755555121f3df64ca6 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "in", + "left": {"op": "ident", "name": ["span_attributes", "type"]}, "right": {"op": + "literal", "value": ["tool"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '863' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":null,"last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:31 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 16808c837fedc33331e77d172952efee.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - aZw3w8jTSGFE-JXWsHaHFrNWT8R7uH72AG3nQLgjd559QGoCMgwMOw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7760' + x-bt-api-duration-ms: + - '100' + x-bt-brainstore-duration-ms: + - '69' + x-bt-internal-trace-id: + - 6face3b5aa7a7407a1d1b4c831ff9674 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "in", "left": {"op": + "ident", "name": ["span_attributes", "name"]}, "right": {"op": "literal", "value": + ["search", "lookup"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '866' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":null,"last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:31 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 4ec5f8da969dc981ba2067c9dad5dad8.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - zFZ-y5rVpWkYdKZE5Z9_1lVfhlyFPLHudMEjqiQvsuj55QLf18TGyQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '10454' + x-bt-api-duration-ms: + - '53' + x-bt-brainstore-duration-ms: + - '39' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - 139de50086068811c04e2cab85245d86 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "in", + "left": {"op": "ident", "name": ["span_attributes", "name"]}, "right": {"op": + "literal", "value": ["search", "lookup"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '875' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":null,"last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:31 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 4ec5f8da969dc981ba2067c9dad5dad8.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - _OA6G8a99ZxK2-XpE9GO9Th7v0yBsQhNE9J4Wx2LjqBrvJtt0hbjZA== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7760' + x-bt-api-duration-ms: + - '54' + x-bt-brainstore-duration-ms: + - '42' + x-bt-internal-trace-id: + - d8f3f0a81c909dd1ce795a14cf4a0c3b + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "isnotnull", "expr": + {"op": "ident", "name": ["error"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '796' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAI","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:32 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 74797197cacba7d22a7c3a7685b38272.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - 2ohCpWy7388PlueB240ftOUXxriIspy2OLD1-rhXM5prwe2MKGBhxw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '9569' + x-bt-api-duration-ms: + - '284' + x-bt-brainstore-duration-ms: + - '208' + x-bt-cursor: + - aqK7CRArAAI + x-bt-internal-trace-id: + - 2f86da33cd0be9c5b85728b5adfce1b1 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAI", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "isnotnull", + "expr": {"op": "ident", "name": ["error"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '805' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:32 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 dcd16c430149132ea12a5783d54ff114.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - J3ChSIPwyu3imZ72y9x-rAwKy-esv2PBG4erGhqhT5l2HeqXFOVZNQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '130' + x-bt-brainstore-duration-ms: + - '111' + x-bt-internal-trace-id: + - 802a01403dffd1d26187c7b8a1eecbfb + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "isnull", "expr": {"op": + "ident", "name": ["error"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '793' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840768","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"span-filters-root","input":null,"is_root":true,"metadata":null,"metrics":null,"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"root","type":"task"},"span_id":"span-filters-root","span_parents":null,"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAA","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:32 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 50d743941b822ae5fa30db69233863a6.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - 0LR_B9SNm6PghQ_xkngPgOwMjccCVEUmzTGjHxwL0m6gadiccrrzxQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '10350' + x-bt-api-duration-ms: + - '93' + x-bt-brainstore-duration-ms: + - '66' + x-bt-cursor: + - aqK7CRArAAA + x-bt-internal-trace-id: + - c4802712e5562d0a1daf2c78a38322b6 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAA", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "isnull", + "expr": {"op": "ident", "name": ["error"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '802' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:32 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 890304274d84dce52c3c8a65cb402758.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - BmdiasIMTqwxt1UYTitP1S5i2AjWs9NUdWUv3B908Qp__EK7t3PXCg== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '77' + x-bt-brainstore-duration-ms: + - '68' + x-bt-internal-trace-id: + - b3a76fd9d0b7325dbb52fdb0db205961 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "eq", "left": {"op": + "ident", "name": ["metadata", "request", "region"]}, "right": {"op": "literal", + "value": "us"}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '856' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:34 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 890304274d84dce52c3c8a65cb402758.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - 5v4ppWHIyRN3MnNvp_R2fCS3X-akTtiKaYHulQsOzJJpjvYw6rKv1g== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '8701' + x-bt-api-duration-ms: + - '1329' + x-bt-brainstore-duration-ms: + - '1317' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - 150f6c695752a3fe7c82467d217a1815 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "eq", + "left": {"op": "ident", "name": ["metadata", "request", "region"]}, "right": + {"op": "literal", "value": "us"}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '865' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:34 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 21c66eb5f493a6e3ddbaa803cebfe014.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - xSFS_4fOaNg0_q8LZ2jjc0_hMd_KmRGwvrbV1PoXxwlVJCx_dWeE2w== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '90' + x-bt-brainstore-duration-ms: + - '78' + x-bt-internal-trace-id: + - 0b1818bf50e82eda204b38f7e331c327 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "isnull", "expr": {"op": + "ident", "name": ["metadata", "request", "model"]}}]}}, "use_columnstore": false, + "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '816' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840768","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"span-filters-root","input":null,"is_root":true,"metadata":null,"metrics":null,"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"root","type":"task"},"span_id":"span-filters-root","span_parents":null,"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAA","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:34 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 10f12ad63ad88e4e38e4e73deb3e9570.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - idsLKtVsNJQ_L7u8szGEGc81IYNH5lH6HRm9AfJSm10dkN21CajJYw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '11215' + x-bt-api-duration-ms: + - '191' + x-bt-brainstore-duration-ms: + - '177' + x-bt-cursor: + - aqK7CRArAAA + x-bt-internal-trace-id: + - 947a4da1b8b7a78038aff628af8e5a5f + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAA", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "isnull", + "expr": {"op": "ident", "name": ["metadata", "request", "model"]}}]}}, "use_columnstore": + false, "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '825' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:35 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 74797197cacba7d22a7c3a7685b38272.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - JpHB4ljCSqb19eJNgCzj1WslT81iego_-DSV8OR8hHJsXGnJ9rg_pQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '141' + x-bt-brainstore-duration-ms: + - '132' + x-bt-internal-trace-id: + - 8f18ea7f3c58b5b692a9f043d8c186ec + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "eq", "left": {"op": + "ident", "name": ["metadata", "flag"]}, "right": {"op": "literal", "value": + true}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '843' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:35 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 0e761f7a5b2481acd893422a702c9fa8.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - fToHrhG3bQu9Vgsdb1KBAooSwL3_SYiaM4xv4gJUQNScM9NG1gegQQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '9606' + x-bt-api-duration-ms: + - '99' + x-bt-brainstore-duration-ms: + - '85' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - bab902048f2ca7a3b7b22904c9eff5e2 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "eq", + "left": {"op": "ident", "name": ["metadata", "flag"]}, "right": {"op": "literal", + "value": true}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '852' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:35 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 0e761f7a5b2481acd893422a702c9fa8.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - qMC-xkRmQIz6xn48_57emZwCQSleBFBUFpGfu1u9uevokk2hnwYRTw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '309' + x-bt-brainstore-duration-ms: + - '207' + x-bt-internal-trace-id: + - 5f4e32f01587eb5e4665f019013546a5 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "eq", "left": {"op": + "ident", "name": ["metadata", "flag"]}, "right": {"op": "literal", "value": + 1}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '840' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:36 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 cb0c6226aa19d81a39519501df383968.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - Epqp8VBovzwY6BBXvqYrxWcd-b_Tc-ElptNCItT4jGbystWXPvjR5Q== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '9606' + x-bt-api-duration-ms: + - '98' + x-bt-brainstore-duration-ms: + - '87' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - 71412733d13740322cea2119f7626e15 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "eq", + "left": {"op": "ident", "name": ["metadata", "flag"]}, "right": {"op": "literal", + "value": 1}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '849' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:36 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 16808c837fedc33331e77d172952efee.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - Qk6u0sjPU8hQLgNFP34Ywa3OZifDrrYIfeOLYtCXHUKrIwG9AGKJFA== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '198' + x-bt-brainstore-duration-ms: + - '184' + x-bt-internal-trace-id: + - c2957b80cccf3ee3cde49d87cda71b99 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "ge", "left": {"op": + "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": {"op": + "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + 2}}, {"op": "le", "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", + "end"]}, "right": {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": + "literal", "value": 5}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '1103' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:36 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 3340b5a392e45fce453c4d978abfd6be.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - NCwTsFJVheJb7cQ3f6sklm5V1iE_9OGfIXzGB2lRdBpLJ4-P10n3vQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '9606' + x-bt-api-duration-ms: + - '107' + x-bt-brainstore-duration-ms: + - '95' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - 8b97fd6d90d8a81a79c42ac569d87701 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "ge", + "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": + {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + 2}}, {"op": "le", "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", + "end"]}, "right": {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": + "literal", "value": 5}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '1112' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:36 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 4ec5f8da969dc981ba2067c9dad5dad8.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - IBy7G5UF9MuStPcvaFarjAhOsI_D6zX9frWg9kTlVVdhotcUwl5olg== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '91' + x-bt-brainstore-duration-ms: + - '79' + x-bt-internal-trace-id: + - 7ec2849cc6d494be2ff1072f3020cfb2 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "le", "left": {"op": + "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": {"op": + "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + 0.5}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '919' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAM","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:37 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 e6bfe249d47d39a52673337cf444c9ce.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - QcfByFjuOmEiEHBMhKV-mEUtutkf_fzZybyzZIrl-Eu-9abDc2x77Q== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '8664' + x-bt-api-duration-ms: + - '169' + x-bt-brainstore-duration-ms: + - '151' + x-bt-cursor: + - aqK7CRArAAM + x-bt-internal-trace-id: + - d48d932f9329899ea62d15c368b758bb + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAM", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "le", + "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": + {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + 0.5}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '928' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:37 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 5e2f1ed3ba0ab1e08304bb3d134360de.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - Et0FhJ6kwIbg79JkS6jDRxwYouPYDDq9hMSEU53coibKJ8RXeZozdg== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '81' + x-bt-brainstore-duration-ms: + - '72' + x-bt-internal-trace-id: + - 206551e92b361a6603d79a11eac06f84 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "in", "left": {"op": + "ident", "name": ["span_attributes", "name"]}, "right": {"op": "literal", "value": + ["search"]}}, {"op": "isnull", "expr": {"op": "ident", "name": ["error"]}}, + {"op": "ge", "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", + "end"]}, "right": {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": + "literal", "value": 2}}, {"op": "le", "left": {"op": "sub", "left": {"op": "ident", + "name": ["metrics", "end"]}, "right": {"op": "ident", "name": ["metrics", "start"]}}, + "right": {"op": "literal", "value": 2}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '1290' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:37 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 dcd16c430149132ea12a5783d54ff114.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - MVtKcl1sH5QFzeoal37Ze2vzIAxCk1s1btpXocISj8-qkM8Yuf_aiQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '8701' + x-bt-api-duration-ms: + - '88' + x-bt-brainstore-duration-ms: + - '69' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - fab060abe98a0372c2c11fa33b68ae20 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "in", + "left": {"op": "ident", "name": ["span_attributes", "name"]}, "right": {"op": + "literal", "value": ["search"]}}, {"op": "isnull", "expr": {"op": "ident", "name": + ["error"]}}, {"op": "ge", "left": {"op": "sub", "left": {"op": "ident", "name": + ["metrics", "end"]}, "right": {"op": "ident", "name": ["metrics", "start"]}}, + "right": {"op": "literal", "value": 2}}, {"op": "le", "left": {"op": "sub", + "left": {"op": "ident", "name": ["metrics", "end"]}, "right": {"op": "ident", + "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": 2}}]}}, + "use_columnstore": false, "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '1299' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:37 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 cfcfb1d8fbf5ce2b107182799687a614.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - 8Kv8iGBnQ3QTpScAfsNGYoy02mlUwBCvELANSUB9BCPd3ktXeZYXCQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '88' + x-bt-brainstore-duration-ms: + - '74' + x-bt-internal-trace-id: + - cb302e4a13a6a0c62435e7f9d44dd9c7 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "literal", "value": + false}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '766' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:39 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 2ffb622580a0a24837f798fa62268b12.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - UoRgHvxtvhbTS2MstzXkH7jj52hfpumGxZQMu45fzsq8RARJEzXvVQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '256' + x-bt-brainstore-duration-ms: + - '68' + x-bt-internal-trace-id: + - dd670678c6dfbb3ce88bebe6bf99c123 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": false, + "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '731' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840768","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"span-filters-root","input":null,"is_root":true,"metadata":null,"metrics":null,"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"root","type":"task"},"span_id":"span-filters-root","span_parents":null,"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAA","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:39 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 a7af18c87ffc07d74544efce5f2b0f9c.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - b5mS0WctVO_eNdI5UTsZc-255fcrGrjGgigPDFM8zi0t4fCLY9hYQw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '12120' + x-bt-api-duration-ms: + - '122' + x-bt-brainstore-duration-ms: + - '111' + x-bt-cursor: + - aqK7CRArAAA + x-bt-internal-trace-id: + - 056a92ab4a2ffc5649a1be0d5d1cfcbd + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAA", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": + false, "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '740' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:53 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 a7af18c87ffc07d74544efce5f2b0f9c.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - yEZ-dv5ViUtqEqxcK08Gpldp0IFxP1edEQG1nkPOxnPyiiMxJc6XXg== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '481' + x-bt-brainstore-duration-ms: + - '220' + x-bt-internal-trace-id: + - ad16b9b1b4a75c2e5c98748a42e19755 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": false, + "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '731' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840768","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"span-filters-root","input":null,"is_root":true,"metadata":null,"metrics":null,"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"root","type":"task"},"span_id":"span-filters-root","span_parents":null,"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAA","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:53 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 41c02c3f5acef4f58284b65a8f7a983a.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - gOVjk1VfKTIQq3vmqNcuPydNyM0GmVtBpV6hqtHorcb2Y4WjNZWTyw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '12120' + x-bt-api-duration-ms: + - '80' + x-bt-brainstore-duration-ms: + - '69' + x-bt-cursor: + - aqK7CRArAAA + x-bt-internal-trace-id: + - d0570e7b253118ade85e603ab5966cf1 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAA", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": + false, "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '740' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:53 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 74797197cacba7d22a7c3a7685b38272.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - -2f2cOCD_OglSUfxOBZy3x5T0axiSuJKFVJj8VfIu36zyg5J5hWOHA== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '84' + x-bt-brainstore-duration-ms: + - '71' + x-bt-internal-trace-id: + - c1156fddc8f1bfbfd866dba3eff951fe + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": false, + "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '731' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840768","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"span-filters-root","input":null,"is_root":true,"metadata":null,"metrics":null,"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"root","type":"task"},"span_id":"span-filters-root","span_parents":null,"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAA","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:53 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 6589108eb8812ce79de8a8eef3f72bee.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - bDocnkOwjgFAyMYMq42BNZlWGMaGGLil4_-Sb55PNuGYBhvZu4R36g== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '12120' + x-bt-api-duration-ms: + - '92' + x-bt-brainstore-duration-ms: + - '80' + x-bt-cursor: + - aqK7CRArAAA + x-bt-internal-trace-id: + - 496ff1b3d60a4f8daba49469c2cb2f7e + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAA", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": + false, "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '740' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:54 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 21c66eb5f493a6e3ddbaa803cebfe014.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - W7RnkSN1lhr8MRlGVEgvW7ZYc7MxVMtg9ijXTkOJNhH1IbpRYhV1aA== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '90' + x-bt-brainstore-duration-ms: + - '78' + x-bt-internal-trace-id: + - cd13e05a7f60763bb13f40069b9de0ab + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "ge", "left": {"op": + "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": {"op": + "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + -1}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '918' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:54 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 e6bfe249d47d39a52673337cf444c9ce.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - Ll8T-5G1kKl6TotGSNB5vSN93tvfdlCf6vDSNr_2QCyhF1NIlhGobA== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '10471' + x-bt-api-duration-ms: + - '89' + x-bt-brainstore-duration-ms: + - '76' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - d79c92004e4a6441d003d693a8cb1a6d + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}, {"op": "ge", + "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": + {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + -1}}]}}, "use_columnstore": false, "brainstore_realtime": true, "query_source": + "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '927' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:54 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 21c66eb5f493a6e3ddbaa803cebfe014.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - lhzgFRySh9fF34rRaNY6xEETqJnCymTBIFVylSjTP-teiazG4IE2yw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '382' + x-bt-brainstore-duration-ms: + - '307' + x-bt-internal-trace-id: + - c72937714ae32a471844652b39a580d6 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}, {"op": "ge", "left": {"op": + "sub", "left": {"op": "ident", "name": ["metrics", "end"]}, "right": {"op": + "ident", "name": ["metrics", "start"]}}, "right": {"op": "literal", "value": + 5}}, {"op": "le", "left": {"op": "sub", "left": {"op": "ident", "name": ["metrics", + "end"]}, "right": {"op": "ident", "name": ["metrics", "start"]}}, "right": {"op": + "literal", "value": 2}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '1103' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:55 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 7293b56f3a0eb541aadcbcaa0146d528.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - zSBT3cBwuNr8u0UddFBheginJ_pGrgBuaTw0nBhbCdAExKk4qWsrUw== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '101' + x-bt-brainstore-duration-ms: + - '87' + x-bt-internal-trace-id: + - f3f769ab156674c9ecbbcc14b2afcc96 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "or", "children": + [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", "purpose"]}}, + {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", "purpose"]}, + "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": false, + "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '731' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840772","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"open","input":null,"is_root":false,"metadata":null,"metrics":{"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"open","type":"tool"},"span_id":"open","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840771","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"lookup","input":null,"is_root":false,"metadata":{"request":{}},"metrics":{"duration":0.5,"end":100.5,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"lookup","type":"llm"},"span_id":"lookup","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840768","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"span-filters-root","input":null,"is_root":true,"metadata":null,"metrics":null,"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"root","type":"task"},"span_id":"span-filters-root","span_parents":null,"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAA","realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:55 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 12aa3fefbdb5e80269e58f34f94a99e8.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - xekvHDh5X9-vuGgfCjbdEPt1ZyY6Lm0fufSejljXY48Rlna_ft2hYQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '12120' + x-bt-api-duration-ms: + - '102' + x-bt-brainstore-duration-ms: + - '89' + x-bt-cursor: + - aqK7CRArAAA + x-bt-internal-trace-id: + - 5e4b54ff5edea2b85b7ca8b78524bd01 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAA", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "or", "children": [{"op": "isnull", "expr": {"op": "ident", "name": ["span_attributes", + "purpose"]}}, {"op": "ne", "left": {"op": "ident", "name": ["span_attributes", + "purpose"]}, "right": {"op": "literal", "value": "scorer"}}]}]}}, "use_columnstore": + false, "brainstore_realtime": true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '740' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":{"type":"on","minimum_xact_id":null,"read_bytes":4012,"actual_xact_id":"1000197839408140331"},"freshness_state":{"last_processed_xact_id":"1000197839408140331","last_considered_xact_id":"1000197839408140331"},"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:55 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 3340b5a392e45fce453c4d978abfd6be.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - F0j9lOBjvrbLF12Hd7rbJIRdjSti2Yd42T9fv-k7GtM0W28wCsfpzg== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7777' + x-bt-api-duration-ms: + - '179' + x-bt-brainstore-duration-ms: + - '167' + x-bt-internal-trace-id: + - 5e7979fa4cd2eebfee4fe3f992f9b860 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": null, "limit": 1000, "filter": + {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": "span-filters-root"}}, {"op": "in", "left": + {"op": "ident", "name": ["span_attributes", "name"]}, "right": {"op": "literal", + "value": ["search"]}}]}}, "use_columnstore": false, "brainstore_realtime": true, + "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '619' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[{"_pagination_key":"p07683909561847840773","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"scorer","input":null,"is_root":false,"metadata":null,"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","purpose":"scorer","type":"score"},"span_id":"scorer","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840770","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":"failed","expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"failed","input":null,"is_root":false,"metadata":{"flag":1,"request":{"model":"test","region":"eu"}},"metrics":{"duration":5,"end":105,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"failed","span_parents":["span-filters-root"],"tags":null},{"_pagination_key":"p07683909561847840769","_xact_id":"1000197839408140331","audit_data":[{"_xact_id":"1000197839408140331","audit_data":{"action":"upsert"},"metadata":{},"source":"api"}],"classifications":null,"comments":null,"context":null,"created":"2026-09-10T14:13:29.469Z","error":null,"expected":null,"experiment_id":"ced0d1a7-b4aa-4694-9301-8d9a075bec90","facets":null,"id":"search","input":null,"is_root":false,"metadata":{"flag":true,"request":{"model":null,"region":"us"}},"metrics":{"duration":2,"end":102,"start":100},"origin":null,"output":null,"project_id":"2f3bb2d1-8360-47ec-89a9-7c7e10e22cff","root_span_id":"span-filters-root","scores":null,"span_attributes":{"created_by_api_key_id":"607d8072-e7a7-48d9-a326-de588dc07bf0","created_by_user_id":"c1f71e19-b3ce-4f59-89a9-055901f7755b","name":"search","type":"tool"},"span_id":"search","span_parents":["span-filters-root"],"tags":null}],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"cursor":"aqK7CRArAAE","realtime_state":null,"freshness_state":null,"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:55 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 a7af18c87ffc07d74544efce5f2b0f9c.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - Pnihdh_aAm5SAIglNMPQPXF7MvcuJJrAa4X7SAcohcHSsB28S7S17g== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '10299' + x-bt-api-duration-ms: + - '102' + x-bt-brainstore-duration-ms: + - '88' + x-bt-cursor: + - aqK7CRArAAE + x-bt-internal-trace-id: + - 26f78ff70415482cebd04d92dd1e6665 + status: + code: 200 + message: OK +- request: + body: '{"query": {"select": [{"op": "star"}], "from": {"op": "function", "name": + {"op": "ident", "name": ["experiment"]}, "args": [{"op": "literal", "value": + "ced0d1a7-b4aa-4694-9301-8d9a075bec90"}]}, "cursor": "aqK7CRArAAE", "limit": + 1000, "filter": {"op": "and", "children": [{"op": "eq", "left": {"op": "ident", + "name": ["root_span_id"]}, "right": {"op": "literal", "value": "span-filters-root"}}, + {"op": "in", "left": {"op": "ident", "name": ["span_attributes", "name"]}, "right": + {"op": "literal", "value": ["search"]}}]}}, "use_columnstore": false, "brainstore_realtime": + true, "query_source": "py_sdk_object_fetcher_experiment"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip + Connection: + - keep-alive + Content-Length: + - '628' + Content-Type: + - application/json + User-Agent: + - python-requests/2.34.2 + method: POST + uri: https://api.braintrust.dev/btql + response: + body: + string: '{"data":[],"schema":{"type":"array","items":{"type":"object","properties":{"_pagination_key":{"description":"A + stable, time-ordered key that can be used to paginate over experiment events. + This field is auto-generated by Braintrust and only exists in Brainstore.","type":["string","null"]},"_xact_id":{"description":"The + transaction id of an event is unique to the network operation that processed + the event insertion. Transaction ids are monotonically increasing over time + and can be used to retrieve a versioned snapshot of the experiment (see the + `version` parameter)","type":"string"},"audit_data":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"classifications":{"anyOf":[{"additionalProperties":{"items":{"additionalProperties":false,"properties":{"confidence":{"description":"Optional + confidence score for the classification","type":["number","null"]},"id":{"description":"Stable + classification identifier","type":"string"},"label":{"description":"Original + label of the classification item, which is useful for search and indexing + purposes","type":"string"},"metadata":{"anyOf":[{"additionalProperties":{},"type":"object"},{"type":"null"}],"description":"Optional + metadata associated with the classification"},"source":{"anyOf":[{"anyOf":[{"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"version":{"description":"The + version of the function","type":"string"}},"required":["type","id"],"type":"object"},{"additionalProperties":false,"properties":{"function_type":{"default":"scorer","description":"The + type of global function. Defaults to ''scorer''.","enum":["llm","scorer","task","tool","custom_view","preprocessor","facet","classifier","tag","parameters","sandbox"],"type":"string"},"name":{"type":"string"},"type":{"const":"global","type":"string"}},"required":["type","name"],"type":"object"}]},{"type":"null"}],"description":"Optional + function identifier that produced the classification"}},"required":["id"],"type":"object"},"type":"array"},"properties":{},"type":"object"},{"type":"null"}]},"comments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}]},"context":{"anyOf":[{"additionalProperties":{},"properties":{"caller_filename":{"description":"Name + of the file in code where the experiment event was created","type":["string","null"]},"caller_functionname":{"description":"The + function in code which created the experiment event","type":["string","null"]},"caller_lineno":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"created":{"description":"The + timestamp the experiment event was created","format":"date-time","type":"string"},"error":{"description":"The + error that occurred, if any."},"expected":{"description":"The ground truth + value (an arbitrary, JSON serializable object) that you''d compare to `output` + to determine if your `output` value is correct or not. Braintrust currently + does not compare `output` to `expected` for you, since there are so many different + ways to do that correctly. Instead, these values are just used to help you + navigate your experiments while digging into analyses. However, we may later + use these values to re-score outputs or fine-tune your models"},"experiment_id":{"description":"Unique + identifier for the experiment","format":"uuid","type":"string"},"facets":{"anyOf":[{"additionalProperties":{"type":["string","null"]},"properties":{},"type":"object"},{"type":"null"}]},"id":{"description":"A + unique identifier for the experiment event. If you don''t provide one, Braintrust + will generate one for you","type":"string"},"input":{"description":"The arguments + that uniquely define a test case (an arbitrary, JSON serializable object). + Later on, Braintrust will use the `input` to know whether two test cases are + the same between experiments, so they should not contain experiment-specific + state. A simple rule of thumb is that if you run the same experiment twice, + the `input` should be identical"},"is_root":{"description":"Whether this span + is a root span","type":["boolean","null"]},"metadata":{"anyOf":[{"additionalProperties":{},"properties":{"model":{"description":"The + model used for this example","type":["string","null"]}},"type":"object"},{"type":"null"}]},"metrics":{"anyOf":[{"additionalProperties":{"type":"number"},"properties":{"caller_filename":{"description":"This + metric is deprecated"},"caller_functionname":{"description":"This metric is + deprecated"},"caller_lineno":{"description":"This metric is deprecated"},"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"end":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event finished","type":["number","null"]},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"start":{"description":"A + unix timestamp recording when the section of code which produced the experiment + event started","type":["number","null"]},"tokens":{"anyOf":[{"type":"integer"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"origin":{"anyOf":[{"description":"Reference + to the original object and event this was copied from.","properties":{"_xact_id":{"description":"Transaction + ID of the original event.","type":["string","null"]},"created":{"description":"Created + timestamp of the original event. Used to help sort in the UI","type":["string","null"]},"id":{"description":"ID + of the original event.","type":"string"},"object_id":{"description":"ID of + the object the event is originating from.","format":"uuid","type":"string"},"object_type":{"description":"Type + of the object the event is originating from.","enum":["project_logs","experiment","dataset","prompt","function","prompt_session"],"type":"string"}},"required":["object_type","object_id","id"],"type":"object"},{"type":"null"}]},"output":{"description":"The + output of your application, including post-processing (an arbitrary, JSON + serializable object), that allows you to determine whether the result is correct + or not. For example, in an app that generates SQL queries, the `output` should + be the _result_ of the SQL query generated by the model, not the query itself, + because there may be multiple valid queries that answer a single question"},"project_id":{"description":"Unique + identifier for the project that the experiment belongs under","format":"uuid","type":"string"},"root_span_id":{"description":"A + unique identifier for the trace this experiment event belongs to","type":"string"},"scores":{"anyOf":[{"additionalProperties":{"anyOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"properties":{},"type":"object"},{"type":"null"}]},"span_attributes":{"anyOf":[{"additionalProperties":{},"description":"Human-identifying + attributes of the span, such as name, type, etc.","properties":{"name":{"description":"Name + of the span, for display purposes only","type":["string","null"]},"purpose":{"anyOf":[{"enum":["scorer"],"type":"string"},{"type":"null"}]},"type":{"anyOf":[{"enum":["llm","score","function","eval","task","tool","automation","facet","preprocessor","classifier","review","log"],"type":"string"},{"type":"null"}]}},"type":"object"},{"type":"null"}]},"span_id":{"description":"A + unique identifier used to link different experiment events together as part + of a full trace. See the [tracing guide](https://www.braintrust.dev/docs/instrument) + for full details on tracing","type":"string"},"span_parents":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}]}}}},"realtime_state":null,"freshness_state":null,"warnings":[]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id,x-bt-error-origin,x-bt-used-endpoint,x-bt-overflow-url + Cache-Control: + - private, no-cache + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Thu, 10 Sep 2026 14:13:56 GMT + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Origin + Via: + - 1.1 2ffb622580a0a24837f798fa62268b12.cloudfront.net (CloudFront) + X-Amz-Cf-Id: + - ppcRr_1OHE0Vb1lhUOLAeXtz3A3ZpqiRMtLOVFGV6yURj6r35aodHQ== + X-Amz-Cf-Pop: + - YTO50-P2 + X-Cache: + - Miss from cloudfront + content-length: + - '7596' + x-bt-api-duration-ms: + - '102' + x-bt-brainstore-duration-ms: + - '90' + x-bt-internal-trace-id: + - 70c4eabe47802735d67a3fc288c57832 + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/logger.py b/py/src/braintrust/logger.py index f5ffdb283..524dcb2ca 100644 --- a/py/src/braintrust/logger.py +++ b/py/src/braintrust/logger.py @@ -4886,6 +4886,9 @@ def log_internal(self, event: dict[str, Any] | None = None, internal_data: dict[ metadata=serializable_partial_record.get("metadata"), span_parents=self.span_parents, span_attributes=serializable_partial_record.get("span_attributes"), + error=serializable_partial_record.get("error"), + metrics=serializable_partial_record.get("metrics"), + tags=serializable_partial_record.get("tags"), ) self.state.span_cache.queue_write(self.root_span_id, self.span_id, cached_span) diff --git a/py/src/braintrust/span_cache.py b/py/src/braintrust/span_cache.py index ee9266142..734804415 100644 --- a/py/src/braintrust/span_cache.py +++ b/py/src/braintrust/span_cache.py @@ -14,7 +14,7 @@ from typing import Any from braintrust.types import Metadata -from braintrust.util import merge_dicts +from braintrust.util import clean_nones, merge_dicts # Global registry of active span caches for process exit cleanup @@ -23,7 +23,12 @@ class CachedSpan: - """Cached span data structure.""" + """A span held in the local cache, before it has been flushed to the server. + + Carries the subset of span fields that scorers can filter on, so that a trace can be + queried without a round-trip. Fields the server has but this does not are simply not + filterable locally. + """ def __init__( self, @@ -33,6 +38,9 @@ def __init__( metadata: Metadata | None = None, span_parents: list[str] | None = None, span_attributes: dict[str, Any] | None = None, + error: Any | None = None, + metrics: dict[str, Any] | None = None, + tags: list[str] | None = None, ): self.span_id = span_id self.input = input @@ -40,33 +48,26 @@ def __init__( self.metadata = metadata self.span_parents = span_parents self.span_attributes = span_attributes + self.error = error + self.metrics = metrics + self.tags = tags def to_dict(self) -> dict[str, Any]: - """Convert to dictionary for serialization.""" - result = {"span_id": self.span_id} - if self.input is not None: - result["input"] = self.input - if self.output is not None: - result["output"] = self.output - if self.metadata is not None: - result["metadata"] = self.metadata - if self.span_parents is not None: - result["span_parents"] = self.span_parents - if self.span_attributes is not None: - result["span_attributes"] = self.span_attributes - return result + """Return the span's set fields, dropping those left as None. + + Unset fields are omitted rather than written as null to keep the on-disk record + small; span_id is always present, so it survives the stripping. + """ + return clean_nones(self.__dict__) @classmethod def from_dict(cls, data: dict[str, Any]) -> "CachedSpan": - """Create from dictionary.""" - return cls( - span_id=data["span_id"], - input=data.get("input"), - output=data.get("output"), - metadata=data.get("metadata"), - span_parents=data.get("span_parents"), - span_attributes=data.get("span_attributes"), - ) + """Rebuild a span from a record produced by to_dict(). + + The cache file is written and read by one process, so `data` always has exactly the + fields this class defines and can be passed straight through. + """ + return cls(**data) class DiskSpanRecord: diff --git a/py/src/braintrust/test_span_cache.py b/py/src/braintrust/test_span_cache.py index 9b250d445..767d169ae 100644 --- a/py/src/braintrust/test_span_cache.py +++ b/py/src/braintrust/test_span_cache.py @@ -13,6 +13,9 @@ def test_span_cache_write_and_read(): span_id="span-1", input={"text": "hello"}, output={"response": "world"}, + error={"message": "retryable"}, + metrics={"start": 1, "end": 3}, + tags=["production"], ) span2 = CachedSpan( span_id="span-2", @@ -30,6 +33,10 @@ def test_span_cache_write_and_read(): span_ids = {s.span_id for s in spans} assert "span-1" in span_ids assert "span-2" in span_ids + stored_span1 = next(span for span in spans if span.span_id == "span-1") + assert stored_span1.error == {"message": "retryable"} + assert stored_span1.metrics == {"start": 1, "end": 3} + assert stored_span1.tags == ["production"] cache.stop() cache.dispose() diff --git a/py/src/braintrust/test_trace.py b/py/src/braintrust/test_trace.py index 3a572f68e..a16ae0420 100644 --- a/py/src/braintrust/test_trace.py +++ b/py/src/braintrust/test_trace.py @@ -1,20 +1,169 @@ """Tests for Trace functionality.""" +import os + +import braintrust import pytest -from braintrust.trace import CachedSpanFetcher, LocalTrace, SpanData, SpanFetcher +from braintrust.git_fields import GitMetadataSettings +from braintrust.logger import DATA_API_VERSION, BraintrustState +from braintrust.span_cache import CachedSpan +from braintrust.trace import ( + CachedSpanFetcher, + LocalTrace, + SpanData, + SpanFetcher, + _matches_span_filters, + _normalize_span_filters, +) + + +@pytest.mark.vcr(match_on=["method", "scheme", "host", "port", "path", "query", "body"]) +@pytest.mark.asyncio +async def test_span_filters_backend_parity(vcr_cassette): + state = BraintrustState() + experiment = braintrust.init( + project="python-sdk-vcr-tests", + experiment="span-filters-backend-parity-v2", + update=True, + api_key=os.environ.get("BRAINTRUST_API_KEY", "sk-dummy-for-vcr-replay"), + git_metadata_settings=GitMetadataSettings(collect="none"), + state=state, + set_current=False, + ) + experiment._get_state() + root = "span-filters-root" + spans = [ + SpanData(span_id=root, span_attributes={"name": "root", "type": "task"}), + SpanData( + span_id="search", + span_attributes={"name": "search", "type": "tool"}, + metrics={"start": 100, "end": 102}, + metadata={"request": {"region": "us", "model": None}, "flag": True}, + ), + SpanData( + span_id="failed", + span_attributes={"name": "search", "type": "tool"}, + error="failed", + metrics={"start": 100, "end": 105}, + metadata={"request": {"region": "eu", "model": "test"}, "flag": 1}, + ), + SpanData( + span_id="lookup", + span_attributes={"name": "lookup", "type": "llm"}, + error="", + metrics={"start": 100, "end": 100.5}, + metadata={"request": {}}, + ), + SpanData(span_id="open", span_attributes={"name": "open", "type": "tool"}, metrics={"start": 100}), + SpanData( + span_id="scorer", + span_attributes={"name": "search", "type": "score", "purpose": "scorer"}, + metrics={"start": 100, "end": 102}, + ), + ] + rows = [ + dict( + span.to_dict(), + id=span.span_id, + root_span_id=root, + experiment_id=experiment.id, + span_parents=[] if span.span_id == root else [root], + ) + for span in spans + ] + state.api_conn().post("/logs3", json={"rows": rows, "api_version": DATA_API_VERSION}).raise_for_status() + async def get_state(): + return state -# Helper to create mock spans -def make_span(span_id: str, span_type: str, **extra) -> SpanData: + remote = CachedSpanFetcher( + object_type="experiment", object_id=experiment.id, root_span_id=root, get_state=get_state + ) + cases = [ + ({"span_type": ["tool"]}, {"search", "failed", "open"}), + ({"name": ["search", "lookup"]}, {"search", "failed", "lookup"}), + ({"has_error": True}, {"failed", "lookup"}), + ({"has_error": False}, {root, "search", "open"}), + ({"metadata": {"request": {"region": "us"}}}, {"search"}), + ({"metadata": {"request": {"model": None}}}, {root, "search", "lookup", "open"}), + ({"metadata": {"flag": True}}, {"search"}), + ({"metadata": {"flag": 1}}, {"failed"}), + ({"duration": {"min": 2, "max": 5}}, {"search", "failed"}), + ({"duration": {"max": 0.5}}, {"lookup"}), + ({"name": ["search"], "has_error": False, "duration": {"min": 2, "max": 2}}, {"search"}), + ({"name": []}, set()), + ({"span_type": []}, set()), + ({"metadata": {}}, {root, "search", "failed", "lookup", "open"}), + ({"metadata": {"request": {}}}, {root, "search", "failed", "lookup", "open"}), + ({"duration": {}}, {root, "search", "failed", "lookup", "open"}), + ({"duration": {"min": -1}}, {"search", "failed", "lookup"}), + ({"duration": {"min": 5, "max": 2}}, set()), + ] + # Fetch each filter before populating the complete remote cache. + backend_results = [await remote.get_spans(filters=filters) for filters, _ in cases] + await remote.get_spans() + local = LocalTrace("experiment", experiment.id, root, None, state) + state.span_cache.start() + try: + for span in spans: + state.span_cache.queue_write(root, span.span_id, CachedSpan.from_dict(span.to_dict())) + + request_count = (len(vcr_cassette.requests), vcr_cassette.play_count) + for (filters, expected), backend in zip(cases, backend_results): + assert {span.span_id for span in backend} == expected, filters + assert {span.span_id for span in await remote.get_spans(filters=filters)} == expected, filters + assert {span.span_id for span in await local.get_spans(filters=filters)} == expected, filters + assert { + span.span_id for span in await local.get_spans(filters={"name": ["search"]}, include_scorers=True) + } == {"search", "failed", "scorer"} + assert (len(vcr_cassette.requests), vcr_cassette.play_count) == request_count + finally: + state.span_cache.stop() + state.span_cache.dispose() + assert {span.span_id for span in await remote.get_spans(filters={"name": ["search"]}, include_scorers=True)} == { + "search", + "failed", + "scorer", + } + + +# Helper to create span data +def make_span(span_id: str, span_type: str, *, name: str | None = None, **extra) -> SpanData: + span_attributes = {"type": span_type} + if name is not None: + span_attributes["name"] = name return SpanData( span_id=span_id, input={"text": f"input-{span_id}"}, output={"text": f"output-{span_id}"}, - span_attributes={"type": span_type}, + span_attributes=span_attributes, **extra, ) +@pytest.mark.parametrize( + ("metadata", "expected"), + [ + (None, True), + ({}, True), + ({"request": None}, True), + ({"request": {}}, True), + ({"request": {"model": None}}, True), + ({"request": {"model": "gpt-5"}}, False), + ], +) +def test_null_metadata_filter_matches_missing_paths(metadata, expected): + filters = _normalize_span_filters({"metadata": {"request": {"model": None}}}) + assert _matches_span_filters(SpanData(metadata=metadata), filters) is expected + assert not _matches_span_filters(SpanData(metadata=metadata), {"metadata": {"request": {"model": "other"}}}) + + +@pytest.mark.parametrize("actual, expected", [(True, 1), (1, True), ([True], [1]), ([{"flag": True}], [{"flag": 1}])]) +def test_metadata_filters_do_not_coerce_booleans(actual, expected): + assert not _matches_span_filters(SpanData(metadata={"value": actual}), {"metadata": {"value": expected}}) + assert _matches_span_filters(SpanData(metadata={"value": actual}), {"metadata": {"value": actual}}) + + class TestCachedSpanFetcher: """Test CachedSpanFetcher caching behavior.""" @@ -29,7 +178,7 @@ async def test_fetch_all_spans_without_filter(self): call_count = 0 - async def fetch_fn(span_type): + async def fetch_fn(filters): nonlocal call_count call_count += 1 return mock_spans @@ -50,47 +199,30 @@ async def test_fetch_all_after_typed_fetch_has_no_duplicates(self): make_span("llm-2", "llm"), ] - async def fetch_fn(span_type): + async def fetch_fn(filters): + span_type = filters.get("span_type") if span_type: return [s for s in all_spans if s.span_attributes["type"] in span_type] return all_spans fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - await fetcher.get_spans(["llm"]) + await fetcher.get_spans(filters={"span_type": ["llm"]}) result = await fetcher.get_spans() span_ids = [s.span_id for s in result] assert sorted(span_ids) == ["fn-1", "llm-1", "llm-2"] assert len(span_ids) == len(set(span_ids)), f"duplicate spans: {span_ids}" - @pytest.mark.asyncio - async def test_fetch_preserves_span_result_fields(self): - """Test that fetched spans preserve fields needed for full trace attachments.""" - mock_spans = [ - make_span( - "span-1", - "tool", - expected={"answer": "ok"}, - error={"message": "boom"}, - metrics={"start": 1, "end": 2}, - scores={"quality": 0}, - tags=["debug"], - ) - ] - - async def fetch_fn(span_type): - del span_type - return mock_spans - - fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - result = await fetcher.get_spans() - - assert result[0].expected == {"answer": "ok"} - assert result[0].error == {"message": "boom"} - assert result[0].metrics == {"start": 1, "end": 2} - assert result[0].scores == {"quality": 0} - assert result[0].tags == ["debug"] - assert result[0].to_dict()["error"] == {"message": "boom"} + def test_span_data_roundtrip(self): + row = { + "span_id": "tool-span", + "expected": {"answer": "ok"}, + "error": "boom", + "metrics": {"start": 1, "end": 2}, + "scores": {"quality": 0}, + "tags": ["debug"], + } + assert SpanData.from_dict(row).to_dict() == row @pytest.mark.asyncio async def test_fetch_specific_span_types(self): @@ -99,167 +231,74 @@ async def test_fetch_specific_span_types(self): call_count = 0 - async def fetch_fn(span_type): + async def fetch_fn(filters): nonlocal call_count call_count += 1 - assert span_type == ["llm"] + assert filters == {"span_type": ["llm"]} return llm_spans fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - result = await fetcher.get_spans(span_type=["llm"]) + result = await fetcher.get_spans(filters={"span_type": ["llm"]}) assert call_count == 1 assert len(result) == 2 + @pytest.mark.parametrize( + ("span_type", "expected_ids"), + [ + (None, ["span-1", "span-2", "span-3", "span-4"]), + (["llm"], ["span-1", "span-4"]), + (["llm", "tool"], ["span-1", "span-3", "span-4"]), + (["nonexistent"], []), + ], + ) @pytest.mark.asyncio - async def test_return_cached_spans_after_fetching_all(self): - """Test that cached spans are returned without re-fetching after fetching all.""" - mock_spans = [ - make_span("span-1", "llm"), - make_span("span-2", "function"), - ] - - call_count = 0 - - async def fetch_fn(span_type): - nonlocal call_count - call_count += 1 - return mock_spans - - fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - - # First call - fetches - await fetcher.get_spans() - assert call_count == 1 - - # Second call - should use cache - result = await fetcher.get_spans() - assert call_count == 1 # Still 1 - assert len(result) == 2 - - @pytest.mark.asyncio - async def test_return_cached_spans_for_previously_fetched_types(self): - """Test that previously fetched types are returned from cache.""" - llm_spans = [make_span("span-1", "llm"), make_span("span-2", "llm")] - - call_count = 0 - - async def fetch_fn(span_type): - nonlocal call_count - call_count += 1 - return llm_spans - - fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - - # First call - fetches llm spans - await fetcher.get_spans(span_type=["llm"]) - assert call_count == 1 - - # Second call for same type - should use cache - result = await fetcher.get_spans(span_type=["llm"]) - assert call_count == 1 # Still 1 - assert len(result) == 2 - - @pytest.mark.asyncio - async def test_only_fetch_missing_span_types(self): - """Test that only missing span types are fetched.""" - llm_spans = [make_span("span-1", "llm")] - function_spans = [make_span("span-2", "function")] - - call_count = 0 - - async def fetch_fn(span_type): - nonlocal call_count - call_count += 1 - if span_type == ["llm"]: - return llm_spans - elif span_type == ["function"]: - return function_spans - return [] - - fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - - # First call - fetches llm spans - await fetcher.get_spans(span_type=["llm"]) - assert call_count == 1 + async def test_full_cache_answers_any_span_type_query(self, span_type, expected_ids): + """One unfiltered fetch makes the cache authoritative for every span type. - # Second call for both types - should only fetch function - result = await fetcher.get_spans(span_type=["llm", "function"]) - assert call_count == 2 - assert len(result) == 2 - - @pytest.mark.asyncio - async def test_no_refetch_after_fetching_all_spans(self): - """Test that no re-fetching occurs after fetching all spans.""" + Including types that turn out to be absent: an empty result is a real answer here, + not a cache miss to be retried against the server. + """ all_spans = [ make_span("span-1", "llm"), make_span("span-2", "function"), make_span("span-3", "tool"), + make_span("span-4", "llm"), ] - call_count = 0 - async def fetch_fn(span_type): + async def fetch_fn(filters): nonlocal call_count call_count += 1 return all_spans fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - - # Fetch all spans await fetcher.get_spans() - assert call_count == 1 - - # Subsequent filtered calls should use cache - llm_result = await fetcher.get_spans(span_type=["llm"]) - assert call_count == 1 # Still 1 - assert len(llm_result) == 1 - assert llm_result[0].span_id == "span-1" - function_result = await fetcher.get_spans(span_type=["function"]) - assert call_count == 1 # Still 1 - assert len(function_result) == 1 - assert function_result[0].span_id == "span-2" + result = await fetcher.get_spans(filters={"span_type": span_type} if span_type else None) - @pytest.mark.asyncio - async def test_filter_by_multiple_span_types_from_cache(self): - """Test filtering by multiple span types from cache.""" - all_spans = [ - make_span("span-1", "llm"), - make_span("span-2", "function"), - make_span("span-3", "tool"), - make_span("span-4", "llm"), - ] - - async def fetch_fn(span_type): - return all_spans - - fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - - # Fetch all first - await fetcher.get_spans() - - # Filter for llm and tool - result = await fetcher.get_spans(span_type=["llm", "tool"]) - assert len(result) == 3 - assert {s.span_id for s in result} == {"span-1", "span-3", "span-4"} + assert call_count == 1 + assert sorted(span.span_id for span in result) == expected_ids @pytest.mark.asyncio - async def test_return_empty_for_nonexistent_span_type(self): - """Test that empty array is returned for non-existent span type.""" - all_spans = [make_span("span-1", "llm")] + async def test_partial_cache_fetches_only_missing_types(self): + """A type already in the cache is never re-requested, only the types missing from it.""" + by_type = {"llm": [make_span("span-1", "llm")], "function": [make_span("span-2", "function")]} + requested = [] - async def fetch_fn(span_type): - return all_spans + async def fetch_fn(filters): + requested.append(filters["span_type"]) + return [span for t in filters["span_type"] for span in by_type.get(t, [])] fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - # Fetch all first - await fetcher.get_spans() + assert [s.span_id for s in await fetcher.get_spans(filters={"span_type": ["llm"]})] == ["span-1"] + assert [s.span_id for s in await fetcher.get_spans(filters={"span_type": ["llm"]})] == ["span-1"] + result = await fetcher.get_spans(filters={"span_type": ["llm", "function"]}) - # Query for non-existent type - result = await fetcher.get_spans(span_type=["nonexistent"]) - assert len(result) == 0 + assert sorted(span.span_id for span in result) == ["span-1", "span-2"] + # The second call was served from cache; the third asked only for what it lacked. + assert requested == [["llm"], ["function"]] @pytest.mark.asyncio async def test_handle_spans_with_no_type(self): @@ -270,7 +309,7 @@ async def test_handle_spans_with_no_type(self): SpanData(span_id="span-3", input={}), # No span_attributes ] - async def fetch_fn(span_type): + async def fetch_fn(filters): return spans fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) @@ -280,75 +319,77 @@ async def fetch_fn(span_type): assert len(result) == 3 # Spans without type go into "" bucket - no_type_result = await fetcher.get_spans(span_type=[""]) + no_type_result = await fetcher.get_spans(filters={"span_type": [""]}) assert len(no_type_result) == 2 + @pytest.mark.parametrize("filters", [None, {"span_type": ["llm"]}]) @pytest.mark.asyncio - async def test_empty_then_populated_refetches(self): - """Test that empty results don't permanently cache, allowing re-fetch when data becomes available.""" - call_count = 0 - spans = [make_span("span-1", "llm"), make_span("span-2", "function")] + async def test_empty_results_are_not_cached(self, filters): + """An empty fetch caches nothing, so spans logged later are still picked up. - async def fetch_fn(span_type): - nonlocal call_count - call_count += 1 - if call_count == 1: - return [] - return spans - - fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - - # First call returns empty - result1 = await fetcher.get_spans() - assert len(result1) == 0 - assert call_count == 1 - - # Second call should re-fetch since first was empty - result2 = await fetcher.get_spans() - assert call_count == 2 - assert len(result2) == 2 - assert {s.span_id for s in result2} == {"span-1", "span-2"} - - @pytest.mark.asyncio - async def test_empty_results_with_type_filter(self): - """Test that type-filtered fetches handle empty results correctly.""" + The cache records which types it holds by the spans it saw, so a fetch that returned + nothing leaves no trace and the next call goes back to the server. + """ call_count = 0 - async def fetch_fn(span_type): + async def fetch_fn(_filters): nonlocal call_count call_count += 1 - if call_count == 1: - return [] - return [make_span("span-1", "llm")] + return [] if call_count == 1 else [make_span("span-1", "llm")] fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) - # First call with type filter returns empty - result1 = await fetcher.get_spans(span_type=["llm"]) - assert len(result1) == 0 - - # Second call with same type should re-fetch since type wasn't cached with results - result2 = await fetcher.get_spans(span_type=["llm"]) + assert await fetcher.get_spans(filters=filters) == [] + assert [span.span_id for span in await fetcher.get_spans(filters=filters)] == ["span-1"] assert call_count == 2 - assert len(result2) == 1 @pytest.mark.asyncio - async def test_handle_empty_span_type_array(self): - """Test that empty spanType array is handled same as undefined.""" - mock_spans = [make_span("span-1", "llm")] + async def test_advanced_filters_are_pushed_down_and_never_cached(self): + """Filters the cache cannot reason about go to the fetcher whole, every time. - call_args = [] + The cache is partitioned by span type alone, so it cannot tell whether it holds + every span matching some other field. Rather than guess, these queries are pushed + down in full and their results are used once and discarded. + """ + spans = [ + make_span("errored", "tool", name="search", error={"message": "boom"}), + make_span("successful", "tool", name="search"), + ] + received = [] - async def fetch_fn(span_type): - call_args.append(span_type) - return mock_spans + async def fetch_fn(filters): + received.append(filters) + return [span for span in spans if _matches_span_filters(span, filters)] fetcher = CachedSpanFetcher(fetch_fn=fetch_fn) + filters = {"span_type": ["tool"], "has_error": True} + + first = await fetcher.get_spans(filters=filters) + second = await fetcher.get_spans(filters=filters) - result = await fetcher.get_spans(span_type=[]) + # Handed down whole, returned unchanged (no second, client-side filtering pass), + # and re-fetched rather than served from the first call's results. + assert received == [filters, filters] + assert [span.span_id for span in first] == ["errored"] + assert [span.span_id for span in second] == ["errored"] - assert call_args[0] is None or call_args[0] == [] - assert len(result) == 1 + @pytest.mark.parametrize( + ("filters", "message"), + [ + ({"span_type": "tool"}, "span_type"), + ({"name": [1]}, "name"), + ({"has_error": "yes"}, "has_error"), + ({"metadata": []}, "metadata"), + ({"metadata": {1: "value"}}, "metadata"), + ({"duration": {"min": "slow"}}, "duration"), + ({"duration": {"min": float("nan")}}, "duration"), + ({"duration": {"minimum": 1}}, "duration"), + ({"unknown": True}, "Unsupported"), + ], + ) + def test_rejects_invalid_advanced_filters(self, filters, message): + with pytest.raises(ValueError, match=message): + _normalize_span_filters(filters) @pytest.mark.parametrize( ("brainstore_realtime", "expected"), @@ -393,14 +434,34 @@ async def get_state(): assert calls[0]["json"]["brainstore_realtime"] is False -class _DummySpanCache: - def get_by_root_span_id(self, root_span_id: str): - return None +@pytest.mark.asyncio +@pytest.mark.filterwarnings("error::DeprecationWarning") +async def test_span_type_argument_compatibility(): + state = BraintrustState() + state.span_cache.start() + try: + for span_id, span_type in (("tool", "tool"), ("llm", "llm")): + state.span_cache.queue_write( + "root", span_id, CachedSpan(span_id=span_id, span_attributes={"type": span_type}) + ) + trace = LocalTrace("experiment", "experiment", "root", None, state) + for filters in (None, {}): + assert {span.span_id for span in await trace.get_spans(filters=filters)} == {"tool", "llm"} + assert {span.span_id for span in await trace.get_spans(span_type=[])} == {"tool", "llm"} + assert [span.span_id for span in await trace.get_spans(["tool"])] == ["tool"] + assert [span.span_id for span in await trace.get_spans(span_type=["llm"], filters={"has_error": False})] == [ + "llm" + ] + assert await trace.get_spans(filters={"span_type": []}) == [] + with pytest.raises(ValueError, match="span_type"): + await trace.get_spans(["tool"], filters={"span_type": ["llm"]}) + finally: + state.span_cache.stop() + state.span_cache.dispose() class _DummyState: def __init__(self, api_calls=None): - self.span_cache = _DummySpanCache() self.api_calls = api_calls def login(self): diff --git a/py/src/braintrust/trace.py b/py/src/braintrust/trace.py index b72b8d621..cdcb6455a 100644 --- a/py/src/braintrust/trace.py +++ b/py/src/braintrust/trace.py @@ -6,16 +6,181 @@ """ import asyncio -from collections.abc import Awaitable, Callable -from typing import Any, Protocol, TypedDict +import math +from collections.abc import Awaitable, Callable, Mapping +from typing import Any, Protocol, TypedDict, cast from braintrust.functions.invoke import invoke from braintrust.logger import BraintrustState, ObjectFetcher from braintrust.types import Metadata +from braintrust.util import clean_nones + + +class SpanDurationFilter(TypedDict, total=False): + """Inclusive duration bounds, in seconds.""" + + min: float + """Minimum value of metrics.end - metrics.start.""" + max: float + """Maximum value of metrics.end - metrics.start.""" + + +class SpanFilters(TypedDict, total=False): + """Filters supported by Trace.get_spans(). Different fields combine with AND. + + Empty name/span_type lists match no spans. Empty metadata/duration objects + add no constraints. Omit a field to leave it unfiltered. + """ + + span_type: list[str] + """Match spans whose span_attributes.type equals any of these.""" + name: list[str] + """Match spans whose span_attributes.name equals any of these.""" + has_error: bool + """True to keep only spans that recorded an error, False to keep only those that did not.""" + metadata: dict[str, Any] + """Match named metadata keys at any depth without type coercion. None matches null or missing paths.""" + duration: SpanDurationFilter + """Bound how long the span took, inclusive, in seconds.""" + + +def _metadata_leaves(metadata: Mapping[str, Any], path: tuple[str, ...] = ()) -> list[tuple[tuple[str, ...], Any]]: + """Flatten a partial metadata object into paths shared by local and BTQL matching.""" + leaves = [] + for key, value in metadata.items(): + if not isinstance(key, str): + raise ValueError("filters.metadata keys must be strings") + child_path = (*path, key) + if isinstance(value, Mapping): + leaves.extend(_metadata_leaves(value, child_path)) + else: + leaves.append((child_path, value)) + return leaves + + +def _normalize_span_filters(filters: Any, span_type: list[str] | None = None) -> SpanFilters: + """Check shapes needed by both execution paths and fold in the top-level span_type.""" + if filters is not None and not isinstance(filters, Mapping): + raise ValueError("filters must be an object") + values = dict(filters or {}) + if span_type is not None: + if "span_type" in values: + raise ValueError("span_type cannot be provided both directly and in filters") + # Preserve the original API's span_type=[] meaning of no constraint. + if span_type: + values["span_type"] = span_type + if set(values) - SpanFilters.__annotations__.keys(): + raise ValueError("Unsupported span filter fields") + for field in ("span_type", "name"): + if field in values: + items = values[field] + if not isinstance(items, list) or not all(isinstance(item, str) for item in items): + raise ValueError(f"filters.{field} must be a list of strings") + if "has_error" in values and not isinstance(values["has_error"], bool): + raise ValueError("filters.has_error must be a boolean") + if "metadata" in values: + if not isinstance(values["metadata"], Mapping): + raise ValueError("filters.metadata must be an object") + _metadata_leaves(values["metadata"]) + if "duration" in values: + bounds = values["duration"] + if not isinstance(bounds, Mapping) or set(bounds) - {"min", "max"}: + raise ValueError("filters.duration must be an object with min and/or max") + if any(not _is_finite_number(value) for value in bounds.values()): + raise ValueError("filters.duration bounds must be finite numbers") + return cast(SpanFilters, values) + + +def _is_finite_number(value: Any) -> bool: + return isinstance(value, (int, float)) and not isinstance(value, bool) and math.isfinite(value) + + +def _metadata_equal(actual: Any, expected: Any) -> bool: + """JSON equality without Python's bool/number coercion, including inside arrays.""" + if isinstance(actual, bool) != isinstance(expected, bool): + return False + if isinstance(expected, list): + return ( + isinstance(actual, list) + and len(actual) == len(expected) + and all(_metadata_equal(a, e) for a, e in zip(actual, expected)) + ) + if isinstance(expected, Mapping): + return ( + isinstance(actual, Mapping) + and actual.keys() == expected.keys() + and all(_metadata_equal(actual[key], value) for key, value in expected.items()) + ) + return actual == expected + + +def _matches_span_filters(span: Any, filters: SpanFilters) -> bool: + attributes = span.span_attributes or {} + for field, attribute in (("span_type", "type"), ("name", "name")): + if field in filters and attributes.get(attribute) not in filters[field]: + return False + if "has_error" in filters and (span.error is not None) != filters["has_error"]: + return False + for path, expected in _metadata_leaves(filters.get("metadata", {})): + actual = span.metadata + for key in path: + actual = actual.get(key) if isinstance(actual, Mapping) else None + if not _metadata_equal(actual, expected): + return False + if bounds := filters.get("duration"): + metrics = span.metrics or {} + start, end = metrics.get("start"), metrics.get("end") + if not _is_finite_number(start) or not _is_finite_number(end): + return False + elapsed = end - start + if "min" in bounds and elapsed < bounds["min"]: + return False + if "max" in bounds and elapsed > bounds["max"]: + return False + return True + + +def _btql_cmp(op: str, name: list[str], value: Any) -> dict[str, Any]: + return {"op": op, "left": {"op": "ident", "name": name}, "right": {"op": "literal", "value": value}} + + +def _btql_null_check(op: str, name: list[str]) -> dict[str, Any]: + return {"op": op, "expr": {"op": "ident", "name": name}} + + +def _span_filter_clauses(filters: SpanFilters) -> list[dict[str, Any]]: + children = [] + for field, attribute in (("span_type", "type"), ("name", "name")): + if field in filters: + # BTQL rejects IN []; an empty set of alternatives is always false. + children.append( + _btql_cmp("in", ["span_attributes", attribute], filters[field]) + if filters[field] + else {"op": "literal", "value": False} + ) + if "has_error" in filters: + children.append(_btql_null_check("isnotnull" if filters["has_error"] else "isnull", ["error"])) + for path, value in _metadata_leaves(filters.get("metadata", {})): + name = ["metadata", *path] + children.append(_btql_null_check("isnull", name) if value is None else _btql_cmp("eq", name, value)) + elapsed = { + "op": "sub", + "left": {"op": "ident", "name": ["metrics", "end"]}, + "right": {"op": "ident", "name": ["metrics", "start"]}, + } + bounds = filters.get("duration", {}) + for bound, op in (("min", "ge"), ("max", "le")): + if bound in bounds: + children.append({"op": op, "left": elapsed, "right": {"op": "literal", "value": bounds[bound]}}) + return children class SpanData: - """Span data returned by get_spans().""" + """One span, as returned by get_spans(). + + Fields mirror the span columns; anything the server sends that is not named explicitly + is still kept, as an attribute, so a newer backend does not lose data on the way through. + """ def __init__( self, @@ -49,16 +214,12 @@ def __init__( @classmethod def from_dict(cls, data: dict[str, Any]) -> "SpanData": - """Create SpanData from a dictionary.""" + """Build a span from a row, keeping columns this class does not name.""" return cls(**data) def to_dict(self) -> dict[str, Any]: - """Convert to dictionary.""" - result = {} - for key, value in self.__dict__.items(): - if value is not None: - result[key] = value - return result + """Return the span's set fields, dropping those left as None.""" + return clean_nones(self.__dict__) class SpanFetcher(ObjectFetcher[dict[str, Any]]): @@ -73,12 +234,12 @@ def __init__( object_id: str, root_span_id: str, state: BraintrustState, - span_type_filter: list[str] | None = None, include_scorers: bool = False, brainstore_realtime: bool = True, + filters: SpanFilters | None = None, ): - # Build the filter expression for root_span_id and optionally span_attributes.type - filter_expr = self._build_filter(root_span_id, span_type_filter, include_scorers) + # `filters` is expected to already be normalized by _normalize_span_filters. + filter_expr = self._build_filter(root_span_id, filters, include_scorers) super().__init__( object_type=object_type, @@ -91,52 +252,26 @@ def __init__( @staticmethod def _build_filter( root_span_id: str, - span_type_filter: list[str] | None = None, + filters: SpanFilters | None = None, include_scorers: bool = False, ) -> dict[str, Any]: - """Build BTQL filter expression.""" - children = [ - # Base filter: root_span_id = 'value' - { - "op": "eq", - "left": {"op": "ident", "name": ["root_span_id"]}, - "right": {"op": "literal", "value": root_span_id}, - }, - ] + """Combine trace identity, scorer exclusion, and span filters with AND.""" + # Scorer exclusion is a fetch mode rather than a SpanFilters field, so it stays here. + purpose = ["span_attributes", "purpose"] + children: list[dict[str, Any]] = [_btql_cmp("eq", ["root_span_id"], root_span_id)] if not include_scorers: children.append( { "op": "or", "children": [ - { - "op": "isnull", - "expr": { - "op": "ident", - "name": ["span_attributes", "purpose"], - }, - }, - { - "op": "ne", - "left": { - "op": "ident", - "name": ["span_attributes", "purpose"], - }, - "right": {"op": "literal", "value": "scorer"}, - }, + _btql_null_check("isnull", purpose), + _btql_cmp("ne", purpose, "scorer"), ], } ) - # If span type filter specified, add it - if span_type_filter and len(span_type_filter) > 0: - children.append( - { - "op": "in", - "left": {"op": "ident", "name": ["span_attributes", "type"]}, - "right": {"op": "literal", "value": span_type_filter}, - } - ) + children.extend(_span_filter_clauses(filters or {})) return {"op": "and", "children": children} @@ -148,8 +283,8 @@ def _get_state(self) -> BraintrustState: return self._state -SpanFetchFn = Callable[[list[str] | None], Awaitable[list[SpanData]]] -SpanFetchWithOptionsFn = Callable[[list[str] | None, bool], Awaitable[list[SpanData]]] +SpanFetchFn = Callable[[SpanFilters], Awaitable[list[SpanData]]] +SpanFetchWithOptionsFn = Callable[[SpanFilters, bool], Awaitable[list[SpanData]]] class GetThreadOptions(TypedDict, total=False): @@ -158,12 +293,14 @@ class GetThreadOptions(TypedDict, total=False): class CachedSpanFetcher: """ - Cached span fetcher that handles fetching and caching spans by type. - - Caching strategy: - - Cache spans by span type (dict[spanType, list[SpanData]]) - - Track if all spans have been fetched (all_fetched flag) - - When filtering by spanType, only fetch types not already in cache + Fetches spans for one root span, reusing what it has already seen. + + The cache is keyed by span type, plus a flag for whether an unfiltered fetch has + happened. That shape is what makes it useful and also what bounds it: it can answer a + span_type query offline, because it knows it holds every span of the types it has + fetched, but it cannot answer a query on any other field, because a partial result set + says nothing about the spans it never asked for. Those queries go to the server every + time and their results are used once rather than cached. """ def __init__( @@ -179,13 +316,14 @@ def __init__( self._all_fetched = False if fetch_fn is not None: - # Direct fetch function injection (for testing) + # Direct fetch function injection (for testing). Like the server, the injected + # function is responsible for honoring every filter it is given. async def _fetch_fn( - span_type: list[str] | None, + filters: SpanFilters, include_scorers: bool = False, ) -> list[SpanData]: del include_scorers - return await fetch_fn(span_type) + return await fetch_fn(filters) self._fetch_fn: SpanFetchWithOptionsFn = _fetch_fn else: @@ -196,7 +334,7 @@ async def _fetch_fn( ) async def _fetch_fn( - span_type: list[str] | None, + filters: SpanFilters, include_scorers: bool = False, ) -> list[SpanData]: state = await get_state() @@ -205,61 +343,56 @@ async def _fetch_fn( object_id=object_id, root_span_id=root_span_id, state=state, - span_type_filter=span_type, include_scorers=include_scorers, brainstore_realtime=brainstore_realtime, + filters=filters, ) - rows = list(fetcher.fetch()) - return [ - SpanData( - input=row.get("input"), - output=row.get("output"), - expected=row.get("expected"), - error=row.get("error"), - scores=row.get("scores"), - metrics=row.get("metrics"), - metadata=row.get("metadata"), - span_id=row.get("span_id"), - span_parents=row.get("span_parents"), - span_attributes=row.get("span_attributes"), - id=row.get("id"), - _xact_id=row.get("_xact_id"), - _pagination_key=row.get("_pagination_key"), - root_span_id=row.get("root_span_id"), - is_root=row.get("is_root"), - created=row.get("created"), - tags=row.get("tags"), - ) - for row in rows - ] + spans = [SpanData.from_dict(row) for row in fetcher.fetch()] + # Backend comparisons can coerce metadata types. Keep the same exact + # matching as the local cache while still pushing filters down. + if filters.get("metadata"): + spans = [span for span in spans if _matches_span_filters(span, filters)] + return spans self._fetch_fn = _fetch_fn async def get_spans( self, - span_type: list[str] | None = None, *, + filters: SpanFilters | None = None, include_scorers: bool = False, ) -> list[SpanData]: """ - Get spans, using cache when possible. + Get spans, using the cache where it can answer the query. Args: - span_type: Optional list of span types to filter by + filters: Optional filters for span type, name, error state, metadata, and duration include_scorers: Include spans with span_attributes.purpose = "scorer" Returns: List of matching spans """ + filters = _normalize_span_filters(filters) + span_type = filters.get("span_type") + # A partial cache is only authoritative for the fields it partitions on. + has_advanced_filters = any(field != "span_type" for field in filters) + if span_type == []: + return [] + if include_scorers: - return await self._fetch_fn(span_type, True) + return await self._fetch_fn(filters, True) - # If we've fetched all spans, just filter from cache + # A complete cache can answer every supported filter locally. if self._all_fetched: - return self._get_from_cache(span_type) + spans = self._get_from_cache(span_type) + return [span for span in spans if _matches_span_filters(span, filters)] if has_advanced_filters else spans - # If no filter requested, fetch everything - if not span_type or len(span_type) == 0: + # Arbitrary filtered results are not authoritative for their span type. + if has_advanced_filters: + return await self._fetch_fn(filters, False) + + # If no filter requested, fetch everything. + if not span_type: # A full fetch is authoritative; reset the per-type cache first so a # prior typed fetch's spans are not duplicated by re-fetching them # (_fetch_spans appends). @@ -269,20 +402,19 @@ async def get_spans( self._all_fetched = True return self._get_from_cache(None) - # Find which spanTypes we don't have in cache yet + # Find which span types we don't have in cache yet. missing_types = [t for t in span_type if t not in self._span_cache] - - # If all requested types are cached, return from cache - if not missing_types: - return self._get_from_cache(span_type) - - # Fetch only the missing types - await self._fetch_spans(missing_types) + if missing_types: + await self._fetch_spans(missing_types) return self._get_from_cache(span_type) async def _fetch_spans(self, span_type: list[str] | None) -> None: - """Fetch spans from the server.""" - spans = await self._fetch_fn(span_type, False) + """Fetch spans and file them into the cache under their own type. + + Spans are filed by the type they report, not the type that was asked for, so a + requested type that yields nothing leaves no entry and will be asked for again. + """ + spans = await self._fetch_fn({"span_type": span_type} if span_type else {}, False) for span in spans: span_attrs = span.span_attributes or {} @@ -292,7 +424,11 @@ async def _fetch_spans(self, span_type: list[str] | None) -> None: self._span_cache[span_type_str].append(span) def _get_from_cache(self, span_type: list[str] | None) -> list[SpanData]: - """Get spans from cache, optionally filtering by type.""" + """Read spans back out of the cache, optionally narrowing to some types. + + Assumes the caller has established that the cache holds what is being asked for; + types with no entry are simply absent from the result, not fetched. + """ if not span_type or len(span_type) == 0: # Return all spans result = [] @@ -322,13 +458,15 @@ async def get_spans( self, span_type: list[str] | None = None, *, + filters: SpanFilters | None = None, include_scorers: bool = False, ) -> list[SpanData]: """ Fetch all spans for this root span. Args: - span_type: Optional list of span types to filter by + span_type: Optional span types; may also be provided in filters, but not both + filters: Optional filters for span type, name, error state, metadata, and duration include_scorers: Include spans with span_attributes.purpose = "scorer" Returns: @@ -349,7 +487,7 @@ async def get_thread(self, options: GetThreadOptions | None = None) -> list[Any] ... -class LocalTrace(dict): +class LocalTrace(dict[str, Any]): """ SDK implementation of Trace that uses local span cache and falls back to BTQL. Carries identifying information about the evaluation so scorers can perform @@ -413,6 +551,7 @@ async def get_spans( self, span_type: list[str] | None = None, *, + filters: SpanFilters | None = None, include_scorers: bool = False, ) -> list[SpanData]: """ @@ -421,46 +560,29 @@ async def get_spans( back to CachedSpanFetcher which handles BTQL fetching and caching. Args: - span_type: Optional list of span types to filter by + span_type: Optional span types; may also be provided in filters, but not both + filters: Optional filters for span type, name, error state, metadata, and duration include_scorers: Include spans with span_attributes.purpose = "scorer" Returns: List of matching spans """ + normalized_filters = _normalize_span_filters(filters, span_type) + # Try local span cache first (for recently logged spans not yet flushed) cached_spans = self._state.span_cache.get_by_root_span_id(self._root_span_id) if cached_spans and len(cached_spans) > 0: - # Filter by purpose spans = [ span for span in cached_spans - if include_scorers or not (span.span_attributes or {}).get("purpose") == "scorer" + if (include_scorers or not (span.span_attributes or {}).get("purpose") == "scorer") + and _matches_span_filters(span, normalized_filters) ] - # Filter by span type if requested - if span_type and len(span_type) > 0: - spans = [span for span in spans if (span.span_attributes or {}).get("type", "") in span_type] - - # Convert to SpanData - return [ - SpanData( - input=span.input, - output=span.output, - expected=getattr(span, "expected", None), - error=getattr(span, "error", None), - scores=getattr(span, "scores", None), - metrics=getattr(span, "metrics", None), - metadata=span.metadata, - span_id=span.span_id, - span_parents=span.span_parents, - span_attributes=span.span_attributes, - tags=getattr(span, "tags", None), - ) - for span in spans - ] + return [SpanData.from_dict(span.to_dict()) for span in spans] - # Fall back to CachedSpanFetcher for BTQL fetching with caching - return await self._cached_fetcher.get_spans(span_type, include_scorers=include_scorers) + # Fall back to CachedSpanFetcher for BTQL fetching with caching. + return await self._cached_fetcher.get_spans(filters=normalized_filters, include_scorers=include_scorers) async def get_thread(self, options: GetThreadOptions | None = None) -> list[Any]: """ @@ -479,7 +601,7 @@ async def _fetch_thread(self, options: GetThreadOptions | None = None) -> list[A await asyncio.get_event_loop().run_in_executor(None, lambda: self._state.login()) preprocessor = options.get("preprocessor") if options and options.get("preprocessor") else None - result = await asyncio.get_event_loop().run_in_executor( + result: Any = await asyncio.get_event_loop().run_in_executor( None, lambda: invoke( global_function=preprocessor or "project_default", @@ -498,15 +620,20 @@ async def _fetch_thread(self, options: GetThreadOptions | None = None) -> list[A return result if isinstance(result, list) else [] async def _ensure_spans_ready(self) -> None: - """Ensure spans are flushed before fetching.""" - if self._spans_flushed or not self._ensure_spans_flushed: + """Flush pending spans so a fetch sees them, at most once per trace. + + Concurrent scorers share one in-flight flush rather than each triggering their own. + A failed flush clears that shared handle so the next caller can retry. + """ + ensure_spans_flushed = self._ensure_spans_flushed + if self._spans_flushed or ensure_spans_flushed is None: return if self._spans_flush_promise is None: - async def flush_and_mark(): + async def flush_and_mark() -> None: try: - await self._ensure_spans_flushed() + await ensure_spans_flushed() self._spans_flushed = True except Exception as err: self._spans_flush_promise = None diff --git a/py/src/braintrust/type_tests/test_trace.py b/py/src/braintrust/type_tests/test_trace.py new file mode 100644 index 000000000..8b2e9be09 --- /dev/null +++ b/py/src/braintrust/type_tests/test_trace.py @@ -0,0 +1,8 @@ +from braintrust.trace import SpanData, SpanFilters, Trace + + +async def accepts_span_filters(trace: Trace) -> list[SpanData]: + filters: SpanFilters = {"name": ["search"], "metadata": {"model": None}} + await trace.get_spans(filters=filters) + await trace.get_spans(span_type=["tool"], filters=filters) + return await trace.get_spans(filters={"duration": {"min": 0.5}}, include_scorers=True)