Skip to content

Commit 09fc747

Browse files
Pigbibicodex
andauthored
Add unattended automation control policy (#20)
* Add unattended automation control policy Co-Authored-By: Codex <noreply@openai.com> * Fix automation ledger whitespace Co-Authored-By: Codex <noreply@openai.com> * Address review fallback and ledger retention Co-Authored-By: Codex <noreply@openai.com> * Preserve automation control signals Co-Authored-By: Codex <noreply@openai.com> * Make automation control fail safe Co-Authored-By: Codex <noreply@openai.com> * Keep PR review fallback configurable Co-Authored-By: Codex <noreply@openai.com> * Preserve PR fallback compatibility Co-Authored-By: Codex <noreply@openai.com> * Tighten PR fallback gating Co-Authored-By: Codex <noreply@openai.com> * Split direct API and service fallback controls Co-Authored-By: Codex <noreply@openai.com> * Separate PR review API primary control Co-Authored-By: Codex <noreply@openai.com> * Allow repo variables to override PR review API controls Co-Authored-By: Codex <noreply@openai.com> --------- Co-authored-by: Codex <noreply@openai.com>
1 parent ff6a6d1 commit 09fc747

10 files changed

Lines changed: 735 additions & 12 deletions

.github/workflows/codex_audit.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ on:
2626
description: "Audit provider"
2727
required: false
2828
type: choice
29-
default: "auto"
29+
default: "task_default"
3030
options:
31+
- task_default
3132
- auto
3233
- api
3334
- anthropic
@@ -68,7 +69,7 @@ jobs:
6869
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number || inputs.issue_number }}
6970
SOURCE_REF: ${{ github.event.client_payload.source_ref || inputs.source_ref || 'main' }}
7071
CODEX_AUDIT_MODE: ${{ github.event.client_payload.mode || inputs.mode || 'review_and_fix' }}
71-
CODEX_AUDIT_PROVIDER: ${{ github.event.client_payload.provider || inputs.provider || 'auto' }}
72+
CODEX_AUDIT_PROVIDER: ${{ github.event.client_payload.provider || inputs.provider || 'task_default' }}
7273
CODEX_AUDIT_CODEX_BACKEND: service
7374
CODEX_AUDIT_TASK: ${{ github.event.client_payload.task || inputs.task || 'monthly_snapshot_audit' }}
7475
CODEX_AUDIT_AUTO_MERGE: ${{ github.event.client_payload.auto_merge || inputs.auto_merge || 'false' }}

