Skip to content

feat(cpp): gaia-bash — native C++ bash coding agent with TUI, API server, MCP server #1580

feat(cpp): gaia-bash — native C++ bash coding agent with TUI, API server, MCP server

feat(cpp): gaia-bash — native C++ bash coding agent with TUI, API server, MCP server #1580

Workflow file for this run

# 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/api/**'
- 'src/gaia/agents/base/**'
- 'src/gaia/llm/**'
- '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/api/**'
- 'src/gaia/agents/base/**'
- 'src/gaia/llm/**'
- '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: ${{ 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@v6
- 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
- name: Install Lemonade Server
uses: ./.github/actions/install-lemonade
- name: Start Lemonade Server and Run 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 {
Write-Host "Starting Lemonade server..."
$serverJob = Start-Job -ScriptBlock {
# Workaround for Issue #612: Disable Vulkan cooperative matrix optimization
$env:GGML_VK_DISABLE_COOPMAT = "1"
& lemonade-server serve --ctx-size 8192 --host localhost --port 13305 --no-tray 2>&1
}
Write-Host "Started Lemonade server job with ID: $($serverJob.Id)"
$env:LEMONADE_JOB_ID = $serverJob.Id
# Wait for server to be ready
Write-Host "Waiting for Lemonade server to start..."
$maxWaitTime = 60
$waitTime = 0
$serverReady = $false
while ($waitTime -lt $maxWaitTime -and -not $serverReady) {
Start-Sleep -Seconds 2
$waitTime += 2
try {
$response = Invoke-RestMethod -Uri "http://localhost:13305/api/v1/health" -Method GET -TimeoutSec 5
Write-Host "[OK] Lemonade server is ready"
Write-Host "Health response: $($response | ConvertTo-Json -Compress)"
$serverReady = $true
} catch {
Write-Host "Waiting... ($waitTime/$maxWaitTime seconds)"
}
}
if (-not $serverReady) {
Write-Host "[ERROR] Server health check failed after $maxWaitTime seconds"
throw "Server failed to start"
}
# Pull required model for API tests
Write-Host "`n=== Pulling Required Models ==="
Write-Host "Pulling Qwen3-0.6B-GGUF..."
try {
$body = @{ model_name = "Qwen3-0.6B-GGUF" } | ConvertTo-Json
$response = Invoke-RestMethod -Uri "http://localhost:13305/api/v1/pull" `
-Method POST -ContentType "application/json" -Body $body -TimeoutSec 600
Write-Host " [OK] Qwen3-0.6B-GGUF pull initiated"
} catch {
Write-Host " [WARN] Pull may have failed: $($_.Exception.Message)"
}
# Wait for model to be available
Write-Host "Waiting 5 seconds for model files to sync..."
Start-Sleep -Seconds 5
# Load the model into Lemonade (required for inference)
Write-Host "`n=== Loading LLM Model ==="
try {
$loadRequest = @{ model_name = "Qwen3-0.6B-GGUF" } | ConvertTo-Json
Write-Host "Loading model: Qwen3-0.6B-GGUF"
$loadResponse = Invoke-RestMethod -Uri "http://localhost:13305/api/v1/load" `
-Method POST -Body $loadRequest -ContentType "application/json" -TimeoutSec 120
Write-Host "[OK] Model loaded successfully: $($loadResponse | ConvertTo-Json -Compress)"
} catch {
Write-Host "[ERROR] Model load failed: $($_.Exception.Message)"
if ($_.ErrorDetails) {
Write-Host "Error details: $($_.ErrorDetails.Message)"
}
}
# Wait for llamacpp backend initialization
Write-Host "Waiting 10 seconds for llamacpp backend initialization..."
Start-Sleep -Seconds 10
# Verify models
try {
$models = Invoke-RestMethod -Uri "http://localhost:13305/api/v1/models" -Method GET
Write-Host "`n[OK] Available models:"
$models.data | ForEach-Object { Write-Host " - $($_.id)" }
} catch {
Write-Host "[WARN] Could not list models: $($_.Exception.Message)"
}
# 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"
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
$testExitCode = $LASTEXITCODE
Write-Host "`nTests completed with exit code: $testExitCode"
if ($testExitCode -ne 0) {
throw "Tests failed with exit code $testExitCode"
}
} finally {
# Always cleanup servers
Write-Host "`n=== Stopping Servers ==="
if ($env:API_JOB_ID) {
Write-Host "Stopping API server..."
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_JOB_ID) {
Write-Host "Stopping Lemonade server..."
Stop-Job -Id $env:LEMONADE_JOB_ID -ErrorAction SilentlyContinue
Remove-Job -Id $env:LEMONADE_JOB_ID -ErrorAction SilentlyContinue
Write-Host "[OK] Lemonade server stopped"
}
}
- name: Upload API Server Logs
if: failure()
uses: actions/upload-artifact@v6
with:
name: api-server-logs
path: |
gaia.api.log
gaia_api.log
*.log