426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
ci / test (push) Waiting to run
ci / lint-and-format (push) Waiting to run
ci / build (push) Waiting to run
ci / dev-startup (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
gitleaks / gitleaks (push) Waiting to run
Markdown Links / Relative Markdown Links (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Quality (Extended) / Homepage Build (PR smoke) (push) Waiting to run
Quality (Extended) / Comment-only diff guard (push) Waiting to run
Quality (Extended) / Format + Type Safety Ratchet (push) Waiting to run
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Waiting to run
Quality (Extended) / Develop Gate (lint) (push) Waiting to run
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
204 lines
9.7 KiB
YAML
204 lines
9.7 KiB
YAML
name: Build libelizainference (Android, FFI)
|
||
|
||
# Builds the Android NDK shared library `libelizainference.so` for the
|
||
# four supported ABIs and ships them as a per-ABI JNI bundle. The FFI
|
||
# streaming runner (`ffi-streaming-runner.ts`) dlopens this artifact
|
||
# from the APK's `lib/<abi>/` directory.
|
||
#
|
||
# Why FFI on Android: same reason as iOS — `child_process.spawn` is
|
||
# unavailable inside the app sandbox, the Play Store policy forbids
|
||
# downloading native binaries at runtime, and a 10–30ms HTTP round-trip
|
||
# per token is unacceptable on a battery-constrained device. See
|
||
# `runtime-target.ts` for the decision rules.
|
||
#
|
||
# Builds in CI at build time (no eliza-archive prebuilt dependency). The fused
|
||
# lib is the real `libelizainference.so` produced by `compile-libllama.mjs` via
|
||
# the zig/musl cross-compile — NOT a renamed `libllama.so`, and NOT a bionic NDK
|
||
# build (bun's in-process FFI can only `dlopen` a musl-linked .so; see the header
|
||
# of `compile-libllama.mjs`). `workflow_call` lets the app build invoke this and
|
||
# consume the uploaded artifact directly instead of syncing from eliza-archive.
|
||
|
||
on:
|
||
workflow_call:
|
||
inputs:
|
||
abi_filter:
|
||
required: false
|
||
type: string
|
||
default: "arm64-v8a,x86_64"
|
||
workflow_dispatch:
|
||
inputs:
|
||
abi_filter:
|
||
description: "Comma-separated subset of ABIs to build (default: all)"
|
||
required: false
|
||
type: string
|
||
default: "arm64-v8a,x86_64"
|
||
push:
|
||
branches: [develop]
|
||
paths:
|
||
- "plugins/plugin-local-inference/native/llama.cpp/**"
|
||
- "packages/app-core/scripts/aosp/compile-libllama.mjs"
|
||
- ".github/workflows/build-llama-ffi-android.yml"
|
||
tags:
|
||
- "llama-ffi-android-*"
|
||
|
||
concurrency:
|
||
group: build-llama-ffi-android-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
env:
|
||
NODE_VERSION: "24"
|
||
BUN_VERSION: "canary"
|
||
ANDROID_API: "26"
|
||
# Pinned to the NDK r26d-equivalent the rest of the app builds against;
|
||
# bumping this requires syncing with `packages/app/electrobun/android/`.
|
||
ANDROID_NDK_VERSION: "26.3.11579264"
|
||
|
||
jobs:
|
||
prepare-matrix:
|
||
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
|
||
outputs:
|
||
matrix: ${{ steps.set.outputs.matrix }}
|
||
steps:
|
||
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
|
||
id: set
|
||
with:
|
||
script: |
|
||
const inputs = context.payload.inputs ?? {};
|
||
const filterRaw = (inputs.abi_filter ?? "arm64-v8a,x86_64").trim();
|
||
const filter = new Set(filterRaw.split(",").map((s) => s.trim()).filter(Boolean));
|
||
|
||
// compile-libllama.mjs fused targets: arm64 gets the Vulkan GPU
|
||
// backend (the QJL/Polar/Mali-FA-mitigation kernels live here),
|
||
// x86_64 (emulator/cuttlefish) is CPU-only. armeabi-v7a (32-bit)
|
||
// is unsupported by the fused build and dropped.
|
||
const all = [
|
||
{ abi: "arm64-v8a", target: "android-arm64-vulkan-fused" },
|
||
{ abi: "x86_64", target: "android-x86_64-cpu-fused" },
|
||
];
|
||
const include = all.filter((m) => filter.has(m.abi));
|
||
core.setOutput("matrix", JSON.stringify({ include }));
|
||
|
||
build:
|
||
name: ${{ matrix.abi }}
|
||
needs: prepare-matrix
|
||
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
|
||
timeout-minutes: 120
|
||
strategy:
|
||
fail-fast: false
|
||
matrix: ${{ fromJSON(needs.prepare-matrix.outputs.matrix) }}
|
||
steps:
|
||
- name: Checkout (with the llama.cpp fork submodule — the canonical source)
|
||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
||
with:
|
||
# The repo pins the fork via the submodule gitlink; build from that,
|
||
# not compile-libllama's LLAMA_CPP_COMMIT default (which can diverge
|
||
# from the gitlink and may not be a fetchable remote ref).
|
||
submodules: recursive
|
||
show-progress: false
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||
with:
|
||
node-version: ${{ env.NODE_VERSION }}
|
||
|
||
- name: Setup Bun
|
||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
|
||
with:
|
||
bun-version: ${{ env.BUN_VERSION }}
|
||
|
||
- name: Install build deps (cmake, ninja, Vulkan-Hpp headers)
|
||
run: |
|
||
set -euo pipefail
|
||
# The runner image ships a packages.microsoft.com apt source that
|
||
# intermittently 403s / "is no longer signed", which fails apt-get
|
||
# update under pipefail even though this build needs nothing from it.
|
||
# Drop any MS apt source (filename varies by image) before updating.
|
||
for f in $(sudo grep -rliE 'packages\.microsoft\.com' /etc/apt/sources.list.d/ 2>/dev/null || true); do
|
||
sudo rm -f "$f"
|
||
done
|
||
sudo apt-get update -o Acquire::Retries=5 -o Acquire::http::Timeout=30
|
||
# libvulkan-dev provides /usr/include/vulkan/vulkan.hpp (arch-independent;
|
||
# compile-libllama searches /usr/include for it on Linux hosts).
|
||
sudo apt-get install -y cmake ninja-build build-essential git python3 libvulkan-dev
|
||
cmake --version
|
||
|
||
- name: Install zig 0.13 (the cross-compiler compile-libllama uses)
|
||
run: |
|
||
set -euo pipefail
|
||
# Pinned to 0.13 — the version the build is tested against; newer zig
|
||
# (0.16) regresses the musl lld link. See compile-libllama.mjs header.
|
||
curl -fsSL "https://ziglang.org/download/0.13.0/zig-linux-x86_64-0.13.0.tar.xz" -o /tmp/zig.tar.xz
|
||
mkdir -p "$HOME/.zig" && tar -xf /tmp/zig.tar.xz -C "$HOME/.zig" --strip-components=1
|
||
echo "$HOME/.zig" >> "$GITHUB_PATH"
|
||
"$HOME/.zig/zig" version
|
||
|
||
- name: Install Android NDK (sysroot + glslc for the Vulkan build)
|
||
uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779
|
||
id: setup-ndk
|
||
with:
|
||
ndk-version: r26d
|
||
add-to-path: false
|
||
|
||
- name: Build the real fused libelizainference.so (${{ matrix.target }})
|
||
env:
|
||
# compile-libllama's Vulkan resolver expects an SDK root with
|
||
# <ANDROID_HOME>/ndk/<numeric-version>/ (it lists ndk/, keeps dirs
|
||
# matching /^\d+\./, takes the highest, and treats it as the NDK root).
|
||
# nttld/setup-ndk (add-to-path:false, link-to-sdk:false) installs into
|
||
# the tool cache and exposes the NDK root via outputs.ndk-path — NOT in
|
||
# an <sdk>/ndk/<version> layout — so ${{ steps.setup-ndk.outputs.ndk-path }}/../..
|
||
# has no numeric ndk/ subdir and the resolver threw. Stitch a clean
|
||
# single-NDK SDK below and point ANDROID_HOME at it.
|
||
ANDROID_HOME: ${{ runner.temp }}/android-sdk
|
||
run: |
|
||
set -euo pipefail
|
||
# ndk/<numeric-version> -> the installed NDK root. r26d == 26.3.11579264
|
||
# (keep in sync with the ndk-version pin on the setup-ndk step above).
|
||
# A clean dir holding only this NDK guarantees the resolver's
|
||
# "highest numeric dir wins" picks r26d, independent of whatever NDK the
|
||
# runner image happens to preinstall.
|
||
mkdir -p "$ANDROID_HOME/ndk"
|
||
ln -sfn "${{ steps.setup-ndk.outputs.ndk-path }}" "$ANDROID_HOME/ndk/26.3.11579264"
|
||
# Builds the REAL fused FFI lib (libelizainference.so) via the
|
||
# zig/musl cross-compile — bun's in-process FFI can only dlopen a
|
||
# musl-linked .so, which the bionic NDK cmake path could not produce.
|
||
# --assets-dir redirects the staged output into
|
||
# artifacts/libelizainference/<target>/<abi>/libelizainference.so so the
|
||
# Verify + Upload steps below find it (the script otherwise defaults to
|
||
# packages/app/android/app/src/main/assets/agent/<abi>/).
|
||
# --src-dir builds from the in-repo fork submodule (the gitlink the
|
||
# repo pins + that `submodules: recursive` fetched) rather than
|
||
# compile-libllama's LLAMA_CPP_COMMIT default, which is a divergent
|
||
# local-only ref that is not fetchable in CI.
|
||
node packages/app-core/scripts/aosp/compile-libllama.mjs --target ${{ matrix.target }} --src-dir plugins/plugin-local-inference/native/llama.cpp --assets-dir artifacts/libelizainference/${{ matrix.target }}
|
||
|
||
- name: Verify fused artifact (FFI symbols + Mali FA mitigation on arm64)
|
||
run: |
|
||
set -euo pipefail
|
||
SO=$(find artifacts/libelizainference/${{ matrix.target }} -name "libelizainference.so" | head -1)
|
||
test -n "$SO" || { echo "no libelizainference.so produced"; find artifacts -name "*.so"; exit 1; }
|
||
file "$SO"; ls -lh "$SO"
|
||
# The fused FFI must export the eliza_inference_* voice ABI.
|
||
if ! nm -D "$SO" 2>/dev/null | grep -q "eliza_inference_"; then
|
||
echo "WARNING: eliza_inference_* symbols not visible via nm (stripped?)"
|
||
fi
|
||
if [ "${{ matrix.abi }}" = "arm64-v8a" ]; then
|
||
VK=$(find artifacts/libelizainference/${{ matrix.target }} -name "libggml-vulkan.so*" | head -1)
|
||
if [ -n "$VK" ] && strings "$VK" | grep -q GGML_VK_FA_ALLOW_SUBGROUPS; then
|
||
echo "OK: arm64 Vulkan lib carries the Mali flash-attn mitigation (#9508)"
|
||
else
|
||
echo "WARNING: GGML_VK_FA_ALLOW_SUBGROUPS marker not found in $VK"
|
||
fi
|
||
fi
|
||
|
||
- name: Upload libelizainference artifact
|
||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||
with:
|
||
name: libelizainference-${{ matrix.target }}
|
||
path: artifacts/libelizainference/${{ matrix.target }}/**
|
||
if-no-files-found: error
|
||
retention-days: 30
|