.github/workflows/codex_pr_review.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ on:
1818
required: false
1919
type: boolean
2020
default: false
21+
api_fallback_enabled:
22+
description: "Optional true/false override for direct API fallback after a recoverable Codex service failure. Empty defers to repository variables."
23+
required: false
24+
type: string
25+
default: ""
26+
direct_api_primary_enabled:
27+
description: "Optional true/false override for API-only PR review when CODEX_AUDIT_SERVICE_URL is not configured. Empty defers to repository variables."
28+
required: false
29+
type: string
30+
default: ""
2131
secrets:
2232
CODEX_AUDIT_REUSABLE_WORKFLOW_TOKEN:
2333
description: "Token that can read QuantStrategyLab/AIAuditBridge when this workflow is called from another private repo."
@@ -81,6 +91,8 @@ jobs:
8191
CODEX_AUDIT_SERVICE_AUDIENCE: ${{ vars.CODEX_AUDIT_SERVICE_AUDIENCE || 'quant-codex-audit' }}
8292
CODEX_PR_REVIEW_REPO_ROOT: ${{ github.workspace }}/source
8393
CODEX_PR_REVIEW_ALLOW_UNCONFIGURED_BACKEND: ${{ inputs.allow_unconfigured_backend || 'false' }}
94+
CODEX_PR_REVIEW_API_FALLBACK_ENABLED: ${{ github.event_name == 'workflow_call' && inputs.api_fallback_enabled != '' && inputs.api_fallback_enabled || vars.CODEX_PR_REVIEW_API_FALLBACK_ENABLED || 'true' }}
95+
CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED: ${{ github.event_name == 'workflow_call' && inputs.direct_api_primary_enabled != '' && inputs.direct_api_primary_enabled || vars.CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED || 'true' }}
8496
working-directory: source
8597
run: |
8698
set -euo pipefail

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,23 @@ Configure these values in `QuantStrategyLab/AIAuditBridge`:
7373
`openai,anthropic`.
7474
- Repository variable `OPENAI_MODEL` for OpenAI API fallback.
7575
- Repository variable `ANTHROPIC_MODEL` for Anthropic API fallback.
76+
- Monthly audits default to `provider=auto` for `monthly_snapshot_audit` and
77+
`provider=codex` for `long_horizon_signal_shadow`; override with
78+
`CODEX_AUDIT_PROVIDER` when you need a specific provider. Workflow dispatch
79+
uses `task_default` to defer provider selection to the task policy.
7680
- Monthly audits with `CODEX_AUDIT_PROVIDER=auto` fall back to the configured
7781
API reviewers when the Codex service hits quota/capacity failures.
78-
- PR review workflows fall back to direct API review on recoverable Codex
79-
service failures.
82+
- PR review workflows can fall back to direct API review on recoverable Codex
83+
service failures through `CODEX_PR_REVIEW_API_FALLBACK_ENABLED=true` or the
84+
reusable workflow input `api_fallback_enabled`. The reusable workflow input
85+
accepts string values `true`/`false`; when omitted it defers to repository
86+
variables and then defaults to `true` for compatibility. Codex-only callers
87+
should pass `api_fallback_enabled: "false"`. API-only PR review when no
88+
service URL is configured is controlled separately by
89+
`CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED` or reusable workflow input
90+
`direct_api_primary_enabled`; this uses the same `true`/`false`, variable,
91+
and compatibility default rules and should be set to `"false"` for Codex-only
92+
callers.
8093
- Repository variable `CODEX_AUDIT_SERVICE_MODEL` for the VPS Codex service primary
8194
path; `VPS Codex Service Ops` deploy writes it into the systemd unit.
8295
- Optional repository variable `CODEX_AUDIT_SERVICE_REASONING_EFFORT` for a

README.zh-CN.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,21 @@ AIAuditBridge 只使用 service backend。workflow 运行在 `ubuntu-latest`,
7171
`openai,anthropic`
7272
- repository variable `OPENAI_MODEL`,API fallback 使用的 OpenAI 模型。
7373
- repository variable `ANTHROPIC_MODEL`,API fallback 使用的 Anthropic 模型。
74+
- monthly audit 的默认 provider 随 task 而变:`monthly_snapshot_audit`
75+
默认 `auto``long_horizon_signal_shadow` 默认 `codex`;如需固定 provider,
76+
请显式设置 `CODEX_AUDIT_PROVIDER`。workflow dispatch 使用 `task_default`
77+
把 provider 选择交给 task policy。
7478
- repository variable `CODEX_AUDIT_SERVICE_MODEL`,VPS Codex service 主路径模型;
7579
`VPS Codex Service Ops` deploy 会写入 systemd unit。
80+
- PR review 可以通过 repository variable
81+
`CODEX_PR_REVIEW_API_FALLBACK_ENABLED=true` 或 reusable workflow input
82+
`api_fallback_enabled` 在可恢复的 Codex service 失败后启用 direct API
83+
fallback。reusable workflow input 使用字符串 `true`/`false`;省略时先使用
84+
repository variable,再为兼容旧调用方默认 `true`。只走 Codex 的调用方应传入
85+
`api_fallback_enabled: "false"`。当未配置 service URL 时,是否允许 API-only
86+
PR review 由 `CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED` 或 reusable
87+
workflow input `direct_api_primary_enabled` 单独控制;该项使用同样的变量和
88+
兼容默认规则,Codex-only 调用方应设为 `"false"`
7689
- workflow 已配置 `id-token: write`,用于向 service 提供 GitHub Actions OIDC token。
7790

7891
service host 启动示例:

scripts/run_codex_pr_review.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,15 +492,21 @@ def _allow_unconfigured_backend() -> bool:
492492
return parse_bool(env_value("CODEX_PR_REVIEW_ALLOW_UNCONFIGURED_BACKEND"))
493493

494494

