From 6f70ce90f8fbdad70ea794de02dd455128ecb034 Mon Sep 17 00:00:00 2001 From: limityan Date: Fri, 24 Jul 2026 10:23:26 +0800 Subject: [PATCH] fix(review): align dynamic review copy --- .../src/deep_review/team_definition.rs | 68 +++++-- .../DeepReviewConsentDialog.test.tsx | 47 ++++- .../components/DeepReviewConsentDialog.tsx | 26 +-- .../report/reviewCoverageSource.test.ts | 1 + .../report/reviewCoverageSource.ts | 1 + .../tool-cards/TaskToolDisplay.test.tsx | 11 +- .../flow_chat/tool-cards/TaskToolDisplay.tsx | 7 +- src/web-ui/src/locales/en-US/flow-chat.json | 15 +- .../src/locales/en-US/scenes/agents.json | 85 ++------ src/web-ui/src/locales/zh-CN/flow-chat.json | 43 ++-- .../src/locales/zh-CN/scenes/agents.json | 89 ++------- src/web-ui/src/locales/zh-TW/flow-chat.json | 43 ++-- .../src/locales/zh-TW/scenes/agents.json | 89 ++------- .../shared/services/review-team/defaults.ts | 39 ++-- .../shared/services/review-team/strategy.ts | 6 +- .../services/review-team/workPackets.test.ts | 3 + .../reviewTeamLocaleCompleteness.test.ts | 184 ++++++++++++++++++ .../shared/services/reviewTeamService.test.ts | 2 +- .../src/shared/theme/uiExceptionAccents.ts | 6 +- 19 files changed, 432 insertions(+), 333 deletions(-) diff --git a/src/crates/execution/agent-runtime/src/deep_review/team_definition.rs b/src/crates/execution/agent-runtime/src/deep_review/team_definition.rs index 0d3c5e50e6..a1380c64b3 100644 --- a/src/crates/execution/agent-runtime/src/deep_review/team_definition.rs +++ b/src/crates/execution/agent-runtime/src/deep_review/team_definition.rs @@ -121,26 +121,26 @@ pub fn default_review_team_definition() -> ReviewTeamDefinition { role( "worker", REVIEW_WORKER_AGENT_TYPE, - "Review Worker", - "Dynamic Review Worker", - "A read-only worker whose concrete lens, question, and scope are selected for the current change instead of being fixed in the agent identity.", + "Focused Review", + "On-demand Review Check", + "A read-only check whose focus and scope are chosen for the current change when more evidence would be useful.", &[ - "Apply only the lens and question supplied by the owning Review agent.", - "Stay within the prepared target and return evidence-backed findings and exact coverage.", - "Do not widen permissions, modify files, or repeat the primary review.", + "Check only the question assigned by the main review.", + "Stay within the selected scope and support conclusions with concrete evidence.", + "Do not modify files or repeat work already completed by the main review.", ], "#3b82f6", ), role( "judge", REVIEW_JUDGE_AGENT_TYPE, - "Review Arbiter", - "Review Quality Inspector", - "An independent arbiter used only for high-severity, conflicting, or materially low-confidence conclusions.", + "Independent Review Check", + "Review Quality Check", + "A read-only independent check used only when a serious finding, conflicting evidence, or an uncertain conclusion needs validation.", &[ - "Validate or reject disputed findings against concrete evidence.", - "Spot-check only the claims that need independent verification.", - "Ensure every surviving issue has a safe actionable response.", + "Confirm or reject disputed findings using concrete evidence.", + "Check only the claims that need independent validation.", + "Make sure each retained issue has a safe, practical next step.", ], "#8b5cf6", ), @@ -152,7 +152,7 @@ pub fn default_review_team_definition() -> ReviewTeamDefinition { strategy_profile( "quick", "Quick", - "Quick keeps the primary review concise and allows only a narrowly justified worker lens.", + "Quick keeps the main review concise and allows narrowly focused extra checks only when justified.", "0.4-0.6x", "0.5-0.7x", "fast", @@ -166,7 +166,7 @@ pub fn default_review_team_definition() -> ReviewTeamDefinition { strategy_profile( "normal", "Normal", - "Normal balances evidence depth with one optional dynamically selected specialist lens.", + "Normal balances evidence depth with optional independent checks selected for the current change.", "1x", "1x", "fast", @@ -180,7 +180,7 @@ pub fn default_review_team_definition() -> ReviewTeamDefinition { strategy_profile( "deep", "Deep", - "Deep gives the primary reviewer and one justified dynamic lens the longest bounded budget.", + "Deep gives the main review and any justified independent checks the longest bounded budget.", "1.8-2.5x", "1.5-2.5x", "primary", @@ -208,7 +208,7 @@ pub fn default_review_team_definition() -> ReviewTeamDefinition { ReviewTeamDefinition { id: "default-review-team".to_string(), name: "Code Review".to_string(), - description: "One primary review with an optional dynamically scoped worker and conditional quality inspection.".to_string(), + description: "One main review that can request focused independent checks when more evidence is needed.".to_string(), warning: "Strict review may take longer and usually consumes more tokens than a standard review.".to_string(), default_model: "fast".to_string(), default_strategy_level: "normal".to_string(), @@ -250,6 +250,40 @@ mod tests { .all(|profile| profile.role_directives.len() == 2)); } + #[test] + fn default_team_uses_readable_user_facing_copy() { + let definition = default_review_team_definition(); + let worker = &definition.core_roles[0]; + let judge = &definition.core_roles[1]; + + assert_eq!(worker.fun_name, "Focused Review"); + assert_eq!(worker.role_name, "On-demand Review Check"); + assert_eq!(judge.fun_name, "Independent Review Check"); + assert_eq!(judge.role_name, "Review Quality Check"); + assert_eq!( + definition.description, + "One main review that can request focused independent checks when more evidence is needed." + ); + + let user_facing_copy = definition + .strategy_profiles + .values() + .map(|profile| profile.summary.as_str()) + .chain([worker.description.as_str(), judge.description.as_str()]) + .collect::>() + .join("\n") + .to_ascii_lowercase(); + for implementation_term in ["worker", "lens", "specialist", "inspector"] { + assert!( + !user_facing_copy.contains(implementation_term), + "user-facing copy should not contain {implementation_term}" + ); + } + assert!(!user_facing_copy.contains("one optional")); + assert!(!user_facing_copy.contains("one justified")); + assert!(!user_facing_copy.contains("one narrowly focused")); + } + #[test] fn serialized_default_team_keeps_the_frontend_fallback_contract() { let value = serde_json::to_value(default_review_team_definition()) @@ -258,7 +292,7 @@ mod tests { assert_eq!(value["name"], "Code Review"); assert_eq!( value["description"], - "One primary review with an optional dynamically scoped worker and conditional quality inspection." + "One main review that can request focused independent checks when more evidence is needed." ); assert_eq!(value["coreRoles"][0]["subagentId"], "ReviewWorker"); assert_eq!(value["coreRoles"][0]["accentColor"], "#3b82f6"); diff --git a/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.test.tsx b/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.test.tsx index acb009e162..bc76fff770 100644 --- a/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.test.tsx +++ b/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.test.tsx @@ -299,13 +299,17 @@ describeWithJsdom('DeepReviewConsentDialog', () => { expect(container.textContent).toContain('BitFun selected the most relevant checks for this target.'); expect(container.textContent).not.toContain('Estimated reviewer prompt input'); expect(container.textContent).not.toContain('Reviewer prompt input only'); - expect(container.textContent).toContain('Independent checks: 3 planned review agent run'); - expect(container.textContent).toContain('Up to 4 review agent runs may occur without another confirmation.'); + expect(container.textContent).toContain( + 'Maximum checks: 4. Actual work depends on the review target and the evidence found.', + ); + expect(container.textContent).not.toContain('Expected checks:'); expect(container.textContent).not.toContain('up to 4 initial calls'); expect(container.textContent).toContain('Run strategy: Standard'); expect(container.textContent).not.toContain('Do not show this again'); expect(container.textContent).not.toContain('Risk areas: Backend core'); - expect(container.textContent).toContain('Planned review agent runs; model requests and token use are not estimated here.'); + expect(container.textContent).toContain( + 'The review budget allows optional independent checks. Actual requests and token use depend on the evidence found.', + ); expect(container.textContent).not.toContain('1 extra specialist'); expect(container.textContent).not.toContain('Review depth: Risk-expanded'); expect(container.textContent).not.toContain('Frontend reviewer'); @@ -316,6 +320,31 @@ describeWithJsdom('DeepReviewConsentDialog', () => { expect(container.textContent).not.toContain('Custom security reviewer'); }); + it('keeps a single-check limit grammatically readable', async () => { + const result = vi.fn(); + const basePreview = buildPreviewWithoutSkippedReviewers(); + const preview: ReviewTeamRunManifest = { + ...basePreview, + tokenBudget: { + ...basePreview.tokenBudget, + estimatedReviewerCalls: 1, + maxReviewerCalls: 1, + }, + }; + + await act(async () => { + root.render(); + }); + await act(async () => { + container.querySelector('button')?.dispatchEvent(new window.Event('click', { bubbles: true })); + }); + + expect(container.textContent).toContain( + 'Maximum checks: 1. Actual work depends on the review target and the evidence found.', + ); + expect(container.textContent).not.toContain('1 checks'); + }); + it('uses a generic target summary when the review is not file-based', async () => { const result = vi.fn(); const preview: ReviewTeamRunManifest = { @@ -344,7 +373,9 @@ describeWithJsdom('DeepReviewConsentDialog', () => { expect(container.textContent).toContain('Provided context'); expect(container.textContent).not.toContain('0 files'); expect(container.textContent).not.toContain('Risk areas:'); - expect(container.textContent).toContain('Planned review agent runs; model requests and token use are not estimated here.'); + expect(container.textContent).toContain( + 'The review budget allows optional independent checks. Actual requests and token use depend on the evidence found.', + ); }); it('still opens when skip preference is set but reviewers are skipped', async () => { @@ -426,7 +457,9 @@ describeWithJsdom('DeepReviewConsentDialog', () => { expect(container.querySelectorAll('.deep-review-consent__strategy-heading')).toHaveLength(0); expect(container.textContent).not.toContain('Quick is narrower'); expect(container.textContent).not.toContain('Risk areas: Backend core'); - expect(container.textContent).toContain('Planned review agent runs; model requests and token use are not estimated here.'); + expect(container.textContent).toContain( + 'The review budget allows optional independent checks. Actual requests and token use depend on the evidence found.', + ); expect(container.textContent).not.toContain('1 extra specialist'); expect(container.textContent).not.toContain('Expected cost:'); expect(container.querySelectorAll('.deep-review-consent__strategy-selected-summary')).toHaveLength(0); @@ -434,7 +467,9 @@ describeWithJsdom('DeepReviewConsentDialog', () => { expect(container.querySelectorAll('.deep-review-consent__strategy-option')).toHaveLength(0); expect(container.querySelectorAll('.deep-review-consent__strategy-option--active')).toHaveLength(0); expect(container.textContent).not.toContain('Team default'); - expect(container.textContent).toContain('Standard adds independent coverage while keeping cost practical.'); + expect(container.textContent).toContain( + 'Standard review examines the selected target in more depth and may add independent checks when useful.', + ); expect(container.querySelectorAll('.deep-review-consent__strategy-option-summary')).toHaveLength(0); const quickStrategyButton = Array.from(container.querySelectorAll('button')) diff --git a/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.tsx b/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.tsx index 3121e9486a..7c2d35f39d 100644 --- a/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.tsx +++ b/src/web-ui/src/flow_chat/components/DeepReviewConsentDialog.tsx @@ -28,15 +28,12 @@ export interface DeepReviewConsentControls { deepReviewConsentDialog: React.ReactNode; } -function getInitialReviewCallFacts(preview: ReviewTeamRunManifest): { - planned: number; - maximum: number; -} { - const planned = Math.max(1, preview.tokenBudget.estimatedReviewerCalls || 1); - return { - planned, - maximum: Math.max(planned, preview.tokenBudget.maxReviewerCalls || planned), - }; +function getReviewCallLimit(preview: ReviewTeamRunManifest): number { + return Math.max( + 1, + preview.tokenBudget.estimatedReviewerCalls || 1, + preview.tokenBudget.maxReviewerCalls || 1, + ); } function getReviewTargetFileCount(preview: ReviewTeamRunManifest): number { @@ -123,7 +120,7 @@ export function useDeepReviewConsent(): DeepReviewConsentControls { const skippedCount = skippedReviewers.length; const selectedStrategyLabel = getStrategyLabel(preview.strategyLevel, t); const targetSummary = getReviewTargetSummary(preview, t); - const callFacts = getInitialReviewCallFacts(preview); + const reviewCallLimit = getReviewCallLimit(preview); return (
@@ -159,15 +156,10 @@ export function useDeepReviewConsent(): DeepReviewConsentControls {
- {t('deepReviewConsent.initialCalls', { - planned: callFacts.planned, + {t('deepReviewConsent.callLimit', { + count: reviewCallLimit, })} - - {t('deepReviewConsent.parallelCalls', { - count: callFacts.maximum, - })} -
{preview.workspacePath && ( diff --git a/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.test.ts b/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.test.ts index 364d0c23a3..1da48ebbd7 100644 --- a/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.test.ts +++ b/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.test.ts @@ -5,6 +5,7 @@ describe('formatReviewCoverageSource', () => { it('maps known read-only review roles to user-facing labels', () => { expect(formatReviewCoverageSource('ReviewSecurity')).toBe('Security coverage'); expect(formatReviewCoverageSource('ReviewJudge')).toBe('Quality check'); + expect(formatReviewCoverageSource('Review Quality Check')).toBe('Quality check'); }); it('does not hide Review-prefixed remediation sources', () => { diff --git a/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.ts b/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.ts index 72c736c659..6287fd1fae 100644 --- a/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.ts +++ b/src/web-ui/src/flow_chat/deep-review/report/reviewCoverageSource.ts @@ -33,6 +33,7 @@ const REVIEW_SOURCE_ALIASES: Record = { reviewjudge: 'qualityGate', reviewarbiter: 'qualityGate', reviewqualityinspector: 'qualityGate', + reviewqualitycheck: 'qualityGate', qualityinspector: 'qualityGate', }; diff --git a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.test.tsx b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.test.tsx index b5318eeb11..4668742408 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.test.tsx +++ b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.test.tsx @@ -32,6 +32,12 @@ vi.mock('react-i18next', () => { if (key === 'toolCards.taskTool.defaultAgentKind') { return 'Sub-agent'; } + if (key === 'toolCards.taskTool.reviewCoverageLabel') { + return 'Review check'; + } + if (key === 'toolCards.taskTool.reviewCoverageDescription') { + return 'Checking review coverage'; + } if (key === 'toolCards.taskTool.cancelSession') { return `Cancel session: ${options?.sessionId}`; } @@ -396,7 +402,7 @@ describeWithJsdom('TaskToolDisplay', () => { id: 'launch-review-call-1', input: { packet_id: 'managed-review:batch-1-of-4', - description: '[packet managed-review:batch-1-of-4] Review web UI changes', + description: '[packet managed-review:batch-1-of-4] Review batch 1', prompt: 'Internal worker prompt', subagent_type: 'ReviewGeneral', }, @@ -409,7 +415,8 @@ describeWithJsdom('TaskToolDisplay', () => { ); }); - expect(container.textContent).toContain('Review web UI changes'); + expect(container.textContent).toContain('Checking review coverage'); + expect(container.textContent).not.toContain('Review batch 1'); expect(container.textContent).not.toContain('LaunchReviewAgent'); expect(container.textContent).not.toContain('ReviewGeneral'); expect(container.textContent).not.toContain('managed-review:batch-1-of-4'); diff --git a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.tsx b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.tsx index d2a4bd1626..f2fbcd8b49 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.tsx +++ b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.tsx @@ -376,8 +376,11 @@ export const TaskToolDisplay: React.FC = ({ readStringValue(toolCall.input.modelId); if (isReviewCoverageTask) { - const reviewDescription = readStringValue(description) - .replace(/^\[packet\s+[^\]]+\]\s*/i, ''); + const packetId = readStringValue(toolCall.input.packet_id) + || readStringValue(toolCall.input.packetId); + const reviewDescription = /^managed-review:/i.test(packetId) + ? '' + : readStringValue(description).replace(/^\[packet\s+[^\]]+\]\s*/i, ''); return { description: reviewDescription || t('toolCards.taskTool.reviewCoverageDescription'), prompt: 'Not provided', diff --git a/src/web-ui/src/locales/en-US/flow-chat.json b/src/web-ui/src/locales/en-US/flow-chat.json index 5823278e8b..a0883c3ef2 100644 --- a/src/web-ui/src/locales/en-US/flow-chat.json +++ b/src/web-ui/src/locales/en-US/flow-chat.json @@ -1041,20 +1041,19 @@ "deepReviewConsent": { "windowTitle": "Review plan", "eyebrow": "Review plan", - "title": "Add broader review coverage?", - "body": "BitFun selected additional independent checks for this change. Review the target scope, planned checks, runtime tendency, and read-only boundary before continuing.", + "title": "Start this review?", + "body": "BitFun reviews this change directly and may add focused independent checks only when the evidence needs them. Confirm the target, review budget, expected time, and read-only boundary before continuing.", "readonlyLabel": "Read-only", "readonly": "Reviewers do not modify files.", "sessionConcurrencyTitle": "Active session is busy", "sessionConcurrencyBody": "The target session already has {{count}} review tasks running. Continuing will share the available review capacity.", - "costLabel": "Coverage", - "cost": "Planned review agent runs; model requests and token use are not estimated here.", + "costLabel": "Review budget", + "cost": "The review budget allows optional independent checks. Actual requests and token use depend on the evidence found.", "timeLabel": "Time", "time": "Runs in background and may take longer.", "cancel": "Cancel", "confirm": "Start review", - "initialCalls": "Independent checks: {{planned}} planned review agent run", - "parallelCalls": "Up to {{count}} review agent runs may occur without another confirmation.", + "callLimit": "Maximum checks: {{count}}. Actual work depends on the review target and the evidence found.", "runStrategy": "Run strategy: {{strategy}}", "strategyLabels": { "quick": "Focused", @@ -1063,8 +1062,8 @@ }, "strategySummaries": { "quick": "Focused review checks the most relevant risks for the selected target.", - "normal": "Standard adds independent coverage while keeping cost practical.", - "deep": "Extensive review adds the broadest applicable coverage for high-risk changes." + "normal": "Standard review examines the selected target in more depth and may add independent checks when useful.", + "deep": "Extensive review examines all applicable high-risk areas and may add independent validation when the evidence needs it." }, "summaryTitle": "Review plan", "targetFiles": "{{count}} files", diff --git a/src/web-ui/src/locales/en-US/scenes/agents.json b/src/web-ui/src/locales/en-US/scenes/agents.json index e145ebee9f..7d79d0c034 100644 --- a/src/web-ui/src/locales/en-US/scenes/agents.json +++ b/src/web-ui/src/locales/en-US/scenes/agents.json @@ -298,84 +298,33 @@ "reviewTeams": { "members": { "worker": { - "funName": "Review Worker", - "role": "Dynamic Review Worker", - "description": "A read-only worker whose concrete lens, question, and scope are selected for the current change instead of being fixed in the agent identity.", + "funName": "Focused Review", + "role": "On-demand Review Check", + "description": "A read-only check whose focus and scope are chosen for the current change when more evidence would be useful.", "responsibilities": [ - "Apply only the lens and question supplied by the owning Review agent.", - "Stay within the prepared target and return evidence-backed findings and exact coverage.", - "Do not widen permissions, modify files, or repeat the primary review." - ] - }, - "businessLogic": { - "funName": "Logic Reviewer", - "role": "Business Logic Reviewer", - "description": "A workflow sleuth that inspects business rules, state transitions, recovery paths, and real-user correctness.", - "responsibilities": [ - "Verify workflows, state transitions, and domain rules still behave correctly.", - "Check boundary cases, rollback paths, and data integrity assumptions.", - "Focus on issues that can break user outcomes or product intent." - ] - }, - "performance": { - "funName": "Performance Reviewer", - "role": "Performance Reviewer", - "description": "A speed-focused profiler that hunts hot paths, unnecessary work, blocking calls, and scale-sensitive regressions.", - "responsibilities": [ - "Inspect hot paths, large loops, and unnecessary allocations or recomputation.", - "Flag blocking work, N+1 patterns, and wasteful data movement.", - "Keep performance advice practical and aligned with the existing architecture." - ] - }, - "security": { - "funName": "Security Reviewer", - "role": "Security Reviewer", - "description": "A boundary guardian that scans for injection risks, trust leaks, privilege mistakes, and unsafe file or command handling.", - "responsibilities": [ - "Review trust boundaries, auth assumptions, and sensitive data handling.", - "Look for injection, unsafe command execution, and exposure risks.", - "Highlight concrete fixes that reduce risk without broad rewrites." + "Check only the question assigned by the main review.", + "Stay within the selected scope and support conclusions with concrete evidence.", + "Do not modify files or repeat work already completed by the main review." ] }, "judge": { - "funName": "Review Arbiter", - "role": "Review Quality Inspector", - "description": "An independent third-party arbiter that validates reviewer reports for logical consistency and evidence quality. It spot-checks specific code locations only when a claim needs verification, rather than re-reviewing the codebase from scratch.", - "responsibilities": [ - "Validate, merge, reprioritize, or reject reviewer findings based on logical consistency and evidence quality.", - "Filter out false positives and directionally-wrong optimization advice by examining reviewer reasoning.", - "Spot-check specific code locations only when a reviewer's claim needs verification.", - "Ensure every surviving issue has an actionable fix or follow-up plan." - ] - }, - "architecture": { - "funName": "Architecture Reviewer", - "role": "Architecture Reviewer", - "description": "A structural watchdog that checks module boundaries, dependency direction, API contract design, and abstraction integrity.", - "responsibilities": [ - "Detect layer boundary violations and wrong-direction imports.", - "Verify API contracts, tool schemas, and transport messages stay consistent.", - "Ensure platform-agnostic code does not leak platform-specific details." - ] - }, - "frontend": { - "funName": "Frontend Reviewer", - "role": "Frontend Reviewer", - "description": "A UI specialist that checks i18n synchronization, frontend performance patterns, accessibility, and frontend-backend contract alignment.", + "funName": "Independent Review Check", + "role": "Review Quality Check", + "description": "A read-only independent check used only when a serious finding, conflicting evidence, or an uncertain conclusion needs validation.", "responsibilities": [ - "Verify i18n key completeness across all locales.", - "Check frontend performance patterns (memoization, virtualization, effect/reactivity dependencies).", - "Flag accessibility violations and frontend-backend API contract drift." + "Confirm or reject disputed findings using concrete evidence.", + "Check only the claims that need independent validation.", + "Make sure each retained issue has a safe, practical next step." ] } }, "extraReviewer": { - "role": "Additional Specialist Reviewer", - "description": "Optional specialist coverage for strict Review with its own instructions, tools, and perspective.", + "role": "Additional Review Check", + "description": "An optional independent check for a specific concern chosen by the user.", "responsibilities": [ - "Bring an extra independent review perspective into the same target scope.", - "Stay tightly focused on the requested diff, commit, or workspace changes.", - "Return concrete findings with clear fix suggestions or follow-up steps." + "Add another independent view of the current change.", + "Check only the requested changes and selected files.", + "Return concrete findings with clear fixes or follow-up steps." ] } }, diff --git a/src/web-ui/src/locales/zh-CN/flow-chat.json b/src/web-ui/src/locales/zh-CN/flow-chat.json index dd8fdd33e2..f7ae8cc0e8 100644 --- a/src/web-ui/src/locales/zh-CN/flow-chat.json +++ b/src/web-ui/src/locales/zh-CN/flow-chat.json @@ -928,7 +928,7 @@ "copyDiagnostics": "复制排障摘要", "diagnosticsCopied": "已复制排障摘要", "diagnosticsCopyFailed": "复制排障摘要失败", - "diagnosticsTitle": "严格 Review 排障摘要", + "diagnosticsTitle": "严格审核排障摘要", "diagnosticsErrorType": "错误类型", "diagnosticsDescription": "错误描述", "diagnosticsSuggestedActions": "建议操作", @@ -957,9 +957,9 @@ }, "resultRecovery": { "title": "严格审核需要补全结果", - "missingSubmitCodeReview": "审核已结束,但 BitFun 没有收到可确认的结构化结果。继续会保留已完成的审核工作,并要求 agent 补交缺失的审核报告。", - "invalidSubmitCodeReview": "审核返回了 BitFun 无法读取的结果。继续会保留已完成的审核工作,并要求 agent 修复报告。", - "wrongReviewMode": "审核返回了标准审核结果。继续会保留已完成的审核工作,并要求 agent 提交严格审核报告。" + "missingSubmitCodeReview": "审核已结束,但 BitFun 没有收到可确认的结构化结果。继续会保留已完成的审核工作,并补交缺失的审核报告。", + "invalidSubmitCodeReview": "审核返回了 BitFun 无法读取的结果。继续会保留已完成的审核工作,并修复报告。", + "wrongReviewMode": "审核返回了标准审核结果。继续会保留已完成的审核工作,并提交严格审核报告。" }, "capacityQueue": { "title": "审核正在等待容量", @@ -1001,7 +1001,7 @@ "cancelQueued": "取消等待中的审核", "skipOptionalQueued": "保留核心检查", "openReviewSettings": "打开审核设置", - "controlFailed": "当前无法控制这个 Review 项的容量。可使用停止来中断 Review,或等待容量状态刷新。", + "controlFailed": "当前无法控制这个审核项的容量。可停止本次审核,或等待容量状态刷新。", "controlFailedWithReason": "容量控制失败:{{reason}}。请重试,或在审核卡住时使用停止来中断。", "controlPartiallyFailedWithReason": "容量控制已部分应用;{{total}} 个审核项中有 {{failed}} 个失败:{{reason}}。请等待容量状态刷新后重试,或在卡住时使用停止。" }, @@ -1041,20 +1041,19 @@ "deepReviewConsent": { "windowTitle": "审核方案", "eyebrow": "审核方案", - "title": "增加更广的审核覆盖?", - "body": "BitFun 为本次变更选择了额外的独立检查。继续前可确认目标范围、计划检查、耗时倾向和只读边界。", + "title": "开始本次审核?", + "body": "BitFun 会先直接审核本次变更,仅在证据确实需要时按需增加独立检查。继续前可确认目标范围、审核预算、预计耗时和只读边界。", "readonlyLabel": "只读", "readonly": "审核者不会修改文件。", "sessionConcurrencyTitle": "当前会话较忙", "sessionConcurrencyBody": "目标会话已有 {{count}} 个审核工作在运行,继续后将共享当前可用的审核容量。", - "costLabel": "覆盖", - "cost": "计划的审查代理执行;此处不估算底层模型请求或 Token。", + "costLabel": "审核预算", + "cost": "审核预算用于按需的独立检查;实际调用次数和模型用量取决于审核中发现的证据。", "timeLabel": "耗时", "time": "后台运行,可能需要更久。", "cancel": "取消", "confirm": "开始审核", - "initialCalls": "独立检查:计划 {{planned}} 次审查代理执行", - "parallelCalls": "无需再次确认时,最多可能执行 {{count}} 次审查代理。", + "callLimit": "检查上限:{{count}}。实际工作量取决于审核目标和发现的证据。", "runStrategy": "运行策略:{{strategy}}", "strategyLabels": { "quick": "聚焦", @@ -1063,8 +1062,8 @@ }, "strategySummaries": { "quick": "聚焦审核会检查当前目标最相关的风险。", - "normal": "标准审核会增加独立覆盖,同时保持成本合理。", - "deep": "全面审核会为高风险变更增加适用范围内最广的覆盖。" + "normal": "标准审核会更深入地检查当前目标,并在确有帮助时按需增加独立检查。", + "deep": "全面审核会检查所有适用的高风险领域,并在证据需要验证时按需增加检查。" }, "summaryTitle": "审核方案", "targetFiles": "{{count}} 个文件", @@ -1073,7 +1072,7 @@ "skippedReviewers": "{{count}} 个可选检查未纳入", "skippedReviewers_one": "{{count}} 个可选检查未纳入", "skippedReviewers_other": "{{count}} 个可选检查未纳入", - "skippedGroupTitle": "已选择 Review 范围", + "skippedGroupTitle": "已选择审核范围", "targetSource": { "manualPrompt": "给定内容", "workspaceDiff": "工作区改动", @@ -1682,8 +1681,8 @@ "collapseDetails": "收起详情", "expandDetails": "展开详情", "openInPanel": "在面板中打开详情", - "reviewCoverageLabel": "Review 检查", - "reviewCoverageDescription": "正在检查 Review 覆盖" + "reviewCoverageLabel": "审核检查", + "reviewCoverageDescription": "正在补充审核证据" }, "taskDetailPanel": { "untitled": "未命名任务", @@ -1709,7 +1708,7 @@ "loadingMore": "正在加载更多输出...", "loading": "正在加载任务详情...", "stopReviewWork": "停止此检查", - "stopReviewWorkHint": "仅取消这个检查项,整体 Review 仍可继续并生成摘要。" + "stopReviewWorkHint": "仅取消这个检查项,整体审核仍可继续并生成摘要。" }, "timeout": { "disableTooltip": "关闭超时限制", @@ -1969,7 +1968,7 @@ "runManifest": { "recommendedStrategy": "推荐策略", "riskRecommendationTitle": "风险推荐", - "reviewDepth": "Review 范围", + "reviewDepth": "审核范围", "reviewDepthLabels": { "high_risk_only": "聚焦", "risk_expanded": "扩展", @@ -1979,7 +1978,7 @@ "budget": "预算", "estimatedCalls": "预计审核检查", "activeGroupTitle": "已覆盖", - "skippedGroupTitle": "已选择 Review 范围", + "skippedGroupTitle": "已选择审核范围", "reducedCoverageSummary": "BitFun 已为此目标选择最相关的检查。{{count}} 个可选检查因适用性、配置或预算未纳入本次运行。", "reducedCoverageSummary_one": "BitFun 已为此目标选择最相关的检查。{{count}} 个可选检查因适用性、配置或预算未纳入本次运行。", "reducedCoverageSummary_other": "BitFun 已为此目标选择最相关的检查。{{count}} 个可选检查因适用性、配置或预算未纳入本次运行。" @@ -2013,8 +2012,8 @@ "detail": "{{count}} 个审核结果是部分结果,可信度有限。" }, "reduced_scope": { - "label": "聚焦 Review 范围", - "detail": "本次 Review 使用了聚焦范围配置。" + "label": "聚焦审核范围", + "detail": "本次审核使用了聚焦范围配置。" }, "target_evidence_limited": { "label": "目标证据受限", @@ -2025,7 +2024,7 @@ "detail": "{{count}} 条重试指引用于补足部分审核覆盖。" }, "skipped_reviewers": { - "label": "Review 范围已匹配", + "label": "审核范围已匹配", "detail": "{{count}} 个可选检查因适用性、配置或预算未纳入本次运行。" }, "token_budget_limited": { diff --git a/src/web-ui/src/locales/zh-CN/scenes/agents.json b/src/web-ui/src/locales/zh-CN/scenes/agents.json index be4d163d6a..eb8881441e 100644 --- a/src/web-ui/src/locales/zh-CN/scenes/agents.json +++ b/src/web-ui/src/locales/zh-CN/scenes/agents.json @@ -292,90 +292,39 @@ "createSuccess": "已创建 Agent「{{name}}」", "createFailed": "创建失败:", "review": "评审", - "reviewToolsHint": "Review 检查只能使用只读工具。" + "reviewToolsHint": "审核检查只能使用只读工具。" } }, "reviewTeams": { "members": { "worker": { - "funName": "动态审核员", - "role": "动态审核工作单元", - "description": "一个只读审核工作单元;其具体审核维度、问题和范围会根据当前变更动态确定,而不是固定在 Agent 身份中。", + "funName": "按需审核", + "role": "按需审核检查", + "description": "一项只读检查;只有在需要补充证据时,才会根据当前变更确定检查重点和范围。", "responsibilities": [ - "仅执行所属 Review Agent 指定的审核维度和问题。", - "严格限定在已准备的审核目标内,并返回有证据支持的发现和明确覆盖范围。", - "不得扩大权限、修改文件或重复主审核。" - ] - }, - "businessLogic": { - "funName": "逻辑审核员", - "role": "业务逻辑审核员", - "description": "专门追踪业务规则、状态流转、回滚路径和真实用户正确性的流程侦探。", - "responsibilities": [ - "验证业务流程、状态切换和领域规则是否仍然正确。", - "检查边界条件、回滚路径以及数据一致性假设。", - "优先指出会直接影响用户结果或产品意图的问题。" - ] - }, - "performance": { - "funName": "性能审核员", - "role": "性能审核员", - "description": "专盯热点路径、无效工作、阻塞调用和规模化回退问题的速度分析员。", - "responsibilities": [ - "检查热点路径、大循环以及不必要的分配或重复计算。", - "识别阻塞调用、N+1 模式和低效的数据搬运。", - "给出贴合现有架构、可落地的性能优化建议。" - ] - }, - "security": { - "funName": "安全审核员", - "role": "安全审核员", - "description": "专门盯住注入风险、信任边界、权限错误以及危险文件或命令处理的边界守卫。", - "responsibilities": [ - "审核信任边界、鉴权假设和敏感数据处理方式。", - "寻找注入、危险命令执行与数据暴露风险。", - "优先给出不依赖大改造的具体修复方案。" + "只检查主审核指定的问题。", + "不超出已确定的范围,并用具体证据说明结论。", + "不修改文件,也不重复主审核已经完成的工作。" ] }, "judge": { - "funName": "审核仲裁员", - "role": "审核质检员", - "description": "独立的第三方仲裁者,从逻辑一致性和证据质量角度校验审核员报告。仅在特定声明需要验证时才抽查代码位置,而非从头重新审核代码库。", - "responsibilities": [ - "基于逻辑一致性和证据质量,对各审核员的发现进行验证、合并、重新定级或驳回。", - "通过审核审核员的推理过程,过滤误报以及方向错误的优化建议。", - "仅在审核员的声明需要验证时,对特定代码位置进行抽查。", - "确保每条保留的问题都带有明确修复方案或后续计划。" - ] - }, - "architecture": { - "funName": "架构审核员", - "role": "架构审核员", - "description": "负责检查模块边界、依赖方向、API 契约设计和抽象完整性的结构守护者。", - "responsibilities": [ - "检测层级边界违规和方向错误的导入。", - "验证 API 契约、工具模式和传输消息的一致性。", - "确保平台无关代码不会泄露平台特定细节。" - ] - }, - "frontend": { - "funName": "前端审核员", - "role": "前端审核员", - "description": "检查国际化同步、前端性能模式、无障碍访问和前后端契约一致性的 UI 专家。", + "funName": "独立复核", + "role": "审核质量复核", + "description": "只在严重问题、证据冲突或结论明显不确定时启用的只读独立复核。", "responsibilities": [ - "验证所有语言区域的国际化键完整性。", - "检查前端性能模式(记忆化、虚拟化、effect/reactivity 依赖)。", - "标记无障碍访问违规和前后端 API 契约偏差。" + "根据具体证据确认或驳回有争议的发现。", + "只检查确实需要独立验证的结论。", + "确保每个保留的问题都有安全、可执行的下一步。" ] } }, "extraReviewer": { - "role": "额外专项审核员", - "description": "严格 Review 的可选专项覆盖,会带着自己的系统提示、工具和视角参与审核。", + "role": "额外审核检查", + "description": "用户可按具体关注点添加的独立检查。", "responsibilities": [ - "从额外的独立视角补充本次审核目标中的问题发现。", - "保持 scope 严格聚焦在本次 diff、commit 或工作区改动上。", - "输出清晰、可执行的修复建议或后续计划。" + "从额外的独立角度检查当前变更。", + "只检查用户指定的改动和文件。", + "提供有具体依据的问题、修复建议或后续步骤。" ] } }, @@ -387,7 +336,7 @@ "Explore": "探索智能体:快速浏览代码库,理解项目结构和关键文件", "FileFinder": "文件查找智能体:根据需求定位相关文件和代码片段", "CodeReview": "代码审查智能体:对代码进行质量检查和改进建议", - "DeepReview": "严格 Review 兼容智能体:在历史会话或命令需要时执行最高强度 Review 路径", + "DeepReview": "严格审核兼容模式:仅在历史会话或命令需要时执行最高强度的审核流程", "GenerateDoc": "文档生成智能体:自动生成代码文档和说明", "Init": "初始化智能体:帮助设置项目结构和初始配置", "ReviewFixer": "审查修复智能体:根据审查结果自动修复代码问题", diff --git a/src/web-ui/src/locales/zh-TW/flow-chat.json b/src/web-ui/src/locales/zh-TW/flow-chat.json index 6a123898e3..3c32e8c60c 100644 --- a/src/web-ui/src/locales/zh-TW/flow-chat.json +++ b/src/web-ui/src/locales/zh-TW/flow-chat.json @@ -928,7 +928,7 @@ "copyDiagnostics": "複製排障摘要", "diagnosticsCopied": "已複製排障摘要", "diagnosticsCopyFailed": "複製排障摘要失敗", - "diagnosticsTitle": "嚴格 Review 排障摘要", + "diagnosticsTitle": "嚴格審核疑難排解摘要", "diagnosticsErrorType": "錯誤類型", "diagnosticsDescription": "錯誤描述", "diagnosticsSuggestedActions": "建議操作", @@ -957,9 +957,9 @@ }, "resultRecovery": { "title": "嚴格審核需要補全結果", - "missingSubmitCodeReview": "審核已結束,但 BitFun 沒有收到可確認的結構化結果。繼續會保留已完成的審核工作,並要求 agent 補交缺失的審核報告。", - "invalidSubmitCodeReview": "審核回傳了 BitFun 無法讀取的結果。繼續會保留已完成的審核工作,並要求 agent 修復報告。", - "wrongReviewMode": "審核回傳了標準審核結果。繼續會保留已完成的審核工作,並要求 agent 提交嚴格審核報告。" + "missingSubmitCodeReview": "審核已結束,但 BitFun 沒有收到可確認的結構化結果。繼續會保留已完成的審核工作,並補交缺失的審核報告。", + "invalidSubmitCodeReview": "審核回傳了 BitFun 無法讀取的結果。繼續會保留已完成的審核工作,並修正報告。", + "wrongReviewMode": "審核回傳了標準審核結果。繼續會保留已完成的審核工作,並提交嚴格審核報告。" }, "capacityQueue": { "title": "審核正在等待容量", @@ -1001,7 +1001,7 @@ "cancelQueued": "取消等待中的審核", "skipOptionalQueued": "保留核心檢查", "openReviewSettings": "開啟審核設定", - "controlFailed": "目前無法控制這個 Review 項的容量。可使用停止來中斷 Review,或等待容量狀態刷新。", + "controlFailed": "目前無法控制這個審核項目的容量。可停止本次審核,或等待容量狀態更新。", "controlFailedWithReason": "容量控制失敗:{{reason}}。請重試,或在審核卡住時使用停止來中斷。", "controlPartiallyFailedWithReason": "容量控制已部分套用;{{total}} 個審核項中有 {{failed}} 個失敗:{{reason}}。請等待容量狀態刷新後重試,或在卡住時使用停止。" }, @@ -1041,20 +1041,19 @@ "deepReviewConsent": { "windowTitle": "審核方案", "eyebrow": "審核方案", - "title": "增加更廣的審核覆蓋?", - "body": "BitFun 為本次變更選擇了額外的獨立檢查。繼續前可確認目標範圍、計畫檢查、耗時傾向和唯讀邊界。", + "title": "開始本次審核?", + "body": "BitFun 會先直接審核本次變更,只在證據顯示有必要時增加獨立檢查。繼續前可確認目標範圍、審核預算、預計耗時與唯讀邊界。", "readonlyLabel": "唯讀", "readonly": "審核者不會修改檔案。", "sessionConcurrencyTitle": "目前會話較忙", "sessionConcurrencyBody": "目標會話已有 {{count}} 個審核工作在執行,繼續後將共享目前可用的審核容量。", - "costLabel": "覆蓋", - "cost": "計畫的審查代理執行;此處不估算底層模型請求或 Token。", + "costLabel": "審核預算", + "cost": "審核預算用於視需要執行的獨立檢查;實際呼叫次數和模型用量取決於審核中發現的證據。", "timeLabel": "耗時", "time": "背景執行,可能需要更久。", "cancel": "取消", "confirm": "開始審核", - "initialCalls": "獨立檢查:計畫 {{planned}} 次審查代理執行", - "parallelCalls": "無需再次確認時,最多可能執行 {{count}} 次審查代理。", + "callLimit": "檢查上限:{{count}}。實際工作量取決於審核目標和發現的證據。", "runStrategy": "運行策略:{{strategy}}", "strategyLabels": { "quick": "聚焦", @@ -1063,8 +1062,8 @@ }, "strategySummaries": { "quick": "聚焦審核會檢查目前目標最相關的風險。", - "normal": "標準審核會增加獨立覆蓋,同時保持成本合理。", - "deep": "全面審核會為高風險變更增加適用範圍內最廣的覆蓋。" + "normal": "標準審核會更深入檢查目前目標,並在確有幫助時增加獨立檢查。", + "deep": "全面審核會檢查所有適用的高風險領域,並在證據需要驗證時增加檢查。" }, "summaryTitle": "審核方案", "targetFiles": "{{count}} 個檔案", @@ -1073,7 +1072,7 @@ "skippedReviewers": "{{count}} 個可選檢查未納入", "skippedReviewers_one": "{{count}} 個可選檢查未納入", "skippedReviewers_other": "{{count}} 個可選檢查未納入", - "skippedGroupTitle": "已選擇 Review 範圍", + "skippedGroupTitle": "已選擇審核範圍", "targetSource": { "manualPrompt": "給定內容", "workspaceDiff": "工作區改動", @@ -1682,8 +1681,8 @@ "collapseDetails": "收起詳情", "expandDetails": "展開詳情", "openInPanel": "在面板中開啟詳情", - "reviewCoverageLabel": "Review 檢查", - "reviewCoverageDescription": "正在檢查 Review 覆蓋" + "reviewCoverageLabel": "審核檢查", + "reviewCoverageDescription": "正在補充審核證據" }, "taskDetailPanel": { "untitled": "未命名任務", @@ -1709,7 +1708,7 @@ "loadingMore": "正在載入更多輸出...", "loading": "正在載入任務詳情...", "stopReviewWork": "停止此檢查", - "stopReviewWorkHint": "僅取消這個檢查項,整體 Review 仍可繼續並產生摘要。" + "stopReviewWorkHint": "僅取消這個檢查項目,整體審核仍可繼續並產生摘要。" }, "timeout": { "disableTooltip": "關閉超時限制", @@ -1969,7 +1968,7 @@ "runManifest": { "recommendedStrategy": "推薦策略", "riskRecommendationTitle": "風險推薦", - "reviewDepth": "Review 範圍", + "reviewDepth": "審核範圍", "reviewDepthLabels": { "high_risk_only": "聚焦", "risk_expanded": "擴展", @@ -1979,7 +1978,7 @@ "budget": "預算", "estimatedCalls": "預計審核檢查", "activeGroupTitle": "已覆蓋", - "skippedGroupTitle": "已選擇 Review 範圍", + "skippedGroupTitle": "已選擇審核範圍", "reducedCoverageSummary": "BitFun 已為此目標選擇最相關的檢查。{{count}} 個可選檢查因適用性、設定或預算未納入本次執行。", "reducedCoverageSummary_one": "BitFun 已為此目標選擇最相關的檢查。{{count}} 個可選檢查因適用性、設定或預算未納入本次執行。", "reducedCoverageSummary_other": "BitFun 已為此目標選擇最相關的檢查。{{count}} 個可選檢查因適用性、設定或預算未納入本次執行。" @@ -2013,8 +2012,8 @@ "detail": "{{count}} 個審核結果是部分結果,可信度有限。" }, "reduced_scope": { - "label": "聚焦 Review 範圍", - "detail": "本次 Review 使用了聚焦範圍設定。" + "label": "聚焦審核範圍", + "detail": "本次審核使用了聚焦範圍設定。" }, "target_evidence_limited": { "label": "目標證據受限", @@ -2025,7 +2024,7 @@ "detail": "{{count}} 條重試指引用於補足部分審核覆蓋。" }, "skipped_reviewers": { - "label": "Review 範圍已匹配", + "label": "審核範圍已匹配", "detail": "{{count}} 個可選檢查因適用性、設定或預算未納入本次執行。" }, "token_budget_limited": { diff --git a/src/web-ui/src/locales/zh-TW/scenes/agents.json b/src/web-ui/src/locales/zh-TW/scenes/agents.json index 31de5245cb..afeedbce13 100644 --- a/src/web-ui/src/locales/zh-TW/scenes/agents.json +++ b/src/web-ui/src/locales/zh-TW/scenes/agents.json @@ -292,90 +292,39 @@ "createSuccess": "已建立 Agent「{{name}}」", "createFailed": "建立失敗:", "review": "審查", - "reviewToolsHint": "Review 檢查只能使用唯讀工具。" + "reviewToolsHint": "審核檢查只能使用唯讀工具。" } }, "reviewTeams": { "members": { "worker": { - "funName": "動態審核員", - "role": "動態審核工作單元", - "description": "一個唯讀審核工作單元;其具體審核維度、問題與範圍會依目前變更動態決定,而不是固定在 Agent 身分中。", + "funName": "視需要審核", + "role": "視需要審核檢查", + "description": "一項唯讀檢查;只有在需要補充證據時,才會依目前變更決定檢查重點與範圍。", "responsibilities": [ - "僅執行所屬 Review Agent 指定的審核維度與問題。", - "嚴格限定在已準備的審核目標內,並回傳有證據支持的發現與明確涵蓋範圍。", - "不得擴大權限、修改檔案或重複主要審核。" - ] - }, - "businessLogic": { - "funName": "邏輯審核員", - "role": "業務邏輯審核員", - "description": "專門追蹤業務規則、狀態流轉、回滾路徑和真實用戶正確性的流程偵探。", - "responsibilities": [ - "驗證業務流程、狀態切換和領域規則是否仍然正確。", - "檢查邊界條件、回滾路徑以及資料一致性假設。", - "優先指出會直接影響用戶結果或產品意圖的問題。" - ] - }, - "performance": { - "funName": "效能審核員", - "role": "性能審核員", - "description": "專盯熱點路徑、無效工作、阻塞調用和規模化回退問題的速度分析員。", - "responsibilities": [ - "檢查熱點路徑、大循環以及不必要的分配或重複計算。", - "識別阻塞調用、N+1 模式和低效的資料搬運。", - "給出貼合現有架構、可落地的性能優化建議。" - ] - }, - "security": { - "funName": "安全審核員", - "role": "安全審核員", - "description": "專門盯住注入風險、信任邊界、權限錯誤以及危險檔案或命令處理的邊界守衛。", - "responsibilities": [ - "審核信任邊界、鑑權假設和敏感資料處理方式。", - "尋找注入、危險命令執行與資料暴露風險。", - "優先給出不依賴大改造的具體修復方案。" + "只檢查主要審核指定的問題。", + "不超出已確定的範圍,並以具體證據說明結論。", + "不修改檔案,也不重複主要審核已完成的工作。" ] }, "judge": { - "funName": "審核仲裁員", - "role": "審核質檢員", - "description": "獨立的第三方仲裁者,從邏輯一致性和證據品質角度校驗審核員報告。僅在特定聲明需要驗證時才抽查程式碼位置,而非從頭重新審核程式碼庫。", - "responsibilities": [ - "基於邏輯一致性和證據品質,對各審核員的發現進行驗證、合併、重新定級或駁回。", - "透過審核審核員的推理過程,過濾誤報以及方向錯誤的優化建議。", - "僅在審核員的聲明需要驗證時,對特定程式碼位置進行抽查。", - "確保每條保留的問題都帶有明確修復方案或後續計劃。" - ] - }, - "architecture": { - "funName": "架構審核員", - "role": "架構審核員", - "description": "負責檢查模組邊界、依賴方向、API 契約設計和抽象完整性的結構守護者。", - "responsibilities": [ - "檢測層級邊界違規和方向錯誤的匯入。", - "驗證 API 契約、工具模式和傳輸訊息的一致性。", - "確保平台無關程式碼不會洩露平台特定細節。" - ] - }, - "frontend": { - "funName": "前端審核員", - "role": "前端審核員", - "description": "檢查國際化同步、前端效能模式、無障礙訪問和前後端契約一致性的 UI 專家。", + "funName": "獨立複核", + "role": "審核品質複核", + "description": "只在嚴重問題、證據衝突或結論明顯不確定時啟用的唯讀獨立複核。", "responsibilities": [ - "驗證所有語言區域的國際化鍵完整性。", - "檢查前端效能模式(記憶化、虛擬化、effect/reactivity 依賴)。", - "標記無障礙訪問違規和前後端 API 契約偏差。" + "根據具體證據確認或駁回有爭議的發現。", + "只檢查確實需要獨立驗證的結論。", + "確保每個保留的問題都有安全、可執行的下一步。" ] } }, "extraReviewer": { - "role": "額外專項審核員", - "description": "嚴格 Review 的可選專項覆蓋,會帶著自己的系統提示、工具和視角參與審核。", + "role": "額外審核檢查", + "description": "使用者可依具體關注點新增的獨立檢查。", "responsibilities": [ - "從額外的獨立視角補充本次審核目標中的問題發現。", - "保持 scope 嚴格聚焦在本次 diff、commit 或工作區改動中。", - "輸出清晰、可執行的修復建議或後續計劃。" + "從額外的獨立角度檢查目前變更。", + "只檢查使用者指定的變更和檔案。", + "提供有具體依據的問題、修正建議或後續步驟。" ] } }, @@ -387,7 +336,7 @@ "Explore": "探索智慧體:快速瀏覽程式碼庫,理解專案結構和關鍵檔案", "FileFinder": "檔案查找智慧體:根據需求定位相關檔案和程式碼片段", "CodeReview": "程式碼審查智慧體:對程式碼進行品質檢查和改進建議", - "DeepReview": "嚴格 Review 相容智慧體:在歷史會話或命令需要時執行最高強度 Review 路徑", + "DeepReview": "嚴格審核相容模式:僅在歷史會話或命令需要時執行最高強度的審核流程", "GenerateDoc": "檔案生成智慧體:自動生成程式碼檔案和說明", "Init": "初始化智慧體:幫助設定專案結構和初始設定", "ReviewFixer": "審查修復智慧體:根據審查結果自動修復程式碼問題", diff --git a/src/web-ui/src/shared/services/review-team/defaults.ts b/src/web-ui/src/shared/services/review-team/defaults.ts index 2845de7773..35ebbe85b1 100644 --- a/src/web-ui/src/shared/services/review-team/defaults.ts +++ b/src/web-ui/src/shared/services/review-team/defaults.ts @@ -91,13 +91,12 @@ export const PREDICTIVE_TIMEOUT_BASE_SECONDS: Record { expect(packets).toHaveLength(4); expect(packets.every((packet) => packet.subagentId === 'ReviewWorker')).toBe(true); + expect( + packets.every((packet) => packet.roleName === 'Dynamic Review Worker'), + ).toBe(true); expect(packets.every((packet) => packet.assignedScope.files.length <= 40)).toBe(true); expect(packets.map((packet) => packet.launchBatch)).toEqual([1, 1, 2, 2]); expect(packets.map((packet) => packet.packetId)).toEqual([ diff --git a/src/web-ui/src/shared/services/reviewTeamLocaleCompleteness.test.ts b/src/web-ui/src/shared/services/reviewTeamLocaleCompleteness.test.ts index 9a6769ad13..749ac21d2a 100644 --- a/src/web-ui/src/shared/services/reviewTeamLocaleCompleteness.test.ts +++ b/src/web-ui/src/shared/services/reviewTeamLocaleCompleteness.test.ts @@ -1,9 +1,35 @@ import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; +import { UI_EXCEPTION_ACCENTS } from '@/shared/theme/uiExceptionAccents'; import { FALLBACK_REVIEW_TEAM_DEFINITION } from './reviewTeamService'; +import { EXTRA_MEMBER_DEFAULTS } from './review-team/defaults'; const REVIEW_TEAM_LOCALES = ['en-US', 'zh-CN', 'zh-TW'] as const; +const CHINESE_REVIEW_LOCALES = ['zh-CN', 'zh-TW'] as const; + +const PLAIN_CHINESE_REVIEW_COPY_PATHS = { + flowChat: [ + 'deepReviewActionBar.diagnosticsTitle', + 'deepReviewActionBar.resultRecovery.missingSubmitCodeReview', + 'deepReviewActionBar.resultRecovery.invalidSubmitCodeReview', + 'deepReviewActionBar.resultRecovery.wrongReviewMode', + 'deepReviewActionBar.capacityQueue.controlFailed', + 'deepReviewConsent.skippedGroupTitle', + 'toolCards.taskTool.reviewCoverageLabel', + 'toolCards.taskTool.reviewCoverageDescription', + 'toolCards.taskDetailPanel.stopReviewWorkHint', + 'toolCards.codeReview.runManifest.reviewDepth', + 'toolCards.codeReview.runManifest.skippedGroupTitle', + 'toolCards.codeReview.reliabilityStatus.reduced_scope.label', + 'toolCards.codeReview.reliabilityStatus.reduced_scope.detail', + 'toolCards.codeReview.reliabilityStatus.skipped_reviewers.label', + ], + scenesAgents: [ + 'agentsOverview.form.reviewToolsHint', + 'agentDescriptions.DeepReview', + ], +} as const; type Locale = (typeof REVIEW_TEAM_LOCALES)[number]; type JsonObject = Record; @@ -14,6 +40,9 @@ const REVIEW_TEAM_FLOW_CHAT_KEYS = [ 'deepReviewConsent.strategyLabels.quick', 'deepReviewConsent.strategyLabels.normal', 'deepReviewConsent.strategyLabels.deep', + 'deepReviewConsent.callLimit', + 'toolCards.taskTool.reviewCoverageLabel', + 'toolCards.taskTool.reviewCoverageDescription', 'toolCards.codeReview.runManifest.recommendedStrategy', 'toolCards.codeReview.runManifest.riskRecommendationTitle', 'toolCards.codeReview.runManifest.reviewDepth', @@ -27,6 +56,43 @@ const REVIEW_TEAM_FLOW_CHAT_KEYS = [ 'toolCards.codeReview.reliabilityStatus.target_evidence_limited.detail', ] as const; +const REVIEW_COPY_EXPECTATIONS: Record< + Locale, + { + conditionalJudgeMarker: string; + dynamicConsentMarkers: string[]; + extraReviewRole: string; + forbiddenConsentPhrases: string[]; + reviewConsentTitle: string; + reviewBudgetLabel: string; + } +> = { + 'en-US': { + conditionalJudgeMarker: 'only when', + dynamicConsentMarkers: ['may add', 'review budget'], + extraReviewRole: 'Additional Review Check', + forbiddenConsentPhrases: ['selected additional independent checks', 'review agent run'], + reviewConsentTitle: 'Start this review?', + reviewBudgetLabel: 'Review budget', + }, + 'zh-CN': { + conditionalJudgeMarker: '只在', + dynamicConsentMarkers: ['按需', '审核预算'], + extraReviewRole: '额外审核检查', + forbiddenConsentPhrases: ['选择了额外的独立检查', '审查代理'], + reviewConsentTitle: '开始本次审核?', + reviewBudgetLabel: '审核预算', + }, + 'zh-TW': { + conditionalJudgeMarker: '只在', + dynamicConsentMarkers: ['視需要', '審核預算'], + extraReviewRole: '額外審核檢查', + forbiddenConsentPhrases: ['選擇了額外的獨立檢查', '審查代理'], + reviewConsentTitle: '開始本次審核?', + reviewBudgetLabel: '審核預算', + }, +}; + function readLocaleJson( locale: Locale, namespace: 'flow-chat.json' | 'scenes/agents.json' | 'settings/review.json', @@ -55,6 +121,12 @@ describe('review team locale completeness', () => { 'keeps core review role details translated in %s agents namespace', (locale) => { const scenesAgents = readLocaleJson(locale, 'scenes/agents.json'); + const members = getPathValue(scenesAgents, 'reviewTeams.members') as JsonObject; + const expectedMemberKeys = FALLBACK_REVIEW_TEAM_DEFINITION.coreRoles + .map((role) => role.key) + .sort(); + + expect(Object.keys(members).sort()).toEqual(expectedMemberKeys); for (const role of FALLBACK_REVIEW_TEAM_DEFINITION.coreRoles) { expectNonEmptyLocaleString(scenesAgents, `reviewTeams.members.${role.key}.funName`); @@ -67,7 +139,33 @@ describe('review team locale completeness', () => { `reviewTeams.members.${role.key}.responsibilities.${index}`, ); }); + + const translatedResponsibilities = getPathValue( + scenesAgents, + `reviewTeams.members.${role.key}.responsibilities`, + ); + expect(translatedResponsibilities).toHaveLength(role.responsibilities.length); } + + expect( + getPathValue(scenesAgents, 'reviewTeams.members.judge.description'), + ).toContain(REVIEW_COPY_EXPECTATIONS[locale].conditionalJudgeMarker); + expect(getPathValue(scenesAgents, 'reviewTeams.extraReviewer.role')).toBe( + REVIEW_COPY_EXPECTATIONS[locale].extraReviewRole, + ); + expectNonEmptyLocaleString( + scenesAgents, + 'reviewTeams.extraReviewer.description', + ); + EXTRA_MEMBER_DEFAULTS.responsibilities.forEach((_, index) => { + expectNonEmptyLocaleString( + scenesAgents, + `reviewTeams.extraReviewer.responsibilities.${index}`, + ); + }); + expect( + getPathValue(scenesAgents, 'reviewTeams.extraReviewer.responsibilities'), + ).toHaveLength(EXTRA_MEMBER_DEFAULTS.responsibilities.length); }, ); @@ -81,4 +179,90 @@ describe('review team locale completeness', () => { } }, ); + + it.each(REVIEW_TEAM_LOCALES)( + 'describes optional dynamic review work without implying a fixed plan in %s', + (locale) => { + const flowChat = readLocaleJson(locale, 'flow-chat.json'); + const consentCopy = [ + 'deepReviewConsent.body', + 'deepReviewConsent.cost', + 'deepReviewConsent.callLimit', + 'deepReviewConsent.strategySummaries.normal', + 'deepReviewConsent.strategySummaries.deep', + ].map((path) => String(getPathValue(flowChat, path) ?? '')).join('\n'); + const expectation = REVIEW_COPY_EXPECTATIONS[locale]; + + expect(getPathValue(flowChat, 'deepReviewConsent.title')).toBe( + expectation.reviewConsentTitle, + ); + expect(getPathValue(flowChat, 'deepReviewConsent.costLabel')).toBe( + expectation.reviewBudgetLabel, + ); + for (const marker of expectation.dynamicConsentMarkers) { + expect(consentCopy).toContain(marker); + } + for (const phrase of expectation.forbiddenConsentPhrases) { + expect(consentCopy).not.toContain(phrase); + } + }, + ); + + it('keeps review accent semantics limited to active generic roles', () => { + expect(Object.keys(UI_EXCEPTION_ACCENTS.reviewTeam).sort()).toEqual([ + 'judge', + 'memberDefault', + 'worker', + ]); + }); + + it.each(CHINESE_REVIEW_LOCALES)( + 'keeps user-facing review copy free of internal English terms in %s', + (locale) => { + const flowChat = readLocaleJson(locale, 'flow-chat.json'); + const scenesAgents = readLocaleJson(locale, 'scenes/agents.json'); + const visibleCopy = [ + ...PLAIN_CHINESE_REVIEW_COPY_PATHS.flowChat.map( + (path) => String(getPathValue(flowChat, path) ?? ''), + ), + ...PLAIN_CHINESE_REVIEW_COPY_PATHS.scenesAgents.map( + (path) => String(getPathValue(scenesAgents, path) ?? ''), + ), + ].join('\n'); + + expect(visibleCopy).not.toMatch(/\b(Review|agent|scope)\b/i); + }, + ); + + it('keeps fallback review copy readable and free of implementation role terms', () => { + const worker = FALLBACK_REVIEW_TEAM_DEFINITION.coreRoles.find( + (role) => role.key === 'worker', + ); + const judge = FALLBACK_REVIEW_TEAM_DEFINITION.coreRoles.find( + (role) => role.key === 'judge', + ); + + expect(worker).toMatchObject({ + funName: 'Focused Review', + roleName: 'On-demand Review Check', + }); + expect(judge).toMatchObject({ + funName: 'Independent Review Check', + roleName: 'Review Quality Check', + }); + expect(FALLBACK_REVIEW_TEAM_DEFINITION.description).toBe( + 'One main review that can request focused independent checks when more evidence is needed.', + ); + expect(EXTRA_MEMBER_DEFAULTS.roleName).toBe('Additional Review Check'); + + const userFacingCopy = [ + worker?.description, + judge?.description, + EXTRA_MEMBER_DEFAULTS.description, + ...Object.values(FALLBACK_REVIEW_TEAM_DEFINITION.strategyProfiles) + .map((profile) => profile.summary), + ].join('\n'); + expect(userFacingCopy).not.toMatch(/\b(worker|lens|specialist|inspector)\b/i); + expect(userFacingCopy).not.toMatch(/\bone (optional|justified|narrowly focused)\b/i); + }); }); diff --git a/src/web-ui/src/shared/services/reviewTeamService.test.ts b/src/web-ui/src/shared/services/reviewTeamService.test.ts index 920cba11e0..fef7fe0745 100644 --- a/src/web-ui/src/shared/services/reviewTeamService.test.ts +++ b/src/web-ui/src/shared/services/reviewTeamService.test.ts @@ -479,7 +479,7 @@ describe('reviewTeamService', () => { await expect(loadDefaultReviewTeamDefinition()).resolves.toMatchObject({ name: 'Code Review', description: - 'One primary review with an optional dynamically scoped worker and conditional quality inspection.', + 'One main review that can request focused independent checks when more evidence is needed.', coreRoles: [ expect.objectContaining({ subagentId: 'ReviewWorker', accentColor: '#3b82f6' }), expect.objectContaining({ subagentId: 'ReviewJudge', accentColor: '#8b5cf6' }), diff --git a/src/web-ui/src/shared/theme/uiExceptionAccents.ts b/src/web-ui/src/shared/theme/uiExceptionAccents.ts index 7160876a62..e986cf31e1 100644 --- a/src/web-ui/src/shared/theme/uiExceptionAccents.ts +++ b/src/web-ui/src/shared/theme/uiExceptionAccents.ts @@ -59,11 +59,7 @@ export const UI_EXCEPTION_ACCENTS = { }, reviewTeam: { memberDefault: EXCEPTION_ACCENT.neutral, - businessLogic: EXCEPTION_ACCENT.primary, - performance: EXCEPTION_ACCENT.warning, - security: EXCEPTION_ACCENT.error, - architecture: EXCEPTION_ACCENT.info, - frontend: EXCEPTION_ACCENT.success, + worker: EXCEPTION_ACCENT.primary, judge: EXCEPTION_ACCENT.secondary, }, tealAction: EXCEPTION_ACCENT.teal,