Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
24 changes: 24 additions & 0 deletions .github/workflows/noema-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,23 @@ jobs:
echo "::add-mask::$app_token"
echo "token=$app_token" >>"$GITHUB_OUTPUT"

- name: Resolve Noema target repository visibility
if: env.PR_NUMBER != ''
id: target_visibility
env:
GH_TOKEN: ${{ secrets.NOEMA_REVIEW_TOKEN || steps.noema_github_app_token.outputs.token || steps.noema_oidc_token.outputs.token }}
run: |
set -euo pipefail
is_private="$(gh api "repos/${TARGET_REPOSITORY}" --jq '.private')"
case "$is_private" in
true | false) ;;
*)
echo "::error::Noema target repository visibility did not resolve to true or false."
exit 1
;;
esac
echo "is_private=$is_private" >>"$GITHUB_OUTPUT"

- name: Run Noema LLM review and submit verdict
if: env.PR_NUMBER != ''
env:
Expand All @@ -258,6 +275,8 @@ jobs:
NOEMA_LLM_API_URL: ${{ vars.NOEMA_LLM_API_URL || '' }}
NOEMA_LLM_MODEL: ${{ vars.NOEMA_LLM_MODEL || '' }}
NOEMA_LLM_API_KEY: ${{ secrets.NOEMA_LLM_API_KEY || secrets.OPENAI_API_KEY || '' }}
NVIDIA_NIM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}
TARGET_REPOSITORY_PRIVATE: ${{ steps.target_visibility.outputs.is_private }}
run: |
set -euo pipefail
if [ -z "${PR_NUMBER:-}" ]; then
Expand All @@ -268,6 +287,11 @@ jobs:
echo "::error::Noema reviewer credential selection succeeded but no token was minted; review cannot submit a verdict."
exit 1
fi
if [ "$TARGET_REPOSITORY_PRIVATE" = "false" ] && [ -z "${NOEMA_LLM_API_URL:-}" ] && [ -z "${NOEMA_LLM_MODEL:-}" ]; then
export NOEMA_LLM_API_URL="https://integrate.api.nvidia.com/v1/chat/completions"
export NOEMA_LLM_MODEL="nvidia/nemotron-3-ultra-550b-a55b"
export NOEMA_LLM_API_KEY="${NVIDIA_NIM_API_KEY:-}"
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
if [ -z "${NOEMA_LLM_API_URL:-}" ] || [ -z "${NOEMA_LLM_MODEL:-}" ] || [ -z "${NOEMA_LLM_API_KEY:-}" ]; then
echo "::error::Noema LLM is unconfigured: NOEMA_LLM_API_URL, NOEMA_LLM_MODEL, and NOEMA_LLM_API_KEY (or OPENAI_API_KEY) are required."
exit 1
Expand Down
26 changes: 22 additions & 4 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3341,7 +3341,7 @@ jobs:
"$schema": "https://opencode.ai/config.json",
"model": "github-models/deepseek/deepseek-r1-0528",
"small_model": "github-models/deepseek/deepseek-v3-0324",
"enabled_providers": ["opencode-free", "openai", "openrouter", "github-models"],
"enabled_providers": ["opencode-free", "nvidia-nim", "openai", "openrouter", "github-models"],
"lsp": false,
"mcp": {},
"permission": {
Expand Down Expand Up @@ -3528,6 +3528,24 @@ jobs:
}
}
},
"nvidia-nim": {
"npm": "@ai-sdk/openai-compatible",
"name": "NVIDIA NIM",
"options": {
"baseURL": "https://integrate.api.nvidia.com/v1",
"apiKey": "{env:NVIDIA_NIM_API_KEY}"
},
"models": {
"nvidia/nemotron-3-ultra-550b-a55b": {
"name": "NVIDIA Nemotron 3 Ultra 550B A55B",
"tool_call": true,
"limit": {
"context": 1000000,
"output": 32768
}
}
}
},
"openai": {
"npm": "@ai-sdk/openai",
"name": "OpenAI (direct)",
Expand Down Expand Up @@ -3838,6 +3856,7 @@ jobs:
# in the opencode.jsonc "openai" provider block.
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
NVIDIA_NIM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
SHARE: "false"
NPM_CONFIG_IGNORE_SCRIPTS: "true"
NO_COLOR: "1"
Expand All @@ -3846,8 +3865,7 @@ jobs:
# Their trial/free-period data
# may be logged, retained, or used for product/model improvement, so
# private repositories never include them. The pool then falls
# through to
# DeepSeek V3, the direct GPT-5.6 Luna slot, pinned PAID
# through to NVIDIA NIM, DeepSeek V3, the direct GPT-5.6 Luna slot, pinned PAID
# OpenRouter coder models (free-tier candidates hit the shared
# free-models-per-day cap and hung for the full candidate timeout,
# so the OpenRouter slots use cheap paid models billed against the
Expand All @@ -3857,7 +3875,7 @@ jobs:
# cost-efficient tier, cheaper than the legacy gpt-5 it replaced
# ($1/$6 vs $1.25/$10 per 1M tokens) so the org OpenAI budget
# stretches further between top-ups.
OPENCODE_MODEL_CANDIDATES: "${{ needs.validate-pr-metadata.outputs.is_private == 'false' && 'opencode-free/nemotron-3-ultra-free opencode-free/deepseek-v4-flash-free opencode-free/north-mini-code-free opencode-free/laguna-s-2.1-free opencode-free/ling-3.0-flash-free opencode-free/big-pickle opencode-free/mimo-v2.5-free ' || '' }}github-models/deepseek/deepseek-v3-0324 openai/gpt-5.6-luna openrouter/deepseek/deepseek-v3.2 openrouter/qwen/qwen3-coder github-models/openai/gpt-4.1 github-models/openai/gpt-5 github-models/openai/gpt-5-chat github-models/openai/o3 github-models/deepseek/deepseek-r1-0528 github-models/deepseek/deepseek-r1"
OPENCODE_MODEL_CANDIDATES: "${{ needs.validate-pr-metadata.outputs.is_private == 'false' && 'opencode-free/nemotron-3-ultra-free opencode-free/deepseek-v4-flash-free opencode-free/north-mini-code-free opencode-free/laguna-s-2.1-free opencode-free/ling-3.0-flash-free opencode-free/big-pickle opencode-free/mimo-v2.5-free nvidia-nim/nvidia/nemotron-3-ultra-550b-a55b ' || '' }}github-models/deepseek/deepseek-v3-0324 openai/gpt-5.6-luna openrouter/deepseek/deepseek-v3.2 openrouter/qwen/qwen3-coder github-models/openai/gpt-4.1 github-models/openai/gpt-5 github-models/openai/gpt-5-chat github-models/openai/o3 github-models/deepseek/deepseek-r1-0528 github-models/deepseek/deepseek-r1"
# One attempt per model, then fall through to the next model. Retrying
# the SAME model 5x let a rate-limited/hung leader consume the whole
# step, so the pool never reached a healthy fallback model.
Expand Down
70 changes: 61 additions & 9 deletions .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,27 @@ jobs:
echo "token=$app_token"
} >>"$GITHUB_OUTPUT"