495+
def _api_fallback_enabled() -> bool:
496+
return parse_bool(env_value("CODEX_PR_REVIEW_API_FALLBACK_ENABLED", "true"))
497+
498+
499+
def _direct_api_primary_enabled() -> bool:
500+
return parse_bool(env_value("CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED", "true"))
501+
502+
495503
def run_codex_review_with_fallback(
496504
prompt: str,
497505
timeout_minutes: int,
498506
complexity: str = "",
499507
changed_file_count: int = 0,
500508
changed_line_count: int = 0,
501509
) -> str:
502-
# env_value() returns "" when CODEX_AUDIT_SERVICE_URL is unset, so this
503-
# guard keeps the direct-API path intact without special error handling.
504510
service_url = env_value("CODEX_AUDIT_SERVICE_URL")
505511
service_failure: Exception | None = None
506512
if service_url:
@@ -517,10 +523,15 @@ def run_codex_review_with_fallback(
517523
if not _service_review_should_fallback(exc):
518524
raise
519525
service_failure = exc
520-
print(f"::warning::Codex service review failed; falling back to direct API: {exc}")
526+
print(f"::warning::Codex service review failed: {exc}")
521527
except (json.JSONDecodeError, OSError, urllib.error.URLError) as exc:
522528
service_failure = exc
523-
print(f"::error::Codex service review failed; falling back to direct API: {exc}")
529+
print(f"::error::Codex service review failed: {exc}")
530+
531+
if service_failure is not None and not _api_fallback_enabled():
532+
raise ReviewError(f"Codex service review failed and direct API fallback is disabled: {service_failure}")
533+
if not service_url and not _direct_api_primary_enabled():
534+
raise ReviewError(NO_REVIEW_BACKEND_CONFIGURED)
524535

525536
print("Running Codex review via direct API")
526537
try:

scripts/run_monthly_codex_audit.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
DEFAULT_TASK = "monthly_snapshot_audit"
3939
DEFAULT_MODE = "review_and_fix"
4040
DEFAULT_PROVIDER = "auto"
41+
TASK_DEFAULT_PROVIDER = "task_default"
42+
TASK_DEFAULT_PROVIDERS = {
43+
"monthly_snapshot_audit": "auto",
44+
"long_horizon_signal_shadow": "codex",
45+
}
4146
API_PATCH_SYSTEM_PROMPT = (
4247
"You are AIAuditBridge's API fallback patch provider. "
4348
"Return exactly one JSON object that matches the service patch contract. "
@@ -384,13 +389,19 @@ def validate_task(task: str, source_repo: str) -> str:
384389
return normalized
385390

386391

387-
def validate_provider(provider: str) -> str:
388-
normalized = (provider or DEFAULT_PROVIDER).strip().lower()
392+
def validate_provider(provider: str, task: str = DEFAULT_TASK) -> str:
393+
normalized = (provider or TASK_DEFAULT_PROVIDER).strip().lower()
394+
if normalized == TASK_DEFAULT_PROVIDER:
395+
return default_provider_for_task(task)
389396
if normalized not in SUPPORTED_PROVIDERS:
390397
raise BridgeError(f"Unsupported CODEX_AUDIT_PROVIDER: {provider!r}")
391398
return normalized
392399

393400

401+
def default_provider_for_task(task: str) -> str:
402+
return TASK_DEFAULT_PROVIDERS.get(task, DEFAULT_PROVIDER)
403+
404+
394405
def api_fallback_allowed_source_repos() -> frozenset[str]:
395406
configured = env_value("CODEX_AUDIT_API_FALLBACK_ALLOWED_SOURCE_REPOSITORIES")
396407
if not configured:
@@ -2772,7 +2783,7 @@ def main() -> int:
27722783
mode = env_value("CODEX_AUDIT_MODE", DEFAULT_MODE)
27732784
if mode not in {"review_only", "review_and_fix"}:
27742785
raise BridgeError(f"Unsupported CODEX_AUDIT_MODE: {mode}")
2775-
provider = validate_provider(env_value("CODEX_AUDIT_PROVIDER", DEFAULT_PROVIDER))
2786+
provider = validate_provider(env_value("CODEX_AUDIT_PROVIDER", TASK_DEFAULT_PROVIDER), task=task)
27762787
codex_backend = validate_codex_backend(env_value("CODEX_AUDIT_CODEX_BACKEND", DEFAULT_CODEX_BACKEND))
27772788
issue_number_raw = env_value("ISSUE_NUMBER")
27782789
if not issue_number_raw.isdigit():

0 commit comments

Comments
 (0)