Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7c2bef1
feat(mpp-vscode): init vscode extension project structure
phodal Dec 2, 2025
0fd86e4
feat(mpp-vscode): implement core services and IDE integration
phodal Dec 2, 2025
1a1fad2
feat(mpp-vscode): add DevIns language support and status bar
phodal Dec 2, 2025
578308f
feat(mpp-vscode): add React Webview UI for chat interface
phodal Dec 2, 2025
80020cc
refactor(markdown): move MarkdownTextParser to mpp-core
phodal Dec 2, 2025
aad2201
feat(mpp-vscode): add Timeline-based Sketch Renderer architecture
phodal Dec 2, 2025
4f887f9
feat(mpp-vscode): integrate ConfigManager for ~/.autodev/config.yaml
phodal Dec 3, 2025
407cb3d
feat(mpp-vscode): add ModelSelector and unified toolbar layout
phodal Dec 3, 2025
2975520
fix(mpp-vscode): fix VSCode API acquisition for webview communication
phodal Dec 3, 2025
98facf2
fix(mpp-vscode): prevent duplicate user message in timeline
phodal Dec 3, 2025
d13ce4e
fix(mpp-vscode): address PR #32 review comments
phodal Dec 3, 2025
b569934
feat(mpp-vscode): init vscode extension project structure
phodal Dec 2, 2025
876e3a1
feat(mpp-vscode): implement core services and IDE integration
phodal Dec 2, 2025
7d6a9ce
feat(mpp-vscode): add DevIns language support and status bar
phodal Dec 2, 2025
6e78932
feat(mpp-vscode): add React Webview UI for chat interface
phodal Dec 2, 2025
e434dfe
refactor(markdown): move MarkdownTextParser to mpp-core
phodal Dec 2, 2025
8d64f56
feat(mpp-vscode): add Timeline-based Sketch Renderer architecture
phodal Dec 2, 2025
caca9a3
feat(mpp-vscode): integrate ConfigManager for ~/.autodev/config.yaml
phodal Dec 3, 2025
6b56e8a
feat(mpp-vscode): add ModelSelector and unified toolbar layout
phodal Dec 3, 2025
277e397
fix(mpp-vscode): fix VSCode API acquisition for webview communication
phodal Dec 3, 2025
c5bf005
fix(mpp-vscode): prevent duplicate user message in timeline
phodal Dec 3, 2025
2dd0fd8
fix(mpp-vscode): address PR #32 review comments
phodal Dec 3, 2025
27899f3
feat(vscode): integrate mpp-core CompletionManager for auto-completion
phodal Dec 3, 2025
31fb79f
Merge origin/master into feature/mpp-vscode
phodal Dec 3, 2025
40c4593
feat(vscode): Enhanced Chat Input with DevIn Language Support (#34)
phodal Dec 3, 2025
88781b5
feat(mpp-ui): implement file context management with indexed search
phodal Dec 3, 2025
316c277
feat(mpp-core): implement Task Management Tool for CodingAgent (#38)
phodal Dec 3, 2025
a3d0400
feat(plan): add PlanSummaryBar component across all platforms
phodal Dec 3, 2025
2e17b3a
refactor(plan): remove UPDATE action from PlanManagementTool
phodal Dec 3, 2025
0e8a480
feat(agent): improve plan step rendering and orchestration
phodal Dec 3, 2025
42f6ba7
feat(plan): improve PlanSummaryBar UX and fix parameter passing
phodal Dec 3, 2025
e322d7e
docs(agent): clarify exploration before planning workflow
phodal Dec 3, 2025
a9381b3
fix(editor): adjust iOS input sizing for better keyboard handling
phodal Dec 3, 2025
aceaf34
fix(sketch): remove progress indicator from incomplete content
phodal Dec 3, 2025
1f09174
fix(mpp-vscode): remove unused variables
phodal Dec 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mpp-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ kotlin {
// Kotlin Logging for multiplatform logging
implementation("io.github.oshai:kotlin-logging:7.0.13")

runtimeOnly("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1-0.6.x-compat")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1-0.6.x-compat")
// Koog AI Framework - JVM only for now
implementation("ai.koog:koog-agents:0.5.2")
implementation("ai.koog:agents-mcp:0.5.2")
Expand Down
157 changes: 139 additions & 18 deletions mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/CodingAgentTemplate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,75 @@ All tools use the DevIns format with JSON parameters:
```
</devin>

# Task Completion Strategy
# Task Execution Strategy: Explore First, Then Plan

**IMPORTANT: Focus on completing the task efficiently.**
**CRITICAL: Always explore the codebase BEFORE creating a plan.**

1. **Understand the Task**: Read the user's request carefully
2. **Gather Minimum Required Information**: Only collect information directly needed for the task
3. **Execute the Task**: Make the necessary changes or provide the answer
4. **Verify if Needed**: For code changes, compile/test to verify
5. **Provide Summary**: Always end with a clear summary of what was done
## Phase 1: Exploration (REQUIRED before planning)
Before creating any plan, you MUST gather context:

**Avoid over-exploration**: Don't spend iterations exploring unrelated code. Stay focused on the task.
1. **Understand the request**: What exactly does the user want?
2. **Locate relevant files**: Use `/glob` to find files related to the task
3. **Read key files**: Use `/read-file` to understand existing code structure, patterns, and conventions
4. **Search for references**: Use `/grep` to find related code, usages, or patterns

**Minimum exploration before planning:**
- For code modifications: Read the target file(s) and understand the structure
- For new features: Find similar existing implementations to follow patterns
- For bug fixes: Locate the bug and understand the context

## Phase 2: Plan Creation (after exploration)
Only create a plan AFTER you have sufficient context:

```markdown
1. Task Title
- [ ] Specific step with file path (e.g., "Add field to src/Entity.java")
- [ ] Another specific step

2. Another Task
- [ ] Step with clear action
```

## Plan Actions
- `CREATE`: Create a new plan (only after exploration)
- `COMPLETE_STEP`: Mark a step done (taskIndex=1, stepIndex=1 for first step)
- `VIEW`: View current plan status

## When to Use Planning
- Tasks requiring multiple files to be modified
- Complex features with dependencies between steps
- Skip planning for simple single-file edits

## Plan Update Rules
- Mark ONE step at a time after completing actual work
- Do NOT batch multiple COMPLETE_STEP calls
- Update after work is done, not before

Example workflow:
1. User: "Add validation to UserController"
2. Agent: Use /glob to find UserController
3. Agent: Use /read-file to read UserController
4. Agent: Create plan with specific steps based on what was learned
5. Agent: Execute each step, marking complete as done

<devin>
/plan
```json
{"action": "CREATE", "planMarkdown": "1. Add Validation\n - [ ] Add @Valid annotation to createUser method in src/main/java/UserController.java\n - [ ] Create UserValidator class in src/main/java/validators/"}
```
</devin>

## Avoiding Common Mistakes

**DON'T:**
- Create a plan immediately without reading any files
- Make assumptions about file locations or code structure
- Create vague steps like "implement feature" without specifics

**DO:**
- Read relevant files first to understand the codebase
- Create specific steps with actual file paths
- Base your plan on what you learned during exploration

# Information-Gathering Strategy

Expand Down Expand Up @@ -95,10 +153,15 @@ When a tool fails:

# IMPORTANT: One Tool Per Response

**Execute ONLY ONE tool per response.**
**Execute ONLY ONE tool per response. This is critical for proper execution.**

- ✅ CORRECT: One <devin> block with ONE tool call
- ❌ WRONG: Multiple <devin> blocks
- ❌ WRONG: Multiple <devin> blocks or multiple tool calls

**Special note for /plan tool:**
- Do NOT call multiple COMPLETE_STEP in one response
- Complete one step, wait for confirmation, then proceed to next step
- Each plan update requires a separate response cycle

# Response Format

Expand Down Expand Up @@ -161,17 +224,75 @@ ${'$'}{toolList}
```
</devin>

# 任务完成策略
# 任务执行策略:先探索,后计划

**关键原则:在创建计划之前,必须先探索代码库。**

## 第一阶段:探索(创建计划前必须完成)
在创建任何计划之前,你必须收集上下文:

1. **理解请求**:用户到底想要什么?
2. **定位相关文件**:使用 `/glob` 查找与任务相关的文件
3. **阅读关键文件**:使用 `/read-file` 了解现有代码结构、模式和约定
4. **搜索引用**:使用 `/grep` 查找相关代码、用法或模式

**创建计划前的最少探索:**
- 对于代码修改:读取目标文件,理解其结构
- 对于新功能:找到类似的现有实现以遵循模式
- 对于 bug 修复:定位 bug 并理解上下文

## 第二阶段:创建计划(在探索之后)
只有在获得足够上下文后才创建计划:

```markdown
1. 任务标题
- [ ] 具体步骤带文件路径(如:"在 src/Entity.java 中添加字段")
- [ ] 另一个具体步骤

2. 另一个任务
- [ ] 有明确操作的步骤
```

## 计划操作
- `CREATE`: 创建新计划(仅在探索之后)
- `COMPLETE_STEP`: 标记步骤完成 (taskIndex=1, stepIndex=1 表示第一个任务的第一个步骤)
- `VIEW`: 查看当前计划状态

## 何时使用计划
- 需要修改多个文件的任务
- 步骤之间有依赖关系的复杂功能
- 简单的单文件编辑跳过计划

## 计划更新规则
- 完成实际工作后一次只标记一个步骤
- 不要在一次响应中批量调用 COMPLETE_STEP
- 工作完成后更新,而不是之前

示例工作流:
1. 用户:"给 UserController 添加验证"
2. Agent:使用 /glob 查找 UserController
3. Agent:使用 /read-file 读取 UserController
4. Agent:根据学到的内容创建具体步骤的计划
5. Agent:执行每个步骤,完成后标记

<devin>
/plan
```json
{"action": "CREATE", "planMarkdown": "1. 添加验证\n - [ ] 在 src/main/java/UserController.java 的 createUser 方法添加 @Valid 注解\n - [ ] 在 src/main/java/validators/ 创建 UserValidator 类"}
```
</devin>

**重要:专注于高效完成任务。**
## 避免常见错误

1. **理解任务**:仔细阅读用户的请求
2. **收集最少必要信息**:只收集任务直接需要的信息
3. **执行任务**:进行必要的更改或提供答案
4. **必要时验证**:对于代码更改,编译/测试以验证
5. **提供总结**:始终以清晰的总结结束
**不要:**
- 在没有读取任何文件的情况下立即创建计划
- 对文件位置或代码结构做出假设
- 创建模糊的步骤如"实现功能"而没有具体内容

**避免过度探索**:不要花费迭代次数探索无关代码。保持专注于任务。
**要:**
- 先读取相关文件以了解代码库
- 创建带有实际文件路径的具体步骤
- 基于探索阶段学到的内容制定计划

# 信息收集策略

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package cc.unitmesh.agent.executor
import cc.unitmesh.agent.*
import cc.unitmesh.agent.conversation.ConversationManager
import cc.unitmesh.agent.core.SubAgentManager
import cc.unitmesh.agent.logging.getLogger
import cc.unitmesh.agent.tool.schema.ToolResultFormatter
import cc.unitmesh.agent.orchestrator.ToolExecutionResult
import cc.unitmesh.agent.orchestrator.ToolOrchestrator
import cc.unitmesh.agent.render.CodingAgentRenderer
import cc.unitmesh.agent.state.ToolCall
import cc.unitmesh.agent.state.ToolExecutionState
import cc.unitmesh.agent.plan.PlanSummaryData
import cc.unitmesh.agent.tool.ToolResult
import cc.unitmesh.agent.tool.ToolType
import cc.unitmesh.agent.tool.toToolType
Expand All @@ -24,8 +26,8 @@ import cc.unitmesh.agent.orchestrator.ToolExecutionContext as OrchestratorContex
data class AsyncShellConfig(
/** Initial wait timeout in milliseconds before notifying AI that process is still running */
val initialWaitTimeoutMs: Long = 60_000L, // 1 minute
/** Maximum total wait time in milliseconds */
val maxWaitTimeoutMs: Long = 300_000L, // 5 minutes
/** Maximum total wait time in milliseconds (2 minutes, similar to Cursor/Claude Code) */
val maxWaitTimeoutMs: Long = 120_000L, // 2 minutes
/** Interval for checking process status after initial timeout */
val checkIntervalMs: Long = 30_000L // 30 seconds
)
Expand All @@ -38,7 +40,13 @@ class CodingAgentExecutor(
maxIterations: Int = 100,
private val subAgentManager: SubAgentManager? = null,
enableLLMStreaming: Boolean = true,
private val asyncShellConfig: AsyncShellConfig = AsyncShellConfig()
private val asyncShellConfig: AsyncShellConfig = AsyncShellConfig(),
/**
* When true, only execute the first tool call per LLM response.
* This enforces the "one tool per response" rule even when LLM returns multiple tool calls.
* Default is true to prevent LLM from executing multiple tools in one iteration.
*/
private val singleToolPerIteration: Boolean = true
) : BaseAgentExecutor(
projectPath = projectPath,
llmService = llmService,
Expand All @@ -47,6 +55,7 @@ class CodingAgentExecutor(
maxIterations = maxIterations,
enableLLMStreaming = enableLLMStreaming
) {
private val logger = getLogger("CodingAgentExecutor")
private val steps = mutableListOf<AgentStep>()
private val edits = mutableListOf<AgentEdit>()

Expand Down Expand Up @@ -92,12 +101,22 @@ class CodingAgentExecutor(
break
}

val toolCalls = toolCallParser.parseToolCalls(llmResponse.toString())
if (toolCalls.isEmpty()) {
val allToolCalls = toolCallParser.parseToolCalls(llmResponse.toString())
if (allToolCalls.isEmpty()) {
renderer.renderTaskComplete()
break
}

// When singleToolPerIteration is enabled, only execute the first tool call
// This enforces the "one tool per response" rule even when LLM returns multiple tool calls
val toolCalls = if (singleToolPerIteration && allToolCalls.size > 1) {
logger.warn { "LLM returned ${allToolCalls.size} tool calls, but singleToolPerIteration is enabled. Only executing the first one: ${allToolCalls.first().toolName}" }
renderer.renderError("Warning: LLM returned ${allToolCalls.size} tool calls, only executing the first one")
listOf(allToolCalls.first())
} else {
allToolCalls
}

val toolResults = executeToolCalls(toolCalls)
val toolResultsText = ToolResultFormatter.formatMultipleToolResults(toolResults)
conversationManager!!.addToolResults(toolResultsText)
Expand Down Expand Up @@ -204,15 +223,15 @@ class CodingAgentExecutor(
for (toolCall in toolsToExecute) {
val toolName = toolCall.toolName
val params = toolCall.params.mapValues { it.value as Any }
val paramsStr = params.entries.joinToString(" ") { (key, value) ->
"$key=\"$value\""
}

renderer.renderToolCall(toolName, paramsStr)
// Use renderToolCallWithParams to pass parsed params directly
// This avoids string parsing issues with complex values like planMarkdown
renderer.renderToolCallWithParams(toolName, params)

val executionContext = OrchestratorContext(
workingDirectory = projectPath,
environment = emptyMap()
environment = emptyMap(),
timeout = asyncShellConfig.maxWaitTimeoutMs // Use max timeout for shell commands
)

var executionResult = toolOrchestrator.executeToolCall(
Expand Down Expand Up @@ -273,6 +292,11 @@ class CodingAgentExecutor(
executionResult.metadata
)

// Render plan summary bar after plan tool execution
if (toolName == "plan" && executionResult.isSuccess) {
renderPlanSummaryIfAvailable()
}

val currentToolType = toolName.toToolType()
if ((currentToolType == ToolType.WriteFile) && executionResult.isSuccess) {
recordFileEdit(params)
Expand Down Expand Up @@ -511,4 +535,14 @@ class CodingAgentExecutor(
fun getConversationHistory(): List<cc.unitmesh.devins.llm.Message> {
return conversationManager?.getHistory() ?: emptyList()
}

/**
* Render plan summary bar if a plan is available
*/
private fun renderPlanSummaryIfAvailable() {
val planStateService = toolOrchestrator.getPlanStateService() ?: return
val currentPlan = planStateService.currentPlan.value ?: return
val summary = PlanSummaryData.from(currentPlan)
renderer.renderPlanSummary(summary)
}
}
Loading
Loading