- name: Resolve target repository visibility
id: target_visibility
env:
GH_TOKEN: ${{ steps.target_app_token.outputs.token || secrets.OPENCODE_APPROVE_TOKEN || github.token }}
TARGET_REPOSITORY: ${{ github.event.client_payload.target_repository || github.event.pull_request.base.repo.full_name || github.repository }}
run: |
set -euo pipefail
if [[ ! "$TARGET_REPOSITORY" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]]; then
echo "::error::Strix target repository must belong to ContextualWisdomLab."
exit 1
fi
is_private="$(gh api "repos/${TARGET_REPOSITORY}" --jq '.private')"
case "$is_private" in
true | false) ;;
*)
echo "::error::Target repository visibility did not resolve to true or false."
exit 1
;;
esac
echo "is_private=$is_private" >>"$GITHUB_OUTPUT"

- name: Materialize target workspace
if: github.event_name != 'repository_dispatch'
env:
Expand Down Expand Up @@ -422,11 +443,13 @@ jobs:
- name: Gate Strix secrets
id: gate
env:
STRIX_MODEL: ${{ github.event.client_payload.strix_llm || 'gpt-5.6-luna' }}
STRIX_MODEL: ${{ github.event.client_payload.strix_llm || (steps.target_visibility.outputs.is_private == 'false' && 'nvidia_nim/nvidia/nemotron-3-ultra-550b-a55b' || 'gpt-5.6-luna') }}
STRIX_OPENAI_API_KEY: ${{ secrets.STRIX_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
STRIX_OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
STRIX_NVIDIA_NIM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}
STRIX_VERTEX_CREDENTIALS: ${{ secrets.GCP_SA_KEY }}
STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
TARGET_REPOSITORY_PRIVATE: ${{ steps.target_visibility.outputs.is_private }}
run: |
strix_model="$(printf '%s' "$STRIX_MODEL" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
case "$strix_model" in
Expand Down Expand Up @@ -469,6 +492,20 @@ jobs:
exit 1
fi
;;
nvidia_nim/nvidia/nemotron-3-ultra-550b-a55b)
if [ "$TARGET_REPOSITORY_PRIVATE" != "false" ]; then
echo '::error::NVIDIA NIM hosted trial scans are limited to public repositories.'
exit 1
fi
echo 'enabled=true' >> "$GITHUB_OUTPUT"
echo 'provider_mode=nvidia_nim' >> "$GITHUB_OUTPUT"
sanitized_nvidia_key="$(printf '%s' "$STRIX_NVIDIA_NIM_API_KEY" | tr -d '\r\n')"
trimmed_nvidia_key="$(printf '%s' "$sanitized_nvidia_key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
if [ -z "$trimmed_nvidia_key" ]; then
echo '::error::NVIDIA_NIM_API_KEY is required for Strix NVIDIA NIM scans.'
exit 1
fi
;;
vertex_ai/gemini-3.1-pro-preview-customtools | vertex_ai/gemini-2.5-flash)
echo 'enabled=true' >> "$GITHUB_OUTPUT"
echo 'provider_mode=vertex_ai' >> "$GITHUB_OUTPUT"
Expand All @@ -480,7 +517,7 @@ jobs:
fi
;;
*)
echo '::error::STRIX_LLM must select GitHub Models openai/gpt-5 or newer, direct OpenAI GPT-5.4 or newer, OpenRouter openrouter/free, or an approved organization Vertex AI model.'
echo '::error::STRIX_LLM must select NVIDIA NIM Nemotron, GitHub Models openai/gpt-5 or newer, direct OpenAI GPT-5.4 or newer, OpenRouter openrouter/free, or an approved organization Vertex AI model.'
exit 1
;;
esac
Expand Down Expand Up @@ -550,7 +587,7 @@ jobs:
- name: Mask LLM API key
if: steps.gate.outputs.enabled == 'true'
env:
LLM_API_KEY: ${{ steps.gate.outputs.provider_mode == 'github_models' && (secrets.STRIX_GITHUB_MODELS_TOKEN || github.token) || steps.gate.outputs.provider_mode == 'openai_direct' && (secrets.STRIX_OPENAI_API_KEY || secrets.OPENAI_API_KEY) || steps.gate.outputs.provider_mode == 'openrouter' && secrets.OPENROUTER_API_KEY || '' }}
LLM_API_KEY: ${{ steps.gate.outputs.provider_mode == 'github_models' && (secrets.STRIX_GITHUB_MODELS_TOKEN || github.token) || steps.gate.outputs.provider_mode == 'openai_direct' && (secrets.STRIX_OPENAI_API_KEY || secrets.OPENAI_API_KEY) || steps.gate.outputs.provider_mode == 'openrouter' && secrets.OPENROUTER_API_KEY || steps.gate.outputs.provider_mode == 'nvidia_nim' && secrets.NVIDIA_NIM_API_KEY || '' }}
run: |
# Sanitize CR/LF before masking to prevent broken ::add-mask::
# commands and potential workflow command injection.
Expand All @@ -566,7 +603,7 @@ jobs:
- name: Prepare LLM API key input file
if: steps.gate.outputs.enabled == 'true'
env:
LLM_API_KEY_SECRET: ${{ steps.gate.outputs.provider_mode == 'github_models' && (secrets.STRIX_GITHUB_MODELS_TOKEN || github.token) || steps.gate.outputs.provider_mode == 'openai_direct' && (secrets.STRIX_OPENAI_API_KEY || secrets.OPENAI_API_KEY) || steps.gate.outputs.provider_mode == 'openrouter' && secrets.OPENROUTER_API_KEY || '' }}
LLM_API_KEY_SECRET: ${{ steps.gate.outputs.provider_mode == 'github_models' && (secrets.STRIX_GITHUB_MODELS_TOKEN || github.token) || steps.gate.outputs.provider_mode == 'openai_direct' && (secrets.STRIX_OPENAI_API_KEY || secrets.OPENAI_API_KEY) || steps.gate.outputs.provider_mode == 'openrouter' && secrets.OPENROUTER_API_KEY || steps.gate.outputs.provider_mode == 'nvidia_nim' && secrets.NVIDIA_NIM_API_KEY || '' }}
PROVIDER_MODE: ${{ steps.gate.outputs.provider_mode }}
run: |
sanitized="$(printf '%s' "$LLM_API_KEY_SECRET" | tr -d '\r\n')"
Expand All @@ -583,6 +620,10 @@ jobs:
echo '::error::OPENROUTER_API_KEY is required for Strix OpenRouter scans.'
exit 1
fi
if [ -z "$trimmed" ] && [ "$PROVIDER_MODE" = "nvidia_nim" ]; then
echo '::error::NVIDIA_NIM_API_KEY is required for Strix NVIDIA NIM scans.'
exit 1
fi
umask 077
llm_api_key_file="$RUNNER_TEMP/llm_api_key.txt"
printf '%s' "$trimmed" > "$llm_api_key_file"
Expand All @@ -596,6 +637,14 @@ jobs:
printf '%s' 'https://openrouter.ai/api/v1' > "$llm_api_base_file"
echo "LLM_API_BASE_FILE=$llm_api_base_file" >> "$GITHUB_ENV"

