Skip to content

feat(zai): add Web Search in Chat integration for Z.AI provider #6

feat(zai): add Web Search in Chat integration for Z.AI provider

feat(zai): add Web Search in Chat integration for Z.AI provider #6

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
inputs:
skip_npm:
description: "Skip npm publish"
type: boolean
default: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# scripts/release.ts pushes the version-bump commit and its `v*` tag
# atomically (`git push --atomic origin main refs/tags/v*`), so a release
# now arrives as a single `push` to `refs/heads/main` — we no longer trigger
# on the tag ref at all (see `on.push`). This one branch-push run is therefore
# authoritative: it runs the full build AND, when HEAD carries a release tag,
# the release/publish jobs. `gate` resolves that tag once so downstream jobs
# switch on `is-release` and address the tag by name — `github.ref` is
# `refs/heads/main` here, not the tag. A `workflow_dispatch` from a `v*` tag
# ref is also treated as a release (the manual re-publish escape hatch).
gate:
runs-on: ubuntu-22.04
outputs:
is-release: ${{ steps.check.outputs.is-release }}
release-tag: ${{ steps.check.outputs.release-tag }}
steps:
# Only a main-branch push needs tags fetched, so `git tag --points-at
# HEAD` can see the freshly-pushed `v*`. A tag-ref dispatch reads the
# tag straight from `github.ref_name`, and fetching `--tags` while
# checkout uses an explicit tag refspec makes git refuse — so scope
# fetch-tags to main pushes.
- uses: actions/checkout@v4
with:
fetch-tags: ${{ github.ref == 'refs/heads/main' }}
- name: Detect release tag at HEAD
id: check
shell: bash
run: |
is_release=false
release_tag=""
case "${{ github.ref }}" in
refs/tags/v[0-9]*)
release_tag="${{ github.ref_name }}"
;;
refs/heads/main)
if [ "${{ github.event_name }}" != "pull_request" ]; then
release_tag=$(git tag --points-at HEAD | grep -E '^v[0-9]' | head -n1 || true)
fi
;;
esac
if [ -n "$release_tag" ]; then
echo "HEAD carries release tag $release_tag; this run builds and publishes the release."
is_release=true
fi
{
echo "is-release=$is_release"
echo "release-tag=$release_tag"
} >> "$GITHUB_OUTPUT"
# Compute a stable hash of every input that affects the native cdylib output,
# then look for any prior successful main run that already uploaded the
# native artifacts for this hash. Two independent outputs:
# * `linux-run-id` — set when the linux x64 canary (`pi-natives-linux-x64-modern-h<hash>`)
# is present on a prior main run, so `test`/`native_linux` can reuse it.
# * `release-run-id` — set when ALL native_release platforms also have
# non-expired artifacts on that same prior run, so `native_release` can
# skip the cold rebuild on main pushes after dep changes have already
# warmed sccache there.
# Non-tag native jobs are skipped when their canary hits; the canary
# retention window (see build-native action) is the effective TTL.
rust-hash:
runs-on: ubuntu-22.04
outputs:
hash: ${{ steps.compute.outputs.hash }}
linux-run-id: ${{ steps.find.outputs.linux-run-id }}
release-run-id: ${{ steps.find.outputs.release-run-id }}
steps:
- uses: actions/checkout@v4
- name: Compute rust source hash
id: compute
shell: bash
run: |
hash=$(find crates Cargo.toml Cargo.lock rust-toolchain.toml \
packages/natives/scripts packages/natives/package.json \
scripts/ci-build-native.ts scripts/host-detect.ts \
-type f -print0 \
| sort -z \
| xargs -0 sha256sum \
| sha256sum \
| cut -c1-16)
echo "hash=$hash" >> "$GITHUB_OUTPUT"
echo "Rust source hash: $hash"
- name: Find prior main build with matching native artifacts
id: find
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
hash="${{ steps.compute.outputs.hash }}"
# Canary for native_linux: presence of the modern artifact implies
# the baseline sibling is also there (they upload from the same job).
linux_canary="pi-natives-linux-x64-modern-h${hash}"
# Required set for native_release reuse — names must match the
# `actions/upload-artifact` `name:` template in build-native action.
release_required=(
"pi-natives-linux-arm64-h${hash}"
"pi-natives-darwin-x64-baseline-h${hash}"
"pi-natives-darwin-arm64-h${hash}"
"pi-natives-win32-x64-baseline-h${hash}"
)
linux_run_id=""
release_run_id=""
for candidate in $(gh run list \
--workflow=ci.yml --branch=main --status=success --event=push \
--limit=20 --json databaseId --jq='.[].databaseId'); do
names=$(gh api "/repos/${{ github.repository }}/actions/runs/$candidate/artifacts?per_page=100" \
--jq '.artifacts[] | select(.expired == false) | .name')
if [ -z "$linux_run_id" ] && echo "$names" | grep -qFx "$linux_canary"; then
linux_run_id="$candidate"
fi
if [ -z "$release_run_id" ]; then
all_found=true
# Release reuse requires the linux canary AND every cross-platform
# artifact, since release_binary downloads them from the same run.
if ! echo "$names" | grep -qFx "$linux_canary"; then
all_found=false
else
for req in "${release_required[@]}"; do
if ! echo "$names" | grep -qFx "$req"; then
all_found=false
break
fi
done
fi
if $all_found; then
release_run_id="$candidate"
fi
fi
if [ -n "$linux_run_id" ] && [ -n "$release_run_id" ]; then
break
fi
done
if [ -n "$linux_run_id" ]; then
echo "Reusing native_linux artifacts from run $linux_run_id"
else
echo "No cached native_linux artifacts for hash $hash; native_linux will rebuild."
fi
if [ -n "$release_run_id" ]; then
echo "Reusing native_release artifacts from run $release_run_id"
else
echo "No cached native_release artifacts for hash $hash; native_release will rebuild on main."
fi
{
echo "linux-run-id=$linux_run_id"
echo "release-run-id=$release_run_id"
} >> "$GITHUB_OUTPUT"
# Fast lint + type check (no Rust, no native build needed)
check:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- name: Cache bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Type check workspace
run: bun run ci:check:full
# Linux x64 baseline + modern: required by `test`, so it runs on every PR
# unless rust-hash found a cached run. Release pushes always rebuild for fresh artifacts.
native_linux:
needs: [gate, rust-hash]
if: ${{ needs.gate.outputs.is-release == 'true' || needs.rust-hash.outputs.linux-run-id == '' }}
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- { variant: baseline, rust_checks: true }
- { variant: modern }
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build-native
with:
hash: ${{ needs.rust-hash.outputs.hash }}
platform: linux
arch: x64
variant: ${{ matrix.variant }}
rust_checks: ${{ matrix.rust_checks && 'true' || 'false' }}
save_cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
# Pre-warm the cross-platform native build cache on `main`, in addition to
# building the artifacts that ship in release tags. Skipped on main when the
# rust-hash canary already found a recent run with all artifacts intact.
native_release:
needs: [gate, rust-hash]
if: ${{ needs.gate.outputs.is-release == 'true' || (github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.rust-hash.outputs.release-run-id == '') }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-22.04, platform: linux, arch: arm64, target: aarch64-unknown-linux-gnu }
- { os: macos-15-intel, platform: darwin, arch: x64, variant: baseline }
- { os: macos-14, platform: darwin, arch: arm64 }
- { os: ubuntu-22.04, platform: win32, arch: x64, target: x86_64-pc-windows-msvc, variant: baseline }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build-native
with:
hash: ${{ needs.rust-hash.outputs.hash }}
platform: ${{ matrix.platform }}
arch: ${{ matrix.arch }}
variant: ${{ matrix.variant }}
target: ${{ matrix.target }}
save_cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
test:
runs-on: ubuntu-22.04
needs: [native_linux, rust-hash]
if: ${{ !cancelled() && needs.native_linux.result != 'failure' }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- name: Cache bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- name: Install system deps
run: |
sudo apt-get update
sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev fd-find ripgrep imagemagick
sudo ln -s $(which fdfind) /usr/local/bin/fd
sudo ln -sf /usr/bin/convert /usr/local/bin/magick
- run: bun install --frozen-lockfile
- name: Resolve native source run
id: source
shell: bash
run: |
if [ "${{ needs.native_linux.result }}" = "success" ]; then
echo "run-id=${{ github.run_id }}" >> "$GITHUB_OUTPUT"
else
echo "run-id=${{ needs.rust-hash.outputs.linux-run-id }}" >> "$GITHUB_OUTPUT"
fi
- name: Download native addons
uses: actions/download-artifact@v4
with:
pattern: pi-natives-linux-x64-*-h${{ needs.rust-hash.outputs.hash }}
path: packages/natives/native
merge-multiple: true
run-id: ${{ steps.source.outputs.run-id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Test workspace (TS)
# `test:ts` sets GITHUB_ACTIONS=0 inline so `bun test` skips its
# per-file `::group::`/`::endgroup::` annotations. Under `--workspaces`
# every line is prefixed with `<pkg> test: `, which breaks GHA's
# column-0 parsing and would leak those markers as literal log spam.
run: bun run test:ts
- name: CLI smoke test
run: bun run ci:test:smoke
install_methods:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: nightly-2026-04-29
- uses: Swatinem/rust-cache@v2
with:
shared-key: install-methods-linux-x64
cache-on-failure: true
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
cache-workspace-crates: true
# Layer sccache on top of rust-cache for the same reason as the
# build-native action: tag pushes bump workspace versions and bust
# the target/ cache, but sccache hits at the rustc-unit level survive.
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.10
- name: Enable sccache for cargo
shell: bash
run: |
{
echo "SCCACHE_GHA_ENABLED=true"
echo "RUSTC_WRAPPER=sccache"
echo "CARGO_INCREMENTAL=0"
} >> "$GITHUB_ENV"
- name: Cache bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- name: Install system deps
run: |
sudo apt-get update
sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev fd-find ripgrep imagemagick
sudo ln -s $(which fdfind) /usr/local/bin/fd
sudo ln -sf /usr/bin/convert /usr/local/bin/magick
- run: bun install --frozen-lockfile
- name: Install method smoke tests
run: bun run ci:test:install-methods
release_binary:
if: ${{ needs.gate.outputs.is-release == 'true' && !cancelled() &&
needs.native_linux.result == 'success' && needs.native_release.result ==
'success' && needs.test.result == 'success' && needs.check.result ==
'success' && needs.install_methods.result == 'success' }}
needs: [gate, check, native_linux, native_release, test, install_methods, rust-hash]
strategy:
fail-fast: false
matrix:
include:
- {
os: ubuntu-22.04,
platform: linux,
arch: x64,
target_id: linux-x64,
binary_path: packages/coding-agent/binaries/omp-linux-x64,
}
- {
os: ubuntu-24.04-arm,
platform: linux,
arch: arm64,
target_id: linux-arm64,
binary_path: packages/coding-agent/binaries/omp-linux-arm64,
}
- {
os: macos-15-intel,
platform: darwin,
arch: x64,
target_id: darwin-x64,
binary_path: packages/coding-agent/binaries/omp-darwin-x64,
}
- {
os: macos-14,
platform: darwin,
arch: arm64,
target_id: darwin-arm64,
binary_path: packages/coding-agent/binaries/omp-darwin-arm64,
}
- {
os: ubuntu-22.04,
platform: win32,
arch: x64,
target_id: win32-x64,
binary_path: packages/coding-agent/binaries/omp-windows-x64.exe,
}
runs-on: ${{ matrix.os }}
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- uses: actions/setup-node@v4
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
# Trusted publishing allowed-actions flags require npm >= 11.16.0.
- name: Ensure npm supports trusted publishing
if: ${{ !inputs.skip_npm }}
run: npm install -g npm@latest
- name: Cache bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Download native addon(s)
uses: actions/download-artifact@v4
with:
pattern: pi-natives-${{ matrix.platform }}-${{ matrix.arch }}*-h${{ needs.rust-hash.outputs.hash }}
path: packages/natives/native
merge-multiple: true
- name: Build release binary
env:
RELEASE_TARGETS: ${{ matrix.target_id }}
run: bun run ci:release:build-binaries
# Windows binary is cross-built on Linux, so we have no Windows runner
# to smoke it on. Cross-build correctness is verified via the napi
# entry-point exports (see build-native action) and the bun
# `--compile --target=bun-windows-x64-*` cross-compile.
- name: Smoke release binary
if: matrix.platform != 'win32'
run: |
runtime_dir="$(mktemp -d)"
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" "${{ matrix.binary_path }}" --version
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" "${{ matrix.binary_path }}" --smoke-test
- name: Publish native addon package
if: ${{ !inputs.skip_npm }}
env:
# Fallback auth: setup-node wrote an .npmrc referencing
# NODE_AUTH_TOKEN; npm uses it only when OIDC has no trusted
# publisher for the package (or on a first publish).
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: bun run ci:release:publish-native-leaf ${{ matrix.target_id }}
- name: Upload release binary artifact
uses: actions/upload-artifact@v4
with:
name: omp-binary-${{ matrix.target_id }}
path: ${{ matrix.binary_path }}
release-github:
if: ${{ needs.gate.outputs.is-release == 'true' && !cancelled() &&
needs.release_binary.result == 'success' }}
needs: [gate, release_binary]
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- name: Generate release notes from CHANGELOGs
run: bun scripts/ci-release-notes.ts ${{ needs.gate.outputs.release-tag }}
- name: Download release binaries
uses: actions/download-artifact@v4
with:
pattern: omp-binary-*
path: packages/coding-agent/binaries
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.gate.outputs.release-tag }}
files: |
packages/coding-agent/binaries/omp-*
body_path: release-notes.md
generate_release_notes: true
release_github_verify:
if: ${{ needs.gate.outputs.is-release == 'true' && !cancelled() &&
needs['release-github'].result == 'success' }}
needs: [gate, release-github]
runs-on: macos-14
permissions:
contents: read
steps:
- name: Download published macOS arm64 binary
run: |
curl -fsSL -o omp-darwin-arm64 "https://github.com/${{ github.repository }}/releases/download/${{ needs.gate.outputs.release-tag }}/omp-darwin-arm64"
chmod +x omp-darwin-arm64
- name: Verify published macOS arm64 binary
run: |
codesign -dv ./omp-darwin-arm64
runtime_dir="$(mktemp -d)"
HOME="$runtime_dir/home" XDG_DATA_HOME="$runtime_dir/xdg" ./omp-darwin-arm64 --version
release-npm:
if: ${{ needs.gate.outputs.is-release == 'true' && !cancelled() &&
needs.release_binary.result == 'success' &&
needs.release_github_verify.result == 'success' &&
!inputs.skip_npm }}
needs: [gate, release_binary, release_github_verify]
runs-on: ubuntu-22.04
# `id-token: write` lets npm mint the GitHub OIDC token it exchanges for a
# short-lived publish token (trusted publishing + provenance). When a
# package has no matching trusted publisher configured, npm silently falls
# back to NODE_AUTH_TOKEN below — which also covers first-ever publishes.
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- uses: actions/setup-node@v4
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
# Trusted publishing (OIDC) and auto-provenance need npm >= 11.5.1.
- name: Ensure npm supports OIDC trusted publishing
run: npm install -g npm@latest
- name: Cache bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Publish to npm
env:
# Fallback auth: setup-node wrote an .npmrc referencing
# NODE_AUTH_TOKEN; npm uses it only when OIDC has no trusted
# publisher for the package (or on a first publish).
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: bun run ci:release:publish