feat(zai): add Web Search in Chat integration for Z.AI provider #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |