Skip to content

Commit 38763a6

Browse files
committed
feat(tool): add TaskBoundaryTool for structured task progress #453
Introduce TaskBoundaryTool to communicate task progress via a structured UI, enabling users to track multi-step tasks and status updates. Registers the tool in the built-in tools provider.
1 parent fb2217b commit 38763a6

File tree

3 files changed

+320
-0
lines changed

3 files changed

+320
-0
lines changed

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

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,61 @@ Each tool's parameters are validated against its JSON Schema. Refer to the schem
4646
6. **Handle Errors Gracefully**: When a tool fails, analyze the error and try alternative approaches
4747
7. **Signal Completion**: When done, respond with "TASK_COMPLETE" in your message
4848
49+
## Task Management with /task-boundary
50+
51+
For complex multi-step tasks (3+ distinct steps), use the `/task-boundary` tool to communicate your progress through a structured UI.
52+
53+
**When to use:**
54+
- Complex tasks with multiple phases (planning, implementation, testing)
55+
- Long-running operations where users benefit from progress updates
56+
- When you need to signal major phase transitions
57+
58+
**When NOT to use:**
59+
- Simple one-step tasks (answering questions, quick refactors)
60+
- Single-file edits that don't affect many lines
61+
- Trivial operations
62+
63+
**Usage Pattern:**
64+
65+
1. **First call**: Set task name, initial status (usually PLANNING), and summary describing the goal
66+
```
67+
/task-boundary
68+
```json
69+
{"taskName": "Implementing User Authentication", "status": "PLANNING", "summary": "Analyzing existing code structure"}
70+
```
71+
```
72+
73+
2. **Updates**: Use the SAME taskName to update the same task block
74+
```
75+
/task-boundary
76+
```json
77+
{"taskName": "Implementing User Authentication", "status": "WORKING", "summary": "Adding JWT token validation"}
78+
```
79+
```
80+
81+
3. **Completion**: Mark the task as COMPLETED
82+
```
83+
/task-boundary
84+
```json
85+
{"taskName": "Implementing User Authentication", "status": "COMPLETED", "summary": "Authentication implemented and tested"}
86+
```
87+
```
88+
89+
4. **New task**: Change taskName to create a new task block
90+
```
91+
/task-boundary
92+
```json
93+
{"taskName": "Adding API Rate Limiting", "status": "PLANNING", "summary": "Designing rate limit strategy"}
94+
```
95+
```
96+
97+
**Available statuses:**
98+
- PLANNING: Analyzing and planning the approach
99+
- WORKING: Actively implementing changes
100+
- COMPLETED: Task finished successfully
101+
- BLOCKED: Waiting for external input or unable to proceed
102+
- CANCELLED: Task no longer needed
103+
49104
## Error Handling Guidelines
50105
51106
When a tool execution fails:
@@ -139,6 +194,61 @@ ${'$'}{toolList}
139194
5. **测试更改**: 运行测试或构建命令来验证更改
140195
6. **完成信号**: 完成后,在消息中响应 "TASK_COMPLETE"
141196
197+
## 使用 /task-boundary 进行任务管理
198+
199+
对于复杂的多步骤任务(3+ 步骤),使用 `/task-boundary` 工具通过结构化 UI 传达你的进度。
200+
201+
**何时使用:**
202+
- 具有多个阶段的复杂任务(规划、实施、测试)
203+
- 用户需要进度更新的长时间运行操作
204+
- 需要标记主要阶段转换时
205+
206+
**何时不使用:**
207+
- 简单的单步骤任务(回答问题、快速重构)
208+
- 不影响许多行的单文件编辑
209+
- 琐碎的操作
210+
211+
**使用模式:**
212+
213+
1. **首次调用**: 设置任务名称、初始状态(通常为 PLANNING)和描述目标的摘要
214+
```
215+
/task-boundary
216+
```json
217+
{"taskName": "实现用户身份验证", "status": "PLANNING", "summary": "分析现有代码结构"}
218+
```
219+
```
220+
221+
2. **更新**: 使用相同的 taskName 更新同一任务块
222+
```
223+
/task-boundary
224+
```json
225+
{"taskName": "实现用户身份验证", "status": "WORKING", "summary": "添加 JWT 令牌验证"}
226+
```
227+
```
228+
229+
3. **完成**: 将任务标记为 COMPLETED
230+
```
231+
/task-boundary
232+
```json
233+
{"taskName": "实现用户身份验证", "status": "COMPLETED", "summary": "身份验证已实现并测试"}
234+
```
235+
```
236+
237+
4. **新任务**: 更改 taskName 以创建新的任务块
238+
```
239+
/task-boundary
240+
```json
241+
{"taskName": "添加 API 速率限制", "status": "PLANNING", "summary": "设计速率限制策略"}
242+
```
243+
```
244+
245+
**可用状态:**
246+
- PLANNING: 分析和规划方法
247+
- WORKING: 积极实施更改
248+
- COMPLETED: 任务成功完成
249+
- BLOCKED: 等待外部输入或无法继续
250+
- CANCELLED: 不再需要任务
251+
142252
## 重要:每次响应只执行一个工具
143253
144254
**你必须每次响应只执行一个工具。** 不要在单个响应中包含多个工具调用。
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package cc.unitmesh.agent.tool.impl
2+
3+
import cc.unitmesh.agent.tool.*
4+
import cc.unitmesh.agent.tool.schema.DeclarativeToolSchema
5+
import cc.unitmesh.agent.tool.schema.SchemaPropertyBuilder.string
6+
import cc.unitmesh.agent.tool.schema.ToolCategory
7+
import kotlinx.serialization.Serializable
8+
9+
/**
10+
* Task status enum matching Cursor's task boundary behavior
11+
*/
12+
enum class TaskStatus {
13+
PLANNING,
14+
WORKING,
15+
COMPLETED,
16+
BLOCKED,
17+
CANCELLED
18+
}
19+
20+
/**
21+
* Parameters for task boundary tool
22+
*/
23+
@Serializable
24+
data class TaskBoundaryParams(
25+
/**
26+
* The name/title of the task - used as the header in UI
27+
* Keep the same taskName to update an existing task, change it to create a new task block
28+
*/
29+
val taskName: String,
30+
31+
/**
32+
* Current status of the task (PLANNING, WORKING, COMPLETED, BLOCKED, CANCELLED)
33+
*/
34+
val status: String,
35+
36+
/**
37+
* Brief summary describing what this task accomplishes or what you're doing
38+
*/
39+
val summary: String = ""
40+
)
41+
42+
/**
43+
* Schema for task boundary tool
44+
*/
45+
object TaskBoundarySchema : DeclarativeToolSchema(
46+
description = "Communicate task progress through a structured UI. Use this to keep users informed of your work.",
47+
properties = mapOf(
48+
"taskName" to string(
49+
description = "Task name/title - used as the header. Keep the same name to update an existing task, change it to create a new task block",
50+
required = true,
51+
maxLength = 100
52+
),
53+
"status" to string(
54+
description = "Current task status",
55+
required = true,
56+
enum = listOf("PLANNING", "WORKING", "COMPLETED", "BLOCKED", "CANCELLED")
57+
),
58+
"summary" to string(
59+
description = "Brief summary of what this task does or current activity",
60+
required = false,
61+
maxLength = 500
62+
)
63+
)
64+
) {
65+
override fun getExampleUsage(toolName: String): String {
66+
return """/$toolName taskName="Planning Authentication" status="PLANNING" summary="Analyzing existing auth structure and planning OAuth2 implementation""""
67+
}
68+
}
69+
70+
/**
71+
* Tool invocation for task boundary
72+
*/
73+
class TaskBoundaryInvocation(
74+
params: TaskBoundaryParams,
75+
tool: TaskBoundaryTool
76+
) : BaseToolInvocation<TaskBoundaryParams, ToolResult>(params, tool) {
77+
78+
override fun getDescription(): String {
79+
return "Task: ${params.taskName} [${params.status}]"
80+
}
81+
82+
override fun getToolLocations(): List<ToolLocation> = emptyList()
83+
84+
override suspend fun execute(context: ToolExecutionContext): ToolResult {
85+
// Validate status
86+
val status = try {
87+
TaskStatus.valueOf(params.status.uppercase())
88+
} catch (e: IllegalArgumentException) {
89+
return ToolResult.Error(
90+
message = "Invalid status: ${params.status}. Must be one of: ${TaskStatus.values().joinToString(", ")}",
91+
errorType = ToolErrorType.PARAMETER_OUT_OF_RANGE.code
92+
)
93+
}
94+
95+
// Create metadata for tracking
96+
val metadata = mapOf(
97+
"task_name" to params.taskName,
98+
"status" to status.name,
99+
"summary" to params.summary
100+
)
101+
102+
// Format the output message
103+
val output = buildString {
104+
appendLine("📋 Task Update")
105+
appendLine("Name: ${params.taskName}")
106+
appendLine("Status: ${status.name}")
107+
if (params.summary.isNotEmpty()) {
108+
appendLine("Summary: ${params.summary}")
109+
}
110+
}
111+
112+
return ToolResult.Success(output, metadata)
113+
}
114+
}
115+
116+
/**
117+
* Task Boundary Tool - inspired by Cursor's task management
118+
*
119+
* ## Purpose
120+
* Communicate progress through a structured task UI. This helps users understand what you're working on
121+
* and track your progress through complex multi-step tasks.
122+
*
123+
* ## UI Behavior
124+
* - taskName = Header of the UI block
125+
* - summary = Description of this task
126+
* - status = Current activity (PLANNING, WORKING, COMPLETED, BLOCKED, CANCELLED)
127+
*
128+
* ## Usage Pattern
129+
*
130+
* **First call**: Set taskName using the mode and work area (e.g., "Planning Authentication"),
131+
* set summary to briefly describe the goal, set status to what you're about to start doing.
132+
*
133+
* **Updates**:
134+
* - Same taskName + updated summary/status = Updates accumulate in the same UI block
135+
* - Different taskName = Starts a new UI block with a fresh summary for the new task
136+
*
137+
* ## When to Use
138+
* - For complex tasks with multiple steps (3+ steps)
139+
* - When you want to communicate progress during long-running operations
140+
* - To signal major phase transitions (planning -> implementation -> testing)
141+
*
142+
* ## When NOT to Use
143+
* - Simple one-step tasks (answering questions, quick refactors)
144+
* - Single-file edits that don't affect many lines
145+
* - Trivial operations
146+
*
147+
* ## Example Flow
148+
*
149+
* ```
150+
* /task-boundary taskName="Implementing User Authentication" status="PLANNING" summary="Analyzing existing code structure"
151+
* // ... do some analysis ...
152+
* /task-boundary taskName="Implementing User Authentication" status="WORKING" summary="Adding JWT token validation"
153+
* // ... make changes ...
154+
* /task-boundary taskName="Implementing User Authentication" status="COMPLETED" summary="Authentication implemented and tested"
155+
* ```
156+
*/
157+
class TaskBoundaryTool : BaseExecutableTool<TaskBoundaryParams, ToolResult>() {
158+
159+
override val name: String = "task-boundary"
160+
override val description: String = """
161+
Communicate task progress through a structured UI. Use this for complex multi-step tasks to keep users informed.
162+
163+
- First call: Set taskName, initial status (usually PLANNING), and summary describing the goal
164+
- Updates: Use same taskName to update an existing task, or change taskName to create a new task block
165+
- Status options: PLANNING, WORKING, COMPLETED, BLOCKED, CANCELLED
166+
167+
Skip for simple tasks (quick refactors, answering questions, single-file edits).
168+
""".trimIndent()
169+
170+
override val metadata: ToolMetadata = ToolMetadata(
171+
displayName = "Task Boundary",
172+
tuiEmoji = "📋",
173+
composeIcon = "task",
174+
category = ToolCategory.Utility,
175+
schema = TaskBoundarySchema
176+
)
177+
178+
override fun getParameterClass(): String = TaskBoundaryParams::class.simpleName ?: "TaskBoundaryParams"
179+
180+
override fun createToolInvocation(params: TaskBoundaryParams): ToolInvocation<TaskBoundaryParams, ToolResult> {
181+
// Validate parameters
182+
validateParameters(params)
183+
return TaskBoundaryInvocation(params, this)
184+
}
185+
186+
private fun validateParameters(params: TaskBoundaryParams) {
187+
if (params.taskName.isBlank()) {
188+
throw ToolException("Task name cannot be empty", ToolErrorType.MISSING_REQUIRED_PARAMETER)
189+
}
190+
191+
if (params.status.isBlank()) {
192+
throw ToolException("Status cannot be empty", ToolErrorType.MISSING_REQUIRED_PARAMETER)
193+
}
194+
195+
// Validate status is a valid enum value
196+
try {
197+
TaskStatus.valueOf(params.status.uppercase())
198+
} catch (e: IllegalArgumentException) {
199+
throw ToolException(
200+
"Invalid status: ${params.status}. Must be one of: ${TaskStatus.values().joinToString(", ")}",
201+
ToolErrorType.PARAMETER_OUT_OF_RANGE
202+
)
203+
}
204+
}
205+
}
206+

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/tool/registry/BuiltinToolsProvider.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import cc.unitmesh.agent.tool.impl.GlobTool
77
import cc.unitmesh.agent.tool.impl.GrepTool
88
import cc.unitmesh.agent.tool.impl.ReadFileTool
99
import cc.unitmesh.agent.tool.impl.ShellTool
10+
import cc.unitmesh.agent.tool.impl.TaskBoundaryTool
1011
import cc.unitmesh.agent.tool.impl.WebFetchTool
1112
import cc.unitmesh.agent.tool.impl.WriteFileTool
1213

@@ -44,6 +45,9 @@ class BuiltinToolsProvider : ToolProvider {
4445
}
4546

4647
tools.add(WebFetchTool(dependencies.llmService))
48+
49+
// Task management tool
50+
tools.add(TaskBoundaryTool())
4751

4852
return tools
4953
}

0 commit comments

Comments
 (0)