Skip to content

feat(bot): gateway + CPA dual-channel GitHub AI review/scan/fix bot - #16

Merged
samson910022 merged 4 commits into
mainfrom
feat/github-ai-bot-opencode2api-cpa
Sep 9, 2026
Merged

samson910022 merged 4 commits into
mainfrom
feat/github-ai-bot-opencode2api-cpa

Conversation

@samson910022

@samson910022 samson910022 commented Sep 9, 2026 •

Copy link
Copy Markdown
Owner

feat(bot): gateway + CPA dual-channel GitHub AI review/scan/fix bot

需求對照

  • Issue 調查(quality score+缺訊清單+root-cause 假設,不發 PR verdict)
  • PR 多智能體 review(gateway-safety/api-compat/docs-config+aggregate verdict)
  • /explain(PR 白話解說;issue 轉調查)、thread-aware(已問不重問)
  • 週期掃描(確定性 pre-scan+LLM 複核,fingerprint 去重,max 3 issues/run,不 auto-merge)
  • /fix(恆回 fix plan;opt-in+git apply --check 乾淨才開 draft PR,maxPrsPerRun: 1 由單 issue run+concurrency group 保證)
  • 公開留言不洩模型名/路由,恆回 response_id 供 previous_response_id 鏈接(30min TTL);thinking/signature 逐字透傳不偽造
  • Secrets 僅名不值(${VAR}+secrets 引用),filled-in LLM_config.json git-ignored+CI guard

模型矩陣(primaries 最大分離,mains 互為 fallback;公開留言不出現)

Role Primary(channel/thinking)
triage gemini-3.8-flash-high(CPA/high)
gateway_safety grok-4.6(CPA/high)
api_compat claude-opus-4-6-thinking(CPA/high)
docs_config muse-spark-1.3-contributor-free(gateway/xhigh,CPA 映射 high)
explainer big-pickle(gateway/high)
scanner grok-composer-2.5-fast(CPA/high)
media_ocr gemini-3.8-flash-high(CPA/high)

各角色先試 primary,再走全域 fallbackModels 鏈(三主力置頂互為備援)。免費額度免登入、首次啟動自動生成(匿名開箱即用),因此各 workflow 預設在 job 內起免鑑權 localhost gateway(API_KEY 空+MANAGE_BACKEND=true);GATEWAY_BASE_URL secret 有設才改用外部。

測試證據

  • npx tsc --noEmit → EXIT 0
  • npm test -- --runInBand → 22 suites / 347 tests 全綠
  • PYTHONPATH=github_bot/src python3 -m unittest tests.test_ai_bot → 27/27 OK(含空-key gateway 可用+省略 Auth header)
  • 六向矩陣:GATEWAY_*/CPA_* 在 .env.example/config.json.example/Dockerfile/compose/index.ts/docs/configuration.md 皆零命中(bot Secrets 不進矩陣)
  • secrets:diff 無真值形狀;LLM_config.json 未追蹤+check-ignore 命中;三 workflow YAML 可解析+run 區塊 bash -n 全過

流程

開分支 → 4 位 subagents 分頭調查 → 分階段實作(Phase 1 LLM 層、Phase 2 Bot Actions)→ 每階段 review subagents+fix 循環 → 最終 3 位全面 review(需求/安全/CI文件)→ commit+push+開 PR → 補 in-job gateway delta(review+push)。

後續操作(合併後,預設零 secrets 即可跑)

  1. (可選)外部 gateway:設 GATEWAY_BASE_URL(+GATEWAY_API_KEY,空即免鑑權)則跳過 in-job 啟動;CPA fallback:設 CPA_BASE_URL+CPA_API_KEY,缺則 warning 跑 gateway-only。
  2. 建立 allowlist labels(triage 僅加白名單;security 僅建議):bug, documentation, enhancement, question, needs-info, needs-triage, api-compat, config, tool-safety, support, duplicate, invalid, wontfix, good first issue, help wanted。
  3. 首次試跑:ai-scan 先用 workflow_dispatch(dry_run:true) 觀察 in-job gateway 啟動+fingerprint 去重。