- name: Prepare NVIDIA NIM API base
if: steps.gate.outputs.provider_mode == 'nvidia_nim'
run: |
umask 077
llm_api_base_file="$RUNNER_TEMP/llm_api_base.txt"
printf '%s' 'https://integrate.api.nvidia.com/v1' > "$llm_api_base_file"
echo "LLM_API_BASE_FILE=$llm_api_base_file" >> "$GITHUB_ENV"

- name: Prepare GitHub Models API base
if: steps.gate.outputs.provider_mode == 'github_models'
run: |
Expand All @@ -605,7 +654,7 @@ jobs:
echo "LLM_API_BASE_FILE=$llm_api_base_file" >> "$GITHUB_ENV"

- name: Prepare GitHub Models fallback credentials
if: steps.gate.outputs.provider_mode == 'openai_direct' || steps.gate.outputs.provider_mode == 'openrouter'
if: steps.gate.outputs.provider_mode == 'openai_direct' || steps.gate.outputs.provider_mode == 'openrouter' || steps.gate.outputs.provider_mode == 'nvidia_nim'
env:
GITHUB_MODELS_FALLBACK_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
run: |
Expand Down Expand Up @@ -680,7 +729,7 @@ jobs:
- name: Prepare Strix model input file
if: steps.gate.outputs.enabled == 'true'
env:
STRIX_MODEL: ${{ github.event.client_payload.strix_llm || 'gpt-5.6-luna' }}
STRIX_MODEL: ${{ github.event.client_payload.strix_llm || (steps.target_visibility.outputs.is_private == 'false' && 'nvidia_nim/nvidia/nemotron-3-ultra-550b-a55b' || 'gpt-5.6-luna') }}
run: |
umask 077
strix_llm_file="$RUNNER_TEMP/strix_llm.txt"
Expand Down Expand Up @@ -709,11 +758,14 @@ jobs:
openrouter/free | openrouter/openrouter/free)
printf '%s' 'openrouter/free' > "$strix_llm_file"
;;
nvidia_nim/nvidia/nemotron-3-ultra-550b-a55b)
printf '%s' "$strix_model" > "$strix_llm_file"
;;
vertex_ai/gemini-3.1-pro-preview-customtools | vertex_ai/gemini-2.5-flash)
printf '%s' "$strix_model" > "$strix_llm_file"
;;
*)
echo '::error::STRIX_LLM must select GitHub Models openai/gpt-5 or newer, direct OpenAI GPT-5.4 or newer, OpenRouter openrouter/free, or an approved organization Vertex AI model.'
echo '::error::STRIX_LLM must select NVIDIA NIM Nemotron, GitHub Models openai/gpt-5 or newer, direct OpenAI GPT-5.4 or newer, OpenRouter openrouter/free, or an approved organization Vertex AI model.'
exit 1
;;
esac
Expand All @@ -732,7 +784,7 @@ jobs:
STRIX_LLM_FILE: ${{ env.STRIX_LLM_FILE }}
STRIX_REPO_ROOT: ${{ runner.temp }}/trusted-workspace
LLM_API_BASE_FILE: ${{ env.LLM_API_BASE_FILE }}
STRIX_LLM_DEFAULT_PROVIDER: ${{ steps.gate.outputs.provider_mode == 'vertex_ai' && 'vertex_ai' || 'openai' }}
STRIX_LLM_DEFAULT_PROVIDER: ${{ steps.gate.outputs.provider_mode == 'vertex_ai' && 'vertex_ai' || steps.gate.outputs.provider_mode == 'nvidia_nim' && 'nvidia_nim' || 'openai' }}
LLM_API_KEY_FILE: ${{ env.LLM_API_KEY_FILE }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}
CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE: ${{ env.CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE }}
Expand All @@ -750,7 +802,7 @@ jobs:
STRIX_LLM_MAX_RETRIES: 1
STRIX_TRANSIENT_RETRY_PER_MODEL: 2
STRIX_TRANSIENT_RETRY_BACKOFF_SECONDS: 60
STRIX_FALLBACK_MODELS: ${{ steps.gate.outputs.provider_mode == 'github_models' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || steps.gate.outputs.provider_mode == 'openai_direct' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || steps.gate.outputs.provider_mode == 'openrouter' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || '' }}
STRIX_FALLBACK_MODELS: ${{ steps.gate.outputs.provider_mode == 'github_models' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || steps.gate.outputs.provider_mode == 'openai_direct' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || steps.gate.outputs.provider_mode == 'openrouter' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || steps.gate.outputs.provider_mode == 'nvidia_nim' && 'github_models/openai/o3 github_models/openai/gpt-5-chat' || '' }}
STRIX_GITHUB_MODELS_API_BASE_FILE: ${{ env.STRIX_GITHUB_MODELS_API_BASE_FILE }}
STRIX_GITHUB_MODELS_KEY_FILE: ${{ env.STRIX_GITHUB_MODELS_KEY_FILE }}
STRIX_FAIL_ON_PROVIDER_SIGNAL: "1"
Expand Down
6 changes: 3 additions & 3 deletions scripts/ci/emit_opencode_failed_check_fallback_findings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -956,13 +956,13 @@ extract_strix_failed_check_block "$EVIDENCE_FILE" "$strix_evidence_file"

