Skip to content

fix(serving): apply llama.cpp GPU profile placement #164

fix(serving): apply llama.cpp GPU profile placement

fix(serving): apply llama.cpp GPU profile placement #164

Workflow file for this run

name: Build
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
env:
CARGO_TERM_COLOR: always
RUST_TOOLCHAIN_VERSION: 1.92.0
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
lint-workflows:
name: Lint Workflows
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: rhysd/actionlint@v1.7.8
- name: Check workspace dependency ownership
run: npm run check:dependency-ownership
- name: Check release version alignment
run: npm run check:release-versions
# Build and test Rust backend on all platforms
build-rust:
name: Build Rust (${{ matrix.target }})
needs: [lint-workflows]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: windows-latest
target: x86_64-pc-windows-msvc
- os: macos-14
target: aarch64-apple-darwin
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
targets: ${{ matrix.target }}
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
workspaces: rust -> target
- name: Build Rust
working-directory: ./rust
run: cargo build --workspace --exclude pumas_rustler --release --target ${{ matrix.target }}
- name: Run Rust tests
working-directory: ./rust
run: cargo test --workspace --exclude pumas_rustler --release
- name: Upload Rust artifact
uses: actions/upload-artifact@v4
with:
name: rust-${{ matrix.target }}
path: |
rust/target/${{ matrix.target }}/release/libpumas_uniffi.so
rust/target/${{ matrix.target }}/release/libpumas_uniffi.dylib
rust/target/${{ matrix.target }}/release/pumas_uniffi.dll
if-no-files-found: ignore
- name: Upload pumas-rpc for Electron packaging
uses: actions/upload-artifact@v4
with:
name: rpc-${{ matrix.target }}
path: |
rust/target/${{ matrix.target }}/release/pumas-rpc
rust/target/${{ matrix.target }}/release/pumas-rpc.exe
if-no-files-found: ignore
rust-quality:
name: Rust Quality
needs: [lint-workflows]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
components: rustfmt, clippy
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
workspaces: rust -> target
- name: Run Rust verification contract
run: ./scripts/rust/check.sh
# Build and test frontend
build-frontend:
name: Build Frontend (${{ matrix.os }})
needs: [lint-workflows]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
upload_dist: true
- os: windows-latest
upload_dist: false
- os: macos-14
upload_dist: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Setup Windows RAM disk
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-ramdisk
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.node-version'
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable Corepack
run: corepack enable
- name: Install workspace dependencies
run: corepack pnpm install --frozen-lockfile
- name: Lint
run: npm run -w frontend lint
- name: Check file-size ratchet
run: npm run -w frontend check:size
- name: Type check
run: npm run -w frontend check:types
- name: Run tests
if: matrix.upload_dist
run: npm run -w frontend test:run
- name: Build
if: matrix.upload_dist
run: npm run -w frontend build
- name: Upload frontend artifact
if: matrix.upload_dist
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: frontend/dist/
verify-launcher:
name: Verify Launcher
needs: [lint-workflows]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.node-version'
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable Corepack
run: corepack enable
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version-file: '.python-version'
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
workspaces: rust -> target
- name: Install workspace dependencies
run: corepack pnpm install --frozen-lockfile
- name: Install Python development dependencies
run: python -m pip install -r torch-server/requirements-dev.txt
- name: Install Xvfb
run: sudo apt-get update && sudo apt-get install -y xvfb
- name: Build release artifacts for launcher verification
run: bash launcher.sh --build-release
- name: Run launcher tests
run: npm run test:launcher
- name: Lint Torch sidecar
run: python -m ruff check torch-server
- name: Check Torch sidecar formatting
run: python -m ruff format --check torch-server
- name: Run Torch sidecar tests
run: python -m unittest discover -s torch-server/tests
- name: Run bounded release smoke
run: xvfb-run -a bash launcher.sh --release-smoke
# Generate binding source files (platform-independent, only needs one OS)
generate-bindings:
name: Generate Binding Sources
needs: [build-rust]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
- name: Download Linux Rust artifact
uses: actions/download-artifact@v4
with:
name: rust-x86_64-unknown-linux-gnu
path: rust-artifact
- name: Package pumas-core crate
working-directory: ./rust
run: cargo package -p pumas-library --allow-dirty
- name: Upload pumas-core crate
uses: actions/upload-artifact@v4
with:
name: pumas-core-crate
path: rust/target/package/pumas-library-*.crate
- name: Install uniffi-bindgen
run: cargo install --path rust/crates/pumas-uniffi --bin pumas-uniffi-bindgen --no-default-features --features cli
- name: Install uniffi-bindgen-cs
run: CARGO_NET_GIT_FETCH_WITH_CLI=true cargo install uniffi-bindgen-cs --git https://github.com/NordSecurity/uniffi-bindgen-cs --tag v0.9.0+v0.28.3
- name: Generate Python bindings
working-directory: ./rust
run: |
mkdir -p ../bindings/python
pumas-uniffi-bindgen generate \
--library \
--language python \
--out-dir ../bindings/python \
../rust-artifact/libpumas_uniffi.so
- name: Generate Kotlin bindings
working-directory: ./rust
run: |
mkdir -p ../bindings/kotlin
pumas-uniffi-bindgen generate \
--library \
--language kotlin \
--out-dir ../bindings/kotlin \
../rust-artifact/libpumas_uniffi.so
- name: Generate Swift bindings
working-directory: ./rust
run: |
mkdir -p ../bindings/swift
pumas-uniffi-bindgen generate \
--library \
--language swift \
--out-dir ../bindings/swift \
../rust-artifact/libpumas_uniffi.so
- name: Generate Ruby bindings
working-directory: ./rust
run: |
mkdir -p ../bindings/ruby
pumas-uniffi-bindgen generate \
--library \
--language ruby \
--out-dir ../bindings/ruby \
../rust-artifact/libpumas_uniffi.so
- name: Generate C# bindings
working-directory: ./rust
run: |
mkdir -p ../bindings/csharp
uniffi-bindgen-cs \
--library \
--out-dir ../bindings/csharp \
../rust-artifact/libpumas_uniffi.so
- name: Upload binding sources
uses: actions/upload-artifact@v4
with:
name: binding-sources
path: bindings/
# Package Electron app for each platform
build-electron:
name: Package Electron (${{ matrix.platform }})
needs: [build-rust, build-frontend, verify-launcher]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux
rust-target: x86_64-unknown-linux-gnu
binary-name: pumas-rpc
- os: windows-latest
platform: win
rust-target: x86_64-pc-windows-msvc
binary-name: pumas-rpc.exe
- os: macos-14
platform: mac
rust-target: aarch64-apple-darwin
binary-name: pumas-rpc
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Setup Windows RAM disk
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-ramdisk
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.node-version'
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable Corepack
run: corepack enable
- name: Download pumas-rpc binary
uses: actions/download-artifact@v4
with:
name: rpc-${{ matrix.rust-target }}
path: rust-artifact
- name: Download frontend artifact
uses: actions/download-artifact@v4
with:
name: frontend-dist
path: frontend/dist
- name: Stage Rust binary
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path "electron/resources/bin" | Out-Null
Copy-Item -Path "rust-artifact/${{ matrix.binary-name }}" -Destination "electron/resources/bin/${{ matrix.binary-name }}" -Force
if (-not $IsWindows) {
chmod +x "electron/resources/bin/${{ matrix.binary-name }}"
}
- name: Install workspace dependencies
run: corepack pnpm install --frozen-lockfile
- name: Verify app icon assets
shell: pwsh
run: |
$required = @(
"electron/build/icons/Pumas-Library_05.png",
"electron/build/icons/icon.ico",
"electron/build/icons/icon.icns"
)
foreach ($file in $required) {
if (-not (Test-Path $file)) {
throw "Missing required icon asset: $file"
}
}
- name: Lint Electron
run: corepack pnpm --filter ./electron lint
- name: Test Electron IPC validation
run: corepack pnpm --filter ./electron test
- name: Build Electron TypeScript
run: corepack pnpm --filter ./electron build
- name: Package Electron app
run: corepack pnpm --filter ./electron exec electron-builder --${{ matrix.platform }} --publish never
- name: Upload Electron artifact
uses: actions/upload-artifact@v4
with:
name: electron-${{ matrix.platform }}
path: |
electron/release/*.AppImage
electron/release/*.deb
electron/release/*.exe
electron/release/*.dmg
electron/release/*.zip
if-no-files-found: warn
# Create release when a tag is pushed
release:
name: Create Release
if: startsWith(github.ref, 'refs/tags/v')
needs: [build-rust, rust-quality, build-electron, generate-bindings, verify-launcher]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Extract version from tag
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Rename and organize release artifacts
run: |
mkdir -p release-artifacts
VERSION=${{ steps.version.outputs.version }}
# --- Per-language binding packages ---
# Each package contains the generated source files + native libraries for all platforms
# --- pumas-core source crate ---
cp artifacts/pumas-core-crate/pumas-library-*.crate release-artifacts/
# Collect UniFFI native libraries by target.
mkdir -p staging/uniffi
for target_dir in artifacts/rust-*/; do
TARGET=$(basename "$target_dir" | sed 's/^rust-//')
mkdir -p "staging/uniffi/${TARGET}"
for file in "$target_dir"*; do
[ -f "$file" ] || continue
BASENAME=$(basename "$file")
case "$BASENAME" in
libpumas_uniffi.*|pumas_uniffi.dll)
cp "$file" "staging/uniffi/${TARGET}/"
;;
esac
done
done
# --- Per-language binding packages ---
# Each package contains the generated source files + native libraries for all platforms
for lang in python kotlin swift ruby csharp; do
mkdir -p "staging/${lang}-pkg/native"
cp -r "artifacts/binding-sources/${lang}/." "staging/${lang}-pkg/"
cp -r staging/uniffi/* "staging/${lang}-pkg/native/"
cd "staging/${lang}-pkg"
zip -r "../../release-artifacts/pumas-bindings-${lang}-${VERSION}.zip" .
cd ../..
done
# --- Desktop application ---
# Electron installers (already named with version by electron-builder)
for electron_dir in artifacts/electron-*/; do
for file in "$electron_dir"*; do
[ -f "$file" ] || continue
cp "$file" "release-artifacts/"
done
done
- name: List release artifacts
run: ls -la release-artifacts/
- name: Generate checksums
working-directory: release-artifacts
run: |
mapfile -d '' artifacts < <(
find . -maxdepth 1 -type f ! -name checksums-sha256.txt -printf '%P\0' |
sort -z
)
if (( ${#artifacts[@]} == 0 )); then
echo "No release artifacts found for checksum generation" >&2
exit 1
fi
sha256sum "${artifacts[@]}" > checksums-sha256.txt
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: release-artifacts/*
draft: true
generate_release_notes: true
prerelease: ${{ startsWith(github.ref_name, 'v0.') }}