Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@
rustflags = ["--cfg", "tokio_unstable"]
rustdocflags = ["--cfg", "tokio_unstable"]

[env]
# The deployment reconcile polls a deep async chain on one stack (executor -> resource
# controllers -> the cloud SDKs' tower/hyper/rustls futures). In debug builds those frames
# are un-inlined and the chain needs ~3MB, over tokio's 2MB default thread-stack, so the
# alien-test cloud e2e (push_/pull_) overflows its test thread. Release binaries are
# unaffected (inlined frames fit 2MB), so this only sizes dev/test threads. 8MB matches the
# headroom alien-worker-runtime already gives its runtime for the same reason.
RUST_MIN_STACK = "8388608"

[target.wasm32-unknown-unknown]
rustflags = ['--cfg', 'getrandom_backend="wasm_js"']
13 changes: 7 additions & 6 deletions .github/workflows/ci-fast.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,14 @@ jobs:

- name: TypeScript unit tests
# The per-package vitest suites (commands receiver twins, bindings
# loader/error mapping, core schemas) — `test:ts` above is
# typecheck-only, so without this step they never ran in CI. Must run
# after the dev-addon build: the bindings kv/queue/storage/vault
# suites load the native addon.
# loader/error mapping, core schemas, ai-gateway client/gateway) —
# `test:ts` above is typecheck-only, so without this step they never
# ran in CI. Must run after the dev-addon build: the bindings
# kv/queue/storage/vault suites load the native addon. The ai-gateway
# suites inject a mock addon, so they need no built .node here.
env:
NODE_OPTIONS: "--max-old-space-size=8192"
run: pnpm --filter @alienplatform/core --filter @alienplatform/bindings --filter @alienplatform/commands test
run: pnpm --filter @alienplatform/core --filter @alienplatform/bindings --filter @alienplatform/commands --filter @alienplatform/ai-gateway test

- name: Rust fast tests (non-cloud)
env:
Expand All @@ -178,7 +179,7 @@ jobs:
--exclude byocdb \
--exclude endpoint-agent \
--exclude alien-test-server \
--filter-expr 'not binary_id(alien-build::build_integration_tests) and not binary_id(alien-build::image_shape_tests) and not binary_id(alien-build::rust_integration_tests) and not binary_id(alien-build::typescript_integration_tests) and not binary_id(alien-worker-runtime::lambda) and not binary_id(alien-test::distribution) and not binary_id(alien-test::pull) and not binary_id(alien-test::push) and not binary_id(alien-manager::registry_proxy_cloud_test)'
--filter-expr 'not binary_id(alien-build::build_integration_tests) and not binary_id(alien-build::image_shape_tests) and not binary_id(alien-build::rust_integration_tests) and not binary_id(alien-build::typescript_integration_tests) and not binary_id(alien-worker-runtime::lambda) and not binary_id(alien-test::distribution) and not binary_id(alien-test::pull) and not binary_id(alien-test::push) and not binary_id(alien-manager::registry_proxy_cloud_test) and not binary_id(alien-ai-gateway::live_bedrock) and not binary_id(alien-ai-gateway::live_foundry_claude) and not binary_id(alien-ai-gateway::live_vertex_claude)'

- name: Build all CLIs
if: steps.changes.outcome != 'success' || steps.changes.outputs.examples == 'true' || github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
Expand Down
174 changes: 172 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ jobs:
client-sdks/platform/typescript client-sdks/manager/typescript \
packages/bindings crates/alien-bindings-node \
packages/bindings/npm/darwin-arm64 packages/bindings/npm/darwin-x64 \
packages/bindings/npm/linux-x64-gnu packages/bindings/npm/linux-arm64-gnu; do
packages/bindings/npm/linux-x64-gnu packages/bindings/npm/linux-arm64-gnu \
packages/ai-gateway; do
node -e "
const fs = require('fs');
const path = '${pkg}/package.json';
Expand Down Expand Up @@ -139,6 +140,7 @@ jobs:
packages/bindings/npm/darwin-x64/package.json
packages/bindings/npm/linux-x64-gnu/package.json
packages/bindings/npm/linux-arm64-gnu/package.json
packages/ai-gateway/package.json

