diff --git a/.gitignore b/.gitignore index 9e94a8eb..a3256630 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ Dockerfile.local CLAUDE.local.md .zed tsconfig.tsbuildinfo + +# BTX spec cache +py/src/braintrust/btx/.spec-cache/ diff --git a/py/noxfile.py b/py/noxfile.py index 48add1f6..54063ea5 100644 --- a/py/noxfile.py +++ b/py/noxfile.py @@ -123,6 +123,7 @@ def _pinned_python_version(): CONTRIB_DIR = "braintrust/contrib" DEVSERVER_DIR = "braintrust/devserver" TYPE_TESTS_DIR = "braintrust/type_tests" +BTX_DIR = "braintrust/btx" SILENT_INSTALLS = True @@ -195,6 +196,16 @@ def test_openai_http2_streaming(session, version): _run_tests(session, f"{INTEGRATION_DIR}/openai/test_openai_http2.py", version=version) +@nox.session() +@nox.parametrize("version", OPENAI_VERSIONS, ids=OPENAI_VERSIONS) +def test_btx_openai(session, version): + """Run the BTX cross-language LLM-span spec tests (OpenAI provider).""" + _install_test_deps(session) + _install_matrix_dep(session, "openai", version) + session.install("pyyaml") + _run_tests(session, "braintrust/btx", version=version, env={"BTX_PROVIDER": "openai", "BTX_CLIENT": "openai"}) + + OPENAI_AGENTS_VERSIONS = _get_matrix_versions("openai-agents") @@ -560,6 +571,7 @@ def _run_core_tests(session): CONTRIB_DIR, DEVSERVER_DIR, TYPE_TESTS_DIR, + BTX_DIR, ], ) diff --git a/py/src/braintrust/btx/__init__.py b/py/src/braintrust/btx/__init__.py new file mode 100644 index 00000000..99d798fe --- /dev/null +++ b/py/src/braintrust/btx/__init__.py @@ -0,0 +1,2 @@ +# BTX: Cross-language SDK spec tests for the Braintrust Python SDK. +# Specs are fetched from braintrustdata/braintrust-spec at a pinned ref. diff --git a/py/src/braintrust/btx/conftest.py b/py/src/braintrust/btx/conftest.py new file mode 100644 index 00000000..3b9a21e0 --- /dev/null +++ b/py/src/braintrust/btx/conftest.py @@ -0,0 +1,299 @@ +"""pytest configuration for BTX tests. + +Dual-mode operation: + VCR off (--disable-vcr or --vcr-record=all): + - Real provider API calls + - Spans sent to Braintrust backend via real logger + - Spans fetched back via BTQL for validation + + VCR on (default, cassettes present): + - Provider HTTP replayed from cassettes + - Spans captured in memory via _internal_with_memory_background_logger + - No Braintrust backend calls needed + +The VCR mode is detected from the pytest-vcr options already present in the +test session (--disable-vcr / --vcr-record). +""" + +from __future__ import annotations + +import os +import sys +import tarfile +import tempfile +import urllib.request +from pathlib import Path + +import pytest +from braintrust import logger +from braintrust.test_helpers import init_test_logger + + +_BTX_DIR = Path(__file__).parent +_SPEC_REF_FILE = _BTX_DIR / "spec-ref.txt" +_SPEC_CACHE_DIR = _BTX_DIR / ".spec-cache" + +_TEST_PROJECT = "btx-test-project" + +# Stash key: spec root path, set by pytest_configure before collection +_spec_root_key = pytest.StashKey[Path]() +# Stash key: whether VCR is disabled (live mode) +_vcr_off_key = pytest.StashKey[bool]() + + +# --------------------------------------------------------------------------- +# Spec fetching — before collection +# --------------------------------------------------------------------------- + + +def _read_spec_ref() -> str: + return _SPEC_REF_FILE.read_text().strip() + + +def _fetch_spec_if_needed(ref: str) -> Path: + """Download braintrust-spec@ref into the local cache; skip if already present. + + Pure Python implementation — no bash or curl required, works on all + platforms including Windows. + + Race-condition safe: extracts into a temporary sibling directory and then + atomically renames it into the final cache_dir. If two processes race, + one wins the rename and the other detects the final directory already + exists and returns immediately. + """ + import shutil + + cache_dir = _SPEC_CACHE_DIR / ref + llm_span_root = cache_dir / "test" / "llm_span" + + if llm_span_root.exists(): + return llm_span_root + + _SPEC_CACHE_DIR.mkdir(parents=True, exist_ok=True) + print(f"\n[btx] Fetching braintrust-spec@{ref} ...") + + url = f"https://github.com/braintrustdata/braintrust-spec/archive/{ref}.tar.gz" + + # Extract into a unique temp directory next to the final cache_dir so that + # the eventual os.rename() is atomic (same filesystem, no cross-device move). + tmp_dir = Path(tempfile.mkdtemp(dir=_SPEC_CACHE_DIR, prefix=f"{ref}.tmp.")) + # Use mkstemp (not deprecated mktemp) to atomically create the temp tarball. + tmp_tar_fd, tmp_tar_str = tempfile.mkstemp(suffix=".tar.gz", dir=_SPEC_CACHE_DIR) + os.close(tmp_tar_fd) + tmp_tar = Path(tmp_tar_str) + + try: + urllib.request.urlretrieve(url, tmp_tar) + + with tarfile.open(tmp_tar, "r:gz") as tar: + members = tar.getmembers() + # Strip the top-level directory (e.g. "braintrust-spec-af0e006/") + top = members[0].name.split("/")[0] + "/" + for member in members: + member.name = member.name[len(top) :] + if member.name: + # filter="data" was added in 3.12; fall back gracefully on older Pythons + if sys.version_info >= (3, 12): + tar.extract(member, tmp_dir, filter="data") + else: + tar.extract(member, tmp_dir) # noqa: S202 + + # Atomic rename: if another process already won the race, our tmp_dir + # is redundant — clean it up and use the existing cache_dir. + try: + tmp_dir.rename(cache_dir) + except (FileExistsError, OSError): + # Another process beat us to it; that's fine. + if not llm_span_root.exists(): + raise + except Exception: + shutil.rmtree(tmp_dir, ignore_errors=True) + raise + finally: + Path(tmp_tar).unlink(missing_ok=True) + shutil.rmtree(tmp_dir, ignore_errors=True) + + if not llm_span_root.exists(): + raise FileNotFoundError(f"Expected llm_span dir not found after fetch: {llm_span_root}") + + print(f"[btx] Spec cached at {llm_span_root}") + return llm_span_root + + +def pytest_configure(config: pytest.Config) -> None: + """Fetch specs before collection and detect VCR mode.""" + # --- spec fetch --- + env_override = os.environ.get("BTX_SPEC_ROOT") + if env_override: + spec_root = Path(env_override) + else: + ref = _read_spec_ref() + spec_root = _fetch_spec_if_needed(ref) + + config.stash[_spec_root_key] = spec_root + os.environ["BTX_SPEC_ROOT"] = str(spec_root) + + # --- VCR mode detection --- + # vcr_off means: bypass VCR entirely, make real API calls, validate via BTQL. + # This is only true when --disable-vcr is passed. + # --vcr-record=all means: make real API calls but still use VCR (to record + # cassettes) and capture spans in-memory — so vcr_off stays False. + vcr_off = bool(config.getoption("--disable-vcr", default=False, skip=True)) + config.stash[_vcr_off_key] = vcr_off + + +# --------------------------------------------------------------------------- +# VCR configuration +# --------------------------------------------------------------------------- + +# Response headers to drop before writing cassettes. These carry sensitive or +# ephemeral values (session cookies, org/project IDs, per-request trace IDs) +# that should never be committed to source control. +_SCRUB_RESPONSE_HEADERS = { + "set-cookie", + "openai-organization", + "openai-project", + "x-request-id", + "cf-ray", + "cf-cache-status", + "alt-svc", +} + + +def _scrub_response_headers(response: dict) -> dict: + """Strip sensitive/ephemeral headers from responses before cassette write.""" + response["headers"] = { + k: v for k, v in response.get("headers", {}).items() if k.lower() not in _SCRUB_RESPONSE_HEADERS + } + return response + + +@pytest.fixture(scope="session") +def vcr_config() -> dict: + """In CI: record_mode=none. Locally: record_mode=once.""" + record_mode = "none" if (os.environ.get("CI") or os.environ.get("GITHUB_ACTIONS")) else "once" + return { + "record_mode": record_mode, + "decode_compressed_response": True, + # Match on method + URI + body: the request payload (model, messages, etc.) + # is what determines which cassette response is appropriate. + # Volatile per-version metadata lives in headers, not the body, so we strip + # those via filter_headers instead of dropping body from match_on. + "match_on": ["method", "scheme", "host", "port", "path", "query", "body"], + "filter_headers": [ + "authorization", + "Authorization", + "x-api-key", + "api-key", + "openai-organization", + "openai-api-key", + "x-goog-api-key", + "x-bt-auth-token", + "cookie", + "Cookie", + # Stainless SDK telemetry headers — version-specific, not part of the + # request semantics; strip so cassettes survive SDK version bumps. + "user-agent", + "User-Agent", + "x-stainless-arch", + "x-stainless-async", + "x-stainless-lang", + "x-stainless-os", + "x-stainless-package-version", + "x-stainless-runtime", + "x-stainless-runtime-version", + "x-stainless-read-timeout", + "x-stainless-retry-count", + ], + "before_record_response": _scrub_response_headers, + } + + +def _btx_cassette_path(provider: str, spec_name: str) -> str: + """Return the absolute cassette path for a given provider and spec name. + + Cassettes live in the provider's integration cassette directory so they + share the same version matrix as the rest of that provider's tests: + integrations//cassettes//btx/.yaml + + Using an absolute path causes pytest-vcr to ignore vcr_cassette_dir + entirely and write/read cassettes directly at this location. + """ + from braintrust.integrations.conftest import _versioned_cassette_dir + + integration_cassettes = _BTX_DIR.parent / "integrations" / provider / "cassettes" + versioned_dir = Path(_versioned_cassette_dir(str(integration_cassettes))) + cassette = versioned_dir / "btx" / f"{spec_name}.yaml" + cassette.parent.mkdir(parents=True, exist_ok=True) + return str(cassette) + + +@pytest.fixture +def vcr_cassette_name(request: pytest.FixtureRequest) -> str: + """Return the absolute cassette path for this spec. + + The parametrize ID is '/' (e.g. 'openai/completions'). + Cassettes are routed to the provider's own integration directory: + integrations//cassettes//btx/.yaml + """ + node_name = request.node.name # e.g. "test_btx_spec[openai/completions]" + if "[" in node_name and node_name.endswith("]"): + spec_id = node_name[node_name.index("[") + 1 : -1] + else: + spec_id = node_name + + if "/" in spec_id: + provider, spec_name = spec_id.split("/", 1) + return _btx_cassette_path(provider, spec_name) + return spec_id + + +# --------------------------------------------------------------------------- +# Mode-aware fixtures +# --------------------------------------------------------------------------- + + +@pytest.fixture(scope="session") +def btx_vcr_off(request: pytest.FixtureRequest) -> bool: + """True when running in live (VCR-off) mode.""" + return request.config.stash.get(_vcr_off_key, False) + + +@pytest.fixture(scope="session") +def btx_spec_root(request: pytest.FixtureRequest) -> Path: + """The llm_span spec root (already fetched by pytest_configure).""" + return request.config.stash[_spec_root_key] + + +@pytest.fixture(scope="session") +def btx_project_id(btx_vcr_off: bool) -> str | None: + """Resolve the Braintrust project ID once per session (live mode only). + + In VCR mode this is never called. In live mode the project name/ID is + constant across all test cases, so we look it up once here rather than + once per parametrized test. + """ + if not btx_vcr_off: + return None + project_id = os.environ.get("BRAINTRUST_PROJECT_ID") or os.environ.get("BRAINTRUST_DEFAULT_PROJECT_ID") + if project_id: + return project_id + from .span_fetcher import fetch_project_id + + project = os.environ.get("BRAINTRUST_PROJECT") or os.environ.get( + "BRAINTRUST_DEFAULT_PROJECT_NAME", "python-unit-test" + ) + return fetch_project_id(project) + + +@pytest.fixture +def memory_logger(btx_vcr_off): + """In VCR-on mode: install in-memory span capture. + In VCR-off mode: yield None (spans go to the real Braintrust backend). + """ + if btx_vcr_off: + yield None + else: + init_test_logger(_TEST_PROJECT) + with logger._internal_with_memory_background_logger() as bgl: + yield bgl diff --git a/py/src/braintrust/btx/span_fetcher.py b/py/src/braintrust/btx/span_fetcher.py new file mode 100644 index 00000000..519b909c --- /dev/null +++ b/py/src/braintrust/btx/span_fetcher.py @@ -0,0 +1,171 @@ +"""Fetch brainstore spans from the Braintrust API after a real (non-VCR) run. + +Mirrors the BTQL query logic in sdk-test's ``btx/utils.py`` and the Java +``SpanFetcher`` class. Only used in VCR-off mode; in VCR-on mode spans are +captured in memory by the memory background logger. +""" + +from __future__ import annotations + +import os +import time +from typing import Any + +import requests + + +_BACKOFF_SECONDS = 30 +_MAX_TOTAL_WAIT_SECONDS = 600 + + +def fetch_project_id(project_name: str) -> str: + """Resolve a project name to its UUID via the Braintrust REST API.""" + api_key = _require_api_key() + api_url = _api_url() + + resp = requests.get( + f"{api_url}/v1/project", + headers=_auth_headers(api_key), + params={"project_name": project_name}, + timeout=30, + ) + resp.raise_for_status() + projects = resp.json().get("objects", []) + matching = [p for p in projects if p.get("name") == project_name] + if not matching: + raise ValueError(f"Braintrust project not found: {project_name!r}") + return matching[0]["id"] + + +def fetch_spans(root_span_id: str, project_id: str, num_expected: int) -> list[dict[str, Any]]: + """Fetch child spans for *root_span_id* with retry/backoff. + + Retries every ``_BACKOFF_SECONDS`` seconds for up to + ``_MAX_TOTAL_WAIT_SECONDS`` total wait time. + + Args: + root_span_id: The root span ID returned by ``logger.start_span()``. + project_id: Braintrust project UUID. + num_expected: Number of child (LLM) spans expected. + + Returns: + List of span dicts sorted by ``created`` ascending, scorer spans + excluded. + """ + total_wait = 0 + last_error: Exception | None = None + + while True: + try: + return _fetch_once(root_span_id, project_id, num_expected) + except _RetriableError as exc: + last_error = exc + if total_wait >= _MAX_TOTAL_WAIT_SECONDS: + break + print(f"[btx] Spans not ready yet, retrying in {_BACKOFF_SECONDS}s (waited {total_wait}s so far): {exc}") + time.sleep(_BACKOFF_SECONDS) + total_wait += _BACKOFF_SECONDS + except requests.HTTPError as exc: + if exc.response is not None and exc.response.status_code in (429, 504): + last_error = exc + if total_wait >= _MAX_TOTAL_WAIT_SECONDS: + break + print(f"[btx] HTTP {exc.response.status_code}, retrying in {_BACKOFF_SECONDS}s...") + time.sleep(_BACKOFF_SECONDS) + total_wait += _BACKOFF_SECONDS + else: + raise + + raise TimeoutError( + f"Timed out waiting for {num_expected} span(s) after {_MAX_TOTAL_WAIT_SECONDS}s. Last error: {last_error}" + ) + + +# --------------------------------------------------------------------------- +# Internal helpers +# --------------------------------------------------------------------------- + + +class _RetriableError(Exception): + """Raised when spans aren't ready yet; caller should retry.""" + + +def _fetch_once(root_span_id: str, project_id: str, num_expected: int) -> list[dict[str, Any]]: + api_key = _require_api_key() + api_url = _api_url() + + btql_query = { + "query": { + "select": [{"op": "star"}], + "from": { + "op": "function", + "name": {"op": "ident", "name": ["project_logs"]}, + "args": [{"op": "literal", "value": project_id}], + }, + "filter": { + "op": "and", + "left": { + "op": "eq", + "left": {"op": "ident", "name": ["root_span_id"]}, + "right": {"op": "literal", "value": root_span_id}, + }, + "right": { + "op": "ne", + "left": {"op": "ident", "name": ["span_parents"]}, + "right": {"op": "literal", "value": None}, + }, + }, + "sort": [{"expr": {"op": "ident", "name": ["created"]}, "dir": "asc"}], + "limit": 1000, + }, + "use_columnstore": True, + "use_brainstore": True, + "brainstore_realtime": True, + } + + resp = requests.post( + f"{api_url}/btql", + headers=_auth_headers(api_key), + json=btql_query, + timeout=30, + ) + resp.raise_for_status() + + all_spans: list[dict] = resp.json().get("data", []) + + # Strip scorer spans injected by the Braintrust backend + spans = [s for s in all_spans if (s.get("span_attributes") or {}).get("purpose") != "scorer"] + + if len(spans) == 0: + raise _RetriableError(f"No child spans found yet for root_span_id={root_span_id!r}") + + if len(spans) < num_expected: + raise _RetriableError(f"Found {len(spans)}/{num_expected} child spans for root_span_id={root_span_id!r}") + + if len(spans) > num_expected: + raise RuntimeError( + f"Expected {num_expected} child spans but found {len(spans)} — too many (non-retriable). " + f"root_span_id={root_span_id!r}" + ) + + # Retry if a span arrived but its payload hasn't been indexed yet + for span in spans: + if span.get("output") is None and span.get("metrics") is None: + raise _RetriableError(f"Span arrived but output/metrics not yet indexed (span_id={span.get('span_id')!r})") + + return spans + + +def _require_api_key() -> str: + key = os.environ.get("BRAINTRUST_API_KEY") + if not key: + raise ValueError("BRAINTRUST_API_KEY environment variable is not set") + return key + + +def _api_url() -> str: + return os.environ.get("BRAINTRUST_API_URL", "https://api.braintrust.dev").rstrip("/") + + +def _auth_headers(api_key: str) -> dict[str, str]: + return {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} diff --git a/py/src/braintrust/btx/span_validator.py b/py/src/braintrust/btx/span_validator.py new file mode 100644 index 00000000..d8dd78a4 --- /dev/null +++ b/py/src/braintrust/btx/span_validator.py @@ -0,0 +1,229 @@ +"""Validate in-memory Braintrust spans against BTX YAML spec expectations. + +The validation is recursive and collects *all* failures before raising, +so a single test run shows every mismatch at once. + +Matchers (from spec_loader): + FnMatcher — named predicate or Python lambda expression + StartsWithMatcher — string prefix check + OrMatcher — at-least-one-of + +Semantics: + - dict keys in ``expected`` that are absent from ``actual`` → failure + - extra keys in ``actual`` are ignored (lenient) + - lists: len(actual) >= len(expected); first N elements validated pairwise + - scalar None in ``expected`` → "don't care" (always passes) + - scalars compared with == +""" + +from __future__ import annotations + +import json +from typing import Any + +from braintrust.logger import Attachment + +from .spec_loader import FnMatcher, LlmSpanSpec, OrMatcher, StartsWithMatcher + + +# --------------------------------------------------------------------------- +# Named predicates (mirror of is_* functions in framework.py / SpanValidator.java) +# --------------------------------------------------------------------------- + + +def _is_non_negative_number(value: Any) -> bool: + return isinstance(value, (int, float)) and not isinstance(value, bool) and value >= 0 + + +def _is_non_empty_string(value: Any) -> bool: + return isinstance(value, str) and len(value) > 0 + + +def _is_reasoning_message(value: Any) -> bool: + """A list of {type: summary_text, text: } entries (may be empty).""" + if not isinstance(value, list): + return False + if len(value) == 0: + return True # Empty reasoning list is allowed + for item in value: + if not isinstance(item, dict): + return False + if item.get("type") != "summary_text": + return False + text = item.get("text") + if not isinstance(text, str) or not text.strip(): + return False + return True + + +_NAMED_MATCHERS: dict[str, Any] = { + "is_non_negative_number": _is_non_negative_number, + "is_non_empty_string": _is_non_empty_string, + "is_reasoning_message": _is_reasoning_message, +} + + +def _resolve_fn_matcher(matcher: FnMatcher) -> Any: + """Return a callable for this FnMatcher. + + For well-known names, return the dedicated function. + For anything else, eval() the expression — since this is Python we can + actually execute arbitrary lambda strings from the spec. + """ + if matcher.expr in _NAMED_MATCHERS: + return _NAMED_MATCHERS[matcher.expr] + # Arbitrary Python expression (e.g. "lambda value: \"440\" in value") + try: + func = eval(matcher.expr) # noqa: S307 — intentional, internal test framework + if not callable(func): + raise ValueError(f"!fn expression did not evaluate to a callable: {matcher.expr}") + return func + except Exception as exc: + raise ValueError(f"Failed to evaluate !fn expression {matcher.expr!r}: {exc}") from exc + + +# --------------------------------------------------------------------------- +# Core recursive validator +# --------------------------------------------------------------------------- + + +def _normalize_actual(actual: Any) -> Any: + """Normalize values that have a richer in-memory representation. + + Specifically: ``Attachment`` objects are replaced with their ``.reference`` + dict (``{type: braintrust_attachment, filename, content_type, key}``), + which is what the spec's ``expected_brainstore_spans`` asserts against. + """ + if isinstance(actual, Attachment): + return actual.reference + return actual + + +def _validate_value(actual: Any, expected: Any, path: str, errors: list[str]) -> None: + """Recursively validate ``actual`` against ``expected``, appending to ``errors``.""" + actual = _normalize_actual(actual) + + # --- OrMatcher: try each alternative, succeed if any passes --- + if isinstance(expected, OrMatcher): + or_errors: list[str] = [] + for i, alt in enumerate(expected.alternatives): + alt_errors: list[str] = [] + _validate_value(actual, alt, path, alt_errors) + if not alt_errors: + return # This alternative matched + or_errors.append(f" alternative[{i}]: " + "; ".join(alt_errors)) + errors.append( + f"{path}: none of {len(expected.alternatives)} OR alternatives matched:\n" + "\n".join(or_errors) + ) + return + + # --- FnMatcher --- + if isinstance(expected, FnMatcher): + fn = _resolve_fn_matcher(expected) + try: + result = fn(actual) + except Exception as exc: + errors.append(f"{path}: validator raised {type(exc).__name__}: {exc} (actual={actual!r})") + return + if not result: + errors.append(f"{path}: validator {expected.expr!r} returned False for actual={actual!r}") + return + + # --- StartsWithMatcher --- + if isinstance(expected, StartsWithMatcher): + if not isinstance(actual, str) or not actual.startswith(expected.prefix): + errors.append(f"{path}: expected string starting with {expected.prefix!r}, got {actual!r}") + return + + # --- None expected → don't care --- + if expected is None: + return + + # --- dict: recurse into keys --- + if isinstance(expected, dict): + if not isinstance(actual, dict): + errors.append(f"{path}: expected dict, got {type(actual).__name__} ({actual!r})") + return + for key, exp_val in expected.items(): + if key not in actual: + errors.append(f"{path}.{key}: key not found in actual span") + else: + _validate_value(actual[key], exp_val, f"{path}.{key}", errors) + return + + # --- list: lenient length check, validate first N elements --- + if isinstance(expected, list): + if not isinstance(actual, list): + # Special case: if expected has exactly one dict element and actual is a dict, + # treat it as a single-element list (mirrors Java SpanValidator behaviour) + if len(expected) == 1 and isinstance(expected[0], dict) and isinstance(actual, dict): + _validate_value(actual, expected[0], f"{path}[0]", errors) + return + errors.append(f"{path}: expected list, got {type(actual).__name__} ({actual!r})") + return + if len(actual) < len(expected): + errors.append(f"{path}: list too short — expected at least {len(expected)} elements, got {len(actual)}") + return + for i, exp_item in enumerate(expected): + _validate_value(actual[i], exp_item, f"{path}[{i}]", errors) + return + + # --- scalar: exact equality --- + if actual != expected: + errors.append(f"{path}: expected={expected!r}, actual={actual!r}") + + +# --------------------------------------------------------------------------- +# Public API +# --------------------------------------------------------------------------- + + +def validate_spans(actual_spans: list[dict[str, Any]], spec: LlmSpanSpec) -> None: + """Assert that *actual_spans* match the spec's ``expected_brainstore_spans``. + + ``actual_spans`` are the plain dicts from ``memory_logger.pop()``. + They are already in brainstore format (the same payload that would be + sent to the Braintrust API), so no conversion is needed. + + Spans are sorted by ``span_attributes.exec_counter`` before comparison + so that multi-span specs are matched in creation order regardless of + flush ordering. + + Raises: + AssertionError: with a full description of every mismatch found. + """ + expected_spans = spec.expected_brainstore_spans + + # Filter to LLM spans only (type == "llm") — mirrors the scorer-span + # filtering in the original btx framework + llm_spans = [s for s in actual_spans if s.get("span_attributes", {}).get("type") == "llm"] + + # Sort by exec_counter for deterministic ordering + llm_spans.sort(key=lambda s: s.get("span_attributes", {}).get("exec_counter", 0)) + + if len(llm_spans) < len(expected_spans): + raise AssertionError( + f"{spec.display_name}: expected at least {len(expected_spans)} LLM span(s), " + f"got {len(llm_spans)}.\n" + f"All captured spans:\n{json.dumps(actual_spans, indent=2, default=str)}" + ) + + all_errors: list[str] = [] + + for i, (actual_span, expected_span) in enumerate(zip(llm_spans, expected_spans)): + span_errors: list[str] = [] + for key, exp_val in expected_span.items(): + if key not in actual_span: + span_errors.append(f" span[{i}].{key}: key not found in actual span") + else: + _validate_value(actual_span[key], exp_val, f"span[{i}].{key}", span_errors) + + if span_errors: + all_errors.append( + f"\n--- Span {i} ({actual_span.get('span_attributes', {}).get('name', '?')}) ---\n" + + "\n".join(span_errors) + + f"\n\nFull span JSON:\n{json.dumps(actual_span, indent=2, default=str)}" + ) + + if all_errors: + raise AssertionError(f"{spec.display_name}: span validation failed:\n" + "\n".join(all_errors)) diff --git a/py/src/braintrust/btx/spec-ref.txt b/py/src/braintrust/btx/spec-ref.txt new file mode 100644 index 00000000..45c7a584 --- /dev/null +++ b/py/src/braintrust/btx/spec-ref.txt @@ -0,0 +1 @@ +v0.0.1 diff --git a/py/src/braintrust/btx/spec_executor.py b/py/src/braintrust/btx/spec_executor.py new file mode 100644 index 00000000..ca4b943d --- /dev/null +++ b/py/src/braintrust/btx/spec_executor.py @@ -0,0 +1,222 @@ +"""Execute BTX LLM-span specs in-process using the Braintrust Python SDK. + +Returns the root span ID so the test can fetch the spans back from Braintrust +via BTQL (VCR-off mode) or drain the memory logger (VCR-on mode). + +Client selection +---------------- +The BTX_CLIENT environment variable (set by the nox session) controls which +SDK client is used to make provider API calls. When absent, the client +defaults to the same name as the provider (e.g. provider=openai → client=openai). + +Current client identifiers: + openai — braintrust.wrap_openai(openai.OpenAI()) + anthropic — braintrust.wrap_anthropic(anthropic.Anthropic()) + +Adding a new client (e.g. "openrouter" targeting the openai provider): + 1. Add a branch in _build_client() that constructs the wrapped client. + 2. Add a nox session test_btx_openrouter_openai parametrized over the + openrouter version matrix, passing BTX_PROVIDERS=openai BTX_CLIENT=openrouter. + 3. The rest of the framework (spec loading, cassette routing, validation) + requires no changes. +""" + +from __future__ import annotations + +import copy +import os +from typing import Any + +import braintrust +from braintrust import logger, wrap_openai + +from .spec_loader import LlmSpanSpec + + +def execute_spec(spec: LlmSpanSpec, *, live: bool = False) -> str: + """Execute all requests in *spec* under a Braintrust parent span. + + Args: + spec: The spec to execute. + live: When True (VCR-off mode), calls ``braintrust.init_logger()`` so + spans are sent to the real backend. When False (VCR mode), uses + the module-level logger already initialised by ``init_test_logger`` + in the test fixture — no network calls to Braintrust are made. + + Returns: + The root span ID, used by the test to fetch spans from Braintrust + (live mode) or correlate in-memory spans (VCR mode). + """ + # BTX_CLIENT defaults to BTX_PROVIDER. Both are set by the nox session, + # so "test_btx_openai" (which sets BTX_PROVIDER=openai) implies client=openai + # without needing BTX_CLIENT to be set explicitly. + client_id = os.environ.get("BTX_CLIENT") or os.environ.get("BTX_PROVIDER") + if not client_id: + raise RuntimeError( + "BTX_PROVIDER environment variable is not set. Run btx tests via nox: nox -s 'test_btx_openai(latest)'" + ) + client = _build_client(client_id) + + if live: + project = os.environ.get("BRAINTRUST_PROJECT") or os.environ.get( + "BRAINTRUST_DEFAULT_PROJECT_NAME", "python-unit-test" + ) + project_id = os.environ.get("BRAINTRUST_PROJECT_ID") or os.environ.get("BRAINTRUST_DEFAULT_PROJECT_ID") + bt_logger = braintrust.init_logger(project=project, project_id=project_id or None) + root_span_id: str = "" + with bt_logger.start_span(name=spec.name) as root_span: + root_span_id = root_span.root_span_id + _dispatch(spec, client) + bt_logger.flush() + return root_span_id + else: + # VCR mode: use the global logger already set up by init_test_logger(). + root_span_id = "" + with logger.start_span(name=spec.name) as root_span: + root_span_id = root_span.root_span_id + _dispatch(spec, client) + return root_span_id + + +# --------------------------------------------------------------------------- +# Client construction +# --------------------------------------------------------------------------- + + +def _build_client(client_id: str) -> Any: + """Construct and return a Braintrust-wrapped provider client. + + Args: + client_id: The BTX client identifier (e.g. "openai", "anthropic"). + Matches the nox session name component after "test_btx_". + """ + if client_id == "openai": + import openai as _openai + + return wrap_openai(_openai.OpenAI()) + + if client_id == "anthropic": + import anthropic as _anthropic + from braintrust import wrap_anthropic + + return wrap_anthropic(_anthropic.Anthropic()) + + raise NotImplementedError( + f"BTX executor: unknown client {client_id!r}. Add a branch in _build_client() to support this client." + ) + + +# --------------------------------------------------------------------------- +# Dispatch by provider + endpoint +# --------------------------------------------------------------------------- + + +def _dispatch(spec: LlmSpanSpec, client: Any) -> None: + provider = spec.provider + endpoint = spec.endpoint + + if provider == "openai" and endpoint == "/v1/chat/completions": + _execute_chat_completions(spec.requests, client) + + elif provider == "openai" and endpoint == "/v1/responses": + _execute_responses(spec.requests, client) + + elif provider == "anthropic" and endpoint == "/v1/messages": + _execute_anthropic_messages(spec.requests, client) + + else: + raise NotImplementedError(f"BTX executor: provider={provider!r} endpoint={endpoint!r} not implemented") + + +# --------------------------------------------------------------------------- +# OpenAI /v1/chat/completions +# --------------------------------------------------------------------------- + + +def _execute_chat_completions(requests: list[dict[str, Any]], client: Any) -> None: + conversation_history: list[dict[str, Any]] = [] + + for req in requests: + full_req = copy.deepcopy(req) + if conversation_history: + full_req["messages"] = conversation_history + full_req.get("messages", []) + + is_streaming = full_req.pop("stream", False) + conversation_history.extend(req.get("messages", [])) + + if is_streaming: + # Use the context-manager streaming form (openai >= 1.x) to + # retrieve the accumulated final completion for conversation history. + # Fall back to create(stream=True) for older SDK versions. + if hasattr(client.chat.completions, "stream"): + with client.chat.completions.stream(**full_req) as stream: + final = stream.get_final_completion() + if final.choices: + msg = final.choices[0].message + conversation_history.append({"role": "assistant", "content": msg.content or ""}) + else: + response = client.chat.completions.create(stream=True, **full_req) + for _ in response: + pass + # Can't retrieve final message from raw iterator; history omitted. + else: + response = client.chat.completions.create(**full_req) + if response.choices: + msg = response.choices[0].message + conversation_history.append({"role": "assistant", "content": msg.content or ""}) + + +# --------------------------------------------------------------------------- +# OpenAI /v1/responses (Responses API — reasoning spec) +# --------------------------------------------------------------------------- + + +def _execute_responses(requests: list[dict[str, Any]], client: Any) -> None: + conversation_history: list[Any] = [] + + for req in requests: + full_req = copy.deepcopy(req) + if conversation_history: + full_req["input"] = conversation_history + list(full_req.get("input", [])) + + response = client.responses.create(**full_req) + + conversation_history.extend(req.get("input", [])) + if hasattr(response, "output"): + conversation_history.extend(response.output) + + +# --------------------------------------------------------------------------- +# Anthropic /v1/messages +# --------------------------------------------------------------------------- + + +def _execute_anthropic_messages(requests: list[dict[str, Any]], client: Any) -> None: + """Execute Anthropic messages requests. + + Handles streaming (stream=True) by consuming the stream context manager. + Multi-turn is not in the current spec but conversation history is tracked + for future use. + """ + conversation_history: list[dict[str, Any]] = [] + + for req in requests: + full_req = copy.deepcopy(req) + + if conversation_history: + full_req["messages"] = conversation_history + full_req.get("messages", []) + + is_streaming = full_req.get("stream", False) + conversation_history.extend(req.get("messages", [])) + + if is_streaming: + with client.messages.create(**full_req) as stream: + final = stream.get_final_message() + if hasattr(final, "content") and final.content: + text_blocks = [b.text for b in final.content if hasattr(b, "text")] + conversation_history.append({"role": "assistant", "content": " ".join(text_blocks)}) + else: + response = client.messages.create(**full_req) + if hasattr(response, "content") and response.content: + text_blocks = [b.text for b in response.content if hasattr(b, "text")] + conversation_history.append({"role": "assistant", "content": " ".join(text_blocks)}) diff --git a/py/src/braintrust/btx/spec_loader.py b/py/src/braintrust/btx/spec_loader.py new file mode 100644 index 00000000..329c82db --- /dev/null +++ b/py/src/braintrust/btx/spec_loader.py @@ -0,0 +1,173 @@ +"""Load BTX LLM-span spec YAML files. + +Handles the three custom YAML tags used in the spec: + !fn — named predicate or arbitrary lambda (eval'd in Python) + !starts_with — string prefix check + !or [...] — at-least-one-of validator +""" + +from __future__ import annotations + +import dataclasses +import os +from pathlib import Path +from typing import Any + +import yaml + + +# --------------------------------------------------------------------------- +# Matcher types (parallel to SpecMatcher.java) +# --------------------------------------------------------------------------- + + +@dataclasses.dataclass +class FnMatcher: + """A named or lambda-expression validator. + + For well-known names (is_non_negative_number, etc.) the span_validator + module dispatches them to dedicated functions. For arbitrary Python + expressions the expression string is stored and eval()'d at validation + time. + """ + + expr: str # e.g. "is_non_negative_number" or "lambda value: value > 0" + + +@dataclasses.dataclass +class StartsWithMatcher: + prefix: str + + +@dataclasses.dataclass +class OrMatcher: + alternatives: list[Any] + + +# --------------------------------------------------------------------------- +# YAML custom constructors +# --------------------------------------------------------------------------- + + +def _fn_constructor(loader: yaml.SafeLoader, node: yaml.Node) -> FnMatcher: + expr = loader.construct_scalar(node) # type: ignore[arg-type] + return FnMatcher(expr=expr) + + +def _starts_with_constructor(loader: yaml.SafeLoader, node: yaml.Node) -> StartsWithMatcher: + prefix = loader.construct_scalar(node) # type: ignore[arg-type] + return StartsWithMatcher(prefix=prefix) + + +def _or_constructor(loader: yaml.SafeLoader, node: yaml.Node) -> OrMatcher: + alternatives = loader.construct_sequence(node, deep=True) + return OrMatcher(alternatives=alternatives) + + +def _make_loader() -> type: + """Return a SafeLoader subclass with BTX custom tags registered.""" + + class BtxLoader(yaml.SafeLoader): + pass + + BtxLoader.add_constructor("!fn", _fn_constructor) + BtxLoader.add_constructor("!starts_with", _starts_with_constructor) + BtxLoader.add_constructor("!or", _or_constructor) + return BtxLoader + + +# --------------------------------------------------------------------------- +# Spec dataclass +# --------------------------------------------------------------------------- + + +@dataclasses.dataclass +class LlmSpanSpec: + name: str + type: str + provider: str + endpoint: str + requests: list[dict[str, Any]] + expected_brainstore_spans: list[dict[str, Any]] + source_path: Path + + @property + def display_name(self) -> str: + """pytest ID: /""" + return f"{self.provider}/{self.name}" + + @classmethod + def from_dict(cls, data: dict[str, Any], source_path: Path) -> "LlmSpanSpec": + return cls( + name=data["name"], + type=data["type"], + provider=data["provider"], + endpoint=data["endpoint"], + requests=data.get("requests", []), + expected_brainstore_spans=data.get("expected_brainstore_spans", []), + source_path=source_path, + ) + + +# --------------------------------------------------------------------------- +# Loader +# --------------------------------------------------------------------------- + +_BTX_DIR = Path(__file__).parent + + +def _spec_root(override: str | None = None) -> Path: + """Return the llm_span spec root directory. + + Priority: + 1. ``override`` argument (used by the pytest fixture after fetching specs) + 2. ``BTX_SPEC_ROOT`` environment variable + 3. ``/spec/test/llm_span`` (local dev snapshot) + """ + if override: + return Path(override) + env = os.environ.get("BTX_SPEC_ROOT") + if env: + return Path(env) + return _BTX_DIR / "spec" / "test" / "llm_span" + + +def load_specs( + spec_root: str | Path | None = None, + providers: list[str] | None = None, +) -> list[LlmSpanSpec]: + """Load all YAML spec files under *spec_root*. + + Args: + spec_root: Path to the ``test/llm_span`` directory. Falls back to + :func:`_spec_root` resolution if ``None``. + providers: Optional allow-list of provider names (e.g. ``["openai"]``). + If ``None``, all providers are loaded. + + Returns: + Sorted list of :class:`LlmSpanSpec` instances. + """ + root = Path(spec_root) if spec_root is not None else _spec_root() + + if not root.exists(): + raise FileNotFoundError( + f"BTX spec root not found: {root}\n" + "Run the spec-fetch fixture or set BTX_SPEC_ROOT to the llm_span directory." + ) + + loader_cls = _make_loader() + specs: list[LlmSpanSpec] = [] + + for yaml_path in sorted(root.rglob("*.yaml")): + # Filter by provider directory if requested + provider_dir = yaml_path.parent.name + if providers is not None and provider_dir not in providers: + continue + + with open(yaml_path) as f: + data = yaml.load(f, Loader=loader_cls) # noqa: S506 — intentional, custom loader + + spec = LlmSpanSpec.from_dict(data, source_path=yaml_path) + specs.append(spec) + + return specs diff --git a/py/src/braintrust/btx/test_btx.py b/py/src/braintrust/btx/test_btx.py new file mode 100644 index 00000000..db09cb93 --- /dev/null +++ b/py/src/braintrust/btx/test_btx.py @@ -0,0 +1,113 @@ +"""BTX: Cross-language LLM-span spec tests for the Braintrust Python SDK. + +Dual-mode: + + VCR off (--disable-vcr): + Real provider API calls → spans sent to Braintrust backend → fetched via + BTQL and validated against the spec. + + VCR on (default, requires cassettes): + Provider HTTP replayed from cassettes → spans captured in memory → + validated in-memory against the spec. + +Recording cassettes for the first time: + pytest src/braintrust/btx/ --vcr-record=all -v +""" + +from __future__ import annotations + +import os +from pathlib import Path +from typing import Any + +import pytest + +from .span_validator import validate_spans +from .spec_executor import execute_spec +from .spec_loader import LlmSpanSpec, load_specs + + +# --------------------------------------------------------------------------- +# Spec loading at collection time +# (pytest_configure in conftest.py sets BTX_SPEC_ROOT before this runs) +# --------------------------------------------------------------------------- + +_BTX_DIR = Path(__file__).parent + + +def _resolve_providers() -> list[str]: + provider = os.environ.get("BTX_PROVIDER") + if not provider: + raise RuntimeError( + "BTX_PROVIDER environment variable is not set. Run btx tests via nox: nox -s 'test_btx_openai(latest)'" + ) + return [provider.strip()] + + +def _load_specs() -> list[LlmSpanSpec]: + spec_root_env = os.environ.get("BTX_SPEC_ROOT") + if spec_root_env: + spec_root = Path(spec_root_env) + else: + from .conftest import _SPEC_CACHE_DIR, _read_spec_ref + + ref = _read_spec_ref() + spec_root = _SPEC_CACHE_DIR / ref / "test" / "llm_span" + + if not spec_root.exists(): + raise FileNotFoundError( + f"BTX spec root not found: {spec_root}\n" + "This module must be collected after conftest.py's pytest_configure hook " + "has run (which sets BTX_SPEC_ROOT). If you are seeing this error, " + "try running via pytest rather than importing directly." + ) + providers = _resolve_providers() + return load_specs(spec_root=spec_root, providers=providers) + + +_all_specs: list[LlmSpanSpec] = _load_specs() + +if not _all_specs: + providers = _resolve_providers() + raise RuntimeError( + f"No BTX specs found for provider(s) {providers} under {os.environ.get('BTX_SPEC_ROOT')}. " + "Check that BTX_PROVIDER and the spec ref are correct." + ) + +# --------------------------------------------------------------------------- +# Test +# --------------------------------------------------------------------------- + + +@pytest.mark.vcr +@pytest.mark.parametrize( + "spec", + _all_specs, + ids=[f"{s.provider}/{s.name}" for s in _all_specs], +) +def test_btx_spec( + spec: LlmSpanSpec, + memory_logger: Any, + btx_vcr_off: bool, + btx_project_id: str | None, + btx_spec_root: Path, +) -> None: + root_span_id = execute_spec(spec, live=btx_vcr_off) + + if btx_vcr_off: + # Live mode: fetch spans from Braintrust backend via BTQL + from .span_fetcher import fetch_spans + + assert btx_project_id is not None + + num_expected = len(spec.expected_brainstore_spans) + print(f"\n[btx] Fetching {num_expected} span(s) for root_span_id={root_span_id!r} ...") + spans = fetch_spans(root_span_id, btx_project_id, num_expected) + print(f"[btx] Got {len(spans)} span(s), validating...") + else: + # VCR mode: spans captured in memory by memory_logger + assert memory_logger is not None, "memory_logger should be set in VCR mode" + spans = memory_logger.pop() + assert spans, f"{spec.display_name}: no spans captured in memory — check that the client is wrapped correctly" + + validate_spans(spans, spec) diff --git a/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/attachments.yaml b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/attachments.yaml new file mode 100644 index 00000000..0f58768a --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/attachments.yaml @@ -0,0 +1,156 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJCnaJpluKcRLAhJ6IFEPYlb25km\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069349,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:29 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '374' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999220' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJIoOeeAgj8TR5Pa2eURAXaOgFj1\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069722,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:28:42 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '395' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999217' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/completions.yaml b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/completions.yaml new file mode 100644 index 00000000..5efd8872 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/completions.yaml @@ -0,0 +1,144 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJCoFc5SDnJMZ6RmZd3b3M8ZWMUL\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069350,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:30 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '374' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999980' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJIpSYdhtncLSsxchhjnZAfMmMvD\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069723,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:28:43 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '421' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999980' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/reasoning.yaml b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/reasoning.yaml new file mode 100644 index 00000000..226d24cf --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/reasoning.yaml @@ -0,0 +1,429 @@ +interactions: +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0e8a51738b753ae40069ebed26c0cc8195bf51a41fc875aee1\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069350,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069360,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0e8a51738b753ae40069ebed27a91c81958edf1cb2ef5a43ce\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Identifying a number pattern**\\n\\nThe + user asks about the sequence: 2, 6, 12, 20, 30. I notice it\\u2019s likely + linked to triangular numbers, which are 1, 3, 6, 10, 15, each multiplied by + 2. This leads me to the formula for the nth term: a_n = n(n+1). I see it represents + pronic numbers (the product of two consecutive integers). The difference between + terms increases by 2 each time, starting from 4. Therefore, a_n = 2 * T_n + for n \\u2265 1, where T_n = n(n+1)/2.\"\n },\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Clarifying the series formula**\\n\\nI + could express the nth term as a_n = 2 + sum_{k=2}^n 2k, but a simpler way + is a_n = n(n+1). The user gives the sequence: 2, 6, 12, 20, 30, which clearly + reveals pronic numbers\\u2014products of consecutive integers. Each term follows + the pattern: 2=1\\u00b72, 6=2\\u00b73, and so on. The difference between the + terms is an increasing sequence (4, 6, 8, 10). So, I can confidently state + the formula for the nth term as a_n = n(n+1).\"\n }\n ]\n },\n + \ {\n \"id\": \"msg_0e8a51738b753ae40069ebed2f6838819597d64f386d767a88\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"Each term is a \\u201cpronic\\u201d + (or oblong) number, i.e. the product of two consecutive integers:\\n\\n2 = + 1\\u00b72 \\n6 = 2\\u00b73 \\n12 = 3\\u00b74 \\n20 = 4\\u00b75 \\n30 = + 5\\u00b76 \\n\\nIf you label 2 as the 1st term, 6 as the 2nd, etc., then + the nth term is\\n\\na\\u2099 = n\\u00b7(n + 1)\\n\\nYou can also check that + the differences go 6\\u20132=4, 12\\u20136=6, 20\\u201312=8, \\u2026 increasing + by 2 each time.\"\n }\n ],\n \"role\": \"assistant\"\n }\n + \ ],\n \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": + null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n + \ \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": \"detailed\"\n + \ },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": + true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": + \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": + \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": + \"disabled\",\n \"usage\": {\n \"input_tokens\": 41,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 843,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 640\n },\n \"total_tokens\": 884\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:40 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3191' + openai-processing-ms: + - '9534' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_0e8a51738b753ae40069ebed27a91c81958edf1cb2ef5a43ce\",\"summary\":[{\"text\":\"**Identifying + a number pattern**\\n\\nThe user asks about the sequence: 2, 6, 12, 20, 30. + I notice it\u2019s likely linked to triangular numbers, which are 1, 3, 6, 10, + 15, each multiplied by 2. This leads me to the formula for the nth term: a_n + = n(n+1). I see it represents pronic numbers (the product of two consecutive + integers). The difference between terms increases by 2 each time, starting from + 4. Therefore, a_n = 2 * T_n for n \u2265 1, where T_n = n(n+1)/2.\",\"type\":\"summary_text\"},{\"text\":\"**Clarifying + the series formula**\\n\\nI could express the nth term as a_n = 2 + sum_{k=2}^n + 2k, but a simpler way is a_n = n(n+1). The user gives the sequence: 2, 6, 12, + 20, 30, which clearly reveals pronic numbers\u2014products of consecutive integers. + Each term follows the pattern: 2=1\xB72, 6=2\xB73, and so on. The difference + between the terms is an increasing sequence (4, 6, 8, 10). So, I can confidently + state the formula for the nth term as a_n = n(n+1).\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_0e8a51738b753ae40069ebed2f6838819597d64f386d767a88\",\"content\":[{\"annotations\":[],\"text\":\"Each + term is a \u201Cpronic\u201D (or oblong) number, i.e. the product of two consecutive + integers:\\n\\n2 = 1\xB72 \\n6 = 2\xB73 \\n12 = 3\xB74 \\n20 = 4\xB75 \\n30 + = 5\xB76 \\n\\nIf you label 2 as the 1st term, 6 as the 2nd, etc., then the + nth term is\\n\\na\u2099 = n\xB7(n + 1)\\n\\nYou can also check that the differences + go 6\u20132=4, 12\u20136=6, 20\u201312=8, \u2026 increasing by 2 each time.\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1994' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0e8a51738b753ae40069ebed3084c88195979432aa80401334\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069360,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069368,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0e8a51738b753ae40069ebed315ed48195a8aee6ec68301ec7\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Calculating pronic numbers**\\n\\nThe + user is looking for the 10th term of the pronic number sequence and the sum + of the first 10 terms. I\\u2019ve computed that the 10th term, based on the + formula a_n = n(n+1), is 110. For the sum of the first 10 terms, I calculated + S_10 = 440 by adding the sums of squares and the first 10 natural numbers. + So, my final answers are: the 10th term is 110, and the sum of the first 10 + terms is 440.\"\n },\n {\n \"type\": \"summary_text\",\n + \ \"text\": \"**Finalizing pronic numbers**\\n\\nI\\u2019m thinking + about pronic numbers, like 2, 6, and 12, and how their differences are 4 and + 6. I\\u2019ll confirm that the 10th term is 110 and the sum of the first 10 + terms is 440. I can outline the calculations, like a_{10} = 10*11 = 110 and + S_10, which gives a sum of 440. There\\u2019s also a formula for this that + simplifies the process. So my final answers are: the 10th term is 110, and + the sum is 440.\"\n }\n ]\n },\n {\n \"id\": \"msg_0e8a51738b753ae40069ebed38350881958d3154d04a7bf8d8\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The 10th term is \\na\\u2081\\u2080 + = 10\\u00b7(10+1) = 10\\u00b711 = 110. \\n\\nThe sum of the first 10 terms + is \\nS\\u2081\\u2080 = \\u2211_{n=1}^{10} n(n+1) = \\u2211 n\\u00b2 + \\u2211 + n \\n = (10\\u00b711\\u00b721)/6 + (10\\u00b711)/2 \\n = 385 + + 55 \\n = 440. \\n\\nEquivalently, one can use the closed\\u2010form + \ \\n\\u2211_{n=1}^N n(n+1) = N(N+1)(N+2)/3, \\nso for N=10: 10\\u00b711\\u00b712/3 + = 440.\"\n }\n ],\n \"role\": \"assistant\"\n }\n ],\n + \ \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": + null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n + \ \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": \"detailed\"\n + \ },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": + true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": + \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": + \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": + \"disabled\",\n \"usage\": {\n \"input_tokens\": 216,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 617,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 448\n },\n \"total_tokens\": 833\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:49 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3132' + openai-processing-ms: + - '8559' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999575' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0927450cca53dbe30069ebee9bea288197b06daeeff47a3a1a\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069723,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069731,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0927450cca53dbe30069ebee9c534881978ae034fc1a9d5085\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Identifying sequence patterns**\\n\\nThe + user shared a sequence: 2, 6, 12, 20, 30, which represents \\\"pronic\\\" + or \\\"rectangular\\\" numbers defined by the formula n(n+1). For instance, + 2 is from 1*2, 6 is from 2*3, and so on. I see that this sequence can also + be viewed as double the triangular numbers, but the direct formula remains + n(n+1). I\\u2019ve noticed the differences between terms (4, 6, 8, 10) increase + by 2 each time, revealing it's a second-degree polynomial.\"\n },\n + \ {\n \"type\": \"summary_text\",\n \"text\": \"**Clarifying + pronic numbers**\\n\\nI've realized that the sequence can be understood as + the x-th even triangular numbers, leading to the formula a_n = n(n+1) for + the nth term. This reflects the product of two consecutive natural numbers, + and I can also express it as a_n = n^2 + n. The differences between terms + form an arithmetic sequence increasing by 2 each time. So, I\\u2019ll confirm + the sequence of pronic numbers, summarizing that each term is derived from + n multiplied by the next integer.\"\n }\n ]\n },\n {\n \"id\": + \"msg_0927450cca53dbe30069ebeea2cedc81978f9bcd1c18394e29\",\n \"type\": + \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n + \ \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": + [],\n \"text\": \"The terms are the \\u201cpronic\\u201d (or oblong) + numbers, i.e. the product of two consecutive integers:\\n\\n 2 = 1\\u00b72 + \ \\n 6 = 2\\u00b73 \\n12 = 3\\u00b74 \\n20 = 4\\u00b75 \\n30 = 5\\u00b76 + \ \\n\\nHence, if you index so that a\\u2081=2, a\\u2082=6, \\u2026, then\\n\\n + \ a\\u2099 = n\\u00b7(n + 1)\\n\\nYou can also write that as\\n\\n a\\u2099 + = n\\u00b2 + n.\"\n }\n ],\n \"role\": \"assistant\"\n }\n + \ ],\n \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": + null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n + \ \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": \"detailed\"\n + \ },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": + true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": + \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": + \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": + \"disabled\",\n \"usage\": {\n \"input_tokens\": 41,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 838,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 704\n },\n \"total_tokens\": 879\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:28:51 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3161' + openai-processing-ms: + - '7613' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_0927450cca53dbe30069ebee9c534881978ae034fc1a9d5085\",\"summary\":[{\"text\":\"**Identifying + sequence patterns**\\n\\nThe user shared a sequence: 2, 6, 12, 20, 30, which + represents \\\"pronic\\\" or \\\"rectangular\\\" numbers defined by the formula + n(n+1). For instance, 2 is from 1*2, 6 is from 2*3, and so on. I see that this + sequence can also be viewed as double the triangular numbers, but the direct + formula remains n(n+1). I\u2019ve noticed the differences between terms (4, + 6, 8, 10) increase by 2 each time, revealing it's a second-degree polynomial.\",\"type\":\"summary_text\"},{\"text\":\"**Clarifying + pronic numbers**\\n\\nI've realized that the sequence can be understood as the + x-th even triangular numbers, leading to the formula a_n = n(n+1) for the nth + term. This reflects the product of two consecutive natural numbers, and I can + also express it as a_n = n^2 + n. The differences between terms form an arithmetic + sequence increasing by 2 each time. So, I\u2019ll confirm the sequence of pronic + numbers, summarizing that each term is derived from n multiplied by the next + integer.\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_0927450cca53dbe30069ebeea2cedc81978f9bcd1c18394e29\",\"content\":[{\"annotations\":[],\"text\":\"The + terms are the \u201Cpronic\u201D (or oblong) numbers, i.e. the product of two + consecutive integers:\\n\\n 2 = 1\xB72 \\n 6 = 2\xB73 \\n12 = 3\xB74 \\n20 + = 4\xB75 \\n30 = 5\xB76 \\n\\nHence, if you index so that a\u2081=2, a\u2082=6, + \u2026, then\\n\\n a\u2099 = n\xB7(n + 1)\\n\\nYou can also write that as\\n\\n + \ a\u2099 = n\xB2 + n.\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1971' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0927450cca53dbe30069ebeea3e89481979afa93837267ba7c\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069731,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069736,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0927450cca53dbe30069ebeea455308197968f95c8e31142ec\",\n + \ \"type\": \"reasoning\",\n \"summary\": []\n },\n {\n \"id\": + \"msg_0927450cca53dbe30069ebeea6fd6c8197993b17ee71fb39e2\",\n \"type\": + \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n + \ \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": + [],\n \"text\": \"The 10th term is \\n a\\u2081\\u2080 = 10\\u00b7(10 + + 1) = 10\\u00b711 = 110. \\n\\nThe sum of the first 10 terms is \\n S\\u2081\\u2080 + = \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 n(n+1) \\n = \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 + (n\\u00b2 + n) \\n = (\\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 n\\u00b2) + + (\\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 n) \\n = 385 + 55 \\n + \ = 440. \\n\\n(You can also use the closed\\u2010form S\\u2099 = n(n+1)(n+2)/3 + \\u21d2 S\\u2081\\u2080 = 10\\u00b711\\u00b712/3 = 440.)\"\n }\n ],\n + \ \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": true,\n + \ \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 193,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 610,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 384\n },\n \"total_tokens\": 803\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:28:56 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '2195' + openai-processing-ms: + - '4343' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999600' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/streaming.yaml b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/streaming.yaml new file mode 100644 index 00000000..c5ab1c21 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/streaming.yaml @@ -0,0 +1,198 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a thoughtful assistant"},{"role":"user","content":"Count + from 1 to 10 slowly."}],"model":"gpt-4o-mini","max_tokens":800,"stream":true,"stream_options":{"include_usage":true},"temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '241' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: 'data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JZkwlGCNh"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Sure"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Z1EZlwC"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yIsfff3wPX"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + Here"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"f3X5eo"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + we"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"X7LpFYVp"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"muoRFjJg"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":":\n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"6ZBTtO"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"1"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vfTHYNoO31"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hzcal6Yx"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GFx1Cb6"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"2"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"sfUeXGPnPP"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XN19fldY"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"O9WNGoS"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"IqelAyDTDw"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"T4PDsBlB"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"yJnz12R"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"4"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RyOic0VOoe"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"06zGGnwh"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wvBBpGo"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"5"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nK7ADfvmVQ"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NCJ5azsW"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rm3X4zB"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZPYcWb4gl6"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QkclrGYM"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OgJKoWx"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"7"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5FcxlzHO6r"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dSaMy6o0"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jjmmSy1"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"8"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wczzZILC2i"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cWsTY1X4"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"T9jdu3R"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"9"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8sZFdOvPg1"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"L5CdRmd8"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"klxd00a"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"10"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FwzzNHrRM"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WIZpMCPc"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aCz6x"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Take"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"CtEih6D"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + your"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YXzwxO"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + time"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"X5qSkv"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MgsYPA9gej"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"qVpuB"} + + + data: {"id":"chatcmpl-DYJJ2V0fqTR0SKSYXu32W4UJsrk9F","object":"chat.completion.chunk","created":1777069736,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[],"usage":{"prompt_tokens":25,"completion_tokens":40,"total_tokens":65,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"tUsPkse1B5"} + + + data: [DONE] + + + ' + headers: + Connection: + - keep-alive + Content-Type: + - text/event-stream; charset=utf-8 + Date: + - Fri, 24 Apr 2026 22:28:57 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + openai-processing-ms: + - '531' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/tools.yaml b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/tools.yaml new file mode 100644 index 00000000..cb8096e7 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.71.0/btx/tools.yaml @@ -0,0 +1,158 @@ +interactions: +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJD7zL3XRvX6vXAg9uZTIO3AObg7\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069369,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_Xi2ptbz1EouodHdAyAfZZOUS\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:49 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '404' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999987' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJ4uVve8jM0NGt4ufMDXOfHFpWe\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069738,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_zoCC7BsA6VfFz4kmswijoiGv\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:28:58 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '807' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999987' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/attachments.yaml b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/attachments.yaml new file mode 100644 index 00000000..cd292ccf --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/attachments.yaml @@ -0,0 +1,156 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJDAwb3iQUmh10cGiChqhDrcE9w3\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069372,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:52 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '366' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999220' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJ7VRAlgnQxGyeNNbl1mzwnfdft\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069741,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:01 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '555' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999220' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/completions.yaml b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/completions.yaml new file mode 100644 index 00000000..f78f2ddd --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/completions.yaml @@ -0,0 +1,144 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJDB8J55hZsMnEugAR51ComruBFJ\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069373,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:22:53 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '386' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJ7hpCG6zcloH0dZRgF2UQ8Zx3O\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069741,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:02 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '428' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/reasoning.yaml b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/reasoning.yaml new file mode 100644 index 00000000..5565d9e8 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/reasoning.yaml @@ -0,0 +1,455 @@ +interactions: +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0aeafcf19e06f5560069ebed3d8bbc8193a67124cc7e06b1b4\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069373,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069381,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0aeafcf19e06f5560069ebed3e799c8193b9582173f1c80da0\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Analyzing the sequence pattern**\\n\\nThe + user presented the sequence: 2, 6, 12, 20, 30, prompting me to find a pattern + and formula for the nth term. By examining the differences, I noted they're + increasing by 2 each time, leading me to suspect the formula might be n(n+1). + Testing it confirms this since a_n equals n(n+1) fits perfectly. This sequence + represents pronic numbers, which are products of two consecutive integers. + So, the formula can be expressed as n^2 + n.\"\n },\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Finalizing the sequence explanation**\\n\\nI've + concluded that the nth term for the sequence is related to pronic numbers, + represented as a_n = n(n+1). The pattern also highlights that the differences + between terms increase by 2 each time. So, I\\u2019ll present it in both ways: + the formula and the observation about the differences. That should cover everything + clearly and concisely. It feels good to wrap this up!\"\n }\n ]\n + \ },\n {\n \"id\": \"msg_0aeafcf19e06f5560069ebed4533648193b1d6739e4dc07bae\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The \\u201cadd even + numbers\\u201d pattern\\n\\n1. Differences between terms are \\n 6\\u20132=4, + 12\\u20136=6, 20\\u201312=8, 30\\u201320=10, \\u2026 \\n i.e. you keep + adding 4, then 6, then 8, then 10, \\u2026\\n\\n2. Equivalently each term + is a product of two consecutive integers (a \\u201cpronic\\u201d number): + \ \\n a\\u2081=1\\u22c52=2, a\\u2082=2\\u22c53=6, a\\u2083=3\\u22c54=12, + \\u2026\\n\\nSo the nth term is \\n a\\u2099 = n\\u00b7(n + 1) \\nor expanded + \ \\n a\\u2099 = n\\u00b2 + n.\"\n }\n ],\n \"role\": \"assistant\"\n + \ }\n ],\n \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n + \ \"previous_response_id\": null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": + \"in_memory\",\n \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": + \"detailed\"\n },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n + \ \"store\": true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": + {\n \"type\": \"text\"\n },\n \"verbosity\": \"medium\"\n },\n + \ \"tool_choice\": \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": + 1.0,\n \"truncation\": \"disabled\",\n \"usage\": {\n \"input_tokens\": + 41,\n \"input_tokens_details\": {\n \"cached_tokens\": 0\n },\n + \ \"output_tokens\": 536,\n \"output_tokens_details\": {\n \"reasoning_tokens\": + 320\n },\n \"total_tokens\": 577\n },\n \"user\": null,\n \"metadata\": + {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:01 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3221' + openai-processing-ms: + - '8252' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_0aeafcf19e06f5560069ebed3e799c8193b9582173f1c80da0\",\"summary\":[{\"text\":\"**Analyzing + the sequence pattern**\\n\\nThe user presented the sequence: 2, 6, 12, 20, 30, + prompting me to find a pattern and formula for the nth term. By examining the + differences, I noted they're increasing by 2 each time, leading me to suspect + the formula might be n(n+1). Testing it confirms this since a_n equals n(n+1) + fits perfectly. This sequence represents pronic numbers, which are products + of two consecutive integers. So, the formula can be expressed as n^2 + n.\",\"type\":\"summary_text\"},{\"text\":\"**Finalizing + the sequence explanation**\\n\\nI've concluded that the nth term for the sequence + is related to pronic numbers, represented as a_n = n(n+1). The pattern also + highlights that the differences between terms increase by 2 each time. So, I\u2019ll + present it in both ways: the formula and the observation about the differences. + That should cover everything clearly and concisely. It feels good to wrap this + up!\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_0aeafcf19e06f5560069ebed4533648193b1d6739e4dc07bae\",\"content\":[{\"annotations\":[],\"text\":\"The + \u201Cadd even numbers\u201D pattern\\n\\n1. Differences between terms are + \ \\n 6\u20132=4, 12\u20136=6, 20\u201312=8, 30\u201320=10, \u2026 \\n i.e. + you keep adding 4, then 6, then 8, then 10, \u2026\\n\\n2. Equivalently each + term is a product of two consecutive integers (a \u201Cpronic\u201D number): + \ \\n a\u2081=1\u22C52=2, a\u2082=2\u22C53=6, a\u2083=3\u22C54=12, \u2026\\n\\nSo + the nth term is \\n a\u2099 = n\xB7(n + 1) \\nor expanded \\n a\u2099 + = n\xB2 + n.\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2018' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0aeafcf19e06f5560069ebed4632e481938a3955781dd49a1e\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069382,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069389,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0aeafcf19e06f5560069ebed46b4b48193a3daafd94603a3df\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Evaluating pronic numbers**\\n\\nThe + user has found that the sequence involves pronic numbers defined by the formula + \\\\( a_n = n(n+1) \\\\). For the 10th term, I calculate \\\\( a_{10} = 10 + \\\\times 11 = 110 \\\\). The sum of the first 10 terms is computed by adding + the sums of \\\\( n \\\\) and \\\\( n^2 \\\\). This gives \\\\( S = 440 \\\\). + So, I see that the 10th term is 110, and the sum of the first 10 terms is + 440.\"\n },\n {\n \"type\": \"summary_text\",\n \"text\": + \"**Calculating pronic numbers**\\n\\nI've determined the 10th pronic number, + \\\\( a_{10} \\\\), by calculating \\\\( 10 \\\\times 11 = 110 \\\\). Now + for the sum of the first 10 terms, I find that \\\\( S_{10} = \\\\text{sum + } n(n+1) \\\\) can be expressed as the sum of squares plus the sum of integers. + This gives me \\\\( 385 + 55 = 440 \\\\). Alternatively, using the formula + for the sum, I also confirm \\\\( S_{10} = \\\\frac{10 \\\\times 11 \\\\times + 12}{3} = 440 \\\\). So, final results are 10th term = 110, sum = 440.\"\n + \ }\n ]\n },\n {\n \"id\": \"msg_0aeafcf19e06f5560069ebed4d3eb0819381933504ee6f9ece\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The 10th term is \\n + \ a\\u2081\\u2080 = 10\\u00b7(10 + 1) = 10\\u00b711 = 110 \\n\\nThe sum of + the first 10 terms is \\n S\\u2081\\u2080 = \\u2211_{n=1}^{10} n(n+1) \\n + \ = \\u2211 n\\u00b2 + \\u2211 n \\n = (10\\u00b711\\u00b721)/6 + \ + (10\\u00b711)/2 \\n = 385 + 55 \\n = 440 \\n\\n(You can + also use the closed form S\\u2099 = n(n+1)(n+2)/3, which for n=10 gives 10\\u00b711\\u00b712/3 + = 440.)\"\n }\n ],\n \"role\": \"assistant\"\n }\n ],\n + \ \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": + null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n + \ \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": \"detailed\"\n + \ },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": + true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": + \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": + \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": + \"disabled\",\n \"usage\": {\n \"input_tokens\": 242,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 496,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 320\n },\n \"total_tokens\": 738\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:10 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3153' + openai-processing-ms: + - '7972' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999550' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_07be4096a3e2a5ab0069ebeeaea3b88190b5c6c2677a465392\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069742,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069753,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_07be4096a3e2a5ab0069ebeeaf2970819098900f21f121f92f\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Analyzing the sequence**\\n\\nThe + user presents the sequence: 2, 6, 12, 20, 30 and asks for the pattern. I realize + the values are generated by multiplying consecutive integers: 1*2, 2*3, 3*4, + and so on. The formula for the nth term is n(n+1), indicating they're pronic + numbers, or oblong numbers. These can also be expressed as twice the nth triangular + number, leading to 2T_n. Additionally, the differences between terms increase + by 2, hinting at a quadratic nature.\"\n },\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Defining the pattern**\\n\\nTo + clarify, the general formula I've landed on is a_n = n(n+1), which describes + pronic numbers. The sequence starts at n=1, and as n increases, the differences + grow by 2: 4, 6, 8, 10, indicating a quadratic relationship. If I consider + indexing from n=0, I'd use a_n = (n)(n+1), but it feels clearer to start with + n=1. So ultimately, I\\u2019ll express the nth term as a_n = n(n+1). Thus, + the sequence captures products of consecutive integers.\"\n },\n {\n + \ \"type\": \"summary_text\",\n \"text\": \"**Summarizing + the pattern**\\n\\nThe pattern I've identified shows that each term is the + product of its index and the next index. Thus, the formula for the nth term + is a_n = n(n+1), which can also be expressed as n^2 + n. This represents pronic + numbers, where the differences between terms increase by 2, confirming its + quadratic nature: for instance, 6-2 equals 4, then 12-6 equals 6, and so on. + So overall, the nth term is n(n+1), and the sequence consists of products + of consecutive integers.\"\n }\n ]\n },\n {\n \"id\": + \"msg_07be4096a3e2a5ab0069ebeeb8f0c08190b19c397fe99bbec9\",\n \"type\": + \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n + \ \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": + [],\n \"text\": \"The \\u201cmystery\\u201d sequence is \\n 2, 6, + 12, 20, 30, \\u2026 \\nNotice \\n 2=1\\u00b72, \\n 6=2\\u00b73, \\n 12=3\\u00b74, + \ \\n 20=4\\u00b75, \\n 30=5\\u00b76, \\u2026 \\n\\nSo the nth term is the + product of two consecutive integers. If we start counting terms at n=1, then\\n\\n\\u2003a\\u2099 + = n\\u00b7(n + 1) = n\\u00b2 + n.\\n\\nYou can check:\\n\\nn=1 \\u21d2 1\\u00b72=2 + \ \\nn=2 \\u21d2 2\\u00b73=6 \\nn=3 \\u21d2 3\\u00b74=12 \\n\\u2026 and + so on.\"\n }\n ],\n \"role\": \"assistant\"\n }\n ],\n + \ \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": + null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n + \ \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": \"detailed\"\n + \ },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": + true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": + \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": + \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": + \"disabled\",\n \"usage\": {\n \"input_tokens\": 41,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 1292,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 1088\n },\n \"total_tokens\": 1333\n + \ },\n \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:13 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3795' + openai-processing-ms: + - '10910' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_07be4096a3e2a5ab0069ebeeaf2970819098900f21f121f92f\",\"summary\":[{\"text\":\"**Analyzing + the sequence**\\n\\nThe user presents the sequence: 2, 6, 12, 20, 30 and asks + for the pattern. I realize the values are generated by multiplying consecutive + integers: 1*2, 2*3, 3*4, and so on. The formula for the nth term is n(n+1), + indicating they're pronic numbers, or oblong numbers. These can also be expressed + as twice the nth triangular number, leading to 2T_n. Additionally, the differences + between terms increase by 2, hinting at a quadratic nature.\",\"type\":\"summary_text\"},{\"text\":\"**Defining + the pattern**\\n\\nTo clarify, the general formula I've landed on is a_n = n(n+1), + which describes pronic numbers. The sequence starts at n=1, and as n increases, + the differences grow by 2: 4, 6, 8, 10, indicating a quadratic relationship. + If I consider indexing from n=0, I'd use a_n = (n)(n+1), but it feels clearer + to start with n=1. So ultimately, I\u2019ll express the nth term as a_n = n(n+1). + Thus, the sequence captures products of consecutive integers.\",\"type\":\"summary_text\"},{\"text\":\"**Summarizing + the pattern**\\n\\nThe pattern I've identified shows that each term is the product + of its index and the next index. Thus, the formula for the nth term is a_n = + n(n+1), which can also be expressed as n^2 + n. This represents pronic numbers, + where the differences between terms increase by 2, confirming its quadratic + nature: for instance, 6-2 equals 4, then 12-6 equals 6, and so on. So overall, + the nth term is n(n+1), and the sequence consists of products of consecutive + integers.\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_07be4096a3e2a5ab0069ebeeb8f0c08190b19c397fe99bbec9\",\"content\":[{\"annotations\":[],\"text\":\"The + \u201Cmystery\u201D sequence is \\n 2, 6, 12, 20, 30, \u2026 \\nNotice \\n + 2=1\xB72, \\n 6=2\xB73, \\n 12=3\xB74, \\n 20=4\xB75, \\n 30=5\xB76, \u2026 + \ \\n\\nSo the nth term is the product of two consecutive integers. If we start + counting terms at n=1, then\\n\\n\u2003a\u2099 = n\xB7(n + 1) = n\xB2 + n.\\n\\nYou + can check:\\n\\nn=1 \u21D2 1\xB72=2 \\nn=2 \u21D2 2\xB73=6 \\nn=3 \u21D2 3\xB74=12 + \ \\n\u2026 and so on.\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2542' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_07be4096a3e2a5ab0069ebeeb9c3f08190bec5d5da7fe56f2a\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069753,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069759,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_07be4096a3e2a5ab0069ebeeba3b048190a004fd413d9ae87c\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Finding the nth term and sum**\\n\\nThe + user wants to find the 10th term of the sequence defined by \\\\( a_n = n(n+1) + = n^2 + n \\\\) and the sum of the first 10 terms. The 10th term is straightforward: + \\\\( 10 \\\\times 11 = 110 \\\\). \\n\\nFor the sum, I calculate \\\\( \\\\sum_{n=1}^{10} + n(n+1) \\\\), breaking it down into the sum of squares and the arithmetic + series. After some calculations, I find the sum is 440. So, the answers are: + the 10th term is 110, and the total sum is 440.\"\n }\n ]\n },\n + \ {\n \"id\": \"msg_07be4096a3e2a5ab0069ebeebe8c3881909ba966122bc8be18\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The 10th term is \\na\\u2081\\u2080 + = 10\\u00b7(10 + 1) = 10\\u00b711 = 110. \\n\\nThe sum of the first 10 terms + is \\nS\\u2081\\u2080 = \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 n(n+1) + \ \\n = \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 n\\u00b2 + \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 + n \\n = [10\\u00b711\\u00b721]\\u22156 + [10\\u00b711]\\u22152 \\n + \ = 385 + 55 \\n = 440. \\n\\nEquivalently, one can use the closed\\u2010form + \ \\nS\\u2081\\u2080 = 10\\u00b711\\u00b712\\u22153 = 440.\"\n }\n + \ ],\n \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": + true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 234,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 493,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 256\n },\n \"total_tokens\": 727\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:19 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '2721' + openai-processing-ms: + - '5588' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999560' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/streaming.yaml b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/streaming.yaml new file mode 100644 index 00000000..f79f45b5 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/streaming.yaml @@ -0,0 +1,198 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a thoughtful assistant"},{"role":"user","content":"Count + from 1 to 10 slowly."}],"model":"gpt-4o-mini","max_tokens":800,"stream":true,"stream_options":{"include_usage":true},"temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '241' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: 'data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wvG1Rbij1"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Sure"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jr0VhpF"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2lmUcNrjsv"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + Here"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UL5iQe"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + we"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"rovKnPoG"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"r5oZnz2t"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":":\n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EmR5kC"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"1"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RlMRsY2hJy"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"95RD2grK"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tVfYBq1"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"2"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Lu5ntee5bJ"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jhmzgWKu"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9xQUBau"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OFt8JbVyPi"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gFn42Oxd"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uIBKEpb"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"4"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MVhQWVf0Vv"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YJLhHaGB"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1HbrBbz"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"5"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dQvUeAARUX"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"USBf9WuB"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"w8hUhbU"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"geVcIjM2Zt"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LPJjqxjP"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"137ZE5C"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"7"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZzoSYjYez4"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jnhOh5Tq"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cohGxKD"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"8"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZJT7ig2nQq"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3kMmdBBc"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"U0lhUSC"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"9"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QMHGFNnP0x"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"vleBeXCO"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WZ90nyj"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"10"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VjwXIh7lt"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YlAgiAKJ"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"HpC3o"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Take"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4wpmT3u"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + your"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qc2m8s"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + time"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"4GGmGu"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mTWmN1XuWN"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"HEEaj"} + + + data: {"id":"chatcmpl-DYJJPz2UngFguw8TGua6HviapLDAN","object":"chat.completion.chunk","created":1777069759,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[],"usage":{"prompt_tokens":25,"completion_tokens":40,"total_tokens":65,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"hK3jBg58c7"} + + + data: [DONE] + + + ' + headers: + Connection: + - keep-alive + Content-Type: + - text/event-stream; charset=utf-8 + Date: + - Fri, 24 Apr 2026 22:29:19 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + openai-processing-ms: + - '246' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/tools.yaml b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/tools.yaml new file mode 100644 index 00000000..f0e8bb83 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.77.0/btx/tools.yaml @@ -0,0 +1,158 @@ +interactions: +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJDSw4PFUYPborsY0CMkOrqXCBav\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069390,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_M3GczbwANYwRFzTo5sjnHqhF\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:10 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '461' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999987' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJQLlMkjGt6C2DQZW3eIXlsisnP\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069760,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_dP2RPhZ9Cq7n66oHHw5qjVdq\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:21 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '486' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999986' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/attachments.yaml b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/attachments.yaml new file mode 100644 index 00000000..fcb10443 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/attachments.yaml @@ -0,0 +1,156 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJDVbftlpCB9lBrVG8o9PHCg8S7i\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069393,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:13 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '421' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999220' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJTXUBwXopBlkUivMWAMm1eWQ2u\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069763,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_a7190374f3\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:23 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '589' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999217' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/completions.yaml b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/completions.yaml new file mode 100644 index 00000000..0065dc1a --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/completions.yaml @@ -0,0 +1,144 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJDWj8sT15GVWarUZKjT1j7kTIzq\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069394,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:14 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '434' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJU9nPRFsslXSGWG10qHx0rWy0Z\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069764,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:24 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '373' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/reasoning.yaml b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/reasoning.yaml new file mode 100644 index 00000000..cb88637c --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/reasoning.yaml @@ -0,0 +1,459 @@ +interactions: +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0ec7311e7547baf10069ebed52c0c8819780f28f73f074e6d7\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069394,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069409,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0ec7311e7547baf10069ebed538d5881978e67f50149ef553a\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Identifying sequence patterns**\\n\\nThe + user presented the sequence: 2, 6, 12, 20, 30, and I'm exploring its pattern. + It seems to relate to triangular numbers multiplied by 2. Triangular numbers + can be calculated with T_n = n(n+1)/2, and doubling that formula leads to + n(n+1). I also see another way to express it as a_n = n\\u00b2 + n. The differences + between terms increase by 2, confirming this is a quadratic sequence, indicating + it represents pronic numbers. So, the nth term is n(n+1).\"\n },\n + \ {\n \"type\": \"summary_text\",\n \"text\": \"**Exploring + numeric patterns**\\n\\nI'm finding that the sequence can also be viewed as + the sum of the first n even numbers. For example, 2 + 4 + 6 + 8 + 10 equals + 30, and this sum can be expressed as S_n = n(n+1). It matches with earlier + findings that each term can be defined as n(n+1). This confirms the pattern + represents pronic numbers or triangular numbers multiplied by 2. The differences + between terms keep increasing by 2, leading to the nth term formula: a_n = + n(n+1) for n starting at 1.\"\n },\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Clarifying the nth term**\\n\\nThe + formula for the nth term of the sequence is a_n = n\\u00b2 + n. Since that + corresponds to triangular numbers, I can also express it as a_n = 2T_n, where + T_n = n(n+1)/2. The pattern emerges as pronic numbers, where each term is + the product of n and its next integer. The differences between the terms increase + sequentially by 2, confirming that the nth term is quadratic: a_n = n(n+1) + starting from n=1.\"\n }\n ]\n },\n {\n \"id\": \"msg_0ec7311e7547baf10069ebed6080288197aebe0635f6dbcdfb\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The \\u201cgaps\\u201d + between consecutive terms are \\n 6\\u20132=4, 12\\u20136=6, 20\\u201312=8, + 30\\u201320=10 \\u2026 \\nso you\\u2019re adding 4, then 6, then 8, then + 10, \\u2026 i.e. successive even numbers. \\nEquivalently each term is a + product of two consecutive integers:\\n\\n term 1: 1\\u00b72=2 \\n term 2: + 2\\u00b73=6 \\n term 3: 3\\u00b74=12 \\n term 4: 4\\u00b75=20 \\n term + 5: 5\\u00b76=30 \\n\\nHence if you label the first term by n=1, the nth term + is\\n\\n a\\u2099 = n\\u00b7(n+1) = n\\u00b2 + n.\"\n }\n ],\n + \ \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": true,\n + \ \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 41,\n \"input_tokens_details\": {\n + \ \"cached_tokens\": 0\n },\n \"output_tokens\": 1488,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 1280\n },\n \"total_tokens\": 1529\n + \ },\n \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:29 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3849' + openai-processing-ms: + - '14786' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_0ec7311e7547baf10069ebed538d5881978e67f50149ef553a\",\"summary\":[{\"text\":\"**Identifying + sequence patterns**\\n\\nThe user presented the sequence: 2, 6, 12, 20, 30, + and I'm exploring its pattern. It seems to relate to triangular numbers multiplied + by 2. Triangular numbers can be calculated with T_n = n(n+1)/2, and doubling + that formula leads to n(n+1). I also see another way to express it as a_n = + n\xB2 + n. The differences between terms increase by 2, confirming this is a + quadratic sequence, indicating it represents pronic numbers. So, the nth term + is n(n+1).\",\"type\":\"summary_text\"},{\"text\":\"**Exploring numeric patterns**\\n\\nI'm + finding that the sequence can also be viewed as the sum of the first n even + numbers. For example, 2 + 4 + 6 + 8 + 10 equals 30, and this sum can be expressed + as S_n = n(n+1). It matches with earlier findings that each term can be defined + as n(n+1). This confirms the pattern represents pronic numbers or triangular + numbers multiplied by 2. The differences between terms keep increasing by 2, + leading to the nth term formula: a_n = n(n+1) for n starting at 1.\",\"type\":\"summary_text\"},{\"text\":\"**Clarifying + the nth term**\\n\\nThe formula for the nth term of the sequence is a_n = n\xB2 + + n. Since that corresponds to triangular numbers, I can also express it as + a_n = 2T_n, where T_n = n(n+1)/2. The pattern emerges as pronic numbers, where + each term is the product of n and its next integer. The differences between + the terms increase sequentially by 2, confirming that the nth term is quadratic: + a_n = n(n+1) starting from n=1.\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_0ec7311e7547baf10069ebed6080288197aebe0635f6dbcdfb\",\"content\":[{\"annotations\":[],\"text\":\"The + \u201Cgaps\u201D between consecutive terms are \\n 6\u20132=4, 12\u20136=6, + 20\u201312=8, 30\u201320=10 \u2026 \\nso you\u2019re adding 4, then 6, then + 8, then 10, \u2026 i.e. successive even numbers. \\nEquivalently each term + is a product of two consecutive integers:\\n\\n term 1: 1\xB72=2 \\n term 2: + 2\xB73=6 \\n term 3: 3\xB74=12 \\n term 4: 4\xB75=20 \\n term 5: 5\xB76=30 + \ \\n\\nHence if you label the first term by n=1, the nth term is\\n\\n a\u2099 + = n\xB7(n+1) = n\xB2 + n.\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2603' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0ec7311e7547baf10069ebed61d7c4819788756cc7b9597bdb\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069409,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069418,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0ec7311e7547baf10069ebed628de08197a146124fcb75b5f5\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Calculating term and sum**\\n\\nThe + user wants to know the 10th term and the sum of the first 10 terms in a pattern. + Earlier, we found that the nth term is given by a_n = n(n+1). So, for the + 10th term, a_10 = 10 * 11, which equals 110. \\n\\nTo find the sum of the + first 10 terms, I calculated the sum of n(n+1) from 1 to 10, which gives us + 440. Thus, the 10th term is 110, and the sum of the first 10 terms is 440.\"\n + \ },\n {\n \"type\": \"summary_text\",\n \"text\": + \"**Summing pronic numbers**\\n\\nI've noticed that the terms we're discussing + are pronic numbers, also known as rectangular or oblong numbers. The 10th + term is straightforward: it's 10 times 11, which equals 110. \\n\\nFor the + sum of the first 10 terms, I derived the formula and found it's 440. This + comes from summing \\\\( n^2 + n \\\\), leading to the total being 385 (for + \\\\( n^2 \\\\)) plus 55 (for \\\\( n \\\\)). \\n\\nSo, the final answers + are: \\n- 10th term: 110 \\n- Sum of the first 10 terms: 440.\"\n }\n + \ ]\n },\n {\n \"id\": \"msg_0ec7311e7547baf10069ebed69f3388197aff44b644c688e25\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The nth term is a\\u2099 + = n\\u00b7(n+1). \\n1. 10th term: \\n a\\u2081\\u2080 = 10\\u00b7(10+1) + = 10\\u00b711 = 110. \\n2. Sum of the first 10 terms: \\n S\\u2081\\u2080 + = \\u03a3\\u2099\\u208c\\u2081\\u00b9\\u2070 n(n+1) = \\u03a3 n\\u00b2 + \\u03a3 + n \\n = [10\\u00b711\\u00b721/6] + [10\\u00b711/2] \\n = 385 + + 55 \\n = 440. \\n\\n(You can also use the closed-form S_N = N(N+1)(N+2)/3, + which for N=10 gives 10\\u00b711\\u00b712/3 = 440.)\"\n }\n ],\n + \ \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": true,\n + \ \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 248,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 884,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 704\n },\n \"total_tokens\": 1132\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:38 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3198' + openai-processing-ms: + - '8887' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999545' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0f0e19b1e33659e70069ebeec4ac90819395dd1386b77bc12a\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069764,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069774,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0f0e19b1e33659e70069ebeec5129c8193bfdc8491336cba05\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Determining nth term formula**\\n\\nThe + user is interested in identifying the pattern in the sequence: 2, 6, 12, 20, + 30. I notice that each term corresponds to n multiplied by (n + 1): 1*2, 2*3, + 3*4, and so forth. The formula for the nth term is a_n = n(n + 1). Alternatively, + these can be viewed as twice the triangular numbers, and the terms stack up + as pronic numbers. So, the formula remains consistent as a_n = n(n + 1).\"\n + \ },\n {\n \"type\": \"summary_text\",\n \"text\": + \"**Identifying the pronic pattern**\\n\\nThe user asks about the pattern + in the sequence, and it appears to follow a quadratic form resulting from + the product of two consecutive integers, also known as pronic numbers. Each + term can be represented as a_n = n(n + 1). Additionally, I noticed that the + differences between terms\\u20144, 6, 8, 10\\u2014show a consistent second + difference of 2, supporting the quadratic nature. Therefore, the formula for + the nth term is clearly a_n = n(n + 1).\"\n },\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Summarizing the pattern**\\n\\nThe + final answer is that the pattern involves each term being the product of two + consecutive integers, represented by the general term a_n = n(n + 1). The + differences between the terms increase by 2: +4, +6, +8, and so on. The sequence + can also be referred to as pronic numbers. So, for n \\u2265 1, the formula + is a_n = n^2 + n. Alternatively, it falls under the category of oblong or + heteromecic numbers.\"\n }\n ]\n },\n {\n \"id\": \"msg_0f0e19b1e33659e70069ebeece64c08193a62ba6ae521cec7a\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The \\u201cgaps\\u201d + between terms are \\n6\\u20132=4, 12\\u20136=6, 20\\u201312=8, 30\\u201320=10, + \\u2026 \\nso you\\u2019re adding 4,6,8,10,\\u2026 (i.e. the even numbers + increasing by 2). \\nThat makes the sequence quadratic, and one checks that + \ \\na\\u2081=2, a\\u2082=6, a\\u2083=12,\\u2026 all fit \\n\\u2003a\\u2099=n\\u00b2+n. + \ \\n\\nEquivalently, each term is the product of two consecutive integers + (the pronic or oblong numbers): \\n\\u2003a\\u2099 = n\\u00b7(n+1).\"\n }\n + \ ],\n \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": + true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 41,\n \"input_tokens_details\": {\n + \ \"cached_tokens\": 0\n },\n \"output_tokens\": 1259,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 1088\n },\n \"total_tokens\": 1300\n + \ },\n \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:35 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3737' + openai-processing-ms: + - '10398' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_0f0e19b1e33659e70069ebeec5129c8193bfdc8491336cba05\",\"summary\":[{\"text\":\"**Determining + nth term formula**\\n\\nThe user is interested in identifying the pattern in + the sequence: 2, 6, 12, 20, 30. I notice that each term corresponds to n multiplied + by (n + 1): 1*2, 2*3, 3*4, and so forth. The formula for the nth term is a_n + = n(n + 1). Alternatively, these can be viewed as twice the triangular numbers, + and the terms stack up as pronic numbers. So, the formula remains consistent + as a_n = n(n + 1).\",\"type\":\"summary_text\"},{\"text\":\"**Identifying the + pronic pattern**\\n\\nThe user asks about the pattern in the sequence, and it + appears to follow a quadratic form resulting from the product of two consecutive + integers, also known as pronic numbers. Each term can be represented as a_n + = n(n + 1). Additionally, I noticed that the differences between terms\u20144, + 6, 8, 10\u2014show a consistent second difference of 2, supporting the quadratic + nature. Therefore, the formula for the nth term is clearly a_n = n(n + 1).\",\"type\":\"summary_text\"},{\"text\":\"**Summarizing + the pattern**\\n\\nThe final answer is that the pattern involves each term being + the product of two consecutive integers, represented by the general term a_n + = n(n + 1). The differences between the terms increase by 2: +4, +6, +8, and + so on. The sequence can also be referred to as pronic numbers. So, for n \u2265 + 1, the formula is a_n = n^2 + n. Alternatively, it falls under the category + of oblong or heteromecic numbers.\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_0f0e19b1e33659e70069ebeece64c08193a62ba6ae521cec7a\",\"content\":[{\"annotations\":[],\"text\":\"The + \u201Cgaps\u201D between terms are \\n6\u20132=4, 12\u20136=6, 20\u201312=8, + 30\u201320=10, \u2026 \\nso you\u2019re adding 4,6,8,10,\u2026 (i.e. the even + numbers increasing by 2). \\nThat makes the sequence quadratic, and one checks + that \\na\u2081=2, a\u2082=6, a\u2083=12,\u2026 all fit \\n\u2003a\u2099=n\xB2+n. + \ \\n\\nEquivalently, each term is the product of two consecutive integers (the + pronic or oblong numbers): \\n\u2003a\u2099 = n\xB7(n+1).\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2489' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0f0e19b1e33659e70069ebeecf4d4c81939852c1b829c85cfa\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069775,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069782,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0f0e19b1e33659e70069ebeecfe85c81939654f22182d7bf01\",\n + \ \"type\": \"reasoning\",\n \"summary\": []\n },\n {\n \"id\": + \"msg_0f0e19b1e33659e70069ebeed5a2688193803ea2a253dadd96\",\n \"type\": + \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n + \ \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": + [],\n \"text\": \"The 10th term is \\n a\\u2081\\u2080 = 10\\u00b7(10+1) + = 110. \\nThe sum of the first 10 terms is \\n \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 + n(n+1) = \\u2211n\\u00b2 + \\u2211n = 385 + 55 = 440. \\n\\n(Equivalently, + \\u2211\\u2099\\u208c\\u2081\\u207f n(n+1) = n(n+1)(n+2)/3, so for n=10: 10\\u00b711\\u00b712/3 + = 440.)\"\n }\n ],\n \"role\": \"assistant\"\n }\n ],\n + \ \"parallel_tool_calls\": true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": + null,\n \"prompt_cache_key\": null,\n \"prompt_cache_retention\": \"in_memory\",\n + \ \"reasoning\": {\n \"effort\": \"high\",\n \"summary\": \"detailed\"\n + \ },\n \"safety_identifier\": null,\n \"service_tier\": \"default\",\n \"store\": + true,\n \"temperature\": 1.0,\n \"text\": {\n \"format\": {\n \"type\": + \"text\"\n },\n \"verbosity\": \"medium\"\n },\n \"tool_choice\": + \"auto\",\n \"tools\": [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": + \"disabled\",\n \"usage\": {\n \"input_tokens\": 218,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 718,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 576\n },\n \"total_tokens\": 936\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:42 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '2002' + openai-processing-ms: + - '7064' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999575' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/streaming.yaml b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/streaming.yaml new file mode 100644 index 00000000..52d5aeed --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/streaming.yaml @@ -0,0 +1,402 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a thoughtful assistant"},{"role":"user","content":"Count + from 1 to 10 slowly."}],"model":"gpt-4o-mini","max_tokens":800,"stream":true,"stream_options":{"include_usage":true},"temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '241' + Content-Type: + - application/json + Host: + - api.openai.com + X-Stainless-Helper-Method: + - chat.completions.stream + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: 'data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"6ILSJ3H83"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Sure"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0HUQHXV"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WDbW7aXpY0"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + Here"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"92QYSQ"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + we"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OiPq9mC5"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"b2llJLZn"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":":\n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"klFQCV"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"1"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LXr7eoheIl"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nb0F7NXA"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LfkBggM"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"2"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hpcDI3G4n2"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QRqsqegc"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XREPAMg"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KYGOLw44ko"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XyfWB7v2"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"z2gHRL9"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"4"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"XdCCiSXD59"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hg0U7yyA"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"thWPgIC"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"5"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PGPXboZ6io"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"McuVtsel"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dV3hU3y"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"G8imTMWQGb"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"HRqBvkdg"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"zm0zS2A"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"7"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gf5rDQuP9P"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lzH5QDtQ"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"1MNZhBI"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"8"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZeOEIC60IC"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"EpSJ3q5E"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gYXd9gx"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"9"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jqBdqVtQqy"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Pub1Ypu6"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uH5iomU"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"10"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FYfYAhORM"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tRzb82lM"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2fcOT"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"There"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"neHgnz"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + you"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gOgKud0"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + have"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"IxOAME"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + it"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Hs5yTXdx"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gnwvibghB8"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"MdxBv"} + + + data: {"id":"chatcmpl-DYJDvoCMPbusuYo8H3SsPIc0I5bZJ","object":"chat.completion.chunk","created":1777069419,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[],"usage":{"prompt_tokens":25,"completion_tokens":41,"total_tokens":66,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"uFNDrrqCMC"} + + + data: [DONE] + + + ' + headers: + Connection: + - keep-alive + Content-Type: + - text/event-stream; charset=utf-8 + Date: + - Fri, 24 Apr 2026 22:23:39 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + openai-processing-ms: + - '251' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"system","content":"you are a thoughtful assistant"},{"role":"user","content":"Count + from 1 to 10 slowly."}],"model":"gpt-4o-mini","max_tokens":800,"stream":true,"stream_options":{"include_usage":true},"temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '241' + Content-Type: + - application/json + Host: + - api.openai.com + X-Stainless-Helper-Method: + - chat.completions.stream + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: 'data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"O1Ay0f6KZ"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Sure"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hijBbiM"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"pTYkwoohgI"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + Here"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cFs2HD"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + we"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3i9qpfPQ"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"xFO7yiyC"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":":\n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hKat17"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"1"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"7GA4p4r3eQ"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"i4g6E3SY"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SEXyjZV"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"2"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5WlajAo2A5"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LdGs8y5E"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"NISipUj"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3SxCMJVFWn"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"2W4DZCxc"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OxbqPYF"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"4"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"RF7unYdtGZ"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"i6FRCnTf"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"lPW0Ufz"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"5"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5YNUSwydpi"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TSCCSenq"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"us8lJ23"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kvq3isboGx"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"dw0qCGap"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JWKavIT"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"7"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"8wyPEV767o"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tNqWX4hM"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"PWft3xz"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"8"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uFNVWHWO03"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"OxAq5zem"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"FSXjOAy"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"9"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Nes3UFVaak"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"T3BF9KTo"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ivKwGyt"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"10"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jlPDLWyY8"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"iRfNkTIU"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZtJ7z"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Take"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"VXH8oqG"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + your"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"GCnHFg"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + time"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"It5SMF"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"tHtMSkPOdm"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"GY7w0"} + + + data: {"id":"chatcmpl-DYJJmPaxUZh0YogB6BNia2VHxcZ39","object":"chat.completion.chunk","created":1777069782,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[],"usage":{"prompt_tokens":25,"completion_tokens":40,"total_tokens":65,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"zhvVBZX62K"} + + + data: [DONE] + + + ' + headers: + Connection: + - keep-alive + Content-Type: + - text/event-stream; charset=utf-8 + Date: + - Fri, 24 Apr 2026 22:29:43 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + openai-processing-ms: + - '1134' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/tools.yaml b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/tools.yaml new file mode 100644 index 00000000..6f0801a0 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/1.92.0/btx/tools.yaml @@ -0,0 +1,158 @@ +interactions: +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJDwm57pZIPaUtAFW19MIDtT7HHa\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069420,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_rhT4SgoSZp4MlzC8NlsLcesf\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:23:40 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '430' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999987' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJJoe6WpECm6FP0hr0aQp3Hh1uAa\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069784,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_90SKpviW2gcXhBVkVkiQLrKw\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:29:45 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '634' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999987' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/latest/btx/attachments.yaml b/py/src/braintrust/integrations/openai/cassettes/latest/btx/attachments.yaml new file mode 100644 index 00000000..db6339ac --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/latest/btx/attachments.yaml @@ -0,0 +1,79 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":[{"type":"text","text":"What + color is this image?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="}}]}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '353' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJBh4OEtcKC8rGUh4nzfqBNAVSNm\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069281,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The image is red.\",\n \"refusal\": + null,\n \"annotations\": []\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 8522,\n \"completion_tokens\": 5,\n \"total_tokens\": 8527,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_4bbcc62b19\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:21:22 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '827' + openai-processing-ms: + - '729' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-input-images: + - '50000' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-input-images: + - '49999' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999220' + x-ratelimit-reset-input-images: + - 1ms + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/latest/btx/completions.yaml b/py/src/braintrust/integrations/openai/cassettes/latest/btx/completions.yaml new file mode 100644 index 00000000..cb890c08 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/latest/btx/completions.yaml @@ -0,0 +1,73 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a helpful assistant"},{"role":"user","content":"What + is the capital of France?"}],"model":"gpt-4o-mini","temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '171' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJBiYtjOSDKd8RMDGXj5lIHPvQvG\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069282,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The capital of France is Paris.\",\n + \ \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 23,\n \"completion_tokens\": 7,\n \"total_tokens\": 30,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_f957560a82\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:21:23 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '837' + openai-processing-ms: + - '378' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999982' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/latest/btx/reasoning.yaml b/py/src/braintrust/integrations/openai/cassettes/latest/btx/reasoning.yaml new file mode 100644 index 00000000..01ea5aeb --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/latest/btx/reasoning.yaml @@ -0,0 +1,223 @@ +interactions: +- request: + body: '{"input":[{"role":"user","content":"Look at this sequence: 2, 6, 12, 20, + 30. What is the pattern and what would be the formula for the nth term?\n"}],"model":"o4-mini","reasoning":{"effort":"high","summary":"detailed"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '219' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0c4bd3230ad523240069ebece370c88190ab7b2e512bdcf734\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069283,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069295,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0c4bd3230ad523240069ebece445988190a114335cfba8cc0e\",\n + \ \"type\": \"reasoning\",\n \"summary\": [\n {\n \"type\": + \"summary_text\",\n \"text\": \"**Identifying the sequence pattern**\\n\\nThe + user's sequence is 2, 6, 12, 20, 30, and I'm figuring out the pattern and + the formula for the nth term. Each term seems to follow the formula a_n = + n(n + 1), starting with n = 1. This makes sense since: 1*2 = 2, 2*3 = 6, and + so on. These numbers also correspond to doubling the triangular numbers. So, + the formula a_n = n(n + 1) is confirmed as correct!\"\n },\n {\n + \ \"type\": \"summary_text\",\n \"text\": \"**Finalizing + the sequence formula**\\n\\nI realized that indexing from n=0 gives an incorrect + result because it yields 0. The sequence starts at n=1, leading to the conclusion + that a_n = n(n + 1). This pattern shows that the differences between terms + (4, 6, 8, 10, etc.) are increasing, confirming it's quadratic. The final formula + indicates that these are pronic numbers, which can be expressed as products + of consecutive integers. So, the nth term remains a_n = n(n + 1), and that's + settled!\"\n },\n {\n \"type\": \"summary_text\",\n + \ \"text\": \"**Formulating the final answer**\\n\\nI\\u2019ve concluded + it\\u2019s best to start indexing the sequence from n=1. I\\u2019ll provide + the pattern for the differences, which are 4, 6, 8, 10, etc. This leads to + the formula a_n = n^2 + n. Now, I'm composing the final response, summarizing + these key insights and ensuring everything is clear. I'll make sure all the + details align with this formula so that it\\u2019s easily understood. Let's + finalize it!\"\n }\n ]\n },\n {\n \"id\": \"msg_0c4bd3230ad523240069ebecee930881908341f2a0e7613c7d\",\n + \ \"type\": \"message\",\n \"status\": \"completed\",\n \"content\": + [\n {\n \"type\": \"output_text\",\n \"annotations\": + [],\n \"logprobs\": [],\n \"text\": \"The terms are \\n + 2, 6, 12, 20, 30, \\u2026 \\nand the differences between them are + \ \\n 6\\u22122=4, 12\\u22126=6, 20\\u221212=8, 30\\u221220=10, \\u2026 \\nso + the \\u201cgap\\u201d grows by 2 each time \\u21d2 the sequence is quadratic. + \ In fact one checks that\\n\\n a\\u2081=2, a\\u2082=6, a\\u2083=12, \\u2026 + \\n\\nfit the rule \\n a\\u2099 = n\\u00b2+n. \\n\\nEquivalently, each term + is the product of two consecutive integers:\\n\\n a\\u2099 = n\\u00b7(n+1).\"\n + \ }\n ],\n \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": + true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 41,\n \"input_tokens_details\": {\n + \ \"cached_tokens\": 0\n },\n \"output_tokens\": 1125,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 960\n },\n \"total_tokens\": 1166\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:21:35 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '3715' + openai-processing-ms: + - '11967' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999752' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +- request: + body: "{\"input\":[{\"role\":\"user\",\"content\":\"Look at this sequence: 2, + 6, 12, 20, 30. What is the pattern and what would be the formula for the nth + term?\\n\"},{\"id\":\"rs_0c4bd3230ad523240069ebece445988190a114335cfba8cc0e\",\"summary\":[{\"text\":\"**Identifying + the sequence pattern**\\n\\nThe user's sequence is 2, 6, 12, 20, 30, and I'm + figuring out the pattern and the formula for the nth term. Each term seems to + follow the formula a_n = n(n + 1), starting with n = 1. This makes sense since: + 1*2 = 2, 2*3 = 6, and so on. These numbers also correspond to doubling the triangular + numbers. So, the formula a_n = n(n + 1) is confirmed as correct!\",\"type\":\"summary_text\"},{\"text\":\"**Finalizing + the sequence formula**\\n\\nI realized that indexing from n=0 gives an incorrect + result because it yields 0. The sequence starts at n=1, leading to the conclusion + that a_n = n(n + 1). This pattern shows that the differences between terms (4, + 6, 8, 10, etc.) are increasing, confirming it's quadratic. The final formula + indicates that these are pronic numbers, which can be expressed as products + of consecutive integers. So, the nth term remains a_n = n(n + 1), and that's + settled!\",\"type\":\"summary_text\"},{\"text\":\"**Formulating the final answer**\\n\\nI\u2019ve + concluded it\u2019s best to start indexing the sequence from n=1. I\u2019ll + provide the pattern for the differences, which are 4, 6, 8, 10, etc. This leads + to the formula a_n = n^2 + n. Now, I'm composing the final response, summarizing + these key insights and ensuring everything is clear. I'll make sure all the + details align with this formula so that it\u2019s easily understood. Let's finalize + it!\",\"type\":\"summary_text\"}],\"type\":\"reasoning\"},{\"id\":\"msg_0c4bd3230ad523240069ebecee930881908341f2a0e7613c7d\",\"content\":[{\"annotations\":[],\"text\":\"The + terms are \\n 2, 6, 12, 20, 30, \u2026 \\nand the differences between + them are \\n 6\u22122=4, 12\u22126=6, 20\u221212=8, 30\u221220=10, \u2026 \\nso + the \u201Cgap\u201D grows by 2 each time \u21D2 the sequence is quadratic. In + fact one checks that\\n\\n a\u2081=2, a\u2082=6, a\u2083=12, \u2026 \\n\\nfit + the rule \\n a\u2099 = n\xB2+n. \\n\\nEquivalently, each term is the product + of two consecutive integers:\\n\\n a\u2099 = n\xB7(n+1).\",\"type\":\"output_text\",\"logprobs\":[]}],\"role\":\"assistant\",\"status\":\"completed\",\"type\":\"message\"},{\"role\":\"user\",\"content\":\"Using + the pattern you discovered, what would be the 10th term? And can you find the + sum of the first 10 terms?\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"high\",\"summary\":\"detailed\"}}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2471' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: "{\n \"id\": \"resp_0c4bd3230ad523240069ebecf06a108190942c0ca4fef98cbf\",\n + \ \"object\": \"response\",\n \"created_at\": 1777069296,\n \"status\": + \"completed\",\n \"background\": false,\n \"billing\": {\n \"payer\": + \"developer\"\n },\n \"completed_at\": 1777069305,\n \"error\": null,\n + \ \"frequency_penalty\": 0.0,\n \"incomplete_details\": null,\n \"instructions\": + null,\n \"max_output_tokens\": null,\n \"max_tool_calls\": null,\n \"model\": + \"o4-mini-2025-04-16\",\n \"moderation\": null,\n \"output\": [\n {\n + \ \"id\": \"rs_0c4bd3230ad523240069ebecf17210819097082910f1f7da6b\",\n + \ \"type\": \"reasoning\",\n \"summary\": []\n },\n {\n \"id\": + \"msg_0c4bd3230ad523240069ebecf808e48190926a46d82556b9dd\",\n \"type\": + \"message\",\n \"status\": \"completed\",\n \"content\": [\n {\n + \ \"type\": \"output_text\",\n \"annotations\": [],\n \"logprobs\": + [],\n \"text\": \"The general term is \\n a\\u2099 = n\\u00b7(n+1). + \ \\nSo for n=10: \\n a\\u2081\\u2080 = 10\\u00b711 = 110. \\n\\nFor the + sum \\n S\\u2081\\u2080 = \\u2211\\u2099\\u208c\\u2081\\u00b9\\u2070 n(n+1) + \ \\n = \\u2211n\\u00b2 + \\u2211n \\n = (10\\u00b711\\u00b721)/6 + + (10\\u00b711)/2 \\n = 385 + 55 \\n = 440. \\n\\nEquivalently, + one can use the closed\\u2010form \\n \\u2211\\u2099\\u208c\\u2081\\u207f + n(n+1) = n(n+1)(n+2)/3, \\nso for n=10: 10\\u00b711\\u00b712/3 = 440.\"\n + \ }\n ],\n \"role\": \"assistant\"\n }\n ],\n \"parallel_tool_calls\": + true,\n \"presence_penalty\": 0.0,\n \"previous_response_id\": null,\n \"prompt_cache_key\": + null,\n \"prompt_cache_retention\": \"in_memory\",\n \"reasoning\": {\n + \ \"effort\": \"high\",\n \"summary\": \"detailed\"\n },\n \"safety_identifier\": + null,\n \"service_tier\": \"default\",\n \"store\": true,\n \"temperature\": + 1.0,\n \"text\": {\n \"format\": {\n \"type\": \"text\"\n },\n + \ \"verbosity\": \"medium\"\n },\n \"tool_choice\": \"auto\",\n \"tools\": + [],\n \"top_logprobs\": 0,\n \"top_p\": 1.0,\n \"truncation\": \"disabled\",\n + \ \"usage\": {\n \"input_tokens\": 224,\n \"input_tokens_details\": + {\n \"cached_tokens\": 0\n },\n \"output_tokens\": 691,\n \"output_tokens_details\": + {\n \"reasoning_tokens\": 512\n },\n \"total_tokens\": 915\n },\n + \ \"user\": null,\n \"metadata\": {}\n}" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:21:45 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + content-length: + - '2162' + openai-processing-ms: + - '9292' + openai-version: + - '2020-10-01' + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999570' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/latest/btx/streaming.yaml b/py/src/braintrust/integrations/openai/cassettes/latest/btx/streaming.yaml new file mode 100644 index 00000000..dcdb558b --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/latest/btx/streaming.yaml @@ -0,0 +1,204 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"you are a thoughtful assistant"},{"role":"user","content":"Count + from 1 to 10 slowly."}],"model":"gpt-4o-mini","max_tokens":800,"stream":true,"stream_options":{"include_usage":true},"temperature":0.0}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '241' + Content-Type: + - application/json + Host: + - api.openai.com + X-Stainless-Helper-Method: + - chat.completions.stream + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: 'data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"QI7LKcfz0"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"Sure"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Vjv3AEP"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ZIqRkSiO6x"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + Here"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"hDuNBu"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + we"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"nwGOYO6O"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + go"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Yfoy1svO"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":":\n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"qhe4sR"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"1"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Fc4JwTFMrJ"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uG8micA6"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"i0RfzE1"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"2"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UCyvA95buc"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"AJCQJYL0"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BWv1zeX"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YiXgCDwDiC"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"KSVuLCJI"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"cUkZYTc"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"4"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"woRZ8zCgaj"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"gLZ2gGK8"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"MHhIwNj"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"5"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"wTnrzF6x4u"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BSddNyto"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"X5Ml0r5"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"H0LYhiXNZF"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Rg9i9tKf"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"F3SNltj"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"7"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"E1MgcBT7Az"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Zo9QxPFC"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"LR4jBcY"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"8"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"G7AERU7nMx"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0FLAvVp6"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kUlhVqz"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"9"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Bllo9gGt8F"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"3HZaaX5D"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JoXFuwS"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"10"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"kanRLzFo9"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"..."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"YDgaB953"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" \n\n"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"jk3Oa"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"There"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"aNhk1U"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + you"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"SMU9VdS"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + have"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"TrmYKB"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":" + it"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"n7yhanE7"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"JM0wpz1E6b"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"OvJ5J"} + + + data: {"id":"chatcmpl-DYJC637QICO5rMNyVc4LcRllHinAh","object":"chat.completion.chunk","created":1777069306,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_77c1b30b18","choices":[],"usage":{"prompt_tokens":25,"completion_tokens":41,"total_tokens":66,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"MDaX6BWfIo"} + + + data: [DONE] + + + ' + headers: + Connection: + - keep-alive + Content-Type: + - text/event-stream; charset=utf-8 + Date: + - Fri, 24 Apr 2026 22:21:46 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + openai-processing-ms: + - '237' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999985' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1 diff --git a/py/src/braintrust/integrations/openai/cassettes/latest/btx/tools.yaml b/py/src/braintrust/integrations/openai/cassettes/latest/btx/tools.yaml new file mode 100644 index 00000000..7c74b648 --- /dev/null +++ b/py/src/braintrust/integrations/openai/cassettes/latest/btx/tools.yaml @@ -0,0 +1,80 @@ +interactions: +- request: + body: '{"messages":[{"role":"user","content":"What is the weather like in Paris, + France?"}],"model":"gpt-4o","max_tokens":500,"temperature":0.0,"tools":[{"type":"function","function":{"name":"get_weather","description":"Get + the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The + city and state, e.g. San Francisco, CA"},"unit":{"type":"string","enum":["celsius","fahrenheit"],"description":"The + unit of temperature"}},"required":["location"]}}}]}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '511' + Content-Type: + - application/json + Host: + - api.openai.com + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: "{\n \"id\": \"chatcmpl-DYJC77yOw6rmB6Cg3aYumNh3q9VdC\",\n \"object\": + \"chat.completion\",\n \"created\": 1777069307,\n \"model\": \"gpt-4o-2024-08-06\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n + \ \"id\": \"call_n9mTbnAj0OxTE5vQV0sPNobD\",\n \"type\": + \"function\",\n \"function\": {\n \"name\": \"get_weather\",\n + \ \"arguments\": \"{\\\"location\\\":\\\"Paris, France\\\"}\"\n + \ }\n }\n ],\n \"refusal\": null,\n \"annotations\": + []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 85,\n \"completion_tokens\": + 16,\n \"total_tokens\": 101,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_d59908c1a9\"\n}\n" + headers: + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Fri, 24 Apr 2026 22:21:47 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + content-length: + - '1092' + openai-processing-ms: + - '487' + openai-version: + - '2020-10-01' + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '30000000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '29999987' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + status: + code: 200 + message: OK +version: 1