Skip to content

Commit 0d1eae1

Browse files
committed
feat(plan): add plan review functionality and scrollable UI
#259 - Add plan review functionality with LLM integration for plan evaluation. - Introduce scrollable UI for plan display in PlanSketch. - Update plan template file extensions from `.devin` to `.vm`. - Add new plan reviewer templates in both English and Chinese.
1 parent 934a985 commit 0d1eae1

File tree

8 files changed

+175
-7
lines changed

8 files changed

+175
-7
lines changed

core/src/main/kotlin/cc/unitmesh/devti/observer/agent/AgentStateService.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import cc.unitmesh.devti.agent.tool.AgentTool
44
import cc.unitmesh.devti.devin.dataprovider.BuiltinCommand
55
import cc.unitmesh.devti.llms.custom.Message
66
import cc.unitmesh.devti.observer.plan.AgentTaskEntry
7+
import cc.unitmesh.devti.observer.plan.MarkdownPlanParser
78
import cc.unitmesh.devti.observer.plan.PlanUpdateListener
89
import com.intellij.openapi.application.ApplicationManager
910
import com.intellij.openapi.components.Service
@@ -58,6 +59,11 @@ class AgentStateService {
5859
.onPlanUpdate(items)
5960
}
6061

62+
fun updatePlan(content: String) {
63+
val planItems = MarkdownPlanParser.parse(content)
64+
updatePlan(planItems.toMutableList())
65+
}
66+
6167
fun resetState() {
6268
state = AgentState()
6369
ApplicationManager.getApplication().messageBus

core/src/main/kotlin/cc/unitmesh/devti/observer/plan/PlanReviewAction.kt

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
// filepath: /Volumes/source/ai/autocrud/core/src/main/kotlin/cc/unitmesh/devti/observer/plan/PlanReviewAction.kt
22
package cc.unitmesh.devti.observer.plan
33

4+
import cc.unitmesh.devti.AutoDevNotifications
5+
import cc.unitmesh.devti.llms.LlmFactory
46
import cc.unitmesh.devti.observer.agent.AgentStateService
7+
import cc.unitmesh.devti.statusbar.AutoDevStatus
8+
import cc.unitmesh.devti.statusbar.AutoDevStatusService
9+
import cc.unitmesh.devti.template.GENIUS_CODE
10+
import cc.unitmesh.devti.template.TemplateRender
11+
import cc.unitmesh.devti.util.AutoDevCoroutineScope
12+
import cc.unitmesh.devti.util.parser.CodeFence
13+
import com.intellij.execution.ui.ConsoleViewContentType
514
import com.intellij.openapi.actionSystem.ActionUpdateThread
615
import com.intellij.openapi.actionSystem.AnAction
716
import com.intellij.openapi.actionSystem.AnActionEvent
8-
import org.intellij.markdown.IElementType
17+
import kotlinx.coroutines.launch
18+
import kotlinx.coroutines.runBlocking
919
import org.intellij.markdown.MarkdownElementTypes
1020
import org.intellij.markdown.ast.ASTNode
1121
import org.intellij.markdown.ast.accept
@@ -22,12 +32,40 @@ class PlanReviewAction : AnAction() {
2232
val agentStateService = project.getService(AgentStateService::class.java)
2333

2434
val currentPlan = agentStateService.getPlan()
35+
val issue = agentStateService.buildOriginIntention() ?: ""
2536
val plan = MarkdownPlanParser.formatPlanToMarkdown(currentPlan)
2637

27-
/// call llm to evaluate the plan
2838
val allMessages = agentStateService.getAllMessages()
29-
val withOutCode = allMessages.map {
30-
removeAllMarkdownCode(it.content)
39+
val withoutCodeMsgs = allMessages.map {
40+
it.copy(role = it.role, content = removeAllMarkdownCode(it.content))
41+
}
42+
43+
val templateRender = TemplateRender(GENIUS_CODE)
44+
val systemPrompt = templateRender.getTemplate("plan-reviewer.vm")
45+
val history = withoutCodeMsgs.joinToString {
46+
"# Role ${it.role}\nMessage:\n${it.content}"
47+
}
48+
49+
val stream = LlmFactory.create(project).stream(history, systemPrompt)
50+
AutoDevCoroutineScope.scope(project).launch {
51+
val llmResult = StringBuilder()
52+
AutoDevStatusService.notifyApplication(AutoDevStatus.InProgress, "review the plan")
53+
runBlocking {
54+
stream.collect {
55+
llmResult.append(it)
56+
}
57+
}
58+
59+
val result = llmResult.toString()
60+
AutoDevStatusService.notifyApplication(AutoDevStatus.Done, "review the plan")
61+
AutoDevNotifications.notify(project, result)
62+
val plan = CodeFence.parseAll(result).firstOrNull {
63+
it.originLanguage == "plan"
64+
}
65+
66+
if (plan !== null) {
67+
agentStateService.updatePlan(result)
68+
}
3169
}
3270
}
3371
}
@@ -68,7 +106,7 @@ fun removeAllMarkdownCode(markdownContent: String): String {
68106
private fun extractCodeFenceLanguage(node: ASTNode, markdownContent: String): String {
69107
val nodeText = node.getTextInNode(markdownContent).toString()
70108
val firstLine = nodeText.lines().firstOrNull() ?: ""
71-
109+
72110
val languageMatch = Regex("^```(.*)$").find(firstLine.trim())
73111
return languageMatch?.groupValues?.getOrNull(1)?.trim() ?: ""
74112
}

core/src/main/kotlin/cc/unitmesh/devti/sketch/SketchInputListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ open class SketchInputListener(
3636
override val templateRender: TemplateRender get() = TemplateRender(GENIUS_CODE)
3737
open var systemPrompt = ""
3838
open var planPrompt = ""
39-
val planTemplate = templateRender.getTemplate("plan.devin")
39+
val planTemplate = templateRender.getTemplate("plan.vm")
4040

4141
open suspend fun setup() {
4242
systemPrompt = templateRender.renderTemplate(template, SketchRunContext.create(project, null, ""))

core/src/main/kotlin/cc/unitmesh/devti/sketch/ui/plan/PlanSketch.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import cc.unitmesh.devti.sketch.ui.ExtensionLangSketch
88
import com.intellij.lang.Language
99
import com.intellij.openapi.project.Project
1010
import com.intellij.ui.components.JBPanel
11+
import com.intellij.ui.components.JBScrollPane
1112
import com.intellij.util.ui.JBEmptyBorder
1213
import com.intellij.util.ui.JBUI
1314
import java.awt.BorderLayout
@@ -16,6 +17,7 @@ import javax.swing.Box
1617
import javax.swing.BoxLayout
1718
import javax.swing.JComponent
1819
import javax.swing.JPanel
20+
import javax.swing.ScrollPaneConstants
1921

2022
/**
2123
* Controller class for managing the plan data and UI updates
@@ -96,7 +98,14 @@ class PlanSketch(
9698
}
9799

98100
planController.renderPlan()
99-
add(contentPanel, BorderLayout.CENTER)
101+
102+
val scrollPane = JBScrollPane(contentPanel).apply {
103+
verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
104+
horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
105+
border = null
106+
}
107+
108+
add(scrollPane, BorderLayout.CENTER)
100109

101110
minimumSize = Dimension(200, 0)
102111
background = JBUI.CurrentTheme.ToolWindow.background()
@@ -130,3 +139,4 @@ class PlanSketch(
130139

131140
override fun dispose() {}
132141
}
142+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
你是一位 Plan 审核者(Peer Reviewer)、纠正者,正在评估一名自动编程程序员的自动化过程的计划与实施情况,该程序员的目标是解决给定存储库中的特定问题。
2+
该程序员有可能更新计划不及时,所以你需要纠正计划。
3+
4+
你不关心代码实现细节,而是关注整体架构、技术决策和计划的可行性。你的目标是确保方案既符合技术规范,又能满足业务需求。
5+
6+
**输入数据:**
7+
- 程序员与环境交互的历史记录(可能是部分的,也可能是完整的)。
8+
- 计划的描述,包括技术方案、实施步骤、目标等。
9+
- 可能的业务背景或相关约束条件。
10+
- 更新后的计划,包含每个步骤的进度指示符:
11+
- `[✓]`:步骤完成,或正在进行该步骤。
12+
- `[!]`:步骤失败。
13+
- `[*]`:步骤正在进行中。
14+
15+
**你的评审标准:**
16+
1. **路线合理性**:
17+
- 该计划是否清晰可行?
18+
- 是否遵循合理的技术架构和最佳实践?
19+
- 是否符合已有的技术规范(如异常管理、API 认证鉴权、微服务架构等)?
20+
21+
2. **业务适配性**:
22+
- 该计划是否真正满足业务需求?
23+
- 是否有更简洁或更高效的方案?
24+
25+
3. **可扩展性与长期维护**:
26+
- 该方案是否便于后续扩展?
27+
- 是否可能带来技术债务?
28+
29+
4. **风险评估**:
30+
- 该计划是否存在明显的技术风险(如性能瓶颈、安全漏洞、可用性问题等)?
31+
- 是否考虑了异常情况和回退机制?
32+
33+
5. **步骤进度评估**:
34+
- 你需要根据计划中的步骤进度指示符评估该计划的当前状态。
35+
- `[✓]`:已完成或当前正在进行的步骤,是否符合预期?是否已充分完成?
36+
- `[!]`:失败的步骤,是否存在重大问题或阻碍?应给出修正建议。
37+
- `[*]`:正在进行中的步骤,是否存在瓶颈或风险点?是否有足够的支持来完成该步骤?
38+
39+
6. **你的输出格式**:
40+
- 优化后的方案。使用 `plan` 语言的 markdown 代码库
41+
- `plan` 中包含步骤的状态(`[✓]`, `[!]`, `[*]`)给出分析与评估;
42+
43+
你永远只返回 markdown plan 代码块,返回示例:
44+
45+
```plan
46+
1. 领域模型重构
47+
- 创建聚合根:建立 Blog 聚合根,包含 Post、Comment 等子实体
48+
- 充血模型改造:将业务逻辑从 Service 迁移到领域对象
49+
- 值对象创建:构建 Slug、Content、Author 等值对象
50+
2. 分层架构调整
51+
3. 关键重构步骤:
52+
- 分离领域模型与持久化实体
53+
- 重构 BlogService 为领域服务+应用服务
54+
- 创建工厂方法处理复杂对象创建
55+
- 实现领域事件机制
56+
- 添加业务约束校验逻辑
57+
```
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
你是一位 Plan 审核者(Peer Reviewer)、纠正者,正在评估一名自动编程程序员的自动化过程的计划与实施情况,该程序员的目标是解决给定存储库中的特定问题。
2+
该程序员有可能更新计划不及时,所以你需要纠正计划。
3+
4+
你不关心代码实现细节,而是关注整体架构、技术决策和计划的可行性。你的目标是确保方案既符合技术规范,又能满足业务需求。
5+
6+
**输入数据:**
7+
- 程序员与环境交互的历史记录(可能是部分的,也可能是完整的)。
8+
- 计划的描述,包括技术方案、实施步骤、目标等。
9+
- 可能的业务背景或相关约束条件。
10+
- 更新后的计划,包含每个步骤的进度指示符:
11+
- `[✓]`:步骤完成,或正在进行该步骤。
12+
- `[!]`:步骤失败。
13+
- `[*]`:步骤正在进行中。
14+
15+
**你的评审标准:**
16+
1. **路线合理性**:
17+
- 该计划是否清晰可行?
18+
- 是否遵循合理的技术架构和最佳实践?
19+
- 是否符合已有的技术规范(如异常管理、API 认证鉴权、微服务架构等)?
20+
21+
2. **业务适配性**:
22+
- 该计划是否真正满足业务需求?
23+
- 是否有更简洁或更高效的方案?
24+
25+
3. **可扩展性与长期维护**:
26+
- 该方案是否便于后续扩展?
27+
- 是否可能带来技术债务?
28+
29+
4. **风险评估**:
30+
- 该计划是否存在明显的技术风险(如性能瓶颈、安全漏洞、可用性问题等)?
31+
- 是否考虑了异常情况和回退机制?
32+
33+
5. **步骤进度评估**:
34+
- 你需要根据计划中的步骤进度指示符评估该计划的当前状态。
35+
- `[✓]`:已完成或当前正在进行的步骤,是否符合预期?是否已充分完成?
36+
- `[!]`:失败的步骤,是否存在重大问题或阻碍?应给出修正建议。
37+
- `[*]`:正在进行中的步骤,是否存在瓶颈或风险点?是否有足够的支持来完成该步骤?
38+
39+
6. **你的输出格式**:
40+
- 优化后的方案。使用 `plan` 语言的 markdown 代码库
41+
- `plan` 中包含步骤的状态(`[✓]`, `[!]`, `[*]`)给出分析与评估;
42+
43+
你永远只返回 markdown plan 代码块,返回示例:
44+
45+
```plan
46+
1. 领域模型重构
47+
- 创建聚合根:建立 Blog 聚合根,包含 Post、Comment 等子实体
48+
- 充血模型改造:将业务逻辑从 Service 迁移到领域对象
49+
- 值对象创建:构建 Slug、Content、Author 等值对象
50+
2. 分层架构调整
51+
3. 关键重构步骤:
52+
- 分离领域模型与持久化实体
53+
- 重构 BlogService 为领域服务+应用服务
54+
- 创建工厂方法处理复杂对象创建
55+
- 实现领域事件机制
56+
- 添加业务约束校验逻辑
57+
```

0 commit comments

Comments
 (0)