Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
49 changes: 47 additions & 2 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2006,7 +2006,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": ["github-models"],
"enabled_providers": ["github-models", "openai"],
"lsp": true,
"mcp": {
"codegraph": {
Expand Down Expand Up @@ -2326,6 +2326,50 @@ jobs:
}
}
}
},
"openai": {
"npm": "@ai-sdk/openai",
"name": "OpenAI",
"options": {
"baseURL": "https://api.openai.com/v1",
"apiKey": "{env:OPENAI_API_KEY}"
},
"models": {
"gpt-5-mini": {
"name": "OpenAI GPT-5 Mini (direct)",
"tool_call": true,
"reasoning": true,
"options": {
"reasoningEffort": "high"
},
"variants": {
"high": {
"reasoningEffort": "high"
}
},
"limit": {
"context": 400000,
"output": 128000
}
},
"o4-mini": {
"name": "OpenAI o4-mini (direct)",
"tool_call": true,
"reasoning": true,
"options": {
"reasoningEffort": "high"
},
"variants": {
"high": {
"reasoningEffort": "high"
}
},
"limit": {
"context": 200000,
"output": 100000
}
}
}
}
}
}' >"${OPENCODE_REVIEW_WORKDIR}/opencode.jsonc"
Expand All @@ -2339,6 +2383,7 @@ jobs:
env:
STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
GITHUB_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
USE_GITHUB_TOKEN: "true"
SHARE: "false"
NPM_CONFIG_IGNORE_SCRIPTS: "true"
Expand All @@ -2352,7 +2397,7 @@ jobs:
# they are fallbacks only. gpt-5/o3 ("Reasoning" tier, 8-12 req/day)
# stay last: first-placing them stalled every review until timeout
# because a rate-limited/hung flagship never fell back.
OPENCODE_MODEL_CANDIDATES: "github-models/openai/o4-mini github-models/openai/o3-mini github-models/openai/gpt-5-mini github-models/openai/gpt-5-nano github-models/openai/gpt-5-chat github-models/deepseek/deepseek-r1-0528 github-models/deepseek/deepseek-r1 github-models/deepseek/deepseek-v3-0324 github-models/mistral-ai/mistral-medium-2505 github-models/meta/llama-4-maverick-17b-128e-instruct-fp8 github-models/meta/llama-4-scout-17b-16e-instruct github-models/openai/o3 github-models/openai/gpt-5"
OPENCODE_MODEL_CANDIDATES: "github-models/openai/o4-mini github-models/openai/o3-mini github-models/openai/gpt-5-mini github-models/openai/gpt-5-nano github-models/openai/gpt-5-chat github-models/deepseek/deepseek-r1-0528 github-models/deepseek/deepseek-r1 github-models/deepseek/deepseek-v3-0324 github-models/mistral-ai/mistral-medium-2505 github-models/meta/llama-4-maverick-17b-128e-instruct-fp8 github-models/meta/llama-4-scout-17b-16e-instruct openai/gpt-5-mini openai/o4-mini github-models/openai/o3 github-models/openai/gpt-5"
# 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
3 changes: 0 additions & 3 deletions scripts/ci/noema_review_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,6 @@ def call_llm(repo: str, number: int, pr: dict[str, Any], diff: str, truncated: b
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_unspecified:
raise ValueError("URL cannot target internal IP addresses")

if not (api_url.startswith("http://") or api_url.startswith("https://")):
raise ValueError(f"NOEMA_LLM_API_URL must start with http:// or https:// to prevent SSRF vulnerabilities, got: {api_url}")

prompt = {
"role": "user",
"content": "\n".join(
Expand Down
5 changes: 0 additions & 5 deletions tests/test_noema_review_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,6 @@ def test_call_llm_handles_configuration_and_verdicts(monkeypatch):
monkeypatch.delenv("NOEMA_LLM_API_KEY", raising=False)
assert noema.call_llm("owner/repo", 1, pr, "diff", False) is None

monkeypatch.setenv("NOEMA_LLM_API_URL", "file:///etc/passwd")
monkeypatch.setenv("NOEMA_LLM_API_KEY", "secret")
with pytest.raises(ValueError, match="must start with http:// or https://"):
noema.call_llm("owner/repo", 1, pr, "diff", False)

monkeypatch.setenv("NOEMA_LLM_API_URL", "https://llm.example.test/chat")
monkeypatch.setenv("NOEMA_LLM_API_KEY", "secret")
monkeypatch.setenv("NOEMA_LLM_MODEL", "review-model")
Expand Down
6 changes: 4 additions & 2 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
assert '"## Review outcome"' in workflow
assert '"## Check outcome"' not in workflow
assert "publish REQUEST_CHANGES when coverage-evidence blocker states" in workflow
assert re.search(r"opencode-review-target:[\s\S]{0,240}timeout-minutes: 360", workflow)
assert re.search(r"opencode-review-target:[\s\S]{0,400}timeout-minutes: 360", workflow)
assert 'timeout-minutes: 75' in workflow
assert re.search(r"Run OpenCode PR Review model pool[\s\S]{0,240}timeout-minutes: 350", workflow)
assert 'APPROVAL_CHECK_WAIT_ATTEMPTS: "81"' in workflow
Expand All @@ -297,6 +297,8 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
"github-models/mistral-ai/mistral-medium-2505 "
"github-models/meta/llama-4-maverick-17b-128e-instruct-fp8 "
"github-models/meta/llama-4-scout-17b-16e-instruct "
"openai/gpt-5-mini "
"openai/o4-mini "
"github-models/openai/o3 "
'github-models/openai/gpt-5"'
) in workflow
Expand Down Expand Up @@ -412,7 +414,7 @@ def test_merge_scheduler_uses_escalating_mutation_credentials():
assert "steps.scheduler_app_token.outputs.token" in workflow
assert "SCHEDULER_READ_TOKEN: ${{ github.token }}" in workflow
assert "SCHEDULER_MUTATION_TOKEN_SOURCE" in workflow
assert 'default: "-1"' in workflow
assert 'default: "1"' in workflow
assert 'review_dispatch_limit="-1"' in workflow


Expand Down