Skip to content

Harden tool scheduling and subagent streaming #568

Harden tool scheduling and subagent streaming

Harden tool scheduling and subagent streaming #568

Workflow file for this run

name: ci
# Two gates:
# 1. build-test (linux gcc) — the primary gate matching the LOCAL
# toolchain (GCC, Release): does it compile with the same compiler
# used locally, and do the smoke tests pass. Fast + deterministic.
# 2. windows-compile (msvc) — a COMPILE-ONLY gate that mirrors the
# release workflow's Windows configure (vcpkg static + MSVC) but
# stops at the build; no MSI, no signing, no upload. It exists
# because MSVC-only breakage (POSIX-only headers like <unistd.h> /
# <ext/stdio_filebuf.h> compiled into mcp-cpp's tests/examples, which
# agentty's standalone build pulls in) is invisible to the Linux gate
# and used to surface only at release time (C1083). Catch it per-push.
#
# NOTE: if GitHub still shows phantom failing checks named linux-clang19,
# sanitizers (...), macos-gcc, or "fuzz harness smoke", those are REQUIRED
# STATUS CHECKS configured by NAME in the repo's branch-protection rules
# (Settings → Branches → master). No workflow in this repo produces them,
# so they hang forever. Remove those names from the required-checks list
# there — this workflow only emits the two jobs below (the windows check is
# named "windows compile (msvc)", so a required "windows-msvc" name still
# won't match; use the exact job name or drop it).
on:
push:
branches: [master]
pull_request:
branches: [master]
# Cancel an in-flight run when newer commits land on the same ref.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build-test:
name: build + test (linux gcc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Init submodules (HTTPS, race-tolerant)
# Submodule pushes can lag GitHub replica propagation, so a fresh
# `submodule update` may hit "not our ref / Fetched ... but it did
# not contain <sha>". Retry a few times with a full (unshallow)
# fetch before giving up.
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3 4 5; do
if git submodule update --init --recursive --force; then
echo "submodules ready (attempt $attempt)"
break
fi
echo "submodule update failed (attempt $attempt) — full-fetching and retrying"
git submodule sync --recursive
git submodule foreach --recursive 'git fetch --prune origin || true'
sleep $((attempt * 10))
done
git submodule update --init --recursive --force
- name: Install deps
# GCC 14 for C++26 (std::expected / std::format). Mirrors the local
# GCC toolchain; ubuntu-latest's default g++ can lag. Shared libs are
# fine — this isn't a distributable build.
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
g++-14 cmake ninja-build pkg-config \
libssl-dev libnghttp2-dev zlib1g-dev
- name: Configure
env:
CC: gcc-14
CXX: g++-14
run: |
cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=Release \
-DAGENTTY_AUTO_PULL_MAYA=OFF \
-DAGENTTY_USE_MIMALLOC=OFF \
-DAGENTTY_BUILD_TESTS=ON
- name: Build
run: cmake --build build -j"$(nproc)" --target all tests
- name: Test
run: ctest --test-dir build --output-on-failure
# Rust-grade memory-safety gate. Builds agentty's OWN-logic test set under
# -fsanitize=address,undefined and runs it: proves those paths are free of
# use-after-free / buffer overflow / leaks / UB at RUNTIME, complementing the
# compile-time static_assert proofs. Scoped to the `sanitizer`-labelled
# tests (crypto/creds, FSM, tool-arg repair, skills, fuzzy match, and the
# concurrency primitives) because they don't link maya's prebuilt,
# un-instrumented renderer (which would ODR-clash). LTO is off for speed +
# readable traces; the constexpr catalog proofs auto-skip under
# AGENTTY_SANITIZER_BUILD (they already ran green in the build-test job).
sanitizers:
name: sanitizers (asan+ubsan)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Init submodules (HTTPS, race-tolerant)
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3 4 5; do
if git submodule update --init --recursive --force; then
echo "submodules ready (attempt $attempt)"
break
fi
echo "submodule update failed (attempt $attempt) — full-fetching and retrying"
git submodule sync --recursive
git submodule foreach --recursive 'git fetch --prune origin || true'
sleep $((attempt * 10))
done
git submodule update --init --recursive --force
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
g++-14 cmake ninja-build pkg-config \
libssl-dev libnghttp2-dev zlib1g-dev
- name: Configure (ASan + UBSan)
env:
CC: gcc-14
CXX: g++-14
run: |
cmake -S . -B build-san -GNinja -DCMAKE_BUILD_TYPE=Debug \
-DAGENTTY_AUTO_PULL_MAYA=OFF \
-DAGENTTY_USE_MIMALLOC=OFF \
-DAGENTTY_BUILD_TESTS=ON \
-DAGENTTY_SANITIZE_ALL=address,undefined
- name: Build sanitizer test set
run: cmake --build build-san -j"$(nproc)" --target sanitizer_tests
- name: Run under ASan + UBSan
env:
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: ctest --test-dir build-san -L sanitizer --output-on-failure
# Compile-only Windows gate. Mirrors release.yml's build-windows configure
# (vcpkg static openssl+nghttp2, MSVC, Release) but stops at the build:
# no MSI, no signing, no upload. Purpose is narrow but important — prove
# the tree still COMPILES under MSVC so a POSIX-only header or API sneaking
# into a TU that Windows builds (notably mcp-cpp's tests/examples, which
# agentty's standalone build pulls in) is caught here on every push instead
# of blowing up the Windows release leg with C1083 ~19 min into a release.
windows-compile:
name: windows compile (msvc)
runs-on: windows-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Init submodules (HTTPS, race-tolerant)
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3 4 5; do
if git submodule update --init --recursive --force; then break; fi
echo "submodule update failed (attempt $attempt) — full-fetching and retrying"
git submodule sync --recursive
git submodule foreach --recursive 'git fetch --prune origin || true'
sleep $((attempt * 10))
done
git submodule update --init --recursive --force
- name: Install deps (vcpkg static)
shell: pwsh
run: |
git -C "$env:VCPKG_INSTALLATION_ROOT" fetch --depth 1 origin master
git -C "$env:VCPKG_INSTALLATION_ROOT" reset --hard FETCH_HEAD
& "$env:VCPKG_INSTALLATION_ROOT\bootstrap-vcpkg.bat"
& "$env:VCPKG_INSTALLATION_ROOT\vcpkg.exe" install openssl nghttp2 --triplet x64-windows-static
- name: Configure + build (compile only)
shell: pwsh
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release `
-DAGENTTY_STANDALONE=ON -DAGENTTY_AUTO_PULL_MAYA=OFF `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
-DVCPKG_TARGET_TRIPLET=x64-windows-static
cmake --build build --config Release -j
# MinGW / MSYS2 ucrt64 gate. This is the toolchain real Windows users build
# under, and CRUCIALLY it is the ONLY Windows path that actually COMPILES the
# rag-cpp retrieval engine and the acp-cpp FdTransport (both are gated OFF on
# MSVC). A POSIX-ism leaking into those — e.g. rag-cpp's store fsync/kill, or
# acp-cpp's stdio writev — is invisible to the MSVC gate above and only shows
# up here. Compile-only; the CPU retrieval path is exercised, no GPU backend.
windows-mingw:
name: windows compile (msys2 ucrt64)
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Init submodules (HTTPS, race-tolerant)
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3 4 5; do
if git submodule update --init --recursive --force; then break; fi
git submodule sync --recursive
git submodule foreach --recursive 'git fetch --prune origin || true'
sleep $((attempt * 10))
done
git submodule update --init --recursive --force
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-ninja
mingw-w64-ucrt-x86_64-openssl
mingw-w64-ucrt-x86_64-nghttp2
git
- name: Configure + build (compile only)
run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DAGENTTY_STANDALONE=ON -DAGENTTY_AUTO_PULL_MAYA=OFF
cmake --build build -j
# Runtime smoke test. Compile-only cannot catch MSYS2/mintty's runtime
# path: mintty gives a native executable PIPE-backed stdio handles, not
# Win32 console handles. Exercise that exact HANDLE type with cmd.exe's
# `type NUL | agentty.exe`: unlike MSYS bash's /dev/null (a NUL character
# device, NOT a pipe) and its unreliable PE exit-status bookkeeping, cmd
# creates an anonymous pipe and reports the native process exit code.
- name: Runtime smoke test (native pipe, mintty-like)
timeout-minutes: 2
shell: pwsh
env:
# setup-msys2 installs the UCRT runtime below RUNNER_TEMP. A pwsh
# step needs it explicitly for libstdc++/libgcc/nghttp2 DLL lookup.
UCRT64_BIN: ${{ runner.temp }}\msys64\ucrt64\bin
run: |
$ErrorActionPreference = 'Stop'
$env:Path = "$env:UCRT64_BIN;$env:Path"
$env:COLUMNS = '80'
$env:LINES = '24'
$bin = (Resolve-Path 'build/agentty.exe').Path
Write-Host "binary: $bin"
& $bin --version
if ($LASTEXITCODE -ne 0) {
throw "--version failed with exit $LASTEXITCODE"
}
# `type NUL` writes zero bytes then closes its pipe end. agentty must
# select its pipe-terminal implementation, observe EOF/hangup, and
# exit normally — no hidden console, MSYS shell shim, or NUL device.
$cmd = 'type NUL | "' + $bin + '"'
& cmd.exe /d /s /c $cmd 1>smoke.out 2>smoke.err
$rc = $LASTEXITCODE
Write-Host "exit=$rc"
Write-Host '----- stdout (head) -----'
if (Test-Path smoke.out) { Get-Content smoke.out -TotalCount 50 }
Write-Host '----- stderr -----'
if (Test-Path smoke.err) { Get-Content smoke.err }
if ($rc -ne 0) {
Write-Error "agentty exited non-zero ($rc) on a native pipe stdin"
exit 1
}
Write-Host 'smoke test passed: launched and exited cleanly under a native pipe'