Skip to content

Commit 4db8f5e

Browse files
committed
improve workflow and simplify tool call
1 parent 362ca00 commit 4db8f5e

3 files changed

Lines changed: 167 additions & 56 deletions

File tree

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,71 @@
1-
Manages multi-step problem-solving processes with support for sequential progression, branching paths, and step revisions.
1+
# Workflow Tool: Guiding Complex Problem-Solving
22

3-
Use this tool to:
4-
- Break down complex problems into sequential steps
5-
- Create alternative solution paths through branching
6-
- Revise previous steps as your understanding evolves
7-
- Maintain context across multi-step reasoning processes
3+
Manages multi-step problem-solving processes with support for sequential progression, branching paths, and step revisions. This tool is designed to help you (the LLM) structure your reasoning, explore alternatives, and adapt your approach as your understanding of a problem evolves.
84

9-
Returns JSON response with workflow status.
5+
Returns a JSON response detailing the current workflow status, including the last step taken, active branches, and overall progress.
6+
7+
## When to Use This Workflow Tool
8+
9+
This tool is most effective when you need to:
10+
11+
* **Deconstruct Complex Problems**: Break down large or multifaceted tasks into a manageable sequence of discrete steps.
12+
* **Plan and Design Iteratively**: Develop plans or designs where initial assumptions might need revision as more information is processed.
13+
* **Explore Multiple Solution Paths**: Investigate different approaches or hypotheses by creating distinct branches in your reasoning process.
14+
* **Perform In-depth Analysis with Course Correction**: Conduct detailed analysis that may require backtracking or revising earlier conclusions.
15+
* **Handle Problems with Unclear Scope**: Tackle tasks where the full extent of steps or requirements isn't known at the outset.
16+
* **Maintain Long-Term Context**: Keep track of progress and decisions across a series of interactions for a multi-step task.
17+
* **Systematically Generate and Verify Hypotheses**: Formulate a potential solution or explanation, then use subsequent steps to test and validate it.
18+
* **Document Your Reasoning Process**: Clearly lay out each step of your thought process for transparency and review.
19+
20+
## Best Practices for Using the Workflow Tool
21+
22+
To leverage this tool most effectively, please follow these guidelines:
23+
24+
1. **Start with an Initial Estimate, Adapt as Needed**: Begin with a reasonable estimate for `total_steps`. However, feel free to adjust this value (up or down) in subsequent steps as your understanding of the task's complexity changes. The tool will accommodate these adjustments.
25+
2. **Embrace Revisions**: Don't hesitate to use `is_step_revision` and `revises_step` if you realize an earlier step needs correction or refinement. Clearly describe what is being revised and why.
26+
3. **Utilize Branching for Alternatives**: If multiple approaches seem plausible, use `branch_from_step` and `branch_id` to explore them in parallel without losing the main line of thought. Give your branches descriptive `branch_id`s.
27+
4. **Be Explicit About Uncertainty**: If you are unsure about a step or a direction, you can note this in the `step_description`.
28+
5. **Clearly Define Each Step**: Ensure each `step_description` is detailed and clearly states what that specific step accomplishes, any conclusions drawn, or any questions that arise.
29+
6. **Manage `next_step_needed` and `needs_more_steps` Deliberately**:
30+
* Set `next_step_needed` to `false` only when the *current specific sequence or sub-task* is complete.
31+
* Use `needs_more_steps` (optional) to indicate if the *overall problem or workflow* requires further steps, even if the current local sequence (`next_step_needed: false`) is ending. For example, you might finish a branch (`next_step_needed: false`) but still need to return to the main workflow or start a new one (`needs_more_steps: true`). Set `needs_more_steps: false` when you are confident the entire problem is resolved.
32+
7. **Hypothesis Management**:
33+
* When appropriate, use a step to explicitly state a hypothesis in the `step_description`.
34+
* In subsequent steps, describe how you are testing or verifying this hypothesis.
35+
8. **Sequential Integrity**: Ensure `step_number` increments logically. While you can revise past steps, new steps should generally follow in sequence.
36+
9. **Final Answer**: When the entire workflow is complete (`next_step_needed: false` and `needs_more_steps: false` (or omitted and implied false)), the final step's description should ideally contain or clearly lead to the final answer or solution.
1037

1138
## Parameters
1239

