Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -36,55 +36,75 @@ All tools use the DevIns format with JSON parameters:
```
</devin>

# Planning and Task Management
# Task Execution Strategy: Explore First, Then Plan

For complex multi-step tasks, use the `/plan` tool to create and track progress:
**CRITICAL: Always explore the codebase BEFORE creating a plan.**

## When to Use Planning
- Tasks requiring multiple files to be created or modified
- Tasks with dependencies between steps
- Tasks that benefit from structured tracking
## Phase 1: Exploration (REQUIRED before planning)
Before creating any plan, you MUST gather context:

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:

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

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

## Plan Actions
- `CREATE`: Create a new plan with markdown content
- `COMPLETE_STEP`: Mark a step as done (taskIndex=1, stepIndex=1 for first step of first task)
- `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

## IMPORTANT: Plan Update Rules
- **Mark ONE step at a time**: After completing actual work, call COMPLETE_STEP for that single step only
- **Do NOT batch multiple COMPLETE_STEP calls**: Each response should contain at most ONE plan update
- **Update after work is done**: Only mark a step complete AFTER you have actually performed the work
## 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

Example:
<devin>
/plan
```json
{"action": "CREATE", "planMarkdown": "1. Setup\n - [ ] Create entity class\n - [ ] Create repository\n\n2. Implementation\n - [ ] Create service\n - [ ] Create controller"}
{"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>

# Task Completion Strategy
## Avoiding Common Mistakes

**IMPORTANT: Focus on completing the task efficiently.**
**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

1. **Understand the Task**: Read the user's request carefully
2. **Plan if Complex**: For multi-step tasks, create a plan first using `/plan`
3. **Gather Minimum Required Information**: Only collect information directly needed for the task
4. **Execute the Task**: Make the necessary changes, marking steps complete as you go
5. **Verify if Needed**: For code changes, compile/test to verify
6. **Provide Summary**: Always end with a clear summary of what was done

**Avoid over-exploration**: Don't spend iterations exploring unrelated code. Stay focused on the task.
**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 @@ -204,50 +224,75 @@ ${'$'}{toolList}
```
</devin>

# 计划和任务管理
# 任务执行策略:先探索,后计划

对于复杂的多步骤任务,使用 `/plan` 工具来创建和跟踪进度:
**关键原则:在创建计划之前,必须先探索代码库。**

## 何时使用计划
- 需要创建或修改多个文件的任务
- 步骤之间有依赖关系的任务
- 需要结构化跟踪的任务
## 第一阶段:探索(创建计划前必须完成)
在创建任何计划之前,你必须收集上下文:

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

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

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

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

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

## 计划操作
- `CREATE`: 使用 markdown 内容创建新计划
- `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 - [ ] 创建实体类\n - [ ] 创建仓库\n\n2. 实现\n - [ ] 创建服务\n - [ ] 创建控制器"}
{"action": "CREATE", "planMarkdown": "1. 添加验证\n - [ ] 在 src/main/java/UserController.java 的 createUser 方法添加 @Valid 注解\n - [ ] 在 src/main/java/validators/ 创建 UserValidator 类"}
```
</devin>

# 任务完成策略

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

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

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

# 信息收集策略

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,10 @@ 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ interface CodingAgentRenderer {
fun renderLLMResponseEnd()

fun renderToolCall(toolName: String, paramsStr: String)

/**
* Render a tool call with parsed parameters.
* This is the preferred method as it avoids string parsing issues with complex values.
*
* @param toolName The name of the tool being called
* @param params The parsed parameters map
*/
fun renderToolCallWithParams(toolName: String, params: Map<String, Any>) {
// Default implementation: convert to string format for backward compatibility
val paramsStr = params.entries.joinToString(" ") { (key, value) ->
"$key=\"$value\""
}
renderToolCall(toolName, paramsStr)
}

fun renderToolResult(
toolName: String,
success: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,38 @@ object RendererUtils {

/**
* Parse parameter string into a map.
* Handles both quoted and unquoted values.
* Handles both JSON format and key=value format.
*/
fun parseParamsString(paramsStr: String): Map<String, String> {
val params = mutableMapOf<String, String>()
val trimmed = paramsStr.trim()

// Try JSON format first (starts with { and ends with })
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
try {
// Simple JSON parsing for flat objects with string values
val jsonContent = trimmed.substring(1, trimmed.length - 1)
// Match "key": "value" or "key": number patterns
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The complex regex pattern is difficult to understand and maintain. Consider adding an explanatory comment describing what each capture group matches (e.g., group 1: key, group 2: quoted string, group 3: number, group 4: unquoted word).

Suggested change
// Match "key": "value" or "key": number patterns
// Match "key": "value" or "key": number patterns
// Regex capture groups:
// group 1: key
// group 2: quoted string value
// group 3: number value
// group 4: unquoted word value (e.g., true/false)

Copilot uses AI. Check for mistakes.
val jsonRegex = Regex(""""(\w+)"\s*:\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|(\d+(?:\.\d+)?)|(\w+))""")
jsonRegex.findAll(jsonContent).forEach { match ->
val key = match.groups[1]?.value
// Value can be: quoted string, number, or unquoted word (like true/false)
val value = match.groups[2]?.value
?: match.groups[3]?.value
?: match.groups[4]?.value
if (key != null && value != null) {
params[key] = value
}
}
if (params.isNotEmpty()) {
return params
}
} catch (_: Exception) {
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching a broad Exception silently could hide unexpected errors. Consider catching more specific exceptions (e.g., parsing-related exceptions) or logging the exception for debugging purposes.

Suggested change
} catch (_: Exception) {
} catch (e: Exception) {
println("Failed to parse params as JSON: ${e.message}")
e.printStackTrace()

Copilot uses AI. Check for mistakes.
// Fall through to key=value parsing
}
}

// Fallback to key=value format
val regex = Regex("""(\w+)="([^"]*)"|\s*(\w+)=([^\s]+)""")
regex.findAll(paramsStr).forEach { match ->
val key = match.groups[1]?.value ?: match.groups[3]?.value
Expand Down
Loading
Loading