Skip to content

feat(llm): add Gemma 4 E4B as default and native tool_calls priority #190

feat(llm): add Gemma 4 E4B as default and native tool_calls priority

feat(llm): add Gemma 4 E4B as default and native tool_calls priority #190

Workflow file for this run

# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
# SPDX-License-Identifier: MIT
# This workflow builds and tests the C++ library in cpp/
# Tests include: CMake build, GoogleTest mock tests (cloud), integration tests (STX)
# Integration tests: LLM chat/tool-calling, MCP connection, WiFi diagnostics, Health monitoring
# Platform: Cross-platform (Linux and Windows cloud), Windows STX (self-hosted AMD hardware)
name: C++ Build & Test
on:
workflow_call:
push:
branches: [ main ]
paths:
- 'cpp/**'
- '.github/workflows/build_cpp.yml'
- '.github/workflows/benchmark_cpp.yml'
pull_request:
branches: [ main ]
types: [opened, synchronize, reopened, ready_for_review]
paths:
- 'cpp/**'
- '.github/workflows/build_cpp.yml'
- '.github/workflows/benchmark_cpp.yml'
merge_group:
workflow_dispatch:
# Cancel in-progress runs when a new run is triggered
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build-and-test:
name: C++ (${{ matrix.os }})
runs-on: ${{ matrix.os }}
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Install OpenSSL (Linux)
if: runner.os == 'Linux'
run: sudo apt-get install -y libssl-dev
- name: Install OpenSSL (Windows)
if: runner.os == 'Windows'
run: choco install openssl --no-progress -y
- name: Restore FetchContent cache
id: cache-deps
uses: actions/cache@v4
with:
path: cpp/build/_deps
key: fetchcontent-${{ matrix.os }}-${{ hashFiles('cpp/CMakeLists.txt') }}
- name: Configure CMake
run: cmake -B cpp/build -S cpp -DCMAKE_BUILD_TYPE=Release -DGAIA_BUILD_INTEGRATION_TESTS=OFF
- name: Build
run: cmake --build cpp/build --config Release --parallel
- name: Test
run: ctest --test-dir cpp/build -C Release --output-on-failure
# Verify cmake --install + find_package round-trip works
install-test:
name: C++ Install Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Install OpenSSL (Linux)
if: runner.os == 'Linux'
run: sudo apt-get install -y libssl-dev
- name: Restore FetchContent cache
uses: actions/cache@v4
with:
path: cpp/build/_deps
key: fetchcontent-install-${{ matrix.os }}-${{ hashFiles('cpp/CMakeLists.txt') }}
- name: Install OpenSSL (Windows)
if: runner.os == 'Windows'
shell: bash
run: choco install openssl --no-progress -y
- name: Build and install gaia_core
shell: bash
run: |
cmake -B cpp/build -S cpp -DCMAKE_BUILD_TYPE=Release \
-DGAIA_BUILD_TESTS=OFF -DGAIA_BUILD_EXAMPLES=OFF \
-DGAIA_BUILD_INTEGRATION_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX="${{ runner.temp }}/gaia_install"
cmake --build cpp/build --config Release --parallel
cmake --install cpp/build --config Release
- name: Build consumer via find_package
shell: bash
run: |
cmake -B consumer/build -S cpp/examples/fetch_content_consumer \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="${{ runner.temp }}/gaia_install" \
-DUSE_FIND_PACKAGE=ON
cmake --build consumer/build --config Release --parallel
# Verify BUILD_SHARED_LIBS=ON (shared library / DLL) compiles cleanly
shared-lib-test:
name: C++ Shared Library (${{ matrix.os }})
runs-on: ${{ matrix.os }}
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Install OpenSSL (Linux)
if: runner.os == 'Linux'
run: sudo apt-get install -y libssl-dev
- name: Install OpenSSL (Windows)
if: runner.os == 'Windows'
run: choco install openssl --no-progress -y
- name: Restore FetchContent cache
uses: actions/cache@v4
with:
path: cpp/build-shared/_deps
key: fetchcontent-shared-${{ matrix.os }}-${{ hashFiles('cpp/CMakeLists.txt') }}
- name: Build shared library
shell: bash
run: |
cmake -B cpp/build-shared -S cpp -DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DGAIA_BUILD_TESTS=OFF -DGAIA_BUILD_EXAMPLES=OFF \
-DGAIA_BUILD_INTEGRATION_TESTS=OFF
cmake --build cpp/build-shared --config Release --parallel
# Integration tests on STX hardware: LLM + MCP + WiFi + Health
integration-test:
name: C++ Integration Tests (STX)
runs-on: ${{ (contains(github.event.pull_request.labels.*.name, 'stx-test') && 'stx-test') || 'stx' }}
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'ready_for_ci')
steps:
- uses: actions/checkout@v6
- name: Setup Python environment
uses: ./.github/actions/setup-venv
with:
python-version: '3.12'
install-package: '.[lemonade]'
- name: Install Lemonade Server
uses: ./.github/actions/install-lemonade
- name: Ensure C++ build tools are available
shell: powershell
run: |
$ErrorActionPreference = "Stop"
$ProgressPreference = 'SilentlyContinue'
$cmakeVer = "3.31.4"
$mgwVer = "2.5.0"
# --- CMake ---
# Check PATH, then previously downloaded location, then VS, then download
$cmakeCached = "$env:TEMP\cmake\cmake-${cmakeVer}-windows-x86_64\bin"
if (Get-Command cmake -ErrorAction SilentlyContinue) {
Write-Host "CMake found in PATH"
} elseif (Test-Path "$cmakeCached\cmake.exe") {
Write-Host "CMake found at cached location"
echo "$cmakeCached" >> $env:GITHUB_PATH
} else {
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vswhere) {
$vsCmake = & $vswhere -latest `
-requires Microsoft.VisualStudio.Component.VC.CMake.Project `
-find "Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin" 2>$null
if ($vsCmake -and (Test-Path "$vsCmake\cmake.exe")) {
Write-Host "Using VS-bundled CMake"
echo "$vsCmake" >> $env:GITHUB_PATH
}
}
}
if (-not (Get-Command cmake -ErrorAction SilentlyContinue) -and
-not (Test-Path "$cmakeCached\cmake.exe")) {
$url = "https://github.com/Kitware/CMake/releases/download/v${cmakeVer}/cmake-${cmakeVer}-windows-x86_64.zip"
Write-Host "Downloading CMake v${cmakeVer}..."
Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\cmake.zip" -UseBasicParsing
Expand-Archive "$env:TEMP\cmake.zip" "$env:TEMP\cmake" -Force
Remove-Item "$env:TEMP\cmake.zip"
echo "$cmakeCached" >> $env:GITHUB_PATH
}
# --- C++ compiler ---
# Check for MSVC, then g++ in PATH, then cached w64devkit, then download
$hasMSVC = $false
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vswhere) {
$vsPath = & $vswhere -latest -property installationPath 2>$null
if ($vsPath) { $hasMSVC = $true; Write-Host "MSVC found" }
}
$mgwCached = "$env:TEMP\w64devkit\bin"
if (-not $hasMSVC) {
if (Get-Command g++ -ErrorAction SilentlyContinue) {
Write-Host "g++ found in PATH"
} elseif (Test-Path "$mgwCached\g++.exe") {
Write-Host "w64devkit found at cached location"
echo "$mgwCached" >> $env:GITHUB_PATH
} else {
$url = "https://github.com/skeeto/w64devkit/releases/download/v${mgwVer}/w64devkit-x64-${mgwVer}.7z.exe"
Write-Host "Downloading w64devkit (MinGW-w64) v${mgwVer}..."
Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\w64devkit.exe" -UseBasicParsing
Write-Host "Extracting w64devkit..."
& "$env:TEMP\w64devkit.exe" -o"$env:TEMP" -y | Out-Null
Remove-Item "$env:TEMP\w64devkit.exe"
echo "$mgwCached" >> $env:GITHUB_PATH
}
}
Write-Host "Build tools ready"
- name: Restore FetchContent cache
uses: actions/cache@v4
with:
path: cpp/build-integration/_deps
key: fetchcontent-integration-windows-${{ hashFiles('cpp/CMakeLists.txt') }}
- name: Configure and build integration tests
shell: powershell
run: |
# Auto-detect generator: MinGW Makefiles when using w64devkit
$gen = @()
if (Get-Command g++ -ErrorAction SilentlyContinue) {
if (-not (Get-Command cl -ErrorAction SilentlyContinue)) {
$gen = @("-G", "MinGW Makefiles")
}
}
cmake -B cpp/build-integration -S cpp @gen `
-DCMAKE_BUILD_TYPE=Release `
-DGAIA_BUILD_INTEGRATION_TESTS=ON `
-DGAIA_BUILD_TESTS=OFF `
-DGAIA_BUILD_EXAMPLES=OFF `
-DGAIA_ENABLE_SSL=OFF
if ($LASTEXITCODE -ne 0) { throw "CMake configure failed" }
cmake --build cpp/build-integration --config Release --parallel
if ($LASTEXITCODE -ne 0) { throw "CMake build failed" }
- name: Verify uvx is available
shell: powershell
run: |
# uvx is provided by uv (installed by setup-venv)
$uvx = Get-Command uvx -ErrorAction SilentlyContinue
if ($uvx) {
Write-Host "[OK] uvx found at: $($uvx.Source)"
} else {
Write-Host "[WARN] uvx not found -- MCP and Health integration tests will fail"
Write-Host " uvx should be available via uv (installed by setup-venv)"
exit 0
}
# Remove any broken persistent installation that may interfere with uvx.
# Swallow all output/errors — the tool may not be installed and that's fine.
# Run via cmd /c so native stderr never reaches PowerShell's error stream
# (PS 5.1 -Command mode generates NativeCommandError from any native stderr).
cmd /c "uv tool uninstall windows-mcp 2>NUL" 2>$null
$global:LASTEXITCODE = 0
Write-Host "[OK] uvx ready (windows-mcp will run via temporary uvx environments)"
- name: Start Lemonade Server and run integration tests
shell: powershell
timeout-minutes: 30
env:
GAIA_CPP_TEST_MODEL: Qwen3-4B-Instruct-2507-GGUF
GAIA_CPP_BASE_URL: http://localhost:13305/api/v1
run: |
try {
# Start Lemonade with Qwen3-4B-GGUF
.\installer\scripts\start-lemonade.ps1 -ModelName "Qwen3-4B-Instruct-2507-GGUF" -Port 13305 -CtxSize 16384 -InitWaitTime 15
# Verify health
$health = Invoke-RestMethod -Uri "http://localhost:13305/api/v1/health" -Method GET -TimeoutSec 10
if ($health.status -ne "ok") { throw "Lemonade health check failed" }
Write-Host "[OK] Lemonade Server ready with Qwen3-4B-Instruct-2507-GGUF"
# Run all C++ integration tests (LLM + MCP + WiFi + Health)
Write-Host "=== Running C++ Integration Tests (LLM + MCP + WiFi + Health) ==="
$env:GAIA_CPP_TEST_MODEL = "Qwen3-4B-Instruct-2507-GGUF"
$env:GAIA_CPP_BASE_URL = "http://localhost:13305/api/v1"
# -j 1: run tests sequentially so they don't compete for the single LLM server
ctest --test-dir cpp/build-integration -C Release --output-on-failure -j 1
if ($LASTEXITCODE -ne 0) { throw "C++ integration tests failed" }
Write-Host "[SUCCESS] All C++ integration tests passed!"
} catch {
Write-Host "[ERROR] $($_.Exception.Message)"
throw
} finally {
if ($env:LEMONADE_PROCESS_ID) {
Write-Host "Stopping Lemonade Server (PID $env:LEMONADE_PROCESS_ID)..."
Stop-Process -Id $env:LEMONADE_PROCESS_ID -Force -ErrorAction SilentlyContinue
}
}
- name: Upload server logs
if: always()
uses: actions/upload-artifact@v6
with:
name: cpp-integration-lemonade-logs
path: |
lemonade-server-stdout.log
lemonade-server-stderr.log
lemonade-server.log
# Performance benchmarks (runs after build passes)
benchmark:
name: C++ Benchmarks
needs: [build-and-test]
if: needs.build-and-test.result == 'success'
uses: ./.github/workflows/benchmark_cpp.yml
# Summary job
cpp-build-summary:
name: C++ Build Summary
runs-on: ubuntu-latest
needs: [build-and-test, install-test, shared-lib-test, integration-test, benchmark]
if: >-
${{ always() && !cancelled() &&
needs.build-and-test.result != 'cancelled' }}
steps:
- name: Check build results
run: |
echo "=== C++ Build & Test Summary ==="
echo "Build & Test: ${{ needs.build-and-test.result }}"
echo "Install Test: ${{ needs.install-test.result }}"
echo "Shared Lib Test: ${{ needs.shared-lib-test.result }}"
echo "Integration Tests: ${{ needs.integration-test.result }}"
echo "Benchmarks: ${{ needs.benchmark.result }}"
echo ""
if [[ "${{ needs.build-and-test.result }}" == "skipped" ]]; then
echo "All C++ jobs skipped (draft PR - add 'ready_for_ci' label to run)"
exit 0
fi
FAILED=0
[[ "${{ needs.build-and-test.result }}" != "success" ]] && FAILED=1
[[ "${{ needs.install-test.result }}" != "success" ]] && FAILED=1
[[ "${{ needs.shared-lib-test.result }}" != "success" ]] && FAILED=1
# Integration test runs on self-hosted STX hardware; treat
# 'skipped' and 'failure' as non-blocking (warn only) since the
# runner may lack tools like cmake in PATH.
if [[ "${{ needs.integration-test.result }}" == "failure" ]]; then
echo "::warning::Integration tests failed (STX runner infrastructure issue)"
fi
# Benchmarks are non-blocking (regression alerts are warnings only)
if [[ "${{ needs.benchmark.result }}" == "failure" ]]; then
echo "::warning::Benchmark regression detected — review cpp-benchmark-* artifacts"
fi
if [[ "$FAILED" == "0" ]]; then
echo "All required C++ jobs passed (unit tests, install round-trip, shared library)!"
else
echo "One or more required C++ jobs failed"
exit 1
fi