Skip to main content

bamboo_engine/runtime/task_evaluation/
message_builder.rs

1use std::cmp::Reverse;
2
3use bamboo_agent_core::{Message, Session};
4
5use super::super::task_context::{TaskLoopContext, ToolCallRecord};
6
7/// 构建用于 TaskList 评估的 messages
8pub fn build_task_evaluation_messages(ctx: &TaskLoopContext, _session: &Session) -> Vec<Message> {
9    let mut messages = Vec::new();
10
11    let system_prompt = r#"You are a task progress evaluator. Your job is to evaluate whether tasks are complete based on the execution context.
12
13## Your Task
14Review the task list and execution history, then decide if any tasks should be marked as completed or blocked.
15
16## Rules
171. Mark as "completed" if the task goal has been achieved
182. Mark as "blocked" if there are unresolvable issues
193. Keep as "in_progress" if more work is needed
204. Add brief notes explaining your decision
215. If a task includes completion criteria, only mark it completed when every criterion is met
22
23## Available Actions
24- update_task_item: Update the status of a task item
25
26## Constraints
27- Only update items that are currently "in_progress"
28- You MUST call update_task_item if a task is complete
29- Provide clear reasoning in notes
30- When status is "completed" for a task with completion criteria, `criteria_met` MUST use criterion IDs (for example `c1`, `c2`); do not paraphrase criteria text
31"#;
32
33    messages.push(Message::system(system_prompt));
34
35    let task_context = format!(
36        r#"
37## Current Task List (Round {}/{})
38
39{}
40
41## Recent Tool Executions
42{}
43
44## Instructions
45Review each "in_progress" task above. For each task:
461. Check if the goal has been achieved based on tool execution results
472. If complete, call update_task_item with status="completed", brief notes, and `criteria_met` criterion IDs for tasks that define criteria
483. If blocked, call update_task_item with status="blocked" and explain the issue
49
50Remember: You are NOT executing the task. You are only evaluating if existing work has completed it.
51"#,
52        ctx.current_round + 1,
53        ctx.max_rounds,
54        ctx.format_for_prompt(),
55        format_recent_tools(ctx, 5),
56    );
57
58    messages.push(Message::user(task_context));
59    messages
60}
61
62/// 格式化最近的 tool 调用(用于 context)
63pub(super) fn format_recent_tools(ctx: &TaskLoopContext, limit: usize) -> String {
64    let mut all_calls: Vec<(String, &ToolCallRecord)> = Vec::new();
65
66    for item in &ctx.items {
67        for call in &item.tool_calls {
68            all_calls.push((item.description.clone(), call));
69        }
70    }
71
72    all_calls.sort_by_key(|(_, call)| Reverse(call.timestamp));
73
74    let recent: Vec<_> = all_calls.into_iter().take(limit).collect();
75
76    if recent.is_empty() {
77        return "No tool executions yet.".to_string();
78    }
79
80    let mut output = String::new();
81    for (index, (task_desc, call)) in recent.iter().enumerate() {
82        output.push_str(&format!(
83            "{}. [{}] Tool: {} ({})\n   Task: {}\n",
84            index + 1,
85            if call.success { "✓" } else { "✗" },
86            call.tool_name,
87            call.round + 1,
88            task_desc
89        ));
90    }
91
92    output
93}