Skip to content

Commit 8f3e538

Browse files
committed
feat(codereview): prioritize error files and improve patch UI #463
Add explicit error-first priority rules to code review prompts and lint output. Update UI to disable patch actions while fixes are still generating, ensuring only complete patches can be applied or rejected.
1 parent 3a2debe commit 8f3e538

File tree

3 files changed

+352
-155
lines changed

3 files changed

+352
-155
lines changed

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/CodeReviewAgentPromptRenderer.kt

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -132,52 +132,81 @@ $result
132132
"No changed code blocks available."
133133
}
134134

135-
// Format lint results - only for files in changedHunks
135+
// Format lint results - only for files in changedHunks, with priority separation
136136
val relevantFiles = changedHunks.keys
137-
val formattedLintResults = if (lintResults.isNotEmpty()) {
138-
lintResults
139-
.filter { it.filePath in relevantFiles }
140-
.mapNotNull { fileResult ->
141-
if (fileResult.issues.isNotEmpty()) {
137+
val relevantLintResults = lintResults.filter { it.filePath in relevantFiles }
138+
139+
// Separate files by priority: Error files vs Warning-only files
140+
val filesWithErrors = relevantLintResults.filter { it.errorCount > 0 }.sortedByDescending { it.errorCount }
141+
val filesWithWarningsOnly = relevantLintResults.filter { it.errorCount == 0 && it.warningCount > 0 }
142+
143+
val formattedLintResults = if (relevantLintResults.isNotEmpty()) {
144+
buildString {
145+
// Section 1: Files with ERRORS (🚨 CRITICAL PRIORITY)
146+
if (filesWithErrors.isNotEmpty()) {
147+
appendLine("## 🚨 CRITICAL PRIORITY - Files with Errors (MUST FIX FIRST)")
148+
appendLine()
149+
appendLine("**${filesWithErrors.size} file(s) with compilation/lint errors:**")
150+
appendLine()
151+
152+
filesWithErrors.forEach { fileResult ->
142153
val totalCount = fileResult.errorCount + fileResult.warningCount + fileResult.infoCount
143-
buildString {
144-
appendLine("### ${fileResult.filePath}")
145-
appendLine("Total Issues: $totalCount (${fileResult.errorCount} errors, ${fileResult.warningCount} warnings)")
146-
appendLine()
154+
appendLine("### ❌ ${fileResult.filePath}")
155+
appendLine("**Priority: CRITICAL** - ${fileResult.errorCount} error(s), ${fileResult.warningCount} warning(s)")
156+
appendLine()
147157

148-
val critical = fileResult.issues.filter { it.severity == LintSeverity.ERROR }
149-
val warnings = fileResult.issues.filter { it.severity == LintSeverity.WARNING }
150-
151-
if (critical.isNotEmpty()) {
152-
appendLine("**Critical Issues:**")
153-
critical.forEach { issue ->
154-
appendLine("- Line ${issue.line}: ${issue.message}")
155-
val ruleText = issue.rule
156-
if (ruleText != null && ruleText.isNotBlank()) {
157-
appendLine(" Rule: $ruleText")
158-
}
158+
val critical = fileResult.issues.filter { it.severity == LintSeverity.ERROR }
159+
if (critical.isNotEmpty()) {
160+
appendLine("**🔴 ERRORS (Fix Required):**")
161+
critical.forEach { issue ->
162+
appendLine("- Line ${issue.line}: ${issue.message}")
163+
val ruleText = issue.rule
164+
if (ruleText != null && ruleText.isNotBlank()) {
165+
appendLine(" Rule: `$ruleText`")
159166
}
160-
appendLine()
161167
}
168+
appendLine()
169+
}
162170

163-
if (warnings.isNotEmpty()) {
164-
appendLine("**Warnings:**")
165-
warnings.take(5).forEach { issue ->
166-
appendLine("- Line ${issue.line}: ${issue.message}")
167-
val ruleText = issue.rule
168-
if (ruleText != null && ruleText.isNotBlank()) {
169-
appendLine(" Rule: $ruleText")
170-
}
171-
}
172-
if (warnings.size > 5) {
173-
appendLine("... and ${warnings.size - 5} more warnings")
174-
}
171+
val warnings = fileResult.issues.filter { it.severity == LintSeverity.WARNING }
172+
if (warnings.isNotEmpty()) {
173+
appendLine("**⚠️ Warnings (Fix if related to errors):**")
174+
warnings.take(3).forEach { issue ->
175+
appendLine("- Line ${issue.line}: ${issue.message}")
175176
}
177+
if (warnings.size > 3) {
178+
appendLine("... and ${warnings.size - 3} more warnings")
179+
}
180+
appendLine()
181+
}
182+
}
183+
appendLine("---")
184+
appendLine()
185+
}
186+
187+
// Section 2: Files with WARNINGS only (Lower priority)
188+
if (filesWithWarningsOnly.isNotEmpty()) {
189+
appendLine("## ⚠️ LOWER PRIORITY - Files with Warnings Only")
190+
appendLine()
191+
appendLine("**${filesWithWarningsOnly.size} file(s) with warnings (optional fixes):**")
192+
appendLine()
193+
194+
filesWithWarningsOnly.forEach { fileResult ->
195+
appendLine("### ${fileResult.filePath}")
196+
appendLine("${fileResult.warningCount} warning(s) - Fix these only after addressing all errors")
197+
appendLine()
198+
199+
val warnings = fileResult.issues.filter { it.severity == LintSeverity.WARNING }
200+
warnings.take(3).forEach { issue ->
201+
appendLine("- Line ${issue.line}: ${issue.message}")
202+
}
203+
if (warnings.size > 3) {
204+
appendLine("... and ${warnings.size - 3} more warnings")
176205
}
177-
} else {
178-
null
206+
appendLine()
179207
}
180-
}.joinToString("\n\n")
208+
}
209+
}
181210
} else {
182211
"No lint issues found."
183212
}

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/CodeReviewAgentTemplate.kt

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -340,18 +340,31 @@ object FixGenerationTemplate {
340340
341341
Generate **unified diff patches** for the critical issues identified in the analysis.
342342
343+
## 🚨 PRIORITY RULES
344+
345+
**ABSOLUTE PRIORITY: Fix files with ERRORS first!**
346+
347+
1. **🔴 ERRORS (CRITICAL)** - Files with compilation/lint errors MUST be fixed first
348+
- These will break the build or cause runtime failures
349+
- Fix ALL errors in a file before moving to warnings
350+
351+
2. **⚠️ WARNINGS (LOWER PRIORITY)** - Only fix after all errors are resolved
352+
- These are best practices or potential issues
353+
- Can be skipped if time/complexity is high
354+
343355
## Important Constraints
344356
345357
1. **ONE PATCH PER FILE** - If a file has multiple issues, combine all fixes into a single unified diff
346358
2. **Only fix changed code** - Focus ONLY on the code blocks shown below (user's changes)
347-
3. **Maximum 5 files** - Prioritize the most critical issues
359+
3. **Maximum 5 files** - Start with error files, then warnings if space permits
348360
4. **Use exact line numbers** - Line numbers must match the code blocks provided
361+
5. **ERRORS FIRST** - Always prioritize files marked with 🚨 CRITICAL PRIORITY
349362
350363
## Changed Code Blocks (User's Changes)
351364
352365
${'$'}{changedCode}
353366
354-
## Lint Issues (Filtered to changed files)
367+
## Lint Issues (Prioritized by Severity)
355368
356369
${'$'}{lintResults}
357370
@@ -361,11 +374,18 @@ ${'$'}{analysisOutput}
361374
362375
## Your Task
363376
377+
**Step 1: Identify priority files**
378+
- Look for files marked with "🚨 CRITICAL PRIORITY" or "❌" (errors)
379+
- These MUST be fixed first
380+
381+
**Step 2: Generate fixes in priority order**
382+
364383
For each file that needs fixes:
365384
366385
1. Identify all issues in that file from the analysis
367386
2. **Combine** all fixes for that file into **ONE** unified diff patch
368387
3. Ensure the patch applies cleanly to the changed code blocks above
388+
4. Start with ERROR files, then WARNING files if you have remaining slots
369389
370390
### Required Format:
371391
@@ -419,39 +439,64 @@ index abc1234..def5678 100644
419439
420440
### Guidelines:
421441
422-
1. **ONE unified diff per file** - Combine multiple fixes for the same file
423-
2. **Use standard unified diff format** - Must be parseable by standard diff tools
424-
3. **Include context lines** - Show 3 lines of context before and after changes
425-
4. **Accurate line numbers** - Ensure @@ headers have correct line numbers
426-
5. **Complete hunks** - Each hunk should be self-contained and applicable
427-
6. **Priority order** - Start with critical/high severity issues
428-
7. **Maximum 5 files** - Focus on the most important fixes
442+
1. **🚨 ERROR FILES FIRST** - Always fix files with errors before warnings
443+
2. **ONE unified diff per file** - Combine multiple fixes for the same file
444+
3. **Use standard unified diff format** - Must be parseable by standard diff tools
445+
4. **Include context lines** - Show 3 lines of context before and after changes
446+
5. **Accurate line numbers** - Ensure @@ headers have correct line numbers
447+
6. **Complete hunks** - Each hunk should be self-contained and applicable
448+
7. **Maximum 5 files** - Prioritize error files, then warnings if space permits
429449
430450
**CRITICAL RULES**:
451+
- 🔴 **ERRORS FIRST** - Files with errors have absolute priority
431452
- ✅ ONE unified diff per file (combine multiple fixes)
432453
- ✅ Only modify code in the "Changed Code Blocks" section
433454
- ✅ Include 3 lines of context before/after each change
455+
- ⚠️ Warnings can be skipped if all 5 slots are used by error fixes
434456
- ❌ DO NOT use any tools
435457
- ❌ DO NOT generate multiple patches for the same file
458+
459+
**Example Priority:**
460+
```
461+
Fix order:
462+
1. file_with_2_errors.kt (🔴 CRITICAL)
463+
2. file_with_1_error.kt (🔴 CRITICAL)
464+
3. file_with_error_and_warnings.kt (🔴 CRITICAL)
465+
4. file_with_warnings_only.kt (⚠️ Lower priority)
466+
5. another_warnings_file.kt (⚠️ Lower priority)
467+
```
436468
""".trimIndent()
437469

438470
val ZH = """
439471
# 代码修复生成 - 统一差异格式
440472
441473
为分析中识别的关键问题生成 **统一差异补丁**。
442474
475+
## 🚨 优先级规则
476+
477+
**绝对优先:先修复有 ERROR 的文件!**
478+
479+
1. **🔴 ERRORS(关键)** - 有编译/lint 错误的文件必须优先修复
480+
- 这些会导致构建失败或运行时错误
481+
- 先修复文件中的所有错误,再考虑警告
482+
483+
2. **⚠️ WARNINGS(较低优先级)** - 只在所有错误解决后修复
484+
- 这些是最佳实践或潜在问题
485+
- 如果时间/复杂度高可以跳过
486+
443487
## 重要约束
444488
445489
1. **每个文件一个补丁** - 如果一个文件有多个问题,将所有修复合并到一个统一差异中
446490
2. **只修复改动的代码** - 只关注下面显示的代码块(用户的改动)
447-
3. **最多 5 个文件** - 优先处理最关键的问题
491+
3. **最多 5 个文件** - 从错误文件开始,如果有空间再修复警告
448492
4. **使用精确的行号** - 行号必须与提供的代码块匹配
493+
5. **错误优先** - 始终优先处理标记为 🚨 关键优先级的文件
449494
450495
## 改动的代码块(用户的改动)
451496
452497
${'$'}{changedCode}
453498
454-
## Lint 问题(已过滤到改动的文件
499+
## Lint 问题(按严重性优先级排序
455500
456501
${'$'}{lintResults}
457502
@@ -461,11 +506,18 @@ ${'$'}{analysisOutput}
461506
462507
## 你的任务
463508
509+
**步骤 1:识别优先级文件**
510+
- 查找标记为"🚨 关键优先级"或"❌"(错误)的文件
511+
- 这些必须优先修复
512+
513+
**步骤 2:按优先级顺序生成修复**
514+
464515
对于每个需要修复的文件:
465516
466517
1. 从分析中识别该文件的所有问题
467518
2. **合并**该文件的所有修复到**一个**统一差异补丁中
468519
3. 确保补丁可以干净地应用到上面的改动代码块
520+
4. 从 ERROR 文件开始,如果还有剩余位置再处理 WARNING 文件
469521
470522
### 必需格式:
471523
@@ -519,19 +571,31 @@ index abc1234..def5678 100644
519571
520572
### 指南:
521573
522-
1. **每个文件一个统一差异** - 合并同一文件的多个修复
523-
2. **使用标准统一差异格式** - 必须可被标准差异工具解析
524-
3. **包含上下文行** - 在更改前后显示 3 行上下文
525-
4. **准确的行号** - 确保 @@ 头部有正确的行号
526-
5. **完整的块** - 每个块应该是独立的且可应用的
527-
6. **优先级顺序** - 从关键/高严重性问题开始
528-
7. **最多 5 个文件** - 专注于最重要的修复
574+
1. **🚨 错误文件优先** - 始终先修复有错误的文件,再修复警告
575+
2. **每个文件一个统一差异** - 合并同一文件的多个修复
576+
3. **使用标准统一差异格式** - 必须可被标准差异工具解析
577+
4. **包含上下文行** - 在更改前后显示 3 行上下文
578+
5. **准确的行号** - 确保 @@ 头部有正确的行号
579+
6. **完整的块** - 每个块应该是独立的且可应用的
580+
7. **最多 5 个文件** - 优先错误文件,如果有空间再处理警告
529581
530582
**关键规则**:
583+
- 🔴 **错误优先** - 有错误的文件拥有绝对优先级
531584
- ✅ 每个文件一个统一差异(合并多个修复)
532585
- ✅ 只修改"改动的代码块"部分中的代码
533586
- ✅ 在每个更改前后包含 3 行上下文
587+
- ⚠️ 如果所有 5 个位置都被错误修复占用,警告可以跳过
534588
- ❌ 不要使用任何工具
535589
- ❌ 不要为同一文件生成多个补丁
590+
591+
**优先级示例:**
592+
```
593+
修复顺序:
594+
1. file_with_2_errors.kt (🔴 关键)
595+
2. file_with_1_error.kt (🔴 关键)
596+
3. file_with_error_and_warnings.kt (🔴 关键)
597+
4. file_with_warnings_only.kt (⚠️ 较低优先级)
598+
5. another_warnings_file.kt (⚠️ 较低优先级)
599+
```
536600
""".trimIndent()
537601
}

0 commit comments

Comments
 (0)