Skip to content

fix(opencode): free-tier failover timeout hour-class (~3600s) - #683

Merged
seonghobae merged 1 commit into
mainfrom
agent/opencode-free-tier-hour-timeout
Jul 31, 2026
Merged

fix(opencode): free-tier failover timeout hour-class (~3600s)#683
seonghobae merged 1 commit into
mainfrom
agent/opencode-free-tier-hour-timeout

Conversation

@seonghobae

@seonghobae seonghobae commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Raise OPENCODE_FREE_RUN_TIMEOUT_SECONDS from 600 to 3600 in the OpenCode dispatch workflow and the model-pool default for opencode-free/* failover candidates.
  • Document org secret NVIDIA_NIM_API_KEY → env NVIDIA_API_KEY mapping (workflow + pool normalize) so nvidia-nim/* is not skipped when only the org NIM secret is set.
  • Update contract and strix quick-gate asserts to require the hour-class free-tier budget.

Why

Primary/dynamic large-repo OpenCode paths already allow ≥3600s; free-tier failover was still stuck near 600s, aborting long reviews on large repos.

Test plan

  • pytest tests/test_opencode_agent_contract.py -k free/timeout (local)
  • CI on this PR

Summary by CodeRabbit

  • 개선 사항
    • 무료 모델 실행 제한 시간이 10분에서 최대 60분으로 연장되었습니다.
    • 모델 실행과 리뷰 결과 게시 과정에서 NVIDIA NIM 인증 설정이 더욱 명확하게 안내됩니다.
    • 관련 실행 환경의 제한 시간 설정이 일관되게 적용되도록 검증이 강화되었습니다.

Large-repo free-tier failover was still capped at 600s while primary
paths already use ≥3600s. Align OPENCODE_FREE_RUN_TIMEOUT_SECONDS to
3600 in the dispatch workflow and pool default, update contract/quick
gate asserts, and document NVIDIA_NIM_API_KEY → NVIDIA_API_KEY mapping
for nvidia-nim/* candidates.
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

OpenCode 무료 모델의 실행 제한 시간이 600초에서 3600초로 늘어났습니다. NVIDIA NIM 인증 키 매핑 주석이 워크플로와 모델 풀 스크립트에 추가되었습니다. 관련 검증 기대값도 갱신되었습니다.

Changes

OpenCode 실행 및 인증 설정

Layer / File(s) Summary
NVIDIA NIM 키 매핑 설명 갱신
.github/workflows/opencode-review-dispatch.yml, scripts/ci/run_opencode_review_model_pool.sh
NVIDIA NIM 키의 우선순위, 대체 키, 환경 변수 매핑, 로컬 실행 동작을 설명하는 주석을 갱신했습니다.
무료 모델 실행 제한 시간 갱신
.github/workflows/opencode-review-dispatch.yml, scripts/ci/run_opencode_review_model_pool.sh, scripts/ci/test_strix_quick_gate.sh, tests/test_opencode_agent_contract.py
무료 OpenCode 모델의 실행 제한 시간을 3600초로 변경하고 관련 검증 기대값을 갱신했습니다.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 OpenCode 무료 티어 장애 조치 제한 시간을 600초에서 약 3600초로 늘리는 주요 변경을 정확하게 설명합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/opencode-free-tier-hour-timeout

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae enabled auto-merge (squash) July 31, 2026 12:34
@seonghobae
seonghobae merged commit 1dd8929 into main Jul 31, 2026
43 of 46 checks passed
@seonghobae
seonghobae deleted the agent/opencode-free-tier-hour-timeout branch July 31, 2026 12:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_opencode_agent_contract.py (1)

1377-1377: 📐 Maintainability & Code Quality | 🔵 Trivial

전체 테스트 스위트를 실행하세요.

개발 의존성이 준비된 환경에서 python -m pytest를 실행하세요. 이 계약 테스트는 워크플로와 model pool runner의 timeout 설정을 함께 검증합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_opencode_agent_contract.py` at line 1377, Run the complete test
suite with python -m pytest in an environment where all development dependencies
are installed, including the contract test covering
OPENCODE_FREE_RUN_TIMEOUT_SECONDS and the model pool runner timeout
configuration.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/opencode-review-dispatch.yml:
- Line 4092: Adjust the OPENCODE_FREE_RUN_TIMEOUT_SECONDS setting and the
related dynamic pool budget or candidate ordering so all seven opencode-free
candidates can be attempted without exhausting the pool before nvidia-nim or
paid fallbacks run. Preserve fallback execution by ensuring the combined
free-candidate timeout fits within each supported total budget of 2100, 3900,
and 7200 seconds.

---

Nitpick comments:
In `@tests/test_opencode_agent_contract.py`:
- Line 1377: Run the complete test suite with python -m pytest in an environment
where all development dependencies are installed, including the contract test
covering OPENCODE_FREE_RUN_TIMEOUT_SECONDS and the model pool runner timeout
configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f4cc43f0-219f-4040-bde4-97efcd8eeac5

📥 Commits

Reviewing files that changed from the base of the PR and between c7a4bad and 7cf9e5c.

📒 Files selected for processing (4)
  • .github/workflows/opencode-review-dispatch.yml
  • scripts/ci/run_opencode_review_model_pool.sh
  • scripts/ci/test_strix_quick_gate.sh
  • tests/test_opencode_agent_contract.py

OPENCODE_DYNAMIC_TOTAL_BUDGET_CAP_SECONDS: "11700"
OPENCODE_DYNAMIC_MAX_CYCLES_CAP: "1"
OPENCODE_FREE_RUN_TIMEOUT_SECONDS: "600"
OPENCODE_FREE_RUN_TIMEOUT_SECONDS: "3600"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import re
from pathlib import Path

path = Path(".github/workflows/opencode-review-dispatch.yml")
text = path.read_text()

candidate_line = re.search(r"^\s*OPENCODE_MODEL_CANDIDATES:.*$", text, re.MULTILINE).group(0)
free_count = candidate_line.count("opencode-free/")

def value(name: str) -> int:
    return int(re.search(rf"^\s*{name}:\s*\"(\d+)\"$", text, re.MULTILINE).group(1))

free_window = free_count * value("OPENCODE_FREE_RUN_TIMEOUT_SECONDS")
budget = min(value("OPENCODE_TOTAL_RETRY_BUDGET_SECONDS"),
             value("OPENCODE_POOL_STEP_TIMEOUT_SECONDS"))

if free_window > budget:
    raise SystemExit(
        f"free candidates require {free_window}s, but the pool budget is {budget}s"
    )
PY

Repository: ContextualWisdomLab/.github

Length of output: 227


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- workflow references ---'
rg -n -C 8 \
  'OPENCODE_(MODEL_CANDIDATES|FREE_RUN_TIMEOUT_SECONDS|TOTAL_RETRY_BUDGET_SECONDS|POOL_STEP_TIMEOUT_SECONDS)|run_opencode_review_model_pool|free candidate|free 후보' \
  .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '--- model-pool script references ---'
rg -n -C 12 \
  'OPENCODE_(MODEL_CANDIDATES|FREE_RUN_TIMEOUT_SECONDS|TOTAL_RETRY_BUDGET_SECONDS|POOL_STEP_TIMEOUT_SECONDS)|timeout|budget|candidate' \
  scripts/ci/run_opencode_review_model_pool.sh

printf '%s\n' '--- contract-test references ---'
rg -n -C 10 \
  'OPENCODE_(MODEL_CANDIDATES|FREE_RUN_TIMEOUT_SECONDS|TOTAL_RETRY_BUDGET_SECONDS|POOL_STEP_TIMEOUT_SECONDS)|run_opencode_review_model_pool|timeout|budget|candidate' \
  tests/test_opencode_agent_contract.py

printf '%s\n' '--- file outlines ---'
ast-grep outline scripts/ci/run_opencode_review_model_pool.sh --lang bash 2>/dev/null || true
ast-grep outline tests/test_opencode_agent_contract.py --lang python 2>/dev/null || true

Repository: ContextualWisdomLab/.github

Length of output: 50385


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- workflow references ---'
rg -n -C 8 \
  'OPENCODE_(MODEL_CANDIDATES|FREE_RUN_TIMEOUT_SECONDS|TOTAL_RETRY_BUDGET_SECONDS|POOL_STEP_TIMEOUT_SECONDS)|run_opencode_review_model_pool|free candidate|free 후보' \
  .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '--- model-pool script references ---'
rg -n -C 12 \
  'OPENCODE_(MODEL_CANDIDATES|FREE_RUN_TIMEOUT_SECONDS|TOTAL_RETRY_BUDGET_SECONDS|POOL_STEP_TIMEOUT_SECONDS)|timeout|budget|candidate' \
  scripts/ci/run_opencode_review_model_pool.sh

printf '%s\n' '--- contract-test references ---'
rg -n -C 10 \
  'OPENCODE_(MODEL_CANDIDATES|FREE_RUN_TIMEOUT_SECONDS|OPENCODE_TOTAL_RETRY_BUDGET_SECONDS|OPENCODE_POOL_STEP_TIMEOUT_SECONDS)|run_opencode_review_model_pool|timeout|budget|candidate' \
  tests/test_opencode_agent_contract.py

printf '%s\n' '--- file outlines ---'
ast-grep outline scripts/ci/run_opencode_review_model_pool.sh --lang bash 2>/dev/null || true
ast-grep outline tests/test_opencode_agent_contract.py --lang python 2>/dev/null || true

Repository: ContextualWisdomLab/.github

Length of output: 50385


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import re
from pathlib import Path

workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text()
runner = Path("scripts/ci/run_opencode_review_model_pool.sh").read_text()

candidate_line = re.search(
    r'^\s*OPENCODE_MODEL_CANDIDATES:\s*"([^"]+)"$', workflow, re.MULTILINE
).group(1)
free_candidates = re.findall(r'\bopencode-free/\S+', candidate_line)
free_timeout = int(re.search(
    r'^\s*OPENCODE_FREE_RUN_TIMEOUT_SECONDS:\s*"(\d+)"$',
    workflow, re.MULTILINE
).group(1))
outer_timeout = int(re.search(
    r'^\s*OPENCODE_POOL_STEP_TIMEOUT_SECONDS:\s*"(\d+)"$',
    workflow, re.MULTILINE
).group(1))

# Extract the budgets selected by the dynamic-cadence branches in the runner.
branch_budgets = {
    "small": int(re.search(
        r'original_run_timeout=.*?'
        r'OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS (\d+)',
        runner, re.DOTALL
    ).group(1)),
    "medium": int(re.search(
        r'OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS (\d+)',
        runner
    ).group(1)),
    "large": int(re.search(
        r'OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS (\d+)',
        runner
    ).group(1)),
    "unknown": int(re.search(
        r'OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS (\d+)',
        runner
    ).group(1)),
}

print(f"free_candidates={len(free_candidates)}")
print(f"free_timeout={free_timeout}s")
print(f"configured_outer_timeout={outer_timeout}s")
print(f"free_max_window={len(free_candidates) * free_timeout}s")
print(f"dynamic_budgets={branch_budgets}")

# Model the runner's one-attempt, deadline-checked loop when every free
# candidate consumes its allowed timeout. This is arithmetic only; it does
# not execute repository code or contact providers.
for cadence, budget in branch_budgets.items():
    elapsed = 0
    attempted = 0
    for _ in free_candidates:
        if elapsed >= budget:
            break
        elapsed += min(free_timeout, budget - elapsed)
        attempted += 1
    print(
        f"{cadence}: attempted_free_candidates={attempted}, "
        f"elapsed={elapsed}s, fallback_reached={'yes' if attempted == len(free_candidates) else 'no'}"
    )
PY

printf '%s\n' '--- relevant contract-test range ---'
sed -n '260,380p' tests/test_opencode_agent_contract.py

Repository: ContextualWisdomLab/.github

Length of output: 6462


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import re
from pathlib import Path

workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text()
runner = Path("scripts/ci/run_opencode_review_model_pool.sh").read_text()

candidate_line = re.search(
    r'^\s*OPENCODE_MODEL_CANDIDATES:\s*"([^"]+)"$', workflow, re.MULTILINE
).group(1)
free_candidates = re.findall(r'\bopencode-free/\S+', candidate_line)
free_timeout = int(re.search(
    r'^\s*OPENCODE_FREE_RUN_TIMEOUT_SECONDS:\s*"(\d+)"$',
    workflow, re.MULTILINE
).group(1))
outer_timeout = int(re.search(
    r'^\s*OPENCODE_POOL_STEP_TIMEOUT_SECONDS:\s*"(\d+)"$',
    workflow, re.MULTILINE
).group(1))

branch_budgets = {
    "small": int(re.search(
        r'OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS (\d+)', runner
    ).group(1)),
    "medium": int(re.search(
        r'OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS (\d+)', runner
    ).group(1)),
    "large": int(re.search(
        r'OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS (\d+)', runner
    ).group(1)),
    "unknown": int(re.search(
        r'OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS (\d+)', runner
    ).group(1)),
}

print(f"free_candidates={len(free_candidates)}")
print(f"free_timeout={free_timeout}s")
print(f"configured_outer_timeout={outer_timeout}s")
print(f"free_max_window={len(free_candidates) * free_timeout}s")
print(f"dynamic_budgets={branch_budgets}")

for cadence, budget in branch_budgets.items():
    elapsed = 0
    attempted = 0
    for _ in free_candidates:
        if elapsed >= budget:
            break
        elapsed += min(free_timeout, budget - elapsed)
        attempted += 1
    print(
        f"{cadence}: attempted_free_candidates={attempted}, "
        f"elapsed={elapsed}s, fallback_reached="
        f"{'yes' if attempted == len(free_candidates) else 'no'}"
    )
PY

printf '%s\n' '--- relevant contract-test range ---'
sed -n '260,380p' tests/test_opencode_agent_contract.py

Repository: ContextualWisdomLab/.github

Length of output: 6462


Free 후보의 timeout과 동적 pool 예산을 함께 조정하세요.

공개 PR에서는 7개의 opencode-free/* 후보가 fallback보다 먼저 실행됩니다. 동적 cadence는 전체 예산을 2100초, 3900초 또는 7200초로 줄입니다. Free 후보가 timeout되면 1~2개만 실행한 뒤 pool이 종료되어 nvidia-nim/* 또는 유료 fallback에 도달하지 못합니다. Free timeout, 후보 수·순서 또는 전체 예산을 조정하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/opencode-review-dispatch.yml at line 4092, Adjust the
OPENCODE_FREE_RUN_TIMEOUT_SECONDS setting and the related dynamic pool budget or
candidate ordering so all seven opencode-free candidates can be attempted
without exhausting the pool before nvidia-nim or paid fallbacks run. Preserve
fallback execution by ensuring the combined free-candidate timeout fits within
each supported total budget of 2100, 3900, and 7200 seconds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant