name: wai-quantum views in agent hosts # The engine's answers drawn as interactive views inside an agent host, through # the Model Context Protocol's extension for them (wai/wai-quantum/src/engine/views.rs, # the page in wai/wai-quantum/views/, the engine inside it in wai/wai-quantum-views/, # the views themselves in wai/quantum-studio/src/views/): # - the committed page is built from its sources as they are (build-views.mjs # --check), and rebuilt here: its script and styles to the same bytes. The # engine inside it is compiled from wai-quantum, and LLVM lays the same code # out differently once anything else in that crate changes, so its bytes are # compared and a difference is a warning to rebuild, not a failure: the # scripted host below holds the committed page's engine to the receipts the # current servers seal; # - the engine inside the views checks a receipt as the engine does, and # engine::views gives the resources, the tool map, each view's data and its # answer in plain words, every view within the size limit; # - a scripted host draws every view from both MCP servers in a headless # browser (test/views.test.mjs): under the extension's default # content-security policy, which refuses WebAssembly, the receipt is checked # in the view by the engine translated to JavaScript, and with WebAssembly # allowed, by the WebAssembly; a changed result fails the check; the view's # own tool for a running job is kept from the model; no view makes a request. concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: push: branches: [main] paths: - 'wai/wai-quantum-views/**' - 'wai/wai-quantum/**' - 'wai/wai-quantum-cli/**' - 'wai/wai-quantum-service/**' - 'wai/wai-quantum-qpu/**' - 'wai/quantum-studio/**' - 'rust-toolchain.toml' - '.github/workflows/wai-quantum-views.yml' pull_request: paths: - 'wai/wai-quantum-views/**' - 'wai/wai-quantum/**' - 'wai/wai-quantum-cli/**' - 'wai/wai-quantum-service/**' - 'wai/wai-quantum-qpu/**' - 'wai/quantum-studio/**' - 'rust-toolchain.toml' - '.github/workflows/wai-quantum-views.yml' jobs: relevant: name: does this change touch it runs-on: gate outputs: run: ${{ steps.gate.outputs.run }} steps: - uses: actions/checkout@v5 with: fetch-depth: 0 - id: gate run: | set -euo pipefail r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-quantum-views.yml \ "${{ github.event.pull_request.base.sha }}" \ "${{ github.event.pull_request.head.sha }}") echo "this change touches the views: $r" echo "run=$r" >> "$GITHUB_OUTPUT" page: name: views · the page and its engine needs: relevant if: needs.relevant.outputs.run == 'true' runs-on: linux timeout-minutes: 60 steps: - uses: actions/checkout@v5 - name: Install Rust 1.99.1 with the wasm32 target shell: bash run: | export PATH="$HOME/.cargo/bin:$PATH" command -v rustup >/dev/null 2>&1 || \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 rustup toolchain install 1.99.1 --profile minimal rustup default 1.99.1 rustup target add wasm32-unknown-unknown echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - uses: actions/setup-node@v4 with: node-version: '22' - name: The committed page is built from these sources shell: bash working-directory: wai/quantum-studio run: | set -euo pipefail npm ci --no-audit --no-fund node build-views.mjs --check - name: The engine inside the views, and engine::views shell: bash run: | set -euo pipefail (cd wai/wai-quantum-views && cargo test --locked --release 2>&1 | tee "$RUNNER_TEMP/views.log") grep -qE '^test result: ok\. 3 passed; 0 failed' "$RUNNER_TEMP/views.log" || { echo "::error::the views' engine tests did not all run and pass"; exit 1; } (cd wai/wai-quantum && cargo test --locked --release --features full --lib engine::views:: 2>&1 | tee "$RUNNER_TEMP/engine.log") grep -qE '^test result: ok\. 4 passed; 0 failed' "$RUNNER_TEMP/engine.log" || { echo "::error::engine::views' tests did not all run and pass"; exit 1; } - name: Rebuilt here, its script and styles to the same bytes shell: bash run: | set -euo pipefail bash wai/wai-quantum-views/build.sh "$RUNNER_TEMP/views" python3 - "$RUNNER_TEMP/views/manifest.json" wai/wai-quantum/views/manifest.json <<'EOF' import json, sys new, old = (json.load(open(p)) for p in sys.argv[1:]) bad = [k for k in ("script", "styles") if new["sha256"][k] != old["sha256"][k]] if bad: print(f"::error::the committed views page's {', '.join(bad)} are not what their sources build: run bash wai/wai-quantum-views/build.sh and commit what it writes") sys.exit(1) for k in ("engine_wasm", "engine_js"): if new["sha256"][k] != old["sha256"][k]: print(f"::warning::the engine inside the views ({k}) compiles to other bytes than the committed page holds: wai-quantum changed since it was built; rebuild it with bash wai/wai-quantum-views/build.sh") print("the page's script and styles are what their sources build") EOF hosts: name: views · a scripted host needs: relevant if: needs.relevant.outputs.run == 'true' runs-on: linux timeout-minutes: 75 steps: - uses: actions/checkout@v5 - name: Install Rust 1.99.1 shell: bash run: | export PATH="$HOME/.cargo/bin:$PATH" command -v rustup >/dev/null 2>&1 || \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 rustup toolchain install 1.99.1 --profile minimal rustup default 1.99.1 echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - uses: actions/setup-node@v4 with: node-version: '22' - name: Both servers shell: bash run: | set -euo pipefail (cd wai/wai-quantum-cli && cargo build --locked --release) (cd wai/wai-quantum-service && cargo build --locked --release) - name: Every view drawn by a scripted host in a browser shell: bash working-directory: wai/quantum-studio env: WAI_E2E_CHANNEL: '' run: | set -euo pipefail npm ci --no-audit --no-fund npx playwright install --with-deps chromium WQ_CLI="$GITHUB_WORKSPACE/wai/wai-quantum-cli/target/release/wai-quantum" \ WQ_SERVICE="$GITHUB_WORKSPACE/wai/wai-quantum-service/target/release/wai-quantum-service" \ node test/views.test.mjs 2>&1 | tee "$RUNNER_TEMP/views.log" grep -q '^every check passed$' "$RUNNER_TEMP/views.log" || { echo "::error::the scripted host's checks did not all pass"; exit 1; }