From 81b99625d3e077b9dea80ab58e9baf69fc4dd3eb Mon Sep 17 00:00:00 2001 From: yuanzonghao Date: Sun, 7 Jun 2026 15:23:25 +0800 Subject: [PATCH 1/2] chore(ci): tune PR Agent config - split per-model banners so two model jobs no longer overwrite each other - raise reviewer findings cap to 8, broaden /improve to readability/cleanup - enable dual-publishing for high-score suggestions (inline annotations) - switch Claude model from opus-4-7 to opus-4-6 (fallback sonnet-4-6) - raise reasoning_effort to high, response_language to zh-CN - drop two dead config keys silently ignored by upstream schema - add best_practices.md with 6 project-specific invariants for /improve --- .github/workflows/pr-agent.yml | 53 +++++++++++++++++++++++++--------- .pr_agent.toml | 35 +++++++++++++++++----- best_practices.md | 31 ++++++++++++++++++++ 3 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 best_practices.md diff --git a/.github/workflows/pr-agent.yml b/.github/workflows/pr-agent.yml index afe8df4..331d1e1 100644 --- a/.github/workflows/pr-agent.yml +++ b/.github/workflows/pr-agent.yml @@ -9,38 +9,56 @@ on: jobs: review-claude: if: > - github.event_name == 'pull_request' || - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - startsWith(github.event.comment.body, '/') && - contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) + github.event.sender.type != 'Bot' && + ( + github.event_name == 'pull_request' || + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + startsWith(github.event.comment.body, '/') && + contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) + ) runs-on: ubuntu-latest permissions: issues: write pull-requests: write contents: read steps: - - name: PR Agent - Claude Opus 4.7 + - name: PR Agent - Claude Opus 4.6 uses: the-pr-agent/pr-agent@main env: OPENAI.KEY: ${{ secrets.PR_REVIEW_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - config.model: "openai/claude-opus-4-7" - config.fallback_models: '["openai/claude-opus-4-6"]' + config.model: "openai/claude-opus-4-6" + config.fallback_models: '["openai/claude-sonnet-4-6"]' config.custom_model_max_tokens: 200000 + config.reasoning_effort: "high" openai.api_base: ${{ secrets.PR_REVIEW_BASE_URL }} github_action_config.auto_review: "true" github_action_config.auto_describe: "true" github_action_config.auto_improve: "true" github_action_config.pr_actions: '["opened", "reopened", "ready_for_review", "synchronize"]' + pr_reviewer.extra_instructions: | + 在评审正文最顶部,单独一行以引用块格式输出: + > 🤖 Reviewed by **Claude Opus 4.6** + 不要评论纯代码风格或格式问题。 + pr_code_suggestions.extra_instructions: | + 在建议表格上方,单独一行以引用块格式输出: + > 🤖 Suggested by **Claude Opus 4.6** + best_practices.md 已包含项目规则,请优先围绕规则违反给出建议。 + pr_description.extra_instructions: | + 在描述顶部以引用块单独一行输出: + > 🤖 Described by **Claude Opus 4.6** review-gpt: if: > - github.event_name == 'pull_request' || - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - startsWith(github.event.comment.body, '/') && - contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) + github.event.sender.type != 'Bot' && + ( + github.event_name == 'pull_request' || + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + startsWith(github.event.comment.body, '/') && + contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) + ) runs-on: ubuntu-latest permissions: issues: write @@ -55,8 +73,17 @@ jobs: config.model: "openai/gpt-5.5" config.fallback_models: '["openai/gpt-5.4-mini"]' config.custom_model_max_tokens: 200000 + config.reasoning_effort: "high" openai.api_base: ${{ secrets.PR_REVIEW_BASE_URL }} github_action_config.auto_review: "true" github_action_config.auto_describe: "false" github_action_config.auto_improve: "true" github_action_config.pr_actions: '["opened", "reopened", "ready_for_review", "synchronize"]' + pr_reviewer.extra_instructions: | + 在评审正文最顶部,单独一行以引用块格式输出: + > 🤖 Reviewed by **GPT 5.5** + 不要评论纯代码风格或格式问题。 + pr_code_suggestions.extra_instructions: | + 在建议表格上方,单独一行以引用块格式输出: + > 🤖 Suggested by **GPT 5.5** + best_practices.md 已包含项目规则,请优先围绕规则违反给出建议。 diff --git a/.pr_agent.toml b/.pr_agent.toml index ca1f7b9..d52a66a 100644 --- a/.pr_agent.toml +++ b/.pr_agent.toml @@ -1,22 +1,41 @@ +# PR-Agent configuration for InfiPlot. +# Per-model banners and tool-specific extra_instructions live in +# .github/workflows/pr-agent.yml. Project-level coding rules live in +# best_practices.md (consumed by /improve). Keep this file structural only. + [config] ai_timeout = 300 temperature = 0.2 +reasoning_effort = "high" +response_language = "zh-CN" [pr_reviewer] -num_code_suggestions = 4 -inline_code_comments = true +num_max_findings = 8 require_security_review = true -extra_instructions = """ -This is a Next.js 16 / React 19 / TypeScript interactive visual novel engine. -Focus on: logic errors, security vulnerabilities, missing error handling, -type safety issues, and architectural violations. -Do not comment on code style or formatting. -""" +require_tests_review = false # repo has no test framework +require_can_be_split_review = true +require_score_review = true +require_todo_scan = true +persistent_comment = false # two model jobs would otherwise overwrite each other [pr_description] generate_ai_title = true publish_labels = true use_bullet_points = true +enable_pr_diagram = true + +[pr_code_suggestions] +num_code_suggestions_per_chunk = 6 +max_number_of_calls = 4 +parallel_calls = true +focus_only_on_problems = false # also surface readability/reuse cleanups, not only bugs +suggestions_score_threshold = 0 +dual_publishing_score_threshold = 7 # high-scoring suggestions also appear as inline comments +persistent_comment = false # two model jobs would otherwise overwrite each other + +[best_practices] +enable_global_best_practices = false +max_lines_allowed = 2000 [ignore] glob = [ diff --git a/best_practices.md b/best_practices.md new file mode 100644 index 0000000..ded77e8 --- /dev/null +++ b/best_practices.md @@ -0,0 +1,31 @@ +# InfiPlot Best Practices + +PR-Agent 的 `/improve` 工具读本文件作为项目级规则。违反时会被打 `Organization best practice` 标签。 + +权威来源是 `AGENTS.md`;本文件只列由 PR-Agent 自动审查的高价值不变量。新增时两边同步。 + +--- + +## Pattern 1: Server 必须无状态 + +引擎语义是 `Session + EngineConfig → SceneResult`。客户端持有完整 `Session` 并在每次请求时发回;服务端不引入按用户键的全局缓存、模块级会话存储或持久化层。 + +## Pattern 2: Writer 不得 patch `StoryState` 的 stable 字段 + +`StoryState` 分两区:stable 字段 `logline / genreTags / protagonist / castNotes` 由 Architect 在会话开始时写入,**Writer 永不覆盖**;volatile 字段(`synopsis / openThreads / relationships / nextHook`)每场景可重写。`applyStoryStatePatch` 必须过滤 patch 中的 stable 键。 + +## Pattern 3: LLM 输出必须经 `parseJsonLoose()` 解析 + +`parseJsonLoose`(`lib/engine/jsonParser.ts`)依次尝试 direct parse、fenced extraction、object slicing、jsonrepair。核心 agent 输出禁止裸 `JSON.parse`。 + +## Pattern 4: Writer prompt 的 stable prefix 不可重排或重排版 + +`buildWriterPlanUserMessage()` 与 `buildWriterBeatsUserMessage()` 的 stable prefix(world / style / story spine / archived history / known scene keys / character list)顺序与格式直接决定 prompt cache 命中率;重排、改 markdown 风格都会击穿缓存。dynamic suffix 可以变。 + +## Pattern 5: TTS 隐私 — 剥离 `referenceAudioBase64` 并尊重 `clientTts` + +客户端在调用 `/api/scene`、`/api/vision`、`/api/insert-beat` 前必须从 `Session` 里 strip 掉 `voice.referenceAudioBase64`,请求返回后本地合并回去。当 `clientTts: true` 时,服务端路由必须 drop `config.tts`,确保用户 TTS 密钥永不触达服务器、服务端 TTS 不被意外触发。 + +## Pattern 6: `orientation` 在会话开始时锁定,缺省值统一回退 `"landscape"` + +`orientation` 控制 prompt framing、生成尺寸、mock 图像与 PlayCanvas 布局,整个会话期间不变。所有进入 `scene.orientation` 的路径(Architect 输出、Prebaked firstact、fallback 分支、异常 / 缺失输入)都必须把无效或缺省值 coerce 成 `"landscape"`,不允许透传 undefined 或非法字符串。fallback 分支尤其容易漏归一化。 From 63cc7a687ee3996812d578015028abb3608c8502 Mon Sep 17 00:00:00 2001 From: yuanzonghao Date: Sun, 7 Jun 2026 15:35:55 +0800 Subject: [PATCH 2/2] chore(ci): stop hiding *.md from PR Agent review The previous "*.md" ignore glob hid best_practices.md and AGENTS.md from the /review diff view (visible in PR #48 where the reviewer hallucinated "this PR does not add a best_practices.md file"). README-style noise on docs PRs is preferable to silently dropping changes to the project's authoritative rule files. --- .pr_agent.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.pr_agent.toml b/.pr_agent.toml index d52a66a..0e3ee39 100644 --- a/.pr_agent.toml +++ b/.pr_agent.toml @@ -43,5 +43,8 @@ glob = [ "*.generated.*", "public/**", "docs/**", - "*.md" + # NOTE: do NOT add "*.md" here — it would hide best_practices.md and + # AGENTS.md from the /review diff view, even though /improve still reads + # best_practices.md directly. README-style noise is preferred over + # silently dropping changes to the project's authoritative rule files. ]