Repository navigation
fix(ui): refuse a tool decision that arrives before its prompt #7069
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. | |
| # SPDX-License-Identifier: MIT | |
| # This workflow tests the GAIA CLI on Windows with full Lemonade server integration | |
| # Tests include: CLI functionality, Lemonade integration, audio features, and core commands | |
| # Platform: Windows (with Lemonade server and NPU support) | |
| name: GAIA CLI Tests (Windows) | |
| on: | |
| push: | |
| branches: ["main"] | |
| paths: | |
| - 'src/gaia/version.py' | |
| - '.github/actions/install-lemonade/**' | |
| - "src/**" | |
| - "tests/**" | |
| - "setup.py" | |
| - "pyproject.toml" | |
| - "installer/scripts/**" | |
| - ".github/workflows/test_gaia_cli_windows.yml" | |
| pull_request: | |
| # No `branches:` filter: it matches the PR base, so `[ main ]` skipped stacked PRs (#2767). | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| paths: | |
| - 'src/gaia/version.py' | |
| - '.github/actions/install-lemonade/**' | |
| - "src/**" | |
| - "tests/**" | |
| - "setup.py" | |
| - "pyproject.toml" | |
| - "installer/scripts/**" | |
| - ".github/workflows/test_gaia_cli_windows.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: | |
| test-gaia-cli-windows: | |
| name: Test GAIA CLI on Windows (Full Integration) | |
| # Runs on the AMD Ryzen DevLab Dispatch ephemeral pool via the devlab-dispatch label. | |
| runs-on: [self-hosted, Windows, devlab-dispatch, strix-halo] | |
| 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@v7 | |
| - name: Setup Python Environment | |
| uses: ./.github/actions/setup-venv | |
| with: | |
| python-version: '3.12' | |
| # Note: 'blender' excluded as bpy requires Blender runtime | |
| install-package: '.[dev,talk,rag,mcp,api]' | |
| - name: Install Lemonade Server | |
| uses: ./.github/actions/install-lemonade | |
| - name: Verify GAIA Installation | |
| run: | | |
| Write-Host "Verifying GAIA installation..." | |
| $gaiaPath = Get-Command gaia -ErrorAction SilentlyContinue | |
| if (-not $gaiaPath) { | |
| Write-Host "Error: gaia not installed correctly" | |
| Write-Host "Current PATH: $env:Path" | |
| exit 1 | |
| } | |
| Write-Host "Found gaia at: $($gaiaPath.Source)" | |
| python --version | |
| python -m pip check | |
| # #2250: the launch-secret DACL cannot be proven off-Windows. The mocked | |
| # layer of test_daemon_secret_acl.py already runs on ubuntu (test_unit.yml), | |
| # but only a real NTFS volume shows whether the ACL is actually applied | |
| # and whether inherited ACEs die. Runs before Lemonade: no server needed. | |
| - name: Run Windows Launch-Secret DACL Tests (CMD) | |
| shell: cmd | |
| env: | |
| PYTHONUTF8: 1 | |
| run: | | |
| REM Activate virtual environment | |
| call "%GITHUB_WORKSPACE%\.venv\Scripts\activate.bat" | |
| echo ================================================================ | |
| echo WINDOWS LAUNCH-SECRET DACL TESTS (issue #2250) | |
| echo ================================================================ | |
| echo Virtual Environment: %VIRTUAL_ENV% | |
| python --version | |
| echo. | |
| REM -rs prints skip reasons: if the win32-gated tests SKIP here, the | |
| REM platform guard is misfiring and the real coverage is silently | |
| REM absent -- that must be visible in the log, not swallowed. | |
| python -m pytest tests\unit\test_daemon_secret_acl.py -v -rs --tb=short | |
| set dacl_exit=%ERRORLEVEL% | |
| echo. | |
| echo ---------------------------------------------------------------- | |
| echo test_daemon_secret_acl.py exit code: %dacl_exit% | |
| if %dacl_exit% equ 0 ( | |
| echo [SUCCESS] Launch-secret DACL tests passed | |
| ) else ( | |
| echo [FAILURE] Launch-secret DACL tests failed | |
| echo The sidecar launch secret may be readable by other local | |
| echo accounts on NTFS - see issue #2250. | |
| ) | |
| echo ---------------------------------------------------------------- | |
| exit /b %dacl_exit% | |
| - name: Run Windows Schedule-Lock Tests (CMD) | |
| shell: cmd | |
| env: | |
| PYTHONUTF8: 1 | |
| run: | | |
| REM Activate virtual environment | |
| call "%GITHUB_WORKSPACE%\.venv\Scripts\activate.bat" | |
| echo ================================================================ | |
| echo WINDOWS SCHEDULE-LOCK TESTS (issue #4208) | |
| echo ================================================================ | |
| REM The single-daemon guard takes msvcrt.locking here and fcntl.flock | |
| REM everywhere else, and tests/unit/ runs on ubuntu-latest only -- so | |
| REM without this step the branch most GAIA users hit is never run. | |
| REM -rs prints skip reasons: if the win32-gated tests SKIP here, the | |
| REM platform guard is misfiring and the real coverage is silently | |
| REM absent -- that must be visible in the log, not swallowed. | |
| python -m pytest tests\unit\test_schedule_lock.py -v -rs --tb=short | |
| set lock_exit=%ERRORLEVEL% | |
| echo. | |
| echo ---------------------------------------------------------------- | |
| echo test_schedule_lock.py exit code: %lock_exit% | |
| if %lock_exit% equ 0 ( | |
| echo [SUCCESS] Schedule-lock tests passed | |
| ) else ( | |
| echo [FAILURE] Schedule-lock tests failed | |
| echo Two `gaia schedule daemon` processes may both start on | |
| echo Windows and fire every schedule twice - see issue #4208. | |
| ) | |
| echo ---------------------------------------------------------------- | |
| exit /b %lock_exit% | |
| # Pin the version: the default `release` resolves through gyan.dev, so that | |
| # host 503ing fails the job outright (2026-08-05, "Cannot get latest release"). | |
| # An explicit version resolves from the GyanD/codexffmpeg GitHub releases API. | |
| - uses: FedericoCarboni/setup-ffmpeg@v3 | |
| id: setup-ffmpeg | |
| with: | |
| ffmpeg-version: '8.1.2' | |
| - name: Start Lemonade Server and Run Tests | |
| timeout-minutes: 20 | |
| env: | |
| HUGGINGFACE_ACCESS_TOKEN: ${{ secrets.HUGGINGFACE_ACCESS_TOKEN }} | |
| HF_TOKEN: ${{ secrets.HUGGINGFACE_ACCESS_TOKEN }} | |
| PYTHONUTF8: 1 | |
| run: | | |
| Write-Host "Verify Python environment" | |
| python -c "import sys; print(sys.executable)" | |
| Write-Host "Find gaia executable location" | |
| $gaiaPath = Get-Command gaia -ErrorAction SilentlyContinue | |
| if (-not $gaiaPath) { | |
| Write-Host "Error: Cannot find gaia executable in PATH" | |
| Write-Host "Current PATH: $env:Path" | |
| exit 1 | |
| } | |
| Write-Host "Found gaia at: $($gaiaPath.Source)" | |
| # Ensure a healthy, Gemma-warmed Lemonade server is up on 13305. The | |
| # helper launches the version-matched server as a persistent Scheduled | |
| # Task (survives across CI jobs since GitHub Actions kills job-spawned | |
| # processes), reuses it if already healthy, and warms Gemma-4. | |
| powershell -ExecutionPolicy Bypass -File installer\scripts\ensure-lemonade-running.ps1 -WarmModel "Gemma-4-E4B-it-GGUF" | |
| if ($LASTEXITCODE -ne 0) { throw "Lemonade server not ready" } | |
| - name: Run Unit Tests (Direct CMD - Full Error Visibility) | |
| shell: cmd | |
| env: | |
| PYTHONUTF8: 1 | |
| run: | | |
| REM Activate virtual environment | |
| call "%GITHUB_WORKSPACE%\.venv\Scripts\activate.bat" | |
| echo ================================================================ | |
| echo GAIA UNIT TESTS - FULL ERROR LOGGING | |
| echo ================================================================ | |
| echo Virtual Environment: %VIRTUAL_ENV% | |
| echo Python Version: | |
| python --version | |
| echo Working Directory: %CD% | |
| echo. | |
| REM Initialize test tracking | |
| set test_llm_exit=0 | |
| set test_asr_exit=0 | |
| set test_tts_exit=0 | |
| REM ================================================================ | |
| REM TEST_LLM.PY | |
| REM ================================================================ | |
| echo **************************************************************** | |
| echo TEST_LLM.PY | |
| echo **************************************************************** | |
| echo Starting test_llm.py at %TIME%... | |
| echo. | |
| python tests\unit\test_llm.py | |
| set test_llm_exit=%ERRORLEVEL% | |
| echo. | |
| echo ---------------------------------------------------------------- | |
| echo test_llm.py completed at %TIME% with exit code: %test_llm_exit% | |
| if %test_llm_exit% equ 0 ( | |
| echo [SUCCESS] test_llm.py passed | |
| ) else ( | |
| echo [FAILURE] test_llm.py failed with exit code %test_llm_exit% | |
| echo Full error output displayed above - no truncation | |
| ) | |
| echo ---------------------------------------------------------------- | |
| echo. | |
| REM ================================================================ | |
| REM TEST_ASR.PY | |
| REM ================================================================ | |
| echo **************************************************************** | |
| echo TEST_ASR.PY | |
| echo **************************************************************** | |
| echo Starting test_asr.py at %TIME%... | |
| echo. | |
| python tests\unit\test_asr.py | |
| set test_asr_exit=%ERRORLEVEL% | |
| echo. | |
| echo ---------------------------------------------------------------- | |
| echo test_asr.py completed at %TIME% with exit code: %test_asr_exit% | |
| if %test_asr_exit% equ 0 ( | |
| echo [SUCCESS] test_asr.py passed | |
| ) else ( | |
| echo [FAILURE] test_asr.py failed with exit code %test_asr_exit% | |
| echo Full error output displayed above - no truncation | |
| ) | |
| echo ---------------------------------------------------------------- | |
| echo. | |
| REM ================================================================ | |
| REM TEST_LEMONADE_SPEECH.PY | |
| REM ================================================================ | |
| echo **************************************************************** | |
| echo TEST_LEMONADE_SPEECH.PY | |
| echo **************************************************************** | |
| echo Starting test_lemonade_speech.py at %TIME%... | |
| echo. | |
| python -m pytest tests\unit\test_lemonade_speech.py -v | |
| set test_tts_exit=%ERRORLEVEL% | |
| echo. | |
| echo ---------------------------------------------------------------- | |
| echo test_lemonade_speech.py completed at %TIME% with exit code: %test_tts_exit% | |
| if %test_tts_exit% equ 0 ( | |
| echo [SUCCESS] test_lemonade_speech.py passed | |
| ) else ( | |
| echo [FAILURE] test_lemonade_speech.py failed with exit code %test_tts_exit% | |
| echo Full error output displayed above - no truncation | |
| ) | |
| echo ---------------------------------------------------------------- | |
| echo. | |
| REM ================================================================ | |
| REM FINAL SUMMARY | |
| REM ================================================================ | |
| echo ================================================================ | |
| echo FINAL TEST SUMMARY | |
| echo ================================================================ | |
| echo test_llm.py: exit code %test_llm_exit% | |
| echo test_asr.py: exit code %test_asr_exit% | |
| echo test_lemonade_speech.py: exit code %test_tts_exit% | |
| echo ================================================================ | |
| REM Calculate total failures | |
| set /a total_failures=%test_llm_exit%+%test_asr_exit%+%test_tts_exit% | |
| if %total_failures% equ 0 ( | |
| echo [OVERALL SUCCESS] All tests passed successfully | |
| echo ================================================================ | |
| exit /b 0 | |
| ) else ( | |
| echo [OVERALL FAILURE] One or more tests failed | |
| echo ================================================================ | |
| echo FAILED TESTS: | |
| if %test_llm_exit% neq 0 echo - test_llm.py ^(exit code %test_llm_exit%^) | |
| if %test_asr_exit% neq 0 echo - test_asr.py ^(exit code %test_asr_exit%^) | |
| if %test_tts_exit% neq 0 echo - test_lemonade_speech.py ^(exit code %test_tts_exit%^) | |
| echo ================================================================ | |
| echo IMPORTANT: All error messages are displayed in full above | |
| echo No PowerShell wrapping or truncation - raw Python output preserved | |
| echo ================================================================ | |
| exit /b 1 | |
| ) | |
| - name: Run Lemonade Client Integration Tests (CMD) | |
| shell: cmd | |
| env: | |
| PYTHONUTF8: 1 | |
| GAIA_TEST_MODEL: Gemma-4-E4B-it-GGUF | |
| run: | | |
| REM Activate virtual environment | |
| call "%GITHUB_WORKSPACE%\.venv\Scripts\activate.bat" | |
| echo ================================================================ | |
| echo LEMONADE CLIENT INTEGRATION TESTS | |
| echo ================================================================ | |
| echo Virtual Environment: %VIRTUAL_ENV% | |
| echo Python Version: | |
| python --version | |
| echo Test Model: %GAIA_TEST_MODEL% | |
| echo Working Directory: %CD% | |
| echo. | |
| REM Initialize test tracking | |
| set lemonade_exit=0 | |
| REM ================================================================ | |
| REM TEST_LEMONADE_CLIENT.PY - INTEGRATION TESTS ONLY | |
| REM ================================================================ | |
| echo **************************************************************** | |
| echo LEMONADE CLIENT INTEGRATION TESTS | |
| echo **************************************************************** | |
| echo Starting test_lemonade_client.py integration tests at %TIME%... | |
| echo. | |
| REM Run only integration tests (skip mock tests which don't need server) | |
| python -m pytest tests\test_lemonade_client.py -vs --tb=short -k "Integration" | |
| set lemonade_exit=%ERRORLEVEL% | |
| echo. | |
| echo ---------------------------------------------------------------- | |
| echo test_lemonade_client.py completed at %TIME% with exit code: %lemonade_exit% | |
| if %lemonade_exit% equ 0 ( | |
| echo [SUCCESS] Lemonade client integration tests passed | |
| ) else ( | |
| echo [FAILURE] Lemonade client integration tests failed with exit code %lemonade_exit% | |
| echo Full error output displayed above - no truncation | |
| ) | |
| echo ---------------------------------------------------------------- | |
| echo. | |
| REM ================================================================ | |
| REM LEMONADE CLIENT TEST SUMMARY | |
| REM ================================================================ | |
| echo ================================================================ | |
| echo LEMONADE CLIENT TEST SUMMARY | |
| echo ================================================================ | |
| echo test_lemonade_client.py: exit code %lemonade_exit% | |
| echo ================================================================ | |
| if %lemonade_exit% neq 0 ( | |
| echo [FAILURE] Lemonade client integration tests failed | |
| echo ================================================================ | |
| echo FAILED TEST: | |
| echo - test_lemonade_client.py ^(exit code %lemonade_exit%^) | |
| echo ================================================================ | |
| echo IMPORTANT: All error messages are displayed in full above | |
| echo No PowerShell wrapping or truncation - raw Python output preserved | |
| echo ================================================================ | |
| exit /b 1 | |
| ) else ( | |
| echo [SUCCESS] Lemonade client integration tests passed successfully | |
| echo ================================================================ | |
| ) | |
| - name: Debug GAIA Logs on Failure | |
| if: failure() | |
| shell: cmd | |
| run: | | |
| echo === Debugging GAIA failure === | |
| echo === Check for GAIA log files === | |
| if exist "gaia.cli.log" ( | |
| echo Found gaia.cli.log: | |
| type gaia.cli.log | |
| ) else ( | |
| echo No gaia.cli.log found | |
| ) | |
| echo === Check running processes === | |
| tasklist | findstr /i "python gaia lemonade-server" | |
| echo === Check ports in use === | |
| netstat -an | findstr ":8000 :8001" |