Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c1195a1
Add in-process FFI transport for Rust and TypeScript SDKs
SteveSandersonMS Jul 6, 2026
259911f
Remove debug --log-level flag from in-process FFI argv
SteveSandersonMS Jul 6, 2026
c4bba50
TS: align in-process (FFI) transport with .NET behavior
SteveSandersonMS Jul 7, 2026
4d211d9
TS: fix in-process E2E env mirroring (per-test proxy + HMAC)
SteveSandersonMS Jul 7, 2026
6796098
TS: skip in-process-unsupported E2E tests so the inprocess cell is green
SteveSandersonMS Jul 7, 2026
afecf46
Rust: full in-process (FFI) parity with .NET/TS
SteveSandersonMS Jul 7, 2026
e3dcfc0
TS: pump in-process FFI inbound frames promptly (fix macOS RPC hangs)
SteveSandersonMS Jul 7, 2026
02da6b4
Rust CI: include OS (and transport) in job names
SteveSandersonMS Jul 7, 2026
0d9995f
TS: decouple in-process FFI inbound delivery from the native callback
SteveSandersonMS Jul 7, 2026
c64a8aa
Rust CI: run in-process E2E on ubuntu + macOS (exclude windows)
SteveSandersonMS Jul 7, 2026
02e407b
TS: async in-process FFI writes + guard native callbacks
SteveSandersonMS Jul 7, 2026
1553944
TS: defer FFI callback unregister to avoid DEP0168 at teardown
SteveSandersonMS Jul 7, 2026
e72a7d7
TEMP: trace in-process FFI frames to diagnose macOS RPC stalls
SteveSandersonMS Jul 7, 2026
eac8ec7
TS: pump koffi async broker so idle in-process RPC responses arrive
SteveSandersonMS Jul 7, 2026
b950762
TEMP: standalone koffi foreign-thread callback repro + dedicated CI job
SteveSandersonMS Jul 7, 2026
166f211
TEMP: revert to sync FFI writes + add burst repro scenario
SteveSandersonMS Jul 7, 2026
5184218
TEMP: add bidirectional reentrancy scenario to koffi repro
SteveSandersonMS Jul 7, 2026
06048da
TEMP: upgrade koffi 2.16.2 -> 3.1.0 to test macOS in-process delivery
SteveSandersonMS Jul 7, 2026
661a37e
TEMP: replace FFI frame tracing with session-event tracing
SteveSandersonMS Jul 7, 2026
7c75157
TEMP: full sessionId in event trace + sendAndWait receive trace
SteveSandersonMS Jul 7, 2026
4dc4f25
TEMP: run only permissions.e2e over in-process to isolate mac failures
SteveSandersonMS Jul 7, 2026
ebb550c
TEMP: RPC-level tracing + run single permissions RPC test to isolate …
SteveSandersonMS Jul 7, 2026
a71f9c4
Trigger CI
SteveSandersonMS Jul 7, 2026
31acc55
TEMP: full permissions file with event+RPC tracing on mac inproc
SteveSandersonMS Jul 7, 2026
c203b26
TEMP: raise ulimit -n on mac inproc cell to test fd-exhaustion hypoth…
SteveSandersonMS Jul 7, 2026
041ff06
TEMP-test: abort in-flight turn before disconnect in noresult perm te…
SteveSandersonMS Jul 7, 2026
a452096
TEST async writes vs disconnect-while-pending (revert test change to …
SteveSandersonMS Jul 7, 2026
9b2651c
TEMP: callback-liveness tracing (CB-ENTER/EXIT/TICK) + no-result requ…
SteveSandersonMS Jul 7, 2026
2bc7b44
EXPERIMENT: reply approve-once instead of no-result to test orphan-re…
SteveSandersonMS Jul 7, 2026
cd35953
FIX: continuously pump koffi async-callback broker in in-process host
SteveSandersonMS Jul 7, 2026
5f4f75b
EXPERIMENT: run mac inprocess cell on macos-latest-xlarge (6-core vs …
SteveSandersonMS Jul 7, 2026
86ed828
EXPERIMENT: pin Linux inprocess to 1 CPU via taskset to test tokio-wo…
SteveSandersonMS Jul 7, 2026
b5c2943
EXPERIMENT: Linux inprocess on 2 CPUs (taskset -c 0,1) to find worker…
SteveSandersonMS Jul 7, 2026
36719e4
Merge remote-tracking branch 'origin/main' into stevesa/ffi-inproc-ru…
SteveSandersonMS Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions .github/workflows/nodejs-sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,43 @@ permissions:
contents: read

jobs:
# TEMP: standalone koffi foreign-thread callback repro (no SDK/runtime). Fast
# signal on whether koffi delivers a background-thread callback to JS while the
# main loop is idle, across all three OSes. Remove once the in-process hang is fixed.
koffi-callback-repro:
name: "koffi callback repro (${{ matrix.os }})"
if: github.event.repository.fork == false
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
working-directory: ./nodejs
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/setup-node@v6
with:
cache: "npm"
cache-dependency-path: "./nodejs/package-lock.json"
node-version: 22
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Run koffi callback repro
run: npx vitest run test/e2e/_koffi_callback_repro.e2e.test.ts

test:
name: "Node.js SDK Tests"
name: "Node.js SDK Tests (${{ matrix.os }}, ${{ matrix.transport }})"
if: github.event.repository.fork == false
env:
POWERSHELL_UPDATECHECK: Off
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
transport: ["default", "inprocess"]
runs-on: ${{ matrix.os }}
defaults:
run:
Expand Down Expand Up @@ -75,7 +103,36 @@ jobs:
if: runner.os == 'Windows'
run: pwsh.exe -Command "Write-Host 'PowerShell ready'"

- name: Select inprocess transport
if: matrix.transport == 'inprocess'
run: |
echo "COPILOT_SDK_DEFAULT_CONNECTION=inprocess" >> "$GITHUB_ENV"
echo "COPILOT_EVENT_TRACE=1" >> "$GITHUB_ENV"
echo "COPILOT_FFI_TRACE=1" >> "$GITHUB_ENV"
# TEMP experiment: run the FULL permissions file with event+RPC+callback-liveness
# tracing over in-process to determine whether koffi STOPS invoking the inbound
# callback at the wedge (CB-ENTER count stops -> worker/cdylib side) or invokes
# it but stalls inside (CB-ENTER without CB-EXIT -> JS side), while TICKs prove
# the event loop is alive.
echo "TEST_TARGET=test/e2e/permissions.e2e.test.ts" >> "$GITHUB_ENV"
echo 'TEST_NAME_FILTER=' >> "$GITHUB_ENV"

- name: Run Node.js SDK tests
env:
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
run: npm test
run: |
# TEMP experiment: on Linux inprocess, pin the whole process tree to a single
# CPU via taskset so tokio's default worker count (available_parallelism, which
# respects CPU affinity on Linux) is 1. If Linux then reproduces the mac/win
# in-process wedge, the trigger is tokio worker-thread count, not OS/arch.
RUNNER=""
if [ "$RUNNER_OS" = "Linux" ] && [ "$COPILOT_SDK_DEFAULT_CONNECTION" = "inprocess" ]; then
nproc || true
RUNNER="taskset -c 0,1"
echo "Pinning to 2 CPUs via: $RUNNER"
fi
if [ -n "$TEST_NAME_FILTER" ]; then
$RUNNER npx vitest run "$TEST_TARGET" -t "$TEST_NAME_FILTER"
else
$RUNNER npx vitest run $TEST_TARGET
fi
82 changes: 80 additions & 2 deletions .github/workflows/rust-sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

jobs:
test:
name: "Rust SDK Tests"
name: "Rust SDK Tests (${{ matrix.os }}, default)"
if: github.event.repository.fork == false
env:
POWERSHELL_UPDATECHECK: Off
Expand Down Expand Up @@ -129,14 +129,92 @@
# The dedicated `bundle` job below exercises the embed pipeline.
run: cargo test --no-default-features --features test-support -- --test-threads=4 --nocapture

# Exercises the in-process FFI transport (`Transport::InProcess`, the Rust
# analogue of the .NET `RuntimeConnection.ForInProcess()`), mirroring the
# `inprocess` transport cell in dotnet-sdk-tests.yml. Sets
# COPILOT_SDK_DEFAULT_CONNECTION=inprocess so the client hosts the runtime
# cdylib in-process instead of spawning a stdio child, then runs the whole
# E2E suite over the in-process transport. The suite runs serially in-process
# (the harness forces concurrency to 1) because it mirrors each test's
# environment onto the shared process environment the in-process worker inherits.
# Runs the whole E2E suite over the in-process transport on all three OSes,
# matching the Node in-process matrix.
test-inprocess:
name: "Rust SDK Tests (${{ matrix.os }}, inprocess)"
if: github.event.repository.fork == false
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
working-directory: ./rust
steps:
- uses: actions/checkout@v6.0.2

- uses: ./.github/actions/setup-copilot
id: setup-copilot

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow or composite action Medium

Unpinned 3rd party Action 'Rust SDK Tests' step
Uses Step
uses 'dtolnay/rust-toolchain' with ref 'stable', not a pinned commit hash
with:
toolchain: "1.94.0"

- uses: Swatinem/rust-cache@v2

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow or composite action Medium

Unpinned 3rd party Action 'Rust SDK Tests' step
Uses Step
uses 'Swatinem/rust-cache' with ref 'v2', not a pinned commit hash
with:
workspaces: "rust"
prefix-key: v1-rust-no-bin
cache-bin: false

- name: Read pinned @github/copilot CLI version
id: cli-version
working-directory: ./nodejs
run: |
version=$(node -p "require('./package-lock.json').packages['node_modules/@github/copilot'].version")
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Pinned CLI version: $version"

- name: Cache bundled CLI tarball
uses: actions/cache@v4
with:
path: ./rust/.bundled-cli-cache
key: bundled-cli-${{ matrix.os }}-${{ steps.cli-version.outputs.version }}

- name: Install test harness dependencies
working-directory: ./test/harness
run: npm ci --ignore-scripts

- name: Warm up PowerShell
if: runner.os == 'Windows'
run: pwsh.exe -Command "Write-Host 'PowerShell ready'"

- name: Select in-process transport
run: echo "COPILOT_SDK_DEFAULT_CONNECTION=inprocess" >> "$GITHUB_ENV"

- name: cargo test (in-process transport, full E2E suite)
timeout-minutes: 60
env:
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }}
BUNDLED_CLI_CACHE_DIR: ${{ github.workspace }}/rust/.bundled-cli-cache
# The harness forces serial execution in-process (both the async semaphore and
# libtest via --test-threads=1) because it mirrors each test's environment onto
# the shared process environment, so RUST_E2E_CONCURRENCY is not set here.
run: cargo test --no-default-features --features test-support --test e2e -- --test-threads=1 --nocapture

# Validates the bundled-CLI build path on all three supported
# platforms. While the regular `cargo test` job above also exercises
# build.rs (bundling is on by default now), this matrix job is the
# dedicated cross-platform smoke test for the download / verify /
# extract / embed pipeline. Catches regressions before they ship to
# crates.io and before bundling consumers hit them downstream.
bundle:
name: "Rust SDK Bundled CLI Build"
name: "Rust SDK Bundled CLI Build (${{ matrix.os }})"
if: github.event.repository.fork == false
env:
CARGO_TERM_COLOR: always
Expand Down
Loading
Loading