Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d25fd2b
feat(ai): add the AI gateway, resource, controllers, and emitters
ItamarZand88 Jul 22, 2026
96a4594
fix(ai): apply carve review findings
ItamarZand88 Jul 22, 2026
3153781
feat(ai): embed the ai-gateway addon into compiled Workers
ItamarZand88 Jul 22, 2026
a92f401
chore(ai): satisfy biome formatting on ai-gateway packages
ItamarZand88 Jul 22, 2026
15d1d12
chore(ai): drop the carried-over Postgres runtime binding
ItamarZand88 Jul 22, 2026
0bdaad5
chore(ai): keep this PR AI-only, drop an unrelated InitialSetup log t…
ItamarZand88 Jul 22, 2026
d0155b4
refactor(ai): spawn the launcher binary instead of a napi addon
ItamarZand88 Jul 22, 2026
10a3833
feat(ai): filter getAvailableModels by runtime cloud availability
ItamarZand88 Jul 23, 2026
cb439e2
chore(sdk): restore the literal em dash in the package description
ItamarZand88 Jul 23, 2026
081bcc1
ci(release): ship the ai-gateway launcher binary as per-platform preb…
ItamarZand88 Jul 23, 2026
c50f43b
test(ai): answer the Claude availability probe in the two-cloud integ…
ItamarZand88 Jul 23, 2026
925e836
fix: size dev/test thread stacks for the deep deployment async chain
ItamarZand88 Jul 23, 2026
b1a4333
fix(ai): treat a 400 probe response as an unavailable model
ItamarZand88 Jul 23, 2026
00e79d1
fix(ai): let one-shot hosts exit by unref-ing the gateway stdio
ItamarZand88 Jul 24, 2026
6689961
fix(ai): enable aiplatform on the GCP Terraform path
ItamarZand88 Jul 24, 2026
6204eb4
fix(ai): refresh the ambient bearer token single-flight
ItamarZand88 Jul 24, 2026
2500039
fix(ai): fail closed on an unsupported BYO provider
ItamarZand88 Jul 24, 2026
66c01dd
fix(ai): point BYO-Anthropic defaults at active models
ItamarZand88 Jul 24, 2026
c871d12
refactor(ai): split the gateway router into per-provider modules
ItamarZand88 Jul 24, 2026
e8adba9
fix(ai): remove the 2MB proxy body limit
ItamarZand88 Jul 24, 2026
f4ad243
fix(ai): bound the ambient metadata token fetch with a timeout
ItamarZand88 Jul 24, 2026
0e3bc42
fix(ai): fail fast on a BYO-Anthropic Responses call
ItamarZand88 Jul 24, 2026
82df49b
test(ai): cover the ai import-data types in the schema snapshot
ItamarZand88 Jul 24, 2026
fe0ac8f
docs(ai): correct the AWS signing-service names in the creds module doc
ItamarZand88 Jul 24, 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
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 @@ -159,13 +159,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 @@ -177,7 +178,7 @@ jobs:
--exclude byocdb \
--exclude endpoint-agent \
--exclude alien-test-server \
--filter-expr 'not (package(alien-aws-clients) and kind(test)) and not (package(alien-gcp-clients) and kind(test)) and not (package(alien-azure-clients) and kind(test)) and not (package(alien-bindings) and kind(test)) and 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::cloudrun) 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 (package(alien-aws-clients) and kind(test)) and not (package(alien-gcp-clients) and kind(test)) and not (package(alien-azure-clients) and kind(test)) and not (package(alien-bindings) and kind(test)) and 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::cloudrun) 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