Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
809c488
add new smoke test for cloudflare + vite
ibolmo Jan 15, 2026
1a5f0b3
add vite dev test
ibolmo Jan 15, 2026
257e639
revert
ibolmo Jan 16, 2026
d5a0d9c
split smoke jobs
ibolmo Jan 16, 2026
b2f2f03
make sure to run the npm run test:vitest-dev always
ibolmo Jan 16, 2026
c99e945
add multiple cloudflare tests and change bundling for the browser build
cpinn Jan 15, 2026
0e3026b
remove support in nextjs
cpinn Jan 15, 2026
0e8dc7b
updates
cpinn Jan 16, 2026
5f77bc6
add full matrix of compatibility
cpinn Jan 16, 2026
c63ff07
ensure all 4 environments are checked
cpinn Jan 16, 2026
f4f105b
add back proper error, undo browser test changes
cpinn Jan 16, 2026
0c5f091
modifications to run deno mjs and deno browser
cpinn Jan 16, 2026
8d2e5e2
initial isomorph commit
cpinn Jan 16, 2026
7da0b6f
fix nunjucks prompt tests and add a bit of cleanup
cpinn Jan 16, 2026
91f012d
only include configure node in the test that needs it
cpinn Jan 16, 2026
9159c37
refactor cloudflare worker tests and add more information on the test…
cpinn Jan 16, 2026
07135b3
modify vite react hono cloudflare test to use braintrust/browser
cpinn Jan 16, 2026
bb23716
modify isomorph configuration, cleanup
cpinn Jan 16, 2026
c418c77
allow error to be thrown for vite-react-hono
cpinn Jan 16, 2026
a8b7824
fix the type errors
cpinn Jan 16, 2026
ae41133
fix missing node: prefix, require eslint node: prefix, and update tsu…
ibolmo Jan 16, 2026
6d2287c
tweak prepare to use turbo
ibolmo Jan 16, 2026
3477596
nest deno browser and deno node under deno
cpinn Jan 16, 2026
fa95170
still requiring some node modules in deno node, fix cloudflare packag…
cpinn Jan 16, 2026
369434d
small workflow update, deno update
cpinn Jan 17, 2026
1539428
remove all the node modules in the node deno file
cpinn Jan 17, 2026
24392f7
mark a few packages as noexternal to be easier for deno
cpinn Jan 17, 2026
bc25fda
add simplifications to the deno flow
cpinn Jan 17, 2026
6233f9c
remove no-external
cpinn Jan 20, 2026
9108e84
remove browser templates
cpinn Jan 20, 2026
9ec8e9d
Smoke v2 (#1283)
ibolmo Jan 20, 2026
8f578db
Merge branch 'main' into caitlin/externalize
cpinn Jan 20, 2026
04ebd69
add a recent compatibility date
cpinn Jan 20, 2026
51afb78
remove the additional no external
cpinn Jan 20, 2026
ea95479
Revert "add a recent compatibility date"
cpinn Jan 21, 2026
4d03120
Merge branch 'main' into caitlin/externalize
cpinn Jan 21, 2026
7180b69
try to fix deno
ibolmo Jan 21, 2026
0247412
avoid deno install
ibolmo Jan 21, 2026
5f5dc16
try removing deno lock
ibolmo Jan 21, 2026
c42ed80
fix deno-browserg
ibolmo Jan 21, 2026
0c31a02
Merge branch 'main' into caitlin/externalize
cpinn Jan 21, 2026
fa88223
Modify package json exports for browser environments (#1295)
cpinn Jan 22, 2026
a8072d6
Robust-er smoke tests (#1299)
ibolmo Jan 23, 2026
e722771
Remove advanced templating option (#1277)
cpinn Jan 29, 2026
b0472d3
Merge branch 'main' into caitlin/externalize
cpinn Jan 29, 2026
cda1390
Merge branch 'main' into caitlin/externalize
cpinn Feb 4, 2026
89312ca
Merge branch 'main' into caitlin/externalize
cpinn Feb 9, 2026
3ffe46a
modify dependency
cpinn Feb 9, 2026
715f2a5
make dependency reliant on 3.0.0 version
cpinn Feb 9, 2026
4f5eb82
update lockfile
cpinn Feb 9, 2026
490fe4d
ensure only one copy of browser configuration is enabled
cpinn Feb 9, 2026
72d4261
change to casting as
cpinn Feb 9, 2026
0132561
Merge branch 'main' into caitlin/externalize
cpinn Feb 10, 2026
347b5d6
add symbols to main braintrust package for configuring node and setti…
cpinn Feb 11, 2026
3c523bd
fix
cpinn Feb 11, 2026
9b887f9
some weird state management
cpinn Feb 11, 2026
44426cb
fix an issue with global state
cpinn Feb 13, 2026
23a6a99
Merge branch 'main' into caitlin/externalize
cpinn Feb 13, 2026
71d5ef5
remove unused import
cpinn Feb 13, 2026
aff3244
update readme and exports
cpinn Feb 16, 2026
25867b4
Merge branch 'main' into caitlin/externalize
cpinn Feb 17, 2026
0ca79c5
replace and don't re-use the string variable
cpinn Feb 17, 2026
73c28c3
remove the symbol file
cpinn Feb 17, 2026
cec0960
update readme with email
cpinn Feb 17, 2026
429595e
Small pending improvements to bt 3.x (#1383)
ibolmo Feb 18, 2026
c16291c
Remove braintrust browser from some wrangler tests (#1386)
cpinn Feb 18, 2026
ca9ab58
Merge branch 'main' into caitlin/externalize
cpinn Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
440 changes: 100 additions & 340 deletions .github/workflows/js.yaml

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions .github/workflows/templates-nunjucks-build-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: templates-nunjucks-js

on:
pull_request:
paths:
- "integrations/templates-nunjucks/**"
- "js/**"
- ".github/workflows/templates-nunjucks-build-test.yaml"
push:
branches: [main]
paths:
- "integrations/templates-nunjucks/**"
- "js/**"

jobs:
build-and-test:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
node-version: [20, 22]

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- uses: pnpm/action-setup@v4

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build braintrust
working-directory: js
run: pnpm run build

- name: Build @braintrust/templates-nunjucks-js
working-directory: integrations/templates-nunjucks
run: pnpm run build

- name: Run @braintrust/templates-nunjucks-js tests
working-directory: integrations/templates-nunjucks
run: pnpm run test
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ repos:
)$
args:
- "-L"
- "rouge,coo,couldn,unsecure,ontext,afterall"
- "rouge,coo,couldn,unsecure,ontext,afterall,als"
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.3.2
hooks:
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ js-build:
pnpm run build

js-test: js-build
pnpm run test
# Run tests only for the JS workspace packages and exclude integration scenario tests
pnpm --filter ./js... run test
cd js && make test

js-docs: js-build
Expand Down
77 changes: 77 additions & 0 deletions integrations/browser-js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Braintrust Browser SDK

Official browser-only SDK for [Braintrust](https://braintrust.dev).

This is an integration package that provides browser-optimized builds of the Braintrust SDK with AsyncLocalStorage polyfill support for standard browsers.

Note: This package supports limited functionality in the browser. We're aware of a CORS issue that users may run into if they use this outside of the braintrust.dev domain. If you'd like to use this package in your own domain, please provide us feedback [support@braintrust.dev](mailto:support@braintrust.dev)

## Installation

```bash
npm install @braintrust/browser braintrust
# or
pnpm add @braintrust/browser braintrust
# or
yarn add @braintrust/browser braintrust
```

Note: `braintrust` is a peer dependency and must be installed alongside `@braintrust/browser`.

## Usage

```typescript
import * as braintrust from "@braintrust/browser";

const experiment = await braintrust.init("BrowserExperiment", {
apiKey: "YOUR_API_KEY",
});

// Use tracing in browser
const result = await braintrust.traced(
async () => {
// Your code here
return "result";
},
{ name: "myOperation" },
);
```

## Differences from Main Package

This package:

- **Includes** `als-browser` polyfill for AsyncLocalStorage (bundled)
- **Requires** `braintrust`

## When to Use

Use `@braintrust/browser` when:

- Building browser-only applications
- Need AsyncLocalStorage support in standard browsers

Use `braintrust` directly when:

- Building Node.js applications
- Using in Next.js or other full-stack frameworks (with proper module resolution)
- Need CLI tools or filesystem access

## Features

All browser-compatible features from the main SDK:

- Logging and tracing
- Experiments and datasets
- Prompt management
- AI provider wrappers (OpenAI, Anthropic, Google)
- Evaluation framework
- OpenTelemetry integration

## Documentation

For full documentation, visit [https://www.braintrust.dev/docs](https://www.braintrust.dev/docs)

## License

Apache-2.0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#nit I think we're almost always MIT. I could be wrong

Copy link
Copy Markdown
Contributor Author

@cpinn Caitlin Pinn (cpinn) Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually something I have been meaning to ask about.

We keep declaring our license as MIT but our license is actually Apache 2.0 (so it would overwrite and publish as apache 2.0). I have been pretty confused which license we were intending to go with.

See actual license used during publishing to npm: https://github.com/braintrustdata/braintrust-sdk/blob/main/LICENSE

  • I got pretty confused when I was publishing and noticing a totally different license was being included.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah no you're right then i think we are apache then 👍🏻

55 changes: 55 additions & 0 deletions integrations/browser-js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "@braintrust/browser",
"version": "0.0.2-rc.4",
"description": "Braintrust SDK for browser environments with AsyncLocalStorage polyfill",
"type": "module",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist",
"README.md"
],
"scripts": {
"build": "tsup",
"watch": "tsup --watch",
"clean": "rm -rf dist",
"test": "vitest run"
},
"dependencies": {
"als-browser": "^1.0.1",
"braintrust": ">=3.0.0-rc.29"
},
"devDependencies": {
"@types/node": "^20.10.5",
"braintrust": "workspace:*",
"tsup": "^8.3.5",
"typescript": "^5.3.3",
"vitest": "^2.1.9"
},
"peerDependencies": {
"zod": "^3.25.34 || ^4.0"
},
"peerDependenciesMeta": {
"zod": {
"optional": false
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/braintrustdata/braintrust-sdk.git",
"directory": "sdk/integrations/browser-js"
},
"homepage": "https://www.braintrust.dev/docs",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}
}
41 changes: 41 additions & 0 deletions integrations/browser-js/src/browser-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { _internalIso as iso, _internalSetInitialState } from "braintrust";
import { AsyncLocalStorage as BrowserAsyncLocalStorage } from "als-browser";

export function configureBrowser() {
// Set build type indicator
iso.buildType = "browser-js";

iso.newAsyncLocalStorage = <T>() => new BrowserAsyncLocalStorage<T>();

iso.getEnv = (name: string) => {
if (typeof process === "undefined" || typeof process.env === "undefined") {
return undefined;
}
return process.env[name];
};

// noop implementations for git config
iso.getRepoInfo = async () => ({
commit: null,
branch: null,
tag: null,
dirty: false,
});
iso.getCallerLocation = () => undefined;

// Implement browser-compatible hash function using a simple hash algorithm
iso.hash = (data: string): string => {
// Simple hash function for browser compatibility
let hash = 0;
for (let i = 0; i < data.length; i++) {
const char = data.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32bit integer
}
// Convert to hex string
const hashHex = (hash >>> 0).toString(16).padStart(8, "0");
return hashHex.repeat(8).substring(0, 64); // Make it look like a SHA-256 hash length
};

_internalSetInitialState();
}
5 changes: 5 additions & 0 deletions integrations/browser-js/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { configureBrowser } from "./browser-config";

configureBrowser();

export * from "braintrust";
15 changes: 15 additions & 0 deletions integrations/browser-js/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"declaration": true,
"lib": ["es2022", "dom"],
"module": "esnext",
"target": "es2022",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
14 changes: 14 additions & 0 deletions integrations/browser-js/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig } from "tsup";

export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
dts: true,
sourcemap: true,
clean: true,
external: ["braintrust", "zod"],
target: "es2022",
platform: "browser",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so nice to see this

outDir: "./dist",
treeshake: true,
});
10 changes: 10 additions & 0 deletions integrations/browser-js/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://turbo.build/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["braintrust#build"],
"outputs": ["dist/**"]
}
}
}
7 changes: 7 additions & 0 deletions integrations/browser-js/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from "vitest/config";