- name: Commit and tag
if: ${{ !inputs.dry_run }}
Expand All @@ -151,7 +153,8 @@ jobs:
client-sdks/platform/typescript/package.json client-sdks/manager/typescript/package.json \
packages/bindings/package.json crates/alien-bindings-node/package.json \
packages/bindings/npm/darwin-arm64/package.json packages/bindings/npm/darwin-x64/package.json \
packages/bindings/npm/linux-x64-gnu/package.json packages/bindings/npm/linux-arm64-gnu/package.json
packages/bindings/npm/linux-x64-gnu/package.json packages/bindings/npm/linux-arm64-gnu/package.json \
packages/ai-gateway/package.json
git commit -m "chore: release v${VERSION}"
git tag "v${VERSION}"
git push
Expand Down Expand Up @@ -356,26 +359,38 @@ jobs:
fail-fast: false
matrix:
include:
# gateway_target/gateway_artifact drive the alien-ai-gateway launcher
# binary built alongside the addon: darwin legs share the addon's
# target; linux legs build it statically against musl, so one binary
# (per arch) serves both the glibc and Alpine prebuild packages.
- runner: depot-macos-15
os: macos
target: aarch64-apple-darwin
triple: darwin-arm64
expect_arch: arm64
gateway_target: aarch64-apple-darwin
gateway_artifact: darwin-arm64
- runner: depot-macos-15
os: macos
target: x86_64-apple-darwin
triple: darwin-x64
expect_arch: x86_64
gateway_target: x86_64-apple-darwin
gateway_artifact: darwin-x64
- runner: depot-ubuntu-24.04-16
os: linux
target: x86_64-unknown-linux-gnu
triple: linux-x64-gnu
expect_arch: x86-64
gateway_target: x86_64-unknown-linux-musl
gateway_artifact: linux-x64
- runner: depot-ubuntu-24.04-arm-16
os: linux
target: aarch64-unknown-linux-gnu
triple: linux-arm64-gnu
expect_arch: aarch64
gateway_target: aarch64-unknown-linux-musl
gateway_artifact: linux-arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
env:
Expand All @@ -397,6 +412,11 @@ jobs:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/bindings/scripts/validate-release-version.mjs "$VERSION"

- name: Validate ai-gateway release version lockstep
env:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/ai-gateway/scripts/validate-release-version.mjs "$VERSION"

# Rust toolchain: Linux via the shared composite; macOS uses dtolnay +
# brew protoc directly (plain `napi build`, not `depot cargo`, so no
# Depot/sccache setup here). The addon depends on alien-bindings, whose
Expand Down Expand Up @@ -460,6 +480,29 @@ jobs:
retention-days: 1
path: packages/bindings/npm/${{ matrix.triple }}/alien-bindings-node.${{ matrix.triple }}.node

# The AI gateway ships as a standalone launcher binary, not an addon. It
# reuses this matrix (same runners/toolchains; it depends on
# alien-bindings' credential resolver, so protoc is already set up).
- name: Add gateway build target (${{ matrix.gateway_target }})
run: rustup target add ${{ matrix.gateway_target }}

- name: Build ai-gateway binary (${{ matrix.gateway_artifact }})
env:
CARGO_NET_GIT_FETCH_WITH_CLI: "true"
run: |
cargo build --release -p alien-ai-gateway --bin alien-ai-gateway \
--target ${{ matrix.gateway_target }}

- name: Assert ai-gateway binary architecture
run: file "target/${{ matrix.gateway_target }}/release/alien-ai-gateway" | grep -q "${{ matrix.expect_arch }}"

- name: Upload ai-gateway binary artifact
uses: actions/upload-artifact@v6
with:
name: ai-gateway-bin-${{ matrix.gateway_artifact }}
retention-days: 1
path: target/${{ matrix.gateway_target }}/release/alien-ai-gateway

# This job deliberately has no Rust compiler or protoc setup. It
# starts from the already-built artifacts and proves that a consumer whose
# only direct dependency is @alienplatform/bindings gets the right optional
Expand Down Expand Up @@ -503,6 +546,11 @@ jobs:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/bindings/scripts/validate-release-version.mjs "$VERSION"

- name: Validate ai-gateway release version lockstep
env:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/ai-gateway/scripts/validate-release-version.mjs "$VERSION"

- uses: pnpm/action-setup@v6
with:
version: 10.11.0
Expand Down Expand Up @@ -561,6 +609,11 @@ jobs:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/bindings/scripts/validate-release-version.mjs "$VERSION"

- name: Validate ai-gateway release version lockstep
env:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/ai-gateway/scripts/validate-release-version.mjs "$VERSION"

