Skip to content

Remove surface gate; fix Anthropic/OpenAI capability, AgentTask retry/budget, FetchUrl error leak #3663

Remove surface gate; fix Anthropic/OpenAI capability, AgentTask retry/budget, FetchUrl error leak

Remove surface gate; fix Anthropic/OpenAI capability, AgentTask retry/budget, FetchUrl error leak #3663

Workflow file for this run

# Every `setup-bun` here takes `latest`, deliberately. The suites are what this
# repository ships against a moving runtime: `bunfig.toml`'s compatibility shim
# is written against the gaps in Bun's own `vitest` shim and each of its guards
# is meant to stand down once Bun ships its own, which only running a new Bun
# can ever reveal. `engines` already states the floor (`bun >= 1.4.0`, where
# `node:sqlite` arrives) and `latest` is always above it.
#
# The cost is real and accepted: a Bun regression can redden every PR on a day
# nobody touched the code. That is the trade — finding out on the day Bun ships
# it, rather than at the next manual bump. One spelling in every job, so there
# is no version to keep in sync; `packageManager` still pins local installs.
#
# Coverage is NOT collected here. Every vitest job below runs one slice of the
# suite, so a per-job number only means something once the fragments are merged
# — an artifact per job, a merge job and a cleanup job, paid for on every push.
# The nightly workflow runs the suite in one job and reports it instead.
name: Build & Test
permissions:
contents: read
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.head.ref || (github.event_name == 'workflow_dispatch' && github.run_id || github.ref_name) }}
cancel-in-progress: true
env:
CI: "true"
DO_NOT_TRACK: "1"
TURBO_TELEMETRY_DISABLED: "1"
# PRs: only packages the change can reach. Push/dispatch: full suite.
TEST_CHANGED: ${{ github.event_name == 'pull_request' && format('--changed {0}', github.event.pull_request.base.sha) || '' }}
jobs:
typecheck-budget:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
# Fails the PR if any package's type-instantiation count grows past its
# committed budget (scripts/typecheck-budget.json). Re-baseline intentional
# growth with: bun run typecheck:budget --update
- name: Typecheck budget guard
run: bun run typecheck:budget
# Co-located `__tests__` are excluded from each package's build program so
# they never reach `dist`, which also takes them out of every tsc run.
# `tsconfig.test.json` is the program that still checks them; without this
# step a type error in a test file is invisible until someone runs it.
# Must follow the budget guard, which is what emits the `dist/*.d.ts` these
# programs resolve their own package against.
- name: Typecheck co-located tests
run: bun run typecheck:tests
test-discovery:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
# Fails if any test file is unreachable by section+kind selection. Every
# other job passes a kind, so an unreachable file silently never runs.
- name: Test discovery guard
run: bun scripts/test.ts --check-sections
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
# The only thing that runs oxlint under CI. `prepare` skips husky when $CI
# is set, so the pre-commit hook -- which `--no-verify` bypasses anyway --
# is otherwise oxlint's sole invoker, and the `error`-level rules in
# .oxlintrc.json can never fail a build.
#
# Still not `needs: build`, but no longer because nothing reads types: the
# `lint` script builds them itself (turbo-cached `build:types`), because
# `--type-aware` resolves cross-package imports through `dist/*.d.ts` and
# types every one of them as `any` when they are missing -- so tsgolint
# silently finds nothing rather than failing.
- name: Lint
run: bun run lint
# `format-check` had no CI invoker at all -- `prepare` skips husky when
# $CI is set, so the pre-commit hook was its only one, and `--no-verify`
# walks around that. Cheap, and the tree is clean today.
- name: Format check
run: bun run format-check
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- run: bun run build
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: build-output
path: |
packages/*/dist/**
providers/*/dist/**
examples/*/dist/**
retention-days: 1
# Sharded, and it is the only job here that is. The unit slice is ~700 files
# and ran four times the wall clock of every other job in this workflow, so
# the run finished when this job did and nothing else on the board mattered.
# Most of that is not test execution: vitest accounts the slice as ~51% setup
# (a fresh module registry per file, `vitest.setup.ts` bootstrapping the task
# registry into each), ~21% transform, ~5% import and ~22% tests — so ~78% is
# paid per FILE, and dividing the file list divides it. Measured 2.9x across
# four shards rather than 4x because transform is the part that does not
# shrink: it is mostly the shared module graph, which every shard still pays
# in full. `scripts/lib/testShards.ts` does the partition and says why it is
# dealt from a sorted list rather than sliced.
#
# `fail-fast: false` because the shards are one job's worth of tests split up:
# cancelling the rest on the first red one would report a fraction of the
# failures and send someone back for a second full run to see the others.
test-vitest-unit:
runs-on: ubuntu-latest
needs: build
strategy:
fail-fast: false
matrix:
# `i/N` verbatim, so the count lives in one place and the job name
# reads as the shard it ran.
shard: ["1/4", "2/4", "3/4", "4/4"]
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .
# An empty shard passes: `--changed` narrows a pull request to a handful
# of files, and the shards past the first then hold none of them.
- name: Run unit tests via vitest (shard ${{ matrix.shard }})
run: bun run test:vitest:unit -- --shard ${{ matrix.shard }} ${{ env.TEST_CHANGED }}
test-vitest-integration:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .
- name: Run integration tests via vitest
env:
WORKGLOW_SECRETS_PASSPHRASE: ${{ secrets.WORKGLOW_SECRETS_PASSPHRASE }}
run: bun run test:vitest:integration -- ${{ env.TEST_CHANGED }}
test-vitest-rag:
runs-on: ubuntu-latest
needs: build
timeout-minutes: 25
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- name: Cache Hugging Face model downloads
uses: actions/cache@v4
with:
path: models
key: hf-models-rag-${{ runner.os }}-${{ hashFiles('packages/test/src/samples/**') }}
restore-keys: |
hf-models-rag-${{ runner.os }}-
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .
- name: Run rag tests via vitest
env:
WORKGLOW_SECRETS_PASSPHRASE: ${{ secrets.WORKGLOW_SECRETS_PASSPHRASE }}
run: bun run test:vitest:rag -- ${{ env.TEST_CHANGED }}
test-vitest-ai-provider-hft:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- name: Cache Hugging Face model downloads
uses: actions/cache@v4
with:
path: models
key: hf-models-hft-${{ runner.os }}-${{ hashFiles('packages/test/src/samples/**') }}
restore-keys: |
hf-models-hft-${{ runner.os }}-
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .
- name: Run HuggingFace Transformers provider tests via vitest
env:
WORKGLOW_SECRETS_PASSPHRASE: ${{ secrets.WORKGLOW_SECRETS_PASSPHRASE }}
run: bun run test:vitest:ai-provider-hft -- ${{ env.TEST_CHANGED }}
test-vitest-ai-provider-nodellama:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- name: Cache Hugging Face / GGUF model downloads
uses: actions/cache@v4
with:
path: models
key: hf-models-nodellama-${{ runner.os }}-${{ hashFiles('packages/test/src/samples/**') }}
restore-keys: |
hf-models-nodellama-${{ runner.os }}-
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .
- name: Run LlamaCpp provider tests via vitest
env:
WORKGLOW_SECRETS_PASSPHRASE: ${{ secrets.WORKGLOW_SECRETS_PASSPHRASE }}
run: bun run test:vitest:ai-provider-nodellama -- ${{ env.TEST_CHANGED }}
test-vitest-ai-provider-api:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: 24
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun i
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .
- name: Run API provider tests via vitest
env:
WORKGLOW_SECRETS_PASSPHRASE: ${{ secrets.WORKGLOW_SECRETS_PASSPHRASE }}
run: bun run test:vitest:ai-provider-api -- ${{ env.TEST_CHANGED }}
cleanup:
runs-on: ubuntu-latest
needs:
[
test-vitest-unit,
test-vitest-integration,
test-vitest-rag,
test-vitest-ai-provider-hft,
test-vitest-ai-provider-nodellama,
test-vitest-ai-provider-api,
]
steps:
- name: Delete build artifacts
uses: geekyeggo/delete-artifact@v6
with:
name: build-output