mirror of
https://github.com/Mesh-LLM/mesh-llm.git
synced 2026-08-08 22:23:19 -04:00
* fix(ci): isolate high-fanout compiler cache writes * fix(ci): use service signal for readiness cleanup
1634 lines
68 KiB
YAML
1634 lines
68 KiB
YAML
name: CI
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
use_depot:
|
|
description: Route eligible non-GPU jobs to Depot for rollout benchmarking.
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
push:
|
|
branches: [main]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
CACHE_NAMESPACE: mesh-llm
|
|
MODEL_URL: https://huggingface.co/unsloth/SmolLM2-135M-Instruct-GGUF/resolve/9e6855bc4be717fca1ef21360a1db4b29d5c559a/SmolLM2-135M-Instruct-Q8_0.gguf
|
|
MODEL_FILE: SmolLM2-135M-Instruct-Q8_0.gguf
|
|
CARGO_INCREMENTAL: "0"
|
|
CARGO_NET_RETRY: "10"
|
|
CARGO_HTTP_MULTIPLEXING: "false"
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama.cpp/build-stage-abi-static
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
|
|
jobs:
|
|
changes:
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
outputs:
|
|
rust: ${{ steps.filter.outputs.rust }}
|
|
ui: ${{ steps.filter.outputs.ui }}
|
|
benchmarks: ${{ steps.filter.outputs.benchmarks }}
|
|
docker: ${{ steps.filter.outputs.docker }}
|
|
windows_cpu: ${{ steps.compute.outputs.windows_cpu_build_required }}
|
|
windows_gpu: ${{ steps.compute.outputs.windows_gpu_build_required }}
|
|
docs: ${{ steps.filter.outputs.docs }}
|
|
affected_crates: ${{ steps.compute.outputs.affected_crates }}
|
|
test_crates: ${{ steps.compute.outputs.test_crates }}
|
|
batches_json: ${{ steps.compute.outputs.batches_json }}
|
|
test_batches_json: ${{ steps.compute.outputs.test_batches_json }}
|
|
linux_test_groups_json: ${{ steps.compute.outputs.linux_test_groups_json }}
|
|
all_rust: ${{ steps.compute.outputs.all_rust }}
|
|
docs_only: ${{ steps.compute.outputs.docs_only }}
|
|
rust_changed: ${{ steps.compute.outputs.rust_changed }}
|
|
backend_changed: ${{ steps.compute.outputs.backend_changed }}
|
|
inference_artifact_required: ${{ steps.compute.outputs.inference_artifact_required }}
|
|
backend_recipe_changed: ${{ steps.compute.outputs.backend_recipe_changed }}
|
|
sdk_smoke_required: ${{ steps.compute.outputs.sdk_smoke_required }}
|
|
runner_contract_required: ${{ steps.compute.outputs.runner_contract_required }}
|
|
ui_dist_cache_key: ${{ steps.ui_key.outputs.ui_dist_cache_key }}
|
|
linux_inference_artifact_required: ${{ github.event_name == 'workflow_dispatch' || steps.compute.outputs.inference_artifact_required == 'true' }}
|
|
macos_inference_artifact_required: ${{ github.event_name == 'workflow_dispatch' || steps.compute.outputs.inference_artifact_required == 'true' || steps.filter.outputs.benchmarks == 'true' }}
|
|
depot_enabled: ${{ steps.runners.outputs.depot_enabled }}
|
|
allow_depot_remote_cache: ${{ steps.runners.outputs.allow_depot_remote_cache }}
|
|
runner: ${{ steps.runners.outputs.runner }}
|
|
runner_4: ${{ steps.runners.outputs.runner_4 }}
|
|
runner_8: ${{ steps.runners.outputs.runner_8 }}
|
|
runner_16: ${{ steps.runners.outputs.runner_16 }}
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
fetch-depth: 0
|
|
- name: Select trusted Linux runners
|
|
id: runners
|
|
uses: ./.github/actions/select-ci-runners
|
|
with:
|
|
event_name: ${{ github.event_name }}
|
|
ref: ${{ github.ref }}
|
|
depot_main_enabled: ${{ vars.DEPOT_RUNNERS_ENABLED == 'true' }}
|
|
manual_use_depot: ${{ inputs.use_depot == true }}
|
|
- uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
|
|
id: filter
|
|
with:
|
|
filters: |
|
|
rust:
|
|
- 'crates/**'
|
|
- 'tools/xtask/**'
|
|
- 'Cargo.toml'
|
|
- 'Cargo.lock'
|
|
- 'Justfile'
|
|
- 'scripts/**'
|
|
- 'third_party/llama.cpp/**'
|
|
- '.github/cache-version.txt'
|
|
- '.github/workflows/ci.yml'
|
|
- '.github/workflows/smoke.yml'
|
|
- '.github/actions/compute-changes/action.yml'
|
|
- '.github/actions/prepare-windows-host-input/**'
|
|
|
|
ui:
|
|
- 'crates/mesh-llm-ui/**'
|
|
benchmarks:
|
|
- 'crates/skippy-bench/**'
|
|
- 'crates/llama-spec-bench/**'
|
|
- 'crates/mesh-llm-gpu-bench/**'
|
|
- '.github/workflows/ci.yml'
|
|
docker:
|
|
- '.dockerignore'
|
|
- 'docker/**'
|
|
- 'fly/Dockerfile'
|
|
- 'crates/**'
|
|
- 'Cargo.toml'
|
|
- 'Cargo.lock'
|
|
- '.github/workflows/docker.yml'
|
|
docs:
|
|
- 'docs/**'
|
|
- '**.md'
|
|
- '!crates/**'
|
|
- '!third_party/**'
|
|
- id: compute
|
|
uses: ./.github/actions/compute-changes
|
|
with:
|
|
event_name: ${{ github.event_name }}
|
|
base_sha: ${{ github.event.before || '' }}
|
|
head_sha: ${{ github.sha }}
|
|
- name: Compute UI dist cache key
|
|
id: ui_key
|
|
run: |
|
|
HASH=$(git ls-files -s crates/mesh-llm-ui .github/cache-version.txt | git hash-object --stdin)
|
|
echo "ui_dist_cache_key=${CACHE_NAMESPACE}-ui-dist-${HASH}" >> "$GITHUB_OUTPUT"
|
|
|
|
arc_runner_image_contract:
|
|
needs: changes
|
|
if: ${{ github.ref == 'refs/heads/main' && (github.event_name == 'workflow_dispatch' || needs.changes.outputs.runner_contract_required == 'true') }}
|
|
name: Runner image / ARC ${{ matrix.architecture }}
|
|
runs-on: ${{ matrix.runner }}
|
|
permissions:
|
|
contents: read
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- architecture: amd64
|
|
runner: mesh-llm-amd64
|
|
machine: x86_64
|
|
- architecture: arm64
|
|
runner: mesh-llm-arm64
|
|
machine: aarch64
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt ARC environment
|
|
env:
|
|
EXPECTED_MACHINE: ${{ matrix.machine }}
|
|
run: |
|
|
test "$(uname -m)" = "$EXPECTED_MACHINE"
|
|
verify-runner-image self-hosted
|
|
cargo check -p mesh-llm-config
|
|
|
|
linux_host_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' }}
|
|
name: Linux immutable release host
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
env:
|
|
MESH_LLM_SKIP_UI: "1"
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
RUSTC_WRAPPER: sccache
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
|
|
- name: Build UI
|
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.ui == 'true' }}
|
|
working-directory: crates/mesh-llm-ui
|
|
run: pnpm i --frozen-lockfile && pnpm run build
|
|
|
|
- name: Test UI
|
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.ui == 'true' }}
|
|
working-directory: crates/mesh-llm-ui
|
|
run: pnpm test
|
|
|
|
- name: Save UI dist cache
|
|
if: ${{ github.ref == 'refs/heads/main' && needs.changes.outputs.ui == 'true' }}
|
|
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: crates/mesh-llm-ui/dist
|
|
key: ${{ needs.changes.outputs.ui_dist_cache_key }}
|
|
|
|
- name: Configure Linux Rust linker
|
|
run: |
|
|
mkdir -p .cargo
|
|
cat > .cargo/config.toml <<'EOF'
|
|
[target.x86_64-unknown-linux-gnu]
|
|
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
|
EOF
|
|
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
continue-on-error: true
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: linux-release-host
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
|
|
- name: Check release-target repo consistency
|
|
run: cargo run -p xtask -- repo-consistency release-targets
|
|
|
|
- name: Check embedded client dependency purity
|
|
run: |
|
|
cargo tree -p mesh-llm-client --prefix=none --no-dedupe > /tmp/mesh-client-deps.txt
|
|
FORBIDDEN="keyring|rpassword|hf-hub|dirs|clap|include_dir|rmcp|keyring-core"
|
|
if grep -E "^[[:space:]│├└─-]*($FORBIDDEN)([[:space:]]|$)" /tmp/mesh-client-deps.txt; then
|
|
echo "ERROR: Forbidden dependency found in mesh-client"
|
|
grep -E "^[[:space:]│├└─-]*($FORBIDDEN)([[:space:]]|$)" /tmp/mesh-client-deps.txt
|
|
exit 1
|
|
fi
|
|
|
|
- name: Prepare UI placeholder
|
|
run: |
|
|
mkdir -p crates/mesh-llm-ui/dist
|
|
test -f crates/mesh-llm-ui/dist/index.html ||
|
|
printf '<html></html>' > crates/mesh-llm-ui/dist/index.html
|
|
|
|
- name: Prepare backend-neutral release host
|
|
uses: ./.github/actions/prepare-host-input
|
|
with:
|
|
profile: release
|
|
output_dir: host-input
|
|
skip_ui: "true"
|
|
|
|
- name: Upload immutable host input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-host-input
|
|
path: host-input/
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
- name: Capture sccache evidence
|
|
if: ${{ !cancelled() }}
|
|
uses: ./.github/actions/capture-sccache-stats
|
|
with:
|
|
artifact_name: sccache-main-linux-host-${{ github.run_attempt }}
|
|
|
|
linux_cpu_runtime_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' }}
|
|
name: Linux CPU runtime
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
env:
|
|
LLAMA_STAGE_BACKEND: cpu
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama.cpp/build-stage-abi-dynamic-cpu
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Resolve CPU native toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
pinned_epoch: mesh-llm-cuda-runner-sha256-8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
|
|
- name: Prepare CPU native runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
with:
|
|
backend: cpu
|
|
target: x86_64-unknown-linux-gnu
|
|
output_dir: runtime-input
|
|
|
|
- name: Upload immutable CPU runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-cpu-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
- name: Capture sccache evidence
|
|
if: ${{ !cancelled() }}
|
|
uses: ./.github/actions/capture-sccache-stats
|
|
with:
|
|
artifact_name: sccache-main-linux-cpu-runtime-${{ github.run_attempt }}
|
|
|
|
linux_cpu_artifact:
|
|
needs: [changes, linux_host_input, linux_cpu_runtime_input]
|
|
if: ${{ needs.linux_host_input.result == 'success' && needs.linux_cpu_runtime_input.result == 'success' }}
|
|
name: Linux CPU product
|
|
runs-on: ${{ needs.changes.outputs.runner_4 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Download immutable host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-host-input
|
|
path: host-input
|
|
- name: Download immutable CPU runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-cpu-runtime-input
|
|
path: runtime-input
|
|
|
|
- name: Compose CPU product from producer inputs
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: ci-product
|
|
backend: cpu
|
|
|
|
- name: Upload Linux composed product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-inference-binaries
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
linux_static_abi_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' && (needs.changes.outputs.test_batches_json != '[]' || needs.changes.outputs.linux_test_groups_json != '[]' || needs.changes.outputs.sdk_smoke_required == 'true') }}
|
|
name: Linux static ABI input
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
uses: ./.github/workflows/static-abi-artifact.yml
|
|
with:
|
|
backend: cpu
|
|
target: x86_64-unknown-linux-gnu
|
|
artifact_name: ci-linux-static-abi-input
|
|
runner_size: '8'
|
|
retention_days: 1
|
|
|
|
rust_crate_tests:
|
|
needs: [changes, linux_static_abi_input]
|
|
if: ${{ needs.linux_static_abi_input.result == 'success' && needs.changes.outputs.test_batches_json != '[]' && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Rust crate tests (${{ matrix.batch.idx }})
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
timeout-minutes: 60
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
batch: ${{ fromJson(needs.changes.outputs.test_batches_json) }}
|
|
env:
|
|
LLAMA_STAGE_BACKEND: cpu
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama.cpp/build-stage-abi-static
|
|
MESH_LLM_SKIP_UI: "1"
|
|
RUSTFLAGS: "-C link-arg=-fuse-ld=lld"
|
|
# Four concurrent crate shards caused 94% of cold-main GHA compiler-cache
|
|
# write errors. Their per-shard Cargo target caches own persistent reuse;
|
|
# keep sccache writable and job-local on GitHub-hosted runners instead.
|
|
# Authorized Depot jobs still select disk,webdav before this GHA opt-out.
|
|
SCCACHE_GHA_ENABLED: "false"
|
|
RUSTC_WRAPPER: sccache
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Resolve static ABI toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
pinned_epoch: mesh-llm-cuda-runner-sha256-8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
continue-on-error: true
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: main-rust-crate-tests-${{ matrix.batch.idx }}
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Prepare UI placeholder
|
|
run: mkdir -p crates/mesh-llm-ui/dist && printf '<html></html>' > crates/mesh-llm-ui/dist/index.html
|
|
- name: Prepare patched llama.cpp source checkout
|
|
if: ${{ contains(matrix.batch.crates, 'skippy-quantize') }}
|
|
run: scripts/prepare-llama.sh pinned
|
|
- name: Download immutable static ABI input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-static-abi-input
|
|
path: ${{ runner.temp }}/static-abi-input
|
|
- name: Restore immutable static ABI input
|
|
run: scripts/restore-static-abi-input.sh "$RUNNER_TEMP/static-abi-input" "$LLAMA_STAGE_BUILD_DIR" x86_64-unknown-linux-gnu cpu
|
|
- name: Run crate tests
|
|
env:
|
|
TEST_CRATES: ${{ toJson(matrix.batch.crates) }}
|
|
run: |
|
|
mapfile -t crates < <(jq -r '.[]' <<<"$TEST_CRATES")
|
|
for crate in "${crates[@]}"; do
|
|
echo "::group::cargo test -p $crate"
|
|
cargo test -p "$crate"
|
|
echo "::endgroup::"
|
|
done
|
|
- name: Capture sccache evidence
|
|
if: ${{ !cancelled() }}
|
|
uses: ./.github/actions/capture-sccache-stats
|
|
with:
|
|
artifact_name: sccache-main-rust-crate-tests-${{ matrix.batch.idx }}-${{ github.run_attempt }}
|
|
|
|
linux_test_groups:
|
|
needs: [changes, linux_static_abi_input]
|
|
if: ${{ needs.linux_static_abi_input.result == 'success' && needs.changes.outputs.docs_only != 'true' && needs.changes.outputs.linux_test_groups_json != '[]' }}
|
|
name: Linux tests (${{ matrix.group }})
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include: ${{ fromJson(needs.changes.outputs.linux_test_groups_json) }}
|
|
env:
|
|
AFFECTED: ${{ needs.changes.outputs.affected_crates }}
|
|
ALL_RUST: ${{ needs.changes.outputs.all_rust }}
|
|
LLAMA_STAGE_BACKEND: cpu
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama.cpp/build-stage-abi-static
|
|
MESH_LLM_SKIP_UI: "1"
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
RUSTC_WRAPPER: sccache
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Resolve static ABI toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
pinned_epoch: mesh-llm-cuda-runner-sha256-8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
|
|
- name: Configure Linux Rust linker
|
|
run: |
|
|
mkdir -p .cargo
|
|
cat > .cargo/config.toml <<'EOF'
|
|
[target.x86_64-unknown-linux-gnu]
|
|
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
|
EOF
|
|
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
continue-on-error: true
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: ${{ matrix.cache_key }}
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
|
|
- name: Download immutable static ABI input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-static-abi-input
|
|
path: ${{ runner.temp }}/static-abi-input
|
|
- name: Restore immutable static ABI input
|
|
run: scripts/restore-static-abi-input.sh "$RUNNER_TEMP/static-abi-input" "$LLAMA_STAGE_BUILD_DIR" x86_64-unknown-linux-gnu cpu
|
|
|
|
- name: Restore Skippy smoke model cache
|
|
if: ${{ matrix.group == 'skippy-smoke' }}
|
|
id: skippy_smoke_model_cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/skippy-ci-smoke-models
|
|
key: ${{ env.CACHE_NAMESPACE }}-${{ runner.os }}-skippy-ci-smoke-models-SmolLM2-135M-Instruct.Q4_K_M.gguf-Falcon-H1-0.5B-Instruct-Q4_K_M.gguf-${{ hashFiles('.github/cache-version.txt') }}
|
|
restore-keys: |
|
|
${{ env.CACHE_NAMESPACE }}-${{ runner.os }}-skippy-ci-smoke-models-
|
|
|
|
- name: Protocol compatibility matrix
|
|
if: ${{ matrix.group == 'protocol' && (needs.changes.outputs.all_rust == 'true' || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm-protocol')) }}
|
|
run: |
|
|
cargo test -p mesh-llm --test protocol_compat_v0_client
|
|
cargo test -p mesh-llm --test protocol_convert_matrix
|
|
|
|
- name: Skippy smoke tests
|
|
if: ${{ matrix.group == 'skippy-smoke' }}
|
|
timeout-minutes: 45
|
|
env:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
HUGGING_FACE_HUB_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
WORK_DIR: ${{ runner.temp }}/skippy-ci-smoke
|
|
MODEL_DIR: ${{ runner.temp }}/skippy-ci-smoke-models
|
|
run: scripts/skippy-ci-smoke.sh
|
|
|
|
- name: Save Skippy smoke model cache
|
|
if: ${{ matrix.group == 'skippy-smoke' && github.ref == 'refs/heads/main' && steps.skippy_smoke_model_cache.outputs.cache-hit != 'true' }}
|
|
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/skippy-ci-smoke-models
|
|
key: ${{ steps.skippy_smoke_model_cache.outputs.cache-primary-key }}
|
|
|
|
- name: Capture sccache evidence
|
|
if: ${{ !cancelled() }}
|
|
uses: ./.github/actions/capture-sccache-stats
|
|
with:
|
|
artifact_name: sccache-main-linux-tests-${{ matrix.group }}-${{ github.run_attempt }}
|
|
|
|
hf_download_smoke:
|
|
needs: changes
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.all_rust == 'true' || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'model-artifact')) && needs.changes.outputs.docs_only != 'true' }}
|
|
name: HuggingFace download smoke
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/hf-download-smoke.yml
|
|
with:
|
|
timeout_minutes: 15
|
|
secrets:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
|
|
inference_smoke_tests:
|
|
needs: [changes, linux_cpu_artifact]
|
|
if: ${{ needs.linux_cpu_artifact.result == 'success' && needs.changes.outputs.linux_inference_artifact_required == 'true' && (github.event_name == 'workflow_dispatch' || needs.changes.outputs.all_rust == 'true' || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'skippy-server') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'skippy-runtime') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'openai-frontend') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'model-artifact')) && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/smoke.yml
|
|
with:
|
|
artifact_name: ci-linux-inference-binaries
|
|
mesh_binary_target: target/release/mesh-llm
|
|
cache_key_prefix: ''
|
|
secrets:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
|
|
agent_live_smokes:
|
|
needs: [changes, linux_cpu_artifact]
|
|
if: ${{ needs.linux_cpu_artifact.result == 'success' && (vars.MESH_AGENT_BASE_URL != '' || vars.MESH_OPENCODE_BASE_URL != '') && (github.event_name == 'workflow_dispatch' || needs.changes.outputs.all_rust == 'true' || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'openai-frontend') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm-client')) && needs.changes.outputs.docs_only != 'true' }}
|
|
runs-on: ${{ needs.changes.outputs.runner_4 }}
|
|
permissions:
|
|
contents: read
|
|
timeout-minutes: 45
|
|
env:
|
|
MESH_AGENT_BASE_URL: ${{ vars.MESH_AGENT_BASE_URL || vars.MESH_OPENCODE_BASE_URL }}
|
|
MESH_AGENT_MODEL: ${{ vars.MESH_AGENT_MODEL || vars.MESH_OPENCODE_MODEL }}
|
|
MESH_OPENCODE_BASE_URL: ${{ vars.MESH_AGENT_BASE_URL || vars.MESH_OPENCODE_BASE_URL }}
|
|
MESH_OPENCODE_MODEL: ${{ vars.MESH_AGENT_MODEL || vars.MESH_OPENCODE_MODEL }}
|
|
AGENT_SMOKE_LONG_PROMPT_CHARS: ${{ vars.AGENT_SMOKE_LONG_PROMPT_CHARS || vars.OPENCODE_SMOKE_LONG_PROMPT_CHARS || '65536' }}
|
|
OPENCODE_SMOKE_LONG_PROMPT_CHARS: ${{ vars.OPENCODE_SMOKE_LONG_PROMPT_CHARS || '65536' }}
|
|
OPENCODE_DISABLE_AUTOUPDATE: "true"
|
|
OPENCODE_DISABLE_PRUNE: "true"
|
|
OPENCODE_DISABLE_LSP_DOWNLOAD: "true"
|
|
steps:
|
|
# Keep live-agent smoke on an explicit Node version so CI does not depend
|
|
# on GitHub-hosted image defaults.
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 24
|
|
- name: Install agent CLIs
|
|
run: |
|
|
corepack enable
|
|
corepack prepare pnpm@10 --activate
|
|
export PNPM_HOME="$HOME/.local/share/pnpm"
|
|
mkdir -p "$PNPM_HOME"
|
|
echo "PNPM_HOME=$PNPM_HOME" >> "$GITHUB_ENV"
|
|
echo "$PNPM_HOME" >> "$GITHUB_PATH"
|
|
pnpm add --global opencode-ai@latest @earendil-works/pi-coding-agent@latest
|
|
opencode --version
|
|
pi --version
|
|
- name: Install Goose
|
|
run: |
|
|
curl -fsSL https://github.com/aaif-goose/goose/releases/download/stable/download_cli.sh | CONFIGURE=false bash
|
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
- name: Check Goose
|
|
run: goose --version
|
|
- name: OpenCode configured mesh coding smoke
|
|
run: scripts/ci-opencode-smoke.sh
|
|
- name: Pi configured mesh coding smoke
|
|
run: scripts/ci-pi-smoke.sh
|
|
- name: Goose configured mesh coding smoke
|
|
run: scripts/ci-goose-smoke.sh
|
|
|
|
two_node_client_serving_smoke:
|
|
needs: [changes, linux_cpu_artifact]
|
|
if: ${{ needs.linux_cpu_artifact.result == 'success' && needs.changes.outputs.linux_inference_artifact_required == 'true' && (github.event_name == 'workflow_dispatch' || needs.changes.outputs.all_rust == 'true' || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'openai-frontend') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm-client')) && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/scripted-binary-smoke.yml
|
|
with:
|
|
artifact_name: ci-linux-inference-binaries
|
|
artifact_path: ci-artifacts/linux
|
|
staged_binary_path: target/release/mesh-llm
|
|
model_cache_scope: two-node-smoke-model
|
|
smoke_script: scripts/ci-two-node-client-serving-smoke.sh
|
|
timeout_minutes: 20
|
|
secrets:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
|
|
rust_sdk_smoke:
|
|
needs: [changes, linux_cpu_artifact]
|
|
if: ${{ needs.linux_cpu_artifact.result == 'success' && needs.changes.outputs.linux_inference_artifact_required == 'true' && needs.changes.outputs.sdk_smoke_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/sdk-smoke.yml
|
|
with:
|
|
sdk_kind: rust
|
|
artifact_name: ci-linux-inference-binaries
|
|
artifact_path: ci-artifacts/linux
|
|
staged_binary_path: target/release/mesh-llm
|
|
model_cache_scope: sdk-smoke-model
|
|
secrets:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
|
|
kotlin_sdk_input:
|
|
name: Kotlin native SDK input
|
|
needs: [changes, linux_static_abi_input]
|
|
if: ${{ needs.linux_static_abi_input.result == 'success' && needs.changes.outputs.sdk_smoke_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
uses: ./.github/workflows/native-sdk-artifact.yml
|
|
with:
|
|
backend: cpu
|
|
target: x86_64-unknown-linux-gnu
|
|
profile: release
|
|
artifact_name: ci-kotlin-native-sdk-input
|
|
static_abi_artifact_name: ci-linux-static-abi-input
|
|
static_abi_artifact_path: native-sdk-static-abi-input
|
|
runner_size: '8'
|
|
retention_days: 1
|
|
|
|
kotlin_sdk_smoke:
|
|
needs: [changes, linux_cpu_artifact, kotlin_sdk_input]
|
|
if: ${{ needs.linux_cpu_artifact.result == 'success' && needs.kotlin_sdk_input.result == 'success' && needs.changes.outputs.linux_inference_artifact_required == 'true' && needs.changes.outputs.sdk_smoke_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/sdk-smoke.yml
|
|
with:
|
|
sdk_kind: kotlin
|
|
artifact_name: ci-linux-inference-binaries
|
|
artifact_path: ci-artifacts/linux
|
|
staged_binary_path: target/release/mesh-llm
|
|
kotlin_artifact_name: ci-kotlin-native-sdk-input
|
|
kotlin_artifact_target: x86_64-unknown-linux-gnu
|
|
kotlin_artifact_backend: cpu
|
|
kotlin_artifact_profile: release
|
|
model_cache_scope: sdk-smoke-model
|
|
secrets:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
|
|
swift_sdk_input:
|
|
name: Swift SDK full input
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.macos_inference_artifact_required == 'true' && needs.changes.outputs.sdk_smoke_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/swift-sdk-artifact.yml
|
|
with:
|
|
mode: full
|
|
artifact_name: ci-swift-sdk-input
|
|
retention_days: 1
|
|
timeout_minutes: 180
|
|
|
|
swift_sdk_smoke:
|
|
needs: [changes, macos_cpu_artifact, swift_sdk_input]
|
|
if: ${{ needs.macos_cpu_artifact.result == 'success' && needs.swift_sdk_input.result == 'success' && needs.changes.outputs.sdk_smoke_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
permissions:
|
|
contents: read
|
|
uses: ./.github/workflows/sdk-smoke.yml
|
|
with:
|
|
sdk_kind: swift
|
|
artifact_name: ci-macos-inference-binaries
|
|
artifact_path: ci-artifacts/macos
|
|
staged_binary_path: target/release/mesh-llm
|
|
swift_artifact_name: ci-swift-sdk-input
|
|
swift_artifact_mode: full
|
|
model_cache_scope: sdk-smoke-model
|
|
timeout_minutes: 30
|
|
secrets:
|
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
|
|
|
macos_host_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.macos_inference_artifact_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
name: macOS immutable release host
|
|
runs-on: macos-15
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
MESH_LLM_SKIP_UI: "1"
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
|
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.ui == 'true' }}
|
|
with:
|
|
version: 10
|
|
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.ui == 'true' }}
|
|
with:
|
|
node-version: 24
|
|
cache: pnpm
|
|
cache-dependency-path: |
|
|
.github/cache-version.txt
|
|
crates/mesh-llm-ui/pnpm-lock.yaml
|
|
- name: Restore UI dist cache
|
|
id: ui-cache
|
|
if: needs.changes.outputs.ui == 'true' || github.event_name == 'workflow_dispatch'
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
|
|
with:
|
|
path: crates/mesh-llm-ui/dist
|
|
key: ${{ needs.changes.outputs.ui_dist_cache_key }}
|
|
- name: Build UI
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.ui == 'true') && steps.ui-cache.outputs.cache-hit != 'true' }}
|
|
working-directory: crates/mesh-llm-ui
|
|
run: pnpm i --frozen-lockfile && pnpm run build
|
|
- name: Install UI deps (cache hit only)
|
|
if: needs.changes.outputs.ui == 'true' && steps.ui-cache.outputs.cache-hit == 'true'
|
|
working-directory: crates/mesh-llm-ui
|
|
run: pnpm i --frozen-lockfile
|
|
- name: Verify UI dist exists
|
|
if: needs.changes.outputs.ui == 'true' || github.event_name == 'workflow_dispatch'
|
|
run: |
|
|
if [ ! -f crates/mesh-llm-ui/dist/index.html ]; then
|
|
echo "ERROR: crates/mesh-llm-ui/dist/index.html not found after restore/build"
|
|
exit 1
|
|
fi
|
|
file_count="$(find crates/mesh-llm-ui/dist -mindepth 1 -maxdepth 1 | wc -l | tr -d ' ')"
|
|
echo "UI dist OK: ${file_count} files"
|
|
- name: Test UI
|
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.ui == 'true' }}
|
|
working-directory: crates/mesh-llm-ui
|
|
run: pnpm test
|
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: macos
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install host build dependencies
|
|
run: brew install jq lld
|
|
- name: Configure macOS Rust linker
|
|
run: |
|
|
mkdir -p .cargo
|
|
lld_prefix="$(brew --prefix lld)"
|
|
cat > .cargo/config.toml <<EOF
|
|
[target.aarch64-apple-darwin]
|
|
rustflags = ["-C", "link-arg=-fuse-ld=$lld_prefix/bin/ld64.lld"]
|
|
|
|
[target.x86_64-apple-darwin]
|
|
rustflags = ["-C", "link-arg=-fuse-ld=$lld_prefix/bin/ld64.lld"]
|
|
EOF
|
|
- name: Prepare UI placeholder
|
|
run: |
|
|
mkdir -p crates/mesh-llm-ui/dist
|
|
test -f crates/mesh-llm-ui/dist/index.html ||
|
|
printf '<html></html>' > crates/mesh-llm-ui/dist/index.html
|
|
|
|
- name: Prepare backend-neutral release host
|
|
uses: ./.github/actions/prepare-host-input
|
|
with:
|
|
profile: release
|
|
output_dir: host-input
|
|
skip_ui: "true"
|
|
|
|
- name: Upload immutable macOS host input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-macos-host-input
|
|
path: host-input/
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
macos_metal_runtime_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.macos_inference_artifact_required == 'true' && needs.changes.outputs.docs_only != 'true' }}
|
|
name: macOS Metal runtime
|
|
runs-on: macos-15
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
LLAMA_STAGE_BACKEND: metal
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/build-stage-abi-dynamic-metal
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Install native runtime dependencies
|
|
run: brew install cmake ninja jq
|
|
- name: Resolve macOS native toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
include_tool_versions: "true"
|
|
- name: Prepare Metal native runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
with:
|
|
backend: metal
|
|
output_dir: runtime-input
|
|
|
|
- name: Upload immutable Metal runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-macos-metal-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
macos_cpu_artifact:
|
|
needs: [changes, macos_host_input, macos_metal_runtime_input]
|
|
if: ${{ needs.macos_host_input.result == 'success' && needs.macos_metal_runtime_input.result == 'success' }}
|
|
name: macOS Metal release product
|
|
runs-on: macos-15
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Download immutable macOS host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-macos-host-input
|
|
path: host-input
|
|
- name: Download immutable Metal runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-macos-metal-runtime-input
|
|
path: runtime-input
|
|
- name: Compose macOS Metal product
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: ci-product
|
|
backend: metal
|
|
|
|
- name: Upload macOS composed release product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-macos-inference-binaries
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
macos_unit_tests:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' && (needs.changes.outputs.all_rust == 'true' || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'model-artifact') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm-host-runtime') || contains(fromJson(needs.changes.outputs.affected_crates || '[]'), 'mesh-llm')) }}
|
|
name: macOS unit tests
|
|
runs-on: macos-15
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
AFFECTED: ${{ needs.changes.outputs.affected_crates }}
|
|
ALL_RUST: ${{ needs.changes.outputs.all_rust }}
|
|
LLAMA_STAGE_BACKEND: metal
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/build-stage-abi-static-metal
|
|
MESH_LLM_SKIP_UI: "1"
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: macos-unit-tests
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install unit-test dependencies
|
|
run: brew install cmake ninja jq lld
|
|
- name: Resolve macOS native toolchain epoch
|
|
id: native_toolchain
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
include_tool_versions: "true"
|
|
- name: Configure macOS Rust linker
|
|
run: |
|
|
mkdir -p .cargo
|
|
lld_prefix="$(brew --prefix lld)"
|
|
cat > .cargo/config.toml <<EOF
|
|
[target.aarch64-apple-darwin]
|
|
rustflags = ["-C", "link-arg=-fuse-ld=$lld_prefix/bin/ld64.lld"]
|
|
|
|
[target.x86_64-apple-darwin]
|
|
rustflags = ["-C", "link-arg=-fuse-ld=$lld_prefix/bin/ld64.lld"]
|
|
EOF
|
|
- name: Ensure static Metal ABI cache directory
|
|
run: mkdir -p "$LLAMA_STAGE_BUILD_DIR"
|
|
- name: Cache static Metal ABI build
|
|
id: llama_cache
|
|
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
|
|
with:
|
|
path: ${{ env.LLAMA_STAGE_BUILD_DIR }}
|
|
key: ${{ env.CACHE_NAMESPACE }}-${{ runner.os }}-${{ runner.arch }}-skippy-abi-static-metal-${{ steps.native_toolchain.outputs.epoch }}-${{ hashFiles('scripts/build-mac.sh', 'scripts/build-llama.sh', 'scripts/prepare-llama.sh', 'third_party/llama.cpp/upstream.txt', 'third_party/llama.cpp/patches/**', 'Justfile', '.github/cache-version.txt') }}
|
|
- name: Prepare patched llama.cpp ABI checkout
|
|
run: scripts/prepare-llama.sh pinned
|
|
- name: Verify cached patched llama.cpp ABI libraries
|
|
if: ${{ steps.llama_cache.outputs.cache-hit == 'true' }}
|
|
run: scripts/build-llama.sh --require-existing
|
|
- name: Build patched llama.cpp ABI libraries
|
|
if: ${{ steps.llama_cache.outputs.cache-hit != 'true' }}
|
|
run: scripts/build-llama.sh
|
|
- name: Unit tests
|
|
run: |
|
|
should_test() {
|
|
local crate="$1"
|
|
[ "$ALL_RUST" = "true" ] || jq -e --arg crate "$crate" 'index($crate) != null' <<<"$AFFECTED" >/dev/null
|
|
}
|
|
|
|
for c in model-artifact mesh-llm-host-runtime mesh-llm; do
|
|
if should_test "$c"; then
|
|
cargo test -p "$c" --lib
|
|
else
|
|
echo "Skipping $c on macOS (not affected)"
|
|
fi
|
|
done
|
|
|
|
linux_cuda_runtime_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' }}
|
|
name: Linux CUDA compatibility runtime
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:c5b85ef527230f77cf9933ef40bcb44316f9bbcb8fd2ce0651b58acda5143dfd
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
env:
|
|
LLAMA_STAGE_BACKEND: cuda
|
|
LLAMA_STAGE_CUDA_ARCHITECTURES: "75;80;86;87;89;90"
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/build-stage-abi-dynamic-cuda-sm75_80_86_87_89_90
|
|
MESH_CUDA_VERSION: "12.9.2"
|
|
MESH_LLM_CUDA_TOOLKIT_MAJOR: "12"
|
|
# CI containers have no GPU driver (libcuda.so.1). Disable VMM and NCCL
|
|
# to avoid linking libraries that require the CUDA driver at runtime.
|
|
GGML_CUDA_NO_VMM: "1"
|
|
LLAMA_STAGE_SKIP_NCCL: "1"
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt backend environment
|
|
run: verify-runner-image public cuda
|
|
- name: Resolve CUDA native toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
pinned_epoch: mesh-llm-cuda-runner-sha256-c5b85ef527230f77cf9933ef40bcb44316f9bbcb8fd2ce0651b58acda5143dfd
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
|
|
- name: Prepare Linux CUDA native runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
with:
|
|
backend: cuda
|
|
target: x86_64-unknown-linux-gnu
|
|
output_dir: runtime-input
|
|
|
|
- name: Upload immutable CUDA runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-cuda-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
linux_cuda_product:
|
|
needs: [changes, linux_host_input, linux_cuda_runtime_input]
|
|
if: ${{ needs.linux_host_input.result == 'success' && needs.linux_cuda_runtime_input.result == 'success' }}
|
|
name: Linux CUDA compatibility
|
|
runs-on: ${{ needs.changes.outputs.runner_4 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Download immutable host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-host-input
|
|
path: host-input
|
|
- name: Download immutable CUDA runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-cuda-runtime-input
|
|
path: runtime-input
|
|
- name: Compose CUDA product
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: product-input
|
|
backend: cuda
|
|
|
|
- name: Upload composed CUDA product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-cuda-product
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
linux_rocm_runtime_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' }}
|
|
name: Linux ROCm slim runtime
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:0e13e5d2d2c121df265ff6c69be81e468989e09f81d6b7ff049b110cc0bb0d2b
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
env:
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/build-stage-abi-dynamic-rocm-gfx1100
|
|
LLAMA_STAGE_BACKEND: rocm
|
|
LLAMA_STAGE_AMDGPU_TARGETS: gfx1100
|
|
CMAKE_PREFIX_PATH: /opt/rocm
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt backend environment
|
|
run: verify-runner-image public rocm
|
|
- name: Resolve ROCm native toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
pinned_epoch: mesh-llm-cuda-runner-sha256-0e13e5d2d2c121df265ff6c69be81e468989e09f81d6b7ff049b110cc0bb0d2b
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
|
|
- name: Prepare Linux ROCm native runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
with:
|
|
backend: rocm
|
|
target: x86_64-unknown-linux-gnu
|
|
output_dir: runtime-input
|
|
|
|
- name: Upload immutable ROCm runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-rocm-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
linux_rocm_product:
|
|
needs: [changes, linux_host_input, linux_rocm_runtime_input]
|
|
if: ${{ needs.linux_host_input.result == 'success' && needs.linux_rocm_runtime_input.result == 'success' }}
|
|
name: Linux ROCm slim
|
|
runs-on: ${{ needs.changes.outputs.runner_4 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Download immutable host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-host-input
|
|
path: host-input
|
|
- name: Download immutable ROCm runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-rocm-runtime-input
|
|
path: runtime-input
|
|
- name: Compose ROCm product
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: product-input
|
|
backend: rocm
|
|
|
|
- name: Upload composed ROCm product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-rocm-product
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
linux_vulkan_runtime_input:
|
|
needs: changes
|
|
if: ${{ needs.changes.outputs.docs_only != 'true' }}
|
|
name: Linux Vulkan runtime
|
|
runs-on: ${{ needs.changes.outputs.runner_8 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:ce55fed5c680cd3184b5d4770d9a77c43a702687690906e5753efd2cea27ed80
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
env:
|
|
LLAMA_STAGE_BACKEND: vulkan
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/build-stage-abi-dynamic-vulkan
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt backend environment
|
|
run: verify-runner-image public vulkan
|
|
- name: Resolve Vulkan native toolchain epoch
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
with:
|
|
pinned_epoch: mesh-llm-cuda-runner-sha256-ce55fed5c680cd3184b5d4770d9a77c43a702687690906e5753efd2cea27ed80
|
|
- uses: ./.github/actions/configure-sccache-gha
|
|
with:
|
|
allow_depot_remote_cache: ${{ needs.changes.outputs.allow_depot_remote_cache }}
|
|
|
|
- name: Prepare Linux Vulkan native runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
with:
|
|
backend: vulkan
|
|
target: x86_64-unknown-linux-gnu
|
|
output_dir: runtime-input
|
|
|
|
- name: Upload immutable Vulkan runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-vulkan-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
linux_vulkan_product:
|
|
needs: [changes, linux_host_input, linux_vulkan_runtime_input]
|
|
if: ${{ needs.linux_host_input.result == 'success' && needs.linux_vulkan_runtime_input.result == 'success' }}
|
|
name: Linux Vulkan
|
|
runs-on: ${{ needs.changes.outputs.runner_4 }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
container:
|
|
image: ghcr.io/mesh-llm/mesh-llm-cuda-runner@sha256:8d93de6ba30173e825a16fdecf011f9c632edc6e1259df7289e491b0a05f829d
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- name: Verify prebuilt CI environment
|
|
run: verify-runner-image public
|
|
- name: Download immutable host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-host-input
|
|
path: host-input
|
|
- name: Download immutable Vulkan runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-linux-vulkan-runtime-input
|
|
path: runtime-input
|
|
- name: Compose Vulkan product
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: product-input
|
|
backend: vulkan
|
|
|
|
- name: Upload composed Vulkan product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-linux-vulkan-product
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
windows_node_checks:
|
|
needs: changes
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.rust == 'true') && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Windows Node SDK checks
|
|
runs-on: windows-2022
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
RUN_WINDOWS_NODE_RELEASE: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.windows_cpu == 'true' }}
|
|
RUSTC_WRAPPER: sccache
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
|
|
- uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: windows-node
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Check Node SDK addon on Windows
|
|
shell: pwsh
|
|
run: cargo check --locked -p mesh-llm-nodejs
|
|
- name: Build Node SDK addon on Windows
|
|
if: ${{ env.RUN_WINDOWS_NODE_RELEASE == 'true' }}
|
|
shell: pwsh
|
|
run: cargo build --release --locked -p mesh-llm-nodejs
|
|
|
|
windows_gpu_runtime_inputs:
|
|
needs: changes
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.windows_gpu == 'true') && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Windows ${{ matrix.name }} runtime input
|
|
runs-on: windows-2022
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
LLAMA_STAGE_BACKEND: ${{ matrix.backend }}
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/windows/build-stage-abi-${{ matrix.backend }}
|
|
RUSTC_WRAPPER: sccache
|
|
WINDOWS_CUDA_VERSION: ${{ vars.CUDA_VERSION || '12.6.3' }}
|
|
WINDOWS_VULKAN_SDK_VERSION: ${{ vars.VULKAN_SDK_VERSION || '1.4.328.1' }}
|
|
ROCM_HIP_SDK_FILENAME: AMD-Software-PRO-Edition-25.Q3-WinSvr2022-For-HIP.exe
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- name: CUDA
|
|
backend: cuda
|
|
cuda_architectures: "75"
|
|
- name: ROCm
|
|
backend: rocm
|
|
rocm_architectures: gfx1100
|
|
- name: Vulkan
|
|
backend: vulkan
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
with:
|
|
python-version: '3.x'
|
|
- name: Test Windows native-runtime dependency resolver
|
|
if: ${{ matrix.backend == 'vulkan' }}
|
|
shell: pwsh
|
|
run: python -m unittest scripts.tests.test_windows_native_runtime_deps -v
|
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
|
|
- uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: windows-runtime-${{ matrix.backend }}
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Resolve Windows native toolchain epoch
|
|
id: native_toolchain
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
- name: Restore exact Windows GPU ABI cache
|
|
uses: ./.github/actions/restore-windows-abi-cache
|
|
with:
|
|
backend: ${{ matrix.backend }}
|
|
build_dir: ${{ env.LLAMA_STAGE_BUILD_DIR }}
|
|
toolchain_epoch: ${{ steps.native_toolchain.outputs.epoch }}
|
|
architecture_set: ${{ matrix.cuda_architectures || matrix.rocm_architectures || '' }}
|
|
cuda_toolchain_version: ${{ env.WINDOWS_CUDA_VERSION }}
|
|
vulkan_toolchain_version: ${{ env.WINDOWS_VULKAN_SDK_VERSION }}
|
|
rocm_toolchain_version: ${{ env.ROCM_HIP_SDK_FILENAME }}
|
|
- name: Install CUDA toolkit
|
|
if: ${{ matrix.backend == 'cuda' }}
|
|
uses: Jimver/cuda-toolkit@3d45d157f327c09c04b50ee6ccdea2d9d017ec76 # v0.2.35
|
|
with:
|
|
cuda: ${{ env.WINDOWS_CUDA_VERSION }}
|
|
method: network
|
|
sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "visual_studio_integration"]'
|
|
use-github-cache: true
|
|
use-local-cache: true
|
|
log-file-suffix: windows-cuda
|
|
- name: Verify CUDA toolkit
|
|
if: ${{ matrix.backend == 'cuda' }}
|
|
shell: pwsh
|
|
run: |
|
|
if (-not $env:CUDA_PATH -or -not (Test-Path $env:CUDA_PATH)) {
|
|
throw "CUDA_PATH was not configured by Jimver/cuda-toolkit."
|
|
}
|
|
& nvcc --version
|
|
$cudaMajor = ("$env:WINDOWS_CUDA_VERSION".Trim() -split '\.', 2)[0]
|
|
"MESH_LLM_CUDA_TOOLKIT_MAJOR=$cudaMajor" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
|
- name: Install Vulkan SDK
|
|
if: ${{ matrix.backend == 'vulkan' }}
|
|
uses: jakoch/install-vulkan-sdk-action@3c53c378c9bfbb2ea122a1cc164a837d4004c871 # v1.5.2
|
|
with:
|
|
vulkan_version: ${{ env.WINDOWS_VULKAN_SDK_VERSION }}
|
|
cache: true
|
|
stripdown: true
|
|
- name: Verify Vulkan SDK
|
|
if: ${{ matrix.backend == 'vulkan' }}
|
|
shell: pwsh
|
|
run: |
|
|
if (-not $env:VULKAN_SDK -or -not (Test-Path $env:VULKAN_SDK)) {
|
|
throw "VULKAN_SDK was not configured by jakoch/install-vulkan-sdk-action."
|
|
}
|
|
$glslc = Join-Path $env:VULKAN_SDK "Bin\glslc.exe"
|
|
if (-not (Test-Path $glslc)) {
|
|
throw "glslc.exe was not found at $glslc"
|
|
}
|
|
& $glslc --version
|
|
- name: Install ROCm HIP SDK
|
|
if: ${{ matrix.backend == 'rocm' }}
|
|
uses: ./.github/actions/setup-windows-rocm-sdk
|
|
with:
|
|
rocm-hip-sdk-filename: ${{ env.ROCM_HIP_SDK_FILENAME }}
|
|
- name: Initialize MSVC for native runtime
|
|
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
|
|
with:
|
|
arch: x64
|
|
- name: Prepare immutable Windows GPU runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
env:
|
|
LLAMA_STAGE_CUDA_ARCHITECTURES: ${{ matrix.cuda_architectures }}
|
|
LLAMA_STAGE_AMDGPU_TARGETS: ${{ matrix.rocm_architectures }}
|
|
with:
|
|
backend: ${{ matrix.backend }}
|
|
target: x86_64-pc-windows-msvc
|
|
output_dir: runtime-input
|
|
- name: Upload immutable Windows GPU runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-windows-${{ matrix.backend }}-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
windows_host_input:
|
|
needs: changes
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.rust == 'true' || needs.changes.outputs.windows_cpu == 'true' || needs.changes.outputs.windows_gpu == 'true') && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Windows immutable release host
|
|
runs-on: windows-2022
|
|
env:
|
|
MESH_LLM_REQUIRE_SCCACHE: "1"
|
|
RUSTC_WRAPPER: sccache
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
with:
|
|
python-version: '3.x'
|
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
|
|
- uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: windows-host-release
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Initialize MSVC for neutral host
|
|
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
|
|
with:
|
|
arch: x64
|
|
- name: Prepare immutable Windows release host
|
|
uses: ./.github/actions/prepare-windows-host-input
|
|
with:
|
|
profile: release
|
|
skip_ui: "true"
|
|
- name: Upload immutable Windows host input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-windows-host-input
|
|
path: host-input/*
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
windows_cpu_runtime_input:
|
|
needs: changes
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.rust == 'true' || needs.changes.outputs.windows_cpu == 'true') && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Windows CPU runtime input
|
|
runs-on: windows-2022
|
|
env:
|
|
LLAMA_STAGE_BACKEND: cpu
|
|
LLAMA_STAGE_BUILD_DIR: .deps/llama-build/windows/build-stage-abi-cpu
|
|
RUSTC_WRAPPER: sccache
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
with:
|
|
python-version: '3.x'
|
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
|
|
- uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12
|
|
with:
|
|
workspaces: . -> target
|
|
cache-bin: "false"
|
|
prefix-key: ${{ env.CACHE_NAMESPACE }}-rust-${{ runner.os }}-${{ hashFiles('.github/cache-version.txt') }}
|
|
shared-key: windows-runtime-cpu
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Resolve Windows native toolchain epoch
|
|
id: native_toolchain
|
|
uses: ./.github/actions/resolve-native-toolchain-epoch
|
|
- name: Restore exact Windows CPU ABI cache
|
|
uses: ./.github/actions/restore-windows-abi-cache
|
|
with:
|
|
backend: cpu
|
|
build_dir: ${{ env.LLAMA_STAGE_BUILD_DIR }}
|
|
toolchain_epoch: ${{ steps.native_toolchain.outputs.epoch }}
|
|
- name: Initialize MSVC for CPU runtime
|
|
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
|
|
with:
|
|
arch: x64
|
|
- name: Prepare immutable Windows CPU runtime
|
|
uses: ./.github/actions/prepare-native-runtime-input
|
|
with:
|
|
backend: cpu
|
|
target: x86_64-pc-windows-msvc
|
|
output_dir: runtime-input
|
|
- name: Upload immutable Windows CPU runtime input
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-windows-cpu-runtime-input
|
|
path: |
|
|
runtime-input/*.tar.gz
|
|
runtime-input/*.sha256
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
windows_cpu_product:
|
|
needs: [changes, windows_host_input, windows_cpu_runtime_input]
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.rust == 'true' || needs.changes.outputs.windows_cpu == 'true') && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Windows CPU
|
|
runs-on: windows-2022
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
with:
|
|
python-version: '3.x'
|
|
- name: Download immutable Windows host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-windows-host-input
|
|
path: host-input
|
|
- name: Download immutable Windows CPU runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-windows-cpu-runtime-input
|
|
path: runtime-input
|
|
- name: Compose Windows CPU product
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: product-input
|
|
backend: cpu
|
|
binary_name: mesh-llm.exe
|
|
readiness_smoke: "true"
|
|
- name: Upload composed Windows CPU product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-windows-cpu-product
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
windows_gpu_products:
|
|
needs: [changes, windows_host_input, windows_gpu_runtime_inputs]
|
|
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.windows_gpu == 'true') && needs.changes.outputs.docs_only != 'true' }}
|
|
name: Windows ${{ matrix.name }}
|
|
runs-on: windows-2022
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- name: CUDA
|
|
backend: cuda
|
|
- name: ROCm
|
|
backend: rocm
|
|
- name: Vulkan
|
|
backend: vulkan
|
|
steps:
|
|
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
with:
|
|
python-version: '3.x'
|
|
- name: Download immutable Windows host input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-windows-host-input
|
|
path: host-input
|
|
- name: Download immutable Windows GPU runtime input
|
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
with:
|
|
name: ci-windows-${{ matrix.backend }}-runtime-input
|
|
path: runtime-input
|
|
- name: Compose Windows GPU product
|
|
id: compose
|
|
uses: ./.github/actions/compose-product-input
|
|
with:
|
|
host_input_dir: host-input
|
|
runtime_input_dir: runtime-input
|
|
output_dir: product-input
|
|
backend: ${{ matrix.backend }}
|
|
binary_name: mesh-llm.exe
|
|
readiness_smoke: "true"
|
|
- name: Upload composed Windows GPU product
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ci-windows-${{ matrix.backend }}-product
|
|
path: ${{ steps.compose.outputs.archive_path }}
|
|
if-no-files-found: error
|
|
retention-days: 1
|