- uses: pnpm/action-setup@v6
with:
version: 10.11.0
Expand Down Expand Up @@ -645,6 +698,123 @@ jobs:
pnpm --filter @alienplatform/bindings publish --access public --no-git-checks
fi

publish-ai-gateway:
needs: [prepare, build-addon, publish-npm]
# Same ordering rules as publish-bindings: the wrapper pins
# `@alienplatform/core: ^<release>`, so it publishes only after core, and
# its per-platform prebuilds publish before the wrapper that pins them.
if: inputs.mode == 'stable' && always() && needs.build-addon.result == 'success' && (inputs.dry_run || needs.publish-npm.result == 'success')
runs-on: depot-ubuntu-24.04-arm-4
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
with:
ref: ${{ inputs.dry_run && github.sha || format('v{0}', needs.prepare.outputs.version) }}

- name: Apply computed version for dry run
if: ${{ inputs.dry_run }}
uses: actions/download-artifact@v7
with:
name: release-version-manifests
path: .

- name: Validate ai-gateway release version lockstep
env:
VERSION: ${{ needs.prepare.outputs.version }}
run: node packages/ai-gateway/scripts/validate-release-version.mjs "$VERSION"

- uses: pnpm/action-setup@v6
with:
version: 10.11.0

- uses: actions/setup-node@v5
with:
node-version: 22
cache: pnpm
registry-url: https://registry.npmjs.org

- name: Validate npm auth
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm whoami

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

- name: Download ai-gateway binaries
uses: actions/download-artifact@v7
with:
pattern: ai-gateway-bin-*
path: ./gateway-bins
merge-multiple: false

- name: Generate prebuild manifests
run: node packages/ai-gateway/scripts/generate-prebuilds.mjs

# The linux binaries are static musl builds, so a triple's gnu and musl
# packages ship the same executable. Artifact download drops the execute
# bit; restore it so npm packs the binary runnable.
- name: Stage binaries into prebuild packages
run: |
for pair in darwin-arm64:darwin-arm64 darwin-x64:darwin-x64 \
linux-x64-gnu:linux-x64 linux-x64-musl:linux-x64 \
linux-arm64-gnu:linux-arm64 linux-arm64-musl:linux-arm64; do
triple="${pair%%:*}"
source="${pair##*:}"
cp "./gateway-bins/ai-gateway-bin-${source}/alien-ai-gateway" \
"packages/ai-gateway/npm/${triple}/alien-ai-gateway"
chmod 755 "packages/ai-gateway/npm/${triple}/alien-ai-gateway"
done

- name: Build wrapper
run: pnpm --filter @alienplatform/ai-gateway build

# Prebuild packages publish FIRST so an install of the wrapper can never
# race ahead of the optionalDependencies it pins.
- name: Publish prebuild packages (first)
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
for triple in darwin-arm64 darwin-x64 linux-x64-gnu linux-x64-musl linux-arm64-gnu linux-arm64-musl; do
package="@alienplatform/ai-gateway-${triple}"
if [ "${{ inputs.dry_run }}" = "true" ]; then
echo "Dry-running ${package}@${VERSION}..."
( cd "packages/ai-gateway/npm/${triple}" && npm publish --access public --dry-run )
continue
fi

# npm has no multi-package transaction; this existence check makes
# a retry resume after a partial publish.
published="$(npm view "${package}@${VERSION}" version 2>/dev/null || true)"
if [ "$published" = "$VERSION" ]; then
echo "${package}@${VERSION} is already published; continuing"
else
echo "Publishing ${package}@${VERSION}..."
( cd "packages/ai-gateway/npm/${triple}" && npm publish --access public )
fi
done

- name: Inject optionalDependencies into the wrapper
run: node packages/ai-gateway/scripts/inject-optional-deps.mjs

- name: Publish wrapper (last)
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
if [ "${{ inputs.dry_run }}" = "true" ]; then
pnpm --filter @alienplatform/ai-gateway publish --access public --no-git-checks --dry-run
exit 0
fi

published="$(npm view "@alienplatform/ai-gateway@${VERSION}" version 2>/dev/null || true)"
if [ "$published" = "$VERSION" ]; then
echo "@alienplatform/ai-gateway@${VERSION} is already published; continuing"
else
pnpm --filter @alienplatform/ai-gateway publish --access public --no-git-checks
fi

# ─── Binary builds (4 targets, all parallel) ───────────────────────

build-binaries-linux-x86_64:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ rustc-ice-*.txt
.codex/

.pnpm-store
packages/ai-gateway/npm/
Loading
Loading