emit_known_missing_string_finding \
"$EVIDENCE_FILE" \
"github.event.client_payload.strix_llm || 'gpt-5.6-luna'" \
"Strix PR scans must default to direct OpenAI GPT-5.6 Luna" \
"steps.target_visibility.outputs.is_private == 'false' && 'nvidia_nim/nvidia/nemotron-3-ultra-550b-a55b' || 'gpt-5.6-luna'" \
"Strix public scans must default to NVIDIA NIM while private scans retain the contracted provider" \
".github/workflows/strix.yml" \
"scripts/ci/test_strix_quick_gate.sh"
emit_known_missing_string_finding \
"$EVIDENCE_FILE" \
"STRIX_LLM must select GitHub Models openai/gpt-5 or newer, direct OpenAI GPT-5.4 or newer, OpenRouter openrouter/free, or an approved organization Vertex AI model" \
"STRIX_LLM must select NVIDIA NIM Nemotron, GitHub Models openai/gpt-5 or newer, direct OpenAI GPT-5.4 or newer, OpenRouter openrouter/free, or an approved organization Vertex AI model" \
"Strix unsupported-model errors must name the allowed providers" \
".github/workflows/strix.yml" \
"scripts/ci/test_strix_quick_gate.sh"
Expand Down
13 changes: 12 additions & 1 deletion scripts/ci/run_opencode_review_model_pool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,13 @@ is_openrouter_candidate() {
esac
}