1340
### Required
14-
- `step_description`: Detailed description of what this step accomplishes
15-
- `step_number`: Current position in the workflow sequence (e.g., 1 for first step)
16-
- `total_steps`: Estimated total number of steps in the complete workflow
17-
- `next_step_needed`: Set to true if another step will follow this one, false if this is the final step
41+
- `step_description` (string): Detailed description of what this step accomplishes, including any reasoning, conclusions, or questions.
42+
- `step_number` (integer): Current position in the workflow sequence (e.g., 1 for first step). Must be >= 1.
43+
- `total_steps` (integer): Your current best estimate of the total number of steps needed for the *entire* workflow. Can be adjusted in subsequent steps. Must be >= `step_number`.
44+
- `next_step_needed` (boolean): Set to `true` if another step is expected to *immediately follow this one* in the current sequence or branch. Set to `false` if this is the last step of the current sequence/branch.
1845

1946
### Optional
20-
- `is_step_revision`: Set to true if this step revises a previous step
21-
- `revises_step`: If revising a previous step, specify which step number is being revised
22-
- `branch_from_step`: If creating a branch, specify which step number this branch starts from
23-
- `branch_id`: A unique identifier for this branch (required when creating a branch)
24-
- `needs_more_steps`: Indicates whether additional steps are required to complete the workflow
25-
26-
## Features
47+
- `is_step_revision` (boolean): Set to `true` if this step revises or corrects a previous step.
48+
- `revises_step` (integer): If `is_step_revision` is true, specify the `step_number` of the step being revised. Must be a valid, existing step number.
49+
- `branch_from_step` (integer): If creating a new branch, specify the `step_number` from which this new branch originates. Must be a valid, existing step number.
50+
- `branch_id` (string): A unique and descriptive identifier for the branch being created or continued (e.g., "explore-alternative-api", "deep-dive-cause-analysis"). Required if `branch_from_step` is provided for a new branch, or if continuing an existing branch.
51+
- `needs_more_steps` (boolean): Set to `true` if you anticipate more steps are needed to fully resolve the *overall problem*, even if `next_step_needed` is `false` for the current step (e.g., you've completed a branch but need to return to the main flow or analyze another aspect). If omitted, the system may infer based on `next_step_needed` and `total_steps`. Set explicitly to `false` when the entire problem is solved.
2752

28-
- **Sequential Progression**: Track steps in order with automatic numbering
29-
- **Branching**: Create alternative solution paths from any step
30-
- **Step Revision**: Update and improve previous steps as understanding evolves
53+
## Features Summary
3154

32-
- **Context Preservation**: Maintain workflow state across multiple interactions
33-
- **Validation**: Automatic validation of step relationships and branching logic
55+
- **Sequential Progression**: Steps are tracked in order.
56+
- **Dynamic `total_steps`**: The `total_steps` can be adjusted by you as the workflow progresses.
57+
- **Branching**: Create and switch between alternative solution paths.
58+
- **Step Revision**: Mark steps that update or correct prior steps.
59+
- **Context Preservation**: Workflow state (history, branches) is maintained across calls.
60+
- **Input Validation**: Ensures logical consistency of parameters.
3461

3562
## Output
3663

37-
Returns a JSON response containing:
38-
- Current step information and status
39-
- Branch information and active branch status
40-
- Step count and completion status
64+
Returns a JSON object detailing the current workflow status:
65+
- `step_number` (integer): The number of the step just processed.
66+
- `total_steps` (integer): The current total number of steps, possibly updated by the last call.
67+
- `next_step_needed` (boolean): The `next_step_needed` value from the last step.
68+
- `last_step_description` (string): The description of the step just processed.
69+
- `current_branch` (string | null): The ID of the active branch, if any.
70+
- `branches` (array of strings): A list of all unique `branch_id`s created so far.
71+
- `step_history_length` (integer): The total number of steps recorded in the main history (includes steps from all branches).

src/developer/mod.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl Developer {
9191
shell: Shell::new().with_ignore_patterns(ignore_patterns),
9292
screen_capture: ScreenCapture::new(),
9393
image_processor: ImageProcessor::new(),
94-
workflow: Workflow::default(),
94+
workflow: Workflow::new(true, None, true),
9595
}
9696
}
9797

