feat(skills): gaia skill publish/install with signature-backed security tiers #2376
Workflow file for this run
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 OpenAI-compatible API server functionality | |
| # Tests include: Chat completions, streaming SSE, model listing, error handling | |
| name: API Server Tests | |
| on: | |
| workflow_call: | |
| push: | |
| branches: ["main"] | |
| paths: | |
| - 'src/gaia/version.py' | |
| - '.github/actions/install-lemonade/**' | |
| - 'src/gaia/api/**' | |
| - 'src/gaia/agents/base/**' | |
| - 'src/gaia/llm/**' | |
| - 'hub/agents/routing/python/**' | |
| - 'hub/agents/code/python/**' | |
| - 'tests/test_api.py' | |
| - 'setup.py' | |
| - '.github/workflows/test_api.yml' | |
| pull_request: | |
| branches: ["main"] | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| paths: | |
| - 'src/gaia/version.py' | |
| - '.github/actions/install-lemonade/**' | |
| - 'src/gaia/api/**' | |
| - 'src/gaia/agents/base/**' | |
| - 'src/gaia/llm/**' | |
| - 'hub/agents/routing/python/**' | |
| - 'hub/agents/code/python/**' | |
| - 'tests/test_api.py' | |
| - 'setup.py' | |
| - '.github/workflows/test_api.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-api: | |
| name: API Tests | |
| runs-on: | |
| - self-hosted | |
| - Windows | |
| - ${{ contains(github.event.pull_request.labels.*.name, 'stx-test') && 'stx-test' || 'stx' }} | |
| timeout-minutes: 30 | |
| 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' | |
| install-package: '.[dev,api]' | |
| - name: Install additional test dependencies | |
| shell: powershell | |
| run: | | |
| uv pip install pytest pytest-timeout requests --python .venv\Scripts\python.exe | |
| # The 'gaia-code' API model routes through RoutingAgent, which now | |
| # ships as the standalone gaia-agent-routing wheel (#1102). Install | |
| # both local hub packages (routing first, since gaia-agent-code | |
| # depends on it and it isn't on PyPI) so the gaia-code streaming | |
| # tests exercise the real agent instead of the missing-wheel error. | |
| uv pip install -e hub/agents/routing/python --python .venv\Scripts\python.exe | |
| uv pip install -e hub/agents/code/python --python .venv\Scripts\python.exe | |
| # The email REST router only mounts when gaia-agent-email is | |
| # importable; without it every /v1/email test in tests/test_api.py | |
| # 404s (red on main since the email agent moved to a hub wheel). | |
| uv pip install -e hub/agents/email/python --python .venv\Scripts\python.exe | |
| - name: Install Lemonade Server | |
| uses: ./.github/actions/install-lemonade | |
| - name: Start Lemonade + API server and run API tests | |
| shell: powershell | |
| run: | | |
| # Set console to UTF-8 for Unicode support | |
| [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 | |
| [Console]::InputEncoding = [System.Text.Encoding]::UTF8 | |
| $OutputEncoding = [System.Text.Encoding]::UTF8 | |
| $env:PYTHONIOENCODING = "utf-8" | |
| $env:PYTHONUTF8 = "1" | |
| chcp 65001 | Out-Null | |
| try { | |
| # Start Lemonade via the shared launcher (server + tests run in ONE | |
| # step so the detached server survives for the test run). It launches | |
| # LemonadeServer.exe --port directly (the `lemonade-server serve` | |
| # shim was removed in Lemonade v10.5), captures stdout/stderr to | |
| # logs, waits for health (dumping the logs on failure), and sets | |
| # LEMONADE_PROCESS_ID for cleanup. | |
| .\installer\scripts\start-lemonade.ps1 -Port 13305 -NoModel | |
| if ($LASTEXITCODE -ne 0) { throw "Lemonade server failed to start" } | |
| # Pull + load + verify the LLM via GAIA's LemonadeClient so CI | |
| # validates our interface to Lemonade (incl. the model-load retry), | |
| # not raw REST. | |
| Write-Host "`n=== Pull + load + verify LLM via LemonadeClient ===" | |
| uv run python tests/ci_lemonade_check.py --model Qwen3-0.6B-GGUF --chat | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Host "=== Server stdout (last 100 lines) ===" | |
| Get-Content lemonade-server-stdout.log -Tail 100 -ErrorAction SilentlyContinue | |
| Write-Host "=== Server stderr (last 100 lines) ===" | |
| Get-Content lemonade-server-stderr.log -Tail 100 -ErrorAction SilentlyContinue | |
| throw "LLM setup/verify via LemonadeClient failed" | |
| } | |
| # Start API server using gaia CLI (runs on default port 8080) | |
| Write-Host "`n=== Starting GAIA API Server ===" | |
| $apiJob = Start-Job -ScriptBlock { | |
| Set-Location $using:PWD | |
| & .\.venv\Scripts\Activate.ps1 | |
| $env:AGENT_ROUTING_MODEL = "Qwen3-0.6B-GGUF" | |
| & gaia api start 2>&1 | |
| } | |
| Write-Host "Started API server job with ID: $($apiJob.Id)" | |
| $env:API_JOB_ID = $apiJob.Id | |
| # Wait for API server to start | |
| Write-Host "Waiting for API server to start..." | |
| $maxWaitTime = 30 | |
| $waitTime = 0 | |
| $apiReady = $false | |
| while ($waitTime -lt $maxWaitTime -and -not $apiReady) { | |
| Start-Sleep -Seconds 2 | |
| $waitTime += 2 | |
| try { | |
| $response = Invoke-RestMethod -Uri "http://localhost:8080/health" -Method GET -TimeoutSec 5 | |
| Write-Host "[OK] API server is running and healthy" | |
| $apiReady = $true | |
| } catch { | |
| Write-Host "Waiting for API server... ($waitTime/$maxWaitTime seconds)" | |
| } | |
| } | |
| if (-not $apiReady) { | |
| Write-Host "[ERROR] API server failed to start after $maxWaitTime seconds" | |
| if ($env:API_JOB_ID) { | |
| Write-Host "=== API server job output ===" | |
| Receive-Job -Id $env:API_JOB_ID -ErrorAction SilentlyContinue | |
| } | |
| throw "API server failed to start" | |
| } | |
| # Run tests in same session while servers are running | |
| Write-Host "`n=== Running API Integration Tests ===" | |
| $env:CI = "true" | |
| uv run pytest tests/test_api.py -v --tb=short --capture=no | |
| if ($LASTEXITCODE -ne 0) { throw "Tests failed with exit code $LASTEXITCODE" } | |
| } finally { | |
| # Always cleanup both servers (same-session vars). | |
| Write-Host "`n=== Stopping Servers ===" | |
| if ($env:API_JOB_ID) { | |
| Stop-Job -Id $env:API_JOB_ID -ErrorAction SilentlyContinue | |
| Remove-Job -Id $env:API_JOB_ID -ErrorAction SilentlyContinue | |
| Write-Host "[OK] API server stopped" | |
| } | |
| if ($env:LEMONADE_PROCESS_ID) { | |
| Stop-Process -Id $env:LEMONADE_PROCESS_ID -Force -ErrorAction SilentlyContinue | |
| Write-Host "[OK] Lemonade server stopped (PID $env:LEMONADE_PROCESS_ID)" | |
| } | |
| } | |
| - name: Upload API Server Logs | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: api-server-logs | |
| path: | | |
| gaia.api.log | |
| gaia_api.log | |
| *.log |