is_nvidia_nim_candidate() {
case "$1" in
nvidia-nim/*) return 0 ;;
*) return 1 ;;
esac
}

is_low_sensitivity_candidate() {
case "$1" in
openai/*-mini | openai/*-nano | \
Expand Down Expand Up @@ -372,6 +379,10 @@ should_skip_model_candidate() {
printf 'Skipping OpenCode %s because OPENROUTER_API_KEY is not configured; falling back to the next provider-qualified candidate.\n' "$model_candidate"
return 0
fi
if is_nvidia_nim_candidate "$model_candidate" && [ -z "${NVIDIA_NIM_API_KEY:-}" ]; then
printf 'Skipping OpenCode %s because NVIDIA_NIM_API_KEY is not configured; falling back to the next provider-qualified candidate.\n' "$model_candidate"
return 0
fi
return 1
}

Expand All @@ -381,7 +392,7 @@ cap_model_run_timeout() {
local cap_seconds

case "$model_candidate" in
opencode-free/*)
opencode-free/* | nvidia-nim/*)
cap_seconds="$(env_integer_or_default OPENCODE_FREE_RUN_TIMEOUT_SECONDS 600)"
;;
github-models/openai/gpt-5 | github-models/openai/gpt-5-chat)
Expand Down
Loading
Loading