@@ -256,32 +256,44 @@ impl Developer {
256256
#[schemars(description = "Detailed description of what this step accomplishes")]
257257
step_description: String,
258258
#[tool(param)]
259-
#[schemars(description = "Current position in the workflow sequence (e.g., 1 for first step)")]
259+
#[schemars(
260+
description = "Current position in the workflow sequence (e.g., 1 for first step)"
261+
)]
260262
step_number: i32,
261263
#[tool(param)]
262264
#[schemars(description = "Estimated total number of steps in the complete workflow")]
263265
total_steps: i32,
264266
#[tool(param)]
265-
#[schemars(description = "Set to true if another step will follow this one, false if this is the final step")]
267+
#[schemars(
268+
description = "Set to true if another step will follow this one, false if this is the final step"
269+
)]
266270
next_step_needed: bool,
267271
#[tool(param)]
268272
#[schemars(description = "Set to true if this step revises a previous step")]
269273
is_step_revision: Option<bool>,
270274
#[tool(param)]
271-
#[schemars(description = "If revising a previous step, specify which step number is being revised")]
275+
#[schemars(
276+
description = "If revising a previous step, specify which step number is being revised"
277+
)]
272278
revises_step: Option<i32>,
273279
#[tool(param)]
274-
#[schemars(description = "If creating a branch, specify which step number this branch starts from")]
280+
#[schemars(
281+
description = "If creating a branch, specify which step number this branch starts from"
282+
)]
275283
branch_from_step: Option<i32>,
276284
#[tool(param)]
277-
#[schemars(description = "A unique identifier for this branch (required when creating a branch)")]
285+
#[schemars(
286+
description = "A unique identifier for this branch (required when creating a branch)"
287+
)]
278288
branch_id: Option<String>,
279289
#[tool(param)]
280-
#[schemars(description = "Indicates whether additional steps are required to complete the workflow")]
290+
#[schemars(
291+
description = "Indicates whether additional steps are required to complete the workflow"
292+
)]
281293
needs_more_steps: Option<bool>,
282294
) -> Result<CallToolResult, McpError> {
283295
use workflow::WorkflowStep;
284-
296+
285297
let step = WorkflowStep {
286298
step_description,
287299
step_number,
@@ -296,8 +308,6 @@ impl Developer {
296308

297309
self.workflow.execute_step(step).await
298310
}
299-
300-
301311
}
302312

303313
#[tool(tool_box)]

src/developer/workflow.rs

Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub struct Workflow {
4040
state: Arc<Mutex<WorkflowState>>,
4141
allow_branches: bool,
4242
max_steps: Option<i32>,
43+
log_steps: bool,
4344
}
4445

4546
impl Default for Workflow {
@@ -48,62 +49,101 @@ impl Default for Workflow {
4849
state: Arc::new(Mutex::new(WorkflowState::default())),
4950
allow_branches: true,
5051
max_steps: None,
52+
log_steps: true,
5153
}
5254
}
5355
}
5456