Dual-provider llm_client (self-hosted gateway free models + CPA
responses, xhigh/high mapping, verbatim thinking passthrough,
response_id session echo, secret redaction); triage/review/explain/
scan/fix-plan pipelines with role-separated primaries
(triage gemini-3.8-flash-high, safety grok-4.6, api-compat
claude-opus-4-6-thinking, docs muse-spark-1.3-contributor-free,
explainer big-pickle, scanner grok-composer-2.5-fast) and
cross-channel fallbacks; ai-review/ai-scan (weekly cron +
fingerprint-dedupe auto-issue)/ai-fix (/fix plans, opt-in draft
PRs only, auto-merge forbidden) workflows; 25 python tests;
docs/AI_BOT.md.
@github-actions

github-actions Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Verdict matrix

  • Roles: gateway_safety, api_compat, docs_config
  • FINAL_VERDICT: NEEDS_CHANGES

Sensitive paths

  • .github/workflows/ai-fix.yml
  • .github/workflows/ai-review.yml
  • .github/workflows/ai-scan.yml
  • .github/workflows/ci.yml
  • github_bot/README.md
  • github_bot/config/LLM_config.example.json
  • github_bot/config/bot_config.json
  • github_bot/prompts/SOUL.md
  • github_bot/prompts/roles/explainer_agent.md
  • github_bot/prompts/roles/reviewer_api_compat.md
  • github_bot/prompts/roles/reviewer_docs_config.md
  • github_bot/prompts/roles/reviewer_gateway_safety.md
  • github_bot/prompts/roles/scanner_agent.md
  • github_bot/prompts/roles/triage_agent.md
  • github_bot/src/init.py
  • github_bot/src/agent_orchestrator.py
  • github_bot/src/github_runner.py
  • github_bot/src/llm_client.py
  • github_bot/src/media_ocr.py
  • github_bot/src/repo_scan.py

Deterministic pre-checks

  • forbidden-file-staged: github_bot/config/bot_config.json:1

gateway_safety

VERDICT: NEEDS_CHANGES

BLOCKING:
none

SHOULD_FIX:
github_bot/config/bot_config.json:1 — deterministic scan flagged "forbidden-file-staged" (evidence: "staged path github_bot/config/bot_config.json must not be committed").
The PR intentionally commits this file as the bot's own configuration (template with no secret values, git-ignored LLM_config.json counterpart, and explicit check-ignore). The scan logic (repo_scan.py + deterministic_findings in agent_orchestrator.py) must be updated to exclude bot_config.json from the forbidden list, otherwise the new scan will always fire on its own config. This is a false-positive in the bot's own deterministic pre-checks.

NITS:
none

The rest of the PR (workflows with redacted secrets, .gitignore updates, CI lint guard, docs, changelog, role prompts, llm_client scrubbing, session meta passthrough, etc.) fully respects every [provider] safety invariant: no secrets/values ever appear, auth discipline is untouched, tool-output logging is absent, wire shapes are not touched, config-matrix sync is not broken, log hygiene is metadata-only, and the bot routes exclusively through the existing [provider] (no new /health or auth changes). The only regression introduced by this PR is the self-flagging of its own committed config file. Fix the scan exclusion and the PR is safe to merge.

api_compat

API Compatibility Review

This PR adds a Python-based GitHub AI bot (github_bot/) alongside new CI workflows. It does not modify any TypeScript [provider] source (src/), route handlers, converters, collectors, retry logic, session stores, or wire-shape code. The review below is scoped to the API-compat checklist items that could be affected, plus safety/config concerns surfaced by the diff and the deterministic pre-finding.


VERDICT: NEEDS_CHANGES


BLOCKING:

  1. github_bot/config/bot_config.json:1 — forbidden file staged (deterministic pre-finding confirmed)
    bot_config.json is flagged by the deterministic scanner rule forbidden-file-staged. The CI guard in .github/workflows/ci.yml:72-76 checks for config.json but the pattern (^|/)config\.json$ will not match bot_config.json. However, the deterministic pre-finding explicitly flags this path. The real concern: bot_config.json embeds the full internal model roster ([model], [model], [model], [model], [model], [model], etc.) in a committed, tracked file. Per the project's safety rules, public comments must never advertise model names or provider routing — yet this file is readable by anyone who clones the repo. While the runtime scrubs these from comments, the config itself is public. This is a policy tension that should be resolved explicitly: either accept that the config is public (and document that decision), or move model IDs to the git-ignored LLM_config.json and reference them by role alias in bot_config.json.

  2. docs/AI_BOT.md:43-55, github_bot/README.md:72-83, CHANGELOG.md:23, github_bot/config/LLM_config.example.json — internal model names committed in public docs/config
    The model routing table in docs/AI_BOT.md and github_bot/README.md lists every internal model name with channel and thinking level. The CHANGELOG entry does the same. The system prompt in github_bot/prompts/SOUL.md says "Public comments must not advertise model names, provider names, or internal routing details" — but these docs are public (tracked in git, visible on GitHub). The LLM_config.example.json similarly lists all model IDs with descriptions naming providers ("Google Gemini", "xAI Grok", "Anthropic Claude"). This contradicts the stated policy. Either:

    • Accept that the repository (as opposed to issue/PR comments) may contain model names and clarify the policy scope, or
    • Redact model IDs from tracked docs/config and keep them only in the git-ignored LLM_config.json.

