






















@@ -190,7 +190,6 @@ jobs:
190190outputs:
191191selected_sha: ${{ steps.validate.outputs.selected_sha }}
192192trusted_reason: ${{ steps.validate.outputs.trusted_reason }}
193-live_model_matrix: ${{ steps.live_model_matrix.outputs.matrix }}
194193steps:
195194 - name: Checkout selected ref
196195uses: actions/checkout@v6
@@ -235,89 +234,6 @@ jobs:
235234 echo "Trust reason: \`$trusted_reason\`"
236235 } >> "$GITHUB_STEP_SUMMARY"
237236238- - name: Resolve live model provider matrix
239-id: live_model_matrix
240-env:
241-INPUT_LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }}
242-shell: bash
243-run: |
244- set -euo pipefail
245-246- all_providers=(anthropic google minimax openai opencode-go openrouter xai zai fireworks)
247-248- provider_label() {
249- case "$1" in
250- anthropic) echo "Anthropic" ;;
251- google) echo "Google" ;;
252- minimax) echo "MiniMax" ;;
253- openai) echo "OpenAI" ;;
254- opencode-go) echo "OpenCode" ;;
255- openrouter) echo "OpenRouter" ;;
256- xai) echo "xAI" ;;
257- zai) echo "Z.ai" ;;
258- fireworks) echo "Fireworks" ;;
259- *) return 1 ;;
260- esac
261- }
262-263- normalize_provider() {
264- local value="${1,,}"
265- case "$value" in
266- z.ai|z-ai) echo "zai" ;;
267- opencode|opencode-go) echo "opencode-go" ;;
268- open-router|openrouter) echo "openrouter" ;;
269- *) echo "$value" ;;
270- esac
271- }
272-273- is_known_provider() {
274- local value="$1"
275- local provider
276- for provider in "${all_providers[@]}"; do
277- [[ "$provider" == "$value" ]] && return 0
278- done
279- return 1
280- }
281-282- selected=()
283- declare -A seen=()
284- raw="${INPUT_LIVE_MODEL_PROVIDERS:-}"
285- normalized_all="${raw,,}"
286- normalized_all="${normalized_all//[[:space:],]/}"
287- if [[ -z "$normalized_all" || "$normalized_all" == "all" ]]; then
288- selected=("${all_providers[@]}")
289- else
290- while IFS= read -r entry; do
291- [[ -z "$entry" ]] && continue
292- provider="$(normalize_provider "$entry")"
293- if ! is_known_provider "$provider"; then
294- echo "Unknown live model provider '${entry}'. Expected one of: ${all_providers[*]}" >&2
295- exit 1
296- fi
297- if [[ -z "${seen[$provider]:-}" ]]; then
298- selected+=("$provider")
299- seen[$provider]=1
300- fi
301- done < <(printf '%s\n' "$raw" | tr ',' '\n' | tr '[:space:]' '\n')
302- fi
303-304- if [[ "${#selected[@]}" -eq 0 ]]; then
305- echo "No live model providers selected." >&2
306- exit 1
307- fi
308-309- matrix_entries="[]"
310- for provider in "${selected[@]}"; do
311- label="$(provider_label "$provider")"
312- matrix_entries="$(jq -c --arg label "$label" --arg provider "$provider" '. + [{provider_label: $label, providers: $provider}]' <<<"$matrix_entries")"
313- done
314- matrix="$(jq -c --argjson include "$matrix_entries" '{include: $include}')"
315- echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
316- {
317- echo
318- echo "Live model providers: \`$(IFS=,; echo "${selected[*]}")\`"
319- } >> "$GITHUB_STEP_SUMMARY"
320-321237 validate_release_live_cache:
322238needs: validate_selected_ref
323239if: inputs.include_live_suites && !inputs.live_models_only
@@ -931,12 +847,31 @@ jobs:
931847validate_live_models_docker:
932848name: Docker live models (${{ matrix.provider_label }})
933849needs: validate_selected_ref
934-if: inputs.include_live_suites
850+if: inputs.include_live_suites && inputs.live_model_providers == ''
935851runs-on: ubuntu-24.04
936852timeout-minutes: 75
937853strategy:
938854fail-fast: false
939-matrix: ${{ fromJSON(needs.validate_selected_ref.outputs.live_model_matrix) }}
855+matrix:
856+include:
857+ - provider_label: Anthropic
858+providers: anthropic
859+ - provider_label: Google
860+providers: google
861+ - provider_label: MiniMax
862+providers: minimax
863+ - provider_label: OpenAI
864+providers: openai
865+ - provider_label: OpenCode
866+providers: opencode-go
867+ - provider_label: OpenRouter
868+providers: openrouter
869+ - provider_label: xAI
870+providers: xai
871+ - provider_label: Z.ai
872+providers: zai
873+ - provider_label: Fireworks
874+providers: fireworks
940875env:
941876OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
942877OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
@@ -1026,6 +961,163 @@ jobs:
1026961 - name: Run Docker live model sweep
1027962run: pnpm test:docker:live-models
1028963964+validate_live_models_docker_targeted:
965+name: Docker live models (selected providers)
966+needs: validate_selected_ref
967+if: inputs.include_live_suites && inputs.live_model_providers != ''
968+runs-on: ubuntu-24.04
969+timeout-minutes: 75
970+env:
971+OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
972+OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
973+ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
974+ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
975+ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
976+BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
977+CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
978+DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
979+GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
980+KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
981+MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
982+MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
983+MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
984+MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
985+OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
986+OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
987+GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
988+GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
989+OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
990+QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
991+XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
992+ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
993+Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
994+CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
995+OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
996+OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
997+OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
998+OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
999+OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
1000+OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
1001+OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
1002+FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
1003+REQUESTED_LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }}
1004+OPENCLAW_VITEST_MAX_WORKERS: "2"
1005+steps:
1006+ - name: Checkout selected ref
1007+uses: actions/checkout@v6
1008+with:
1009+ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
1010+fetch-depth: 1
1011+1012+ - name: Setup Node environment
1013+uses: ./.github/actions/setup-node-env
1014+with:
1015+node-version: ${{ env.NODE_VERSION }}
1016+pnpm-version: ${{ env.PNPM_VERSION }}
1017+install-bun: "true"
1018+1019+ - name: Normalize provider allowlist
1020+shell: bash
1021+run: |
1022+ set -euo pipefail
1023+1024+ all_providers=(anthropic google minimax openai opencode-go openrouter xai zai fireworks)
1025+1026+ normalize_provider() {
1027+ local value="${1,,}"
1028+ case "$value" in
1029+ z.ai|z-ai) echo "zai" ;;
1030+ opencode|opencode-go) echo "opencode-go" ;;
1031+ open-router|openrouter) echo "openrouter" ;;
1032+ *) echo "$value" ;;
1033+ esac
1034+ }
1035+1036+ is_known_provider() {
1037+ local value="$1"
1038+ local provider
1039+ for provider in "${all_providers[@]}"; do
1040+ [[ "$provider" == "$value" ]] && return 0
1041+ done
1042+ return 1
1043+ }
1044+1045+ selected=()
1046+ declare -A seen=()
1047+ raw="${REQUESTED_LIVE_MODEL_PROVIDERS:-}"
1048+ normalized_all="${raw,,}"
1049+ normalized_all="${normalized_all//[[:space:],]/}"
1050+ if [[ -z "$normalized_all" || "$normalized_all" == "all" ]]; then
1051+ selected=("${all_providers[@]}")
1052+ else
1053+ while IFS= read -r entry; do
1054+ [[ -z "$entry" ]] && continue
1055+ provider="$(normalize_provider "$entry")"
1056+ if ! is_known_provider "$provider"; then
1057+ echo "Unknown live model provider '${entry}'. Expected one of: ${all_providers[*]}" >&2
1058+ exit 1
1059+ fi
1060+ if [[ -z "${seen[$provider]:-}" ]]; then
1061+ selected+=("$provider")
1062+ seen[$provider]=1
1063+ fi
1064+ done < <(printf '%s\n' "$raw" | tr ',' '\n' | tr '[:space:]' '\n')
1065+ fi
1066+1067+ if [[ "${#selected[@]}" -eq 0 ]]; then
1068+ echo "No live model providers selected." >&2
1069+ exit 1
1070+ fi
1071+1072+ providers_csv="$(IFS=,; echo "${selected[*]}")"
1073+ echo "OPENCLAW_LIVE_PROVIDERS=$providers_csv" >> "$GITHUB_ENV"
1074+ {
1075+ echo "Live model providers: \`$providers_csv\`"
1076+ } >> "$GITHUB_STEP_SUMMARY"
1077+1078+ - name: Hydrate live auth/profile inputs
1079+run: bash scripts/ci-hydrate-live-auth.sh
1080+1081+ - name: Validate provider credentials
1082+shell: bash
1083+run: |
1084+ set -euo pipefail
1085+1086+ require_any() {
1087+ local label="$1"
1088+ shift
1089+ local key
1090+ for key in "$@"; do
1091+ if [[ -n "${!key:-}" ]]; then
1092+ return 0
1093+ fi
1094+ done
1095+ echo "Missing credential for ${label}: expected one of $*" >&2
1096+ exit 1
1097+ }
1098+1099+ IFS=',' read -r -a providers <<<"${OPENCLAW_LIVE_PROVIDERS}"
1100+ for provider in "${providers[@]}"; do
1101+ case "$provider" in
1102+ anthropic) require_any Anthropic ANTHROPIC_API_KEY ANTHROPIC_API_KEY_OLD ANTHROPIC_API_TOKEN ;;
1103+ google) require_any Google GEMINI_API_KEY GOOGLE_API_KEY ;;
1104+ minimax) require_any MiniMax MINIMAX_API_KEY ;;
1105+ openai) require_any OpenAI OPENAI_API_KEY ;;
1106+ opencode-go) require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY ;;
1107+ openrouter) require_any OpenRouter OPENROUTER_API_KEY ;;
1108+ xai) require_any xAI XAI_API_KEY ;;
1109+ zai) require_any Z.ai ZAI_API_KEY Z_AI_API_KEY ;;
1110+ fireworks) require_any Fireworks FIREWORKS_API_KEY ;;
1111+ *)
1112+ echo "Unhandled live model provider shard: ${provider}" >&2
1113+ exit 1
1114+ ;;
1115+ esac
1116+ done
1117+1118+ - name: Run Docker live model sweep
1119+run: pnpm test:docker:live-models
1120+10291121validate_live_provider_suites:
10301122needs: validate_selected_ref
10311123if: inputs.include_live_suites && !inputs.live_models_only
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。