From 6c1cffa7f887107bcfa16ed8be37bfa2ea05b1db Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 27 Apr 2026 04:08:16 +0100 Subject: [PATCH] ci: fix targeted live model provider run --- .../openclaw-live-and-e2e-checks-reusable.yml | 264 ++++++++++++------ 1 file changed, 178 insertions(+), 86 deletions(-) diff --git a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml index c776f58b509..5e4ad9cbf80 100644 --- a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml +++ b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml @@ -190,7 +190,6 @@ jobs: outputs: selected_sha: ${{ steps.validate.outputs.selected_sha }} trusted_reason: ${{ steps.validate.outputs.trusted_reason }} - live_model_matrix: ${{ steps.live_model_matrix.outputs.matrix }} steps: - name: Checkout selected ref uses: actions/checkout@v6 @@ -235,89 +234,6 @@ jobs: echo "Trust reason: \`$trusted_reason\`" } >> "$GITHUB_STEP_SUMMARY" - - name: Resolve live model provider matrix - id: live_model_matrix - env: - INPUT_LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }} - shell: bash - run: | - set -euo pipefail - - all_providers=(anthropic google minimax openai opencode-go openrouter xai zai fireworks) - - provider_label() { - case "$1" in - anthropic) echo "Anthropic" ;; - google) echo "Google" ;; - minimax) echo "MiniMax" ;; - openai) echo "OpenAI" ;; - opencode-go) echo "OpenCode" ;; - openrouter) echo "OpenRouter" ;; - xai) echo "xAI" ;; - zai) echo "Z.ai" ;; - fireworks) echo "Fireworks" ;; - *) return 1 ;; - esac - } - - normalize_provider() { - local value="${1,,}" - case "$value" in - z.ai|z-ai) echo "zai" ;; - opencode|opencode-go) echo "opencode-go" ;; - open-router|openrouter) echo "openrouter" ;; - *) echo "$value" ;; - esac - } - - is_known_provider() { - local value="$1" - local provider - for provider in "${all_providers[@]}"; do - [[ "$provider" == "$value" ]] && return 0 - done - return 1 - } - - selected=() - declare -A seen=() - raw="${INPUT_LIVE_MODEL_PROVIDERS:-}" - normalized_all="${raw,,}" - normalized_all="${normalized_all//[[:space:],]/}" - if [[ -z "$normalized_all" || "$normalized_all" == "all" ]]; then - selected=("${all_providers[@]}") - else - while IFS= read -r entry; do - [[ -z "$entry" ]] && continue - provider="$(normalize_provider "$entry")" - if ! is_known_provider "$provider"; then - echo "Unknown live model provider '${entry}'. Expected one of: ${all_providers[*]}" >&2 - exit 1 - fi - if [[ -z "${seen[$provider]:-}" ]]; then - selected+=("$provider") - seen[$provider]=1 - fi - done < <(printf '%s\n' "$raw" | tr ',' '\n' | tr '[:space:]' '\n') - fi - - if [[ "${#selected[@]}" -eq 0 ]]; then - echo "No live model providers selected." >&2 - exit 1 - fi - - matrix_entries="[]" - for provider in "${selected[@]}"; do - label="$(provider_label "$provider")" - matrix_entries="$(jq -c --arg label "$label" --arg provider "$provider" '. + [{provider_label: $label, providers: $provider}]' <<<"$matrix_entries")" - done - matrix="$(jq -c --argjson include "$matrix_entries" '{include: $include}')" - echo "matrix=$matrix" >> "$GITHUB_OUTPUT" - { - echo - echo "Live model providers: \`$(IFS=,; echo "${selected[*]}")\`" - } >> "$GITHUB_STEP_SUMMARY" - validate_release_live_cache: needs: validate_selected_ref if: inputs.include_live_suites && !inputs.live_models_only @@ -931,12 +847,31 @@ jobs: validate_live_models_docker: name: Docker live models (${{ matrix.provider_label }}) needs: validate_selected_ref - if: inputs.include_live_suites + if: inputs.include_live_suites && inputs.live_model_providers == '' runs-on: ubuntu-24.04 timeout-minutes: 75 strategy: fail-fast: false - matrix: ${{ fromJSON(needs.validate_selected_ref.outputs.live_model_matrix) }} + matrix: + include: + - provider_label: Anthropic + providers: anthropic + - provider_label: Google + providers: google + - provider_label: MiniMax + providers: minimax + - provider_label: OpenAI + providers: openai + - provider_label: OpenCode + providers: opencode-go + - provider_label: OpenRouter + providers: openrouter + - provider_label: xAI + providers: xai + - provider_label: Z.ai + providers: zai + - provider_label: Fireworks + providers: fireworks env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} @@ -1026,6 +961,163 @@ jobs: - name: Run Docker live model sweep run: pnpm test:docker:live-models + validate_live_models_docker_targeted: + name: Docker live models (selected providers) + needs: validate_selected_ref + if: inputs.include_live_suites && inputs.live_model_providers != '' + runs-on: ubuntu-24.04 + timeout-minutes: 75 + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }} + ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }} + BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }} + CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }} + DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }} + GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }} + KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} + MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }} + MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }} + MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }} + MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }} + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }} + XAI_API_KEY: ${{ secrets.XAI_API_KEY }} + ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }} + Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }} + CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }} + OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }} + OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }} + OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }} + OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }} + OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }} + OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }} + FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }} + REQUESTED_LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }} + OPENCLAW_VITEST_MAX_WORKERS: "2" + steps: + - name: Checkout selected ref + uses: actions/checkout@v6 + with: + ref: ${{ needs.validate_selected_ref.outputs.selected_sha }} + fetch-depth: 1 + + - name: Setup Node environment + uses: ./.github/actions/setup-node-env + with: + node-version: ${{ env.NODE_VERSION }} + pnpm-version: ${{ env.PNPM_VERSION }} + install-bun: "true" + + - name: Normalize provider allowlist + shell: bash + run: | + set -euo pipefail + + all_providers=(anthropic google minimax openai opencode-go openrouter xai zai fireworks) + + normalize_provider() { + local value="${1,,}" + case "$value" in + z.ai|z-ai) echo "zai" ;; + opencode|opencode-go) echo "opencode-go" ;; + open-router|openrouter) echo "openrouter" ;; + *) echo "$value" ;; + esac + } + + is_known_provider() { + local value="$1" + local provider + for provider in "${all_providers[@]}"; do + [[ "$provider" == "$value" ]] && return 0 + done + return 1 + } + + selected=() + declare -A seen=() + raw="${REQUESTED_LIVE_MODEL_PROVIDERS:-}" + normalized_all="${raw,,}" + normalized_all="${normalized_all//[[:space:],]/}" + if [[ -z "$normalized_all" || "$normalized_all" == "all" ]]; then + selected=("${all_providers[@]}") + else + while IFS= read -r entry; do + [[ -z "$entry" ]] && continue + provider="$(normalize_provider "$entry")" + if ! is_known_provider "$provider"; then + echo "Unknown live model provider '${entry}'. Expected one of: ${all_providers[*]}" >&2 + exit 1 + fi + if [[ -z "${seen[$provider]:-}" ]]; then + selected+=("$provider") + seen[$provider]=1 + fi + done < <(printf '%s\n' "$raw" | tr ',' '\n' | tr '[:space:]' '\n') + fi + + if [[ "${#selected[@]}" -eq 0 ]]; then + echo "No live model providers selected." >&2 + exit 1 + fi + + providers_csv="$(IFS=,; echo "${selected[*]}")" + echo "OPENCLAW_LIVE_PROVIDERS=$providers_csv" >> "$GITHUB_ENV" + { + echo "Live model providers: \`$providers_csv\`" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Hydrate live auth/profile inputs + run: bash scripts/ci-hydrate-live-auth.sh + + - name: Validate provider credentials + shell: bash + run: | + set -euo pipefail + + require_any() { + local label="$1" + shift + local key + for key in "$@"; do + if [[ -n "${!key:-}" ]]; then + return 0 + fi + done + echo "Missing credential for ${label}: expected one of $*" >&2 + exit 1 + } + + IFS=',' read -r -a providers <<<"${OPENCLAW_LIVE_PROVIDERS}" + for provider in "${providers[@]}"; do + case "$provider" in + anthropic) require_any Anthropic ANTHROPIC_API_KEY ANTHROPIC_API_KEY_OLD ANTHROPIC_API_TOKEN ;; + google) require_any Google GEMINI_API_KEY GOOGLE_API_KEY ;; + minimax) require_any MiniMax MINIMAX_API_KEY ;; + openai) require_any OpenAI OPENAI_API_KEY ;; + opencode-go) require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY ;; + openrouter) require_any OpenRouter OPENROUTER_API_KEY ;; + xai) require_any xAI XAI_API_KEY ;; + zai) require_any Z.ai ZAI_API_KEY Z_AI_API_KEY ;; + fireworks) require_any Fireworks FIREWORKS_API_KEY ;; + *) + echo "Unhandled live model provider shard: ${provider}" >&2 + exit 1 + ;; + esac + done + + - name: Run Docker live model sweep + run: pnpm test:docker:live-models + validate_live_provider_suites: needs: validate_selected_ref if: inputs.include_live_suites && !inputs.live_models_only