export default defineConfig({
test: {
include: ["tests/**/*.test.ts", "src/**/*.test.ts"],
},
});
1 change: 1 addition & 0 deletions integrations/langchain-js/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
setupFiles: ["./src/test/setup.ts"],
include: ["tests/**/*.test.ts", "src/**/*.test.ts"],
},
});
1 change: 1 addition & 0 deletions integrations/openai-agents-js/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { defineConfig } from "vitest/config";

export default defineConfig({
test: {
include: ["tests/**/*.test.ts", "src/**/*.test.ts"],
// Add any specific test configuration if needed
},
});
3 changes: 3 additions & 0 deletions integrations/otel-js/otel-v1/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ export default defineConfig({
alias: createOtelAliases(cwd),
}
: {},
test: {
include: ["tests/**/*.test.ts", "src/**/*.test.ts"],
},
});
3 changes: 3 additions & 0 deletions integrations/otel-js/otel-v2/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ export default defineConfig({
alias: createOtelAliases(cwd),
}
: {},
test: {
include: ["tests/**/*.test.ts", "src/**/*.test.ts"],
},
});
4 changes: 4 additions & 0 deletions integrations/otel-js/smoke/scenarios/otel-v1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
*.log
.env.local
package-lock.json
60 changes: 60 additions & 0 deletions integrations/otel-js/smoke/scenarios/otel-v1/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.PHONY: setup test

# =============================================================================
# Setup
# =============================================================================

setup:
@echo "==> Setting up otel-v1 scenario"
mise install

@# Check if BRAINTRUST_TAR is set (from parent or CI), otherwise build
@if [ -n "$(BRAINTRUST_TAR)" ]; then \
echo "==> Using BRAINTRUST_TAR: $(BRAINTRUST_TAR)"; \
else \
echo "==> Building SDK"; \
cd ../../../.. && pnpm exec turbo build --filter=braintrust && mkdir -p artifacts && pnpm pack --pack-destination artifacts; \
\
for f in artifacts/braintrust-*.tgz; do \
if [ "$$(basename $$f)" != "braintrust-latest.tgz" ] && \
[ "$$(basename $$f)" != "braintrust-otel-latest.tgz" ]; then \
cp "$$f" artifacts/braintrust-latest.tgz; \
break; \
fi; \
done; \
fi

@# Build shared package (if not running from parent)
@if [ -z "$(SMOKE_V2_SHARED_DIST)" ]; then \
echo "==> Building shared package"; \
cd ../../../shared && npm ci && npm run build; \
fi

@# Check if BRAINTRUST_OTEL_TAR is set (from parent or CI), otherwise build
@if [ -n "$(BRAINTRUST_OTEL_TAR)" ]; then \
echo "==> Using BRAINTRUST_OTEL_TAR: $(BRAINTRUST_OTEL_TAR)"; \
else \
echo "==> Building @braintrust/otel package"; \
cd ../../../../../integrations/otel-js && pnpm exec turbo build --filter=@braintrust/otel && pnpm pack --pack-destination ../../js/artifacts; \
\
for f in ../../../js/artifacts/braintrust-otel-*.tgz; do \
if [ "$$(basename $$f)" != "braintrust-otel-latest.tgz" ]; then \
cp "$$f" ../../../js/artifacts/braintrust-otel-latest.tgz; \
break; \
fi; \
done; \
fi

npm install --no-package-lock

# =============================================================================
# Test
# =============================================================================

test: setup
@echo "==> Running otel-v1 tests"
@FAILED=0; \
npx tsx tests/basic.test.ts || FAILED=1; \
npx tsx tests/filtering.test.ts || FAILED=1; \
npx tsx tests/shared-suite.test.ts || FAILED=1; \
exit $$FAILED
Loading