5557
impl Workflow {
56-
pub fn new(allow_branches: bool, max_steps: Option<i32>) -> Self {
58+
pub fn new(allow_branches: bool, max_steps: Option<i32>, log_steps: bool) -> Self {
5759
Self {
5860
state: Arc::new(Mutex::new(WorkflowState::default())),
5961
allow_branches,
6062
max_steps,
63+
log_steps,
6164
}
6265
}
6366

6467
pub async fn execute_step(&self, args: WorkflowStep) -> Result<CallToolResult, McpError> {
68+
// Optional: Log the received arguments at the beginning
69+
if self.log_steps {
70+
tracing::debug!(workflow_step_args = ?args, "Workflow step arguments received");
71+
}
72+
6573
if let Some(max) = self.max_steps {
6674
if args.step_number > max {
67-
return Ok(Self::error(format!(
75+
let error_msg = format!(
6876
"Step number {} exceeds configured maximum of {}",
6977
args.step_number, max
70-
)));
78+
);
79+
if self.log_steps {
80+
tracing::warn!(error_msg, "Workflow step validation error");
81+
}
82+
return Ok(Self::error(error_msg));
7183
}
7284
}
7385

7486
let mut state = self.state.lock().await;
7587

7688
let mut step_data = args.clone();
7789
if step_data.step_number > step_data.total_steps {
90+
// Log this adjustment if desired
91+
if self.log_steps {
92+
tracing::info!(
93+
old_total_steps = step_data.total_steps,
94+
new_total_steps = step_data.step_number,
95+
step_number = step_data.step_number,
96+
"Adjusting total_steps to match current step_number as it was greater."
97+
);
98+
}
7899
step_data.total_steps = step_data.step_number;
79100
}
80101

81102
if step_data.revises_step.is_some() && step_data.is_step_revision.is_none() {
82-
return Ok(Self::error(
83-
"When specifying revises_step, is_step_revision must be set to true",
84-
));
103+
let error_msg = "When specifying revises_step, is_step_revision must be set to true";
104+
if self.log_steps {
105+
tracing::warn!(error_msg, invalid_revision_args = ?step_data, "Workflow step validation error");
106+
}
107+
return Ok(Self::error(error_msg));
85108
}
86109

87110
if step_data.branch_id.is_some() && step_data.branch_from_step.is_none() {
88-
return Ok(Self::error(
89-
"When creating a branch (branch_id), you must specify branch_from_step",
90-
));
111+
let error_msg = "When creating a branch (branch_id), you must specify branch_from_step";
112+
if self.log_steps {
113+
tracing::warn!(error_msg, invalid_branch_args = ?step_data, "Workflow step validation error");
114+
}
115+
return Ok(Self::error(error_msg));
91116
}
92117

93118
if let (Some(branch_id), Some(branch_from_step)) =
94119
(&step_data.branch_id, &step_data.branch_from_step)
95120
{
96121
if !self.allow_branches {
97-
return Ok(Self::error(
98-
"Branching is disabled in current configuration",
99-
));
122+
let error_msg = "Branching is disabled in current configuration";
123+
if self.log_steps {
124+
tracing::warn!(error_msg, "Workflow branching validation error");
125+
}
126+
return Ok(Self::error(error_msg));
100127
}
101128

102129
if *branch_from_step <= 0 || *branch_from_step > state.step_history.len() as i32 {
103-
return Ok(Self::error(format!(
130+
let error_msg = format!(
104131
"branch_from_step {} does not exist in step history",
105132
branch_from_step
106-
)));
133+
);
134+
if self.log_steps {
135+
tracing::warn!(error_msg, "Workflow branching validation error");
136+
}
137+
return Ok(Self::error(error_msg));
138+
}
139+
140+
if self.log_steps {
141+
tracing::info!(
142+
branch_id,
143+
branch_from_step,
144+
step_number = step_data.step_number,
145+
"Processing branch step."
146+
);
107147
}
108148

109149
state.current_branch = Some(branch_id.clone());
@@ -113,16 +153,44 @@ impl Workflow {
113153
.or_default()
114154
.push(step_data.clone());
115155
} else if state.current_branch.is_some() && step_data.branch_id.is_none() {
156+
if self.log_steps {
157+
tracing::info!(
158+
previous_branch = ?state.current_branch,
159+
step_number = step_data.step_number,
160+
"Moving from branch back to main history (or default)."
161+
);
162+
}
116163
state.current_branch = None;
117164
}
118165

119166
state.step_history.push(step_data.clone());
120167

121-
let response = self.build_workflow_status(&state, &step_data).await;
168+
// Log before returning success
169+
if self.log_steps {
170+
tracing::info!(
171+
step_number = step_data.step_number,
172+
total_steps = step_data.total_steps,
173+
description = step_data.step_description.as_str(),
174+
is_revision = step_data.is_step_revision,
175+
revises_step = step_data.revises_step,
176+
branch_id = step_data.branch_id.as_deref(),
177+
next_step_needed = step_data.next_step_needed,
178+
needs_more_steps = step_data.needs_more_steps,
179+
"Workflow step processed successfully."
180+
);
181+
}
122182

123-
match serde_json::to_string_pretty(&response) {
183+
let response_status = self.build_workflow_status(&state, &step_data).await;
184+
185+
match serde_json::to_string_pretty(&response_status) {
124186
Ok(json_response) => Ok(Self::success(json_response)),
125-
Err(e) => Ok(Self::error(format!("Failed to serialize response: {}", e))),
187+
Err(e) => {
188+
// Also log serialization errors
189+
if self.log_steps {
190+
tracing::error!(error = %e, "Failed to serialize workflow status response");
191+
}
192+
Ok(Self::error(format!("Failed to serialize response: {}", e)))
193+
}
126194
}
127195
}
128196

@@ -235,18 +303,20 @@ mod tests {
235303

236304
#[test]
237305
fn test_workflow_creation() {
238-
let tool = Workflow::new(true, Some(10));
306+
let tool = Workflow::new(true, Some(10), true);
239307
assert_eq!(tool.allow_branches, true);
240308
assert_eq!(tool.max_steps, Some(10));
309+
assert_eq!(tool.log_steps, true);
241310

242311
let default_tool = Workflow::default();
243312
assert_eq!(default_tool.allow_branches, true);
244313
assert_eq!(default_tool.max_steps, None);
314+
assert_eq!(default_tool.log_steps, true);
245315
}
246316

247317
#[tokio::test]
248318
async fn test_error_conditions() {
249-
let tool = Workflow::new(false, Some(2)); // No branching, max 2 steps
319+
let tool = Workflow::new(false, Some(2), false); // No branching, max 2 steps, no logging for test
250320

251321
// Test max steps exceeded
252322
let step = WorkflowStep {

0 commit comments

Comments
 (0)