SHOULD_FIX:

  1. github_bot/src/llm_client.py — _redact_secrets regex may over-match or under-match in diff context
    github_bot/src/github_runner.py:388 and llm_client.py both define _redact_secrets with the same regex. The pattern (api[_-]?key|apikey|token|password|secret)\s*[:=]\s*['\"]?[^'\"\s,}]+ will match token as a bare word, which could redact legitimate non-secret uses of "token" in issue bodies (e.g., "max_tokens", "token count"). Consider anchoring more tightly or using word-boundary matching. Not a wire-shape issue but affects triage report fidelity.

  2. github_bot/src/github_runner.py:296 — _redact_secrets duplicated from llm_client.py
    Two identical implementations of _redact_secrets exist. If one is updated and the other isn't, redaction gaps appear. Import from llm_client instead.

  3. .github/workflows/ai-fix.yml:47-48 — [REDACTED] fragments in workflow YAML
    Lines like GATEWAY_API_KEY: [REDACTED] secrets.GATEWAY_API_KEY }} appear to be malformed ${{ secrets.* }} expressions where the ${{ was stripped by the diff sanitizer. If these are literal in the committed file, the workflow will fail at runtime with empty credentials. Verify the actual committed YAML has proper ${{ secrets.GATEWAY_API_KEY }} syntax. (Same pattern in ai-review.yml, ai-scan.yml.)

  4. github_bot/src/github_runner.py:258 — label-parsing line has [REDACTED] artifact
    Line token= [REDACTED]" -\'"*").lower()` appears to be a redaction artifact in the diff. If the actual source has a similar corruption, label parsing will fail at runtime. Verify the committed source.

  5. github_bot/config/bot_config.json — scan.autoFix.maxPrsPerRun: 1 is documented but not enforced in code
    The PR description says "maxPrsPerRun: 1 is enforced by single-issue runs + the workflow concurrency group". The _run_fix_plan function in github_runner.py does not read or enforce maxPrsPerRun from config. If the concurrency group assumption breaks (e.g., manual dispatch of multiple issues), multiple PRs could be created. Consider adding a runtime check.

  6. No docs/api-reference.md or N×N matrix update
    The bot adds no new [provider] endpoints, so checklist item 8 is N/A for the [provider]. However, the bot itself exposes implicit "endpoints" (slash commands) that are documented in docs/AI_BOT.md but not cross-referenced in docs/api-reference.md. Minor gap.

NITS:

  1. github_bot/src/agent_orchestrator.py:1-486 — concurrent.futures.ThreadPoolExecutor with no explicit thread naming
    Thread names default to ThreadPoolExecutor-N_M. Adding thread_name_prefix="review" aids debugging.

  2. github_bot/config/bot_config.json:12 — defaultBranchCandidates: ["main"] is a single-element list
    If the intent is to support master as a fallback, add it. Otherwise, simplify to a string.

  3. github_bot/src/llm_client.py — INTERNAL_MODEL_NAMES tuple has 35+ entries
    Consider loading this from LLM_config.example.json at init time rather than maintaining a parallel hardcoded list.

  4. CHANGELOG.md:23 — single changelog entry is 450+ characters
    Extremely long single-line entry. Consider splitting into sub-bullets for readability.

  5. github_bot/prompts/SOUL.md — duplicates the system prompt from the repo's own review bot instructions
    This is the bot's own soul prompt and is intentionally identical to the review-bot system prompt. No action needed, but note that changes to one must be mirrored to the other.


Wire-shape impact assessment

Checklist item Status
1. Route error wire shapes No change — no src/routes/ modifications
2. Converter thinking/signature passthrough No change — no src/converters/ modifications
3. previous_response_id chaining (30min TTL) No change to [provider] code; bot echoes response IDs in comments (read-only)
4. Reasoning effort mapping No change to [provider]; bot's normalize_effort_for_provider is bot-internal only
5. Model alias rules No change — no src/ modifications
6. Collector finish/idle logic No change
7. Retry clamp/jitter No change
8. New endpoints documented N/A — no new [provider] endpoints

Test gaps

  • The 25 Python unit tests (tests/test_ai_bot.py) are not included in the diff, so coverage of edge cases (malformed LLM responses, concurrent review failures, label-parsing edge cases) cannot be verified from this review.
  • No integration test verifies that the bot's _redact_secrets catches all patterns that the [provider]'s own redaction would catch (or vice versa).
  • The _run_fix_plan path has no test for the git apply --check failure branch or the finally checkout recovery.

Cross-protocol regressions

None detected. This PR is additive (new Python bot + workflows + docs) and does not modify any TypeScript [provider] source, route handlers, converters, or wire-shape code.

docs_config

VERDICT: COMMENT

Summary

No [provider] runtime configuration settings were added or altered in this PR. The six-way configuration matrix (.env.example, config.json.example, Dockerfile, docker-compose.yml, index.ts, docs/configuration.md) remains in full sync and untouched, as the bot credentials (GATEWAY_BASE_URL, GATEWAY_API_KEY, CPA_BASE_URL, CPA_API_KEY, OPENCODE_API_KEY) are GitHub Actions repository secrets rather than runtime proxy options.


BLOCKING

  • None (no six-way config matrix breaks or [provider] wire regressions).

SHOULD_FIX

  1. Deterministic false-positive on bot_config.json

    • github_bot/src/agent_orchestrator.py:204 (and github_bot/src/repo_scan.py):
      forbidden = (".env", "config.json", "opencode.json", ".log", ".jks", ".keystore", ".pem")
      ...
      if low == ".env" or low.endswith(tuple(f for f in forbidden if f != ".env")) or low == "config.json":
      low.endswith("config.json") matches github_bot/config/bot_config.json because "bot_config.json" ends with "config.json". This generated the false-positive deterministic pre-finding (forbidden-file-staged) on bot_config.json.
      Fix: Match by exact file basename (e.g. Path(path).name == "config.json" or check low.endswith("/config.json")) rather than open suffix matching.
  2. Language sync status index mirror missing entry

    • docs/README.zh-CN.md:26:
      docs/README.md:47 added | AI Bot | English | canonical | to the "Language sync status" tracking table. The Chinese mirror docs/README.zh-CN.md added the navigation row in the table above, but did not update the language status section below to track AI Bot as English canonical.

NITS

  • docs/AI_BOT.md:38: In the "Model routing" section, table rows mention [model] using xhigh on [provider] and [provider] mapping xhigh→high. The explanation is clear and adheres strictly to names-only (no values or secret leakage).
  • CHANGELOG.md:23: The new entry adheres to English-first conventions with a trailing Traditional Chinese summary.

Files to update to close the gaps

  • github_bot/src/agent_orchestrator.py (and github_bot/src/repo_scan.py if mirrored): tighten forbidden path matcher to avoid suffix collision with bot_config.json.
  • docs/README.zh-CN.md: add AI Bot to the language sync tracking table.

FINAL_VERDICT: NEEDS_CHANGES

Session: response_id=746a3025-3252-93d3-923c-68c02c4c300f,resp_req_vrtx_011CetNmMWoPbhytMLEP516S,resp_6Kuhapm7NKTcvr0Pg-LO0QI (chain via previous_response_id, 30min TTL). model=[model] provider=[provider].

Correct gateway notes/triage playbook: anonymous out-of-box quota,
ephemeral in-job gateway viable, no login-state restore needed.
Each ai workflow starts its own localhost gateway (API_KEY empty =
no auth, OPENCODE_PROXY_MANAGE_BACKEND=true, anonymous out-of-box
quota) unless GATEWAY_BASE_URL secret overrides; CPA creds optional
with warning. llm_client allows empty gateway key end-to-end
(default selection, discovery, candidates, auth header omitted)
while CPA still requires a key. 27 python tests.
@samson910022
samson910022 merged commit 31af6e2 into main Sep 9, 2026
4 checks passed
@samson910022
samson910022 deleted the feat/github-ai-bot-opencode2api-cpa branch September 10, 2026 21:14
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