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 00000000..40c5f99b --- /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 f5ffdb28..524dcb2c 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 ee926614..73480441 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 9b250d44..767d169a 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 3a572f68..a16ae042 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 b72b8d62..cdcb6455 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 00000000..8b2e9be0 --- /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)