Skip to content
Open
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
225 changes: 161 additions & 64 deletions src/tools/impls/background_tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use serde_json::json;

use super::{handlers, Tool, ToolPipeline};
use crate::impl_base_block;
use crate::transcript::{render_approval_prompt, render_prefix, render_result, Block, BlockType, Status};
use crate::transcript::{render_tool_block, Block, BlockType, Status};

// =============================================================================
// ListBackgroundTasks block
Expand Down Expand Up @@ -47,36 +47,7 @@ impl Block for ListBackgroundTasksBlock {
impl_base_block!(BlockType::Tool);

fn render(&self, _width: u16) -> Vec<Line<'_>> {
let mut lines = Vec::new();

// Format: list_background_tasks()
let spans = vec![
self.render_status(),
render_prefix(self.background),
Span::styled("list_background_tasks", Style::default().fg(Color::Magenta)),
Span::styled("()", Style::default().fg(Color::DarkGray)),
];
lines.push(Line::from(spans));

// Approval prompt if pending
if self.status == Status::Pending {
lines.push(render_approval_prompt());
}

// Output if completed
if !self.text.is_empty() {
lines.extend(render_result(&self.text, 10));
}

// Denied message
if self.status == Status::Denied {
lines.push(Line::from(Span::styled(
" Denied by user",
Style::default().fg(Color::DarkGray),
)));
}

lines
render_tool_block(self.status, self.background, "list_background_tasks", vec![], &self.text, 10)
}

fn call_id(&self) -> Option<&str> {
Expand Down Expand Up @@ -126,40 +97,9 @@ impl Block for GetBackgroundTaskBlock {
impl_base_block!(BlockType::Tool);

fn render(&self, _width: u16) -> Vec<Line<'_>> {
let mut lines = Vec::new();

let task_id = self.params["task_id"].as_str().unwrap_or("");

// Format: get_background_task(task_id)
let spans = vec![
self.render_status(),
render_prefix(self.background),
Span::styled("get_background_task", Style::default().fg(Color::Magenta)),
Span::styled("(", Style::default().fg(Color::DarkGray)),
Span::styled(task_id, Style::default().fg(Color::White)),
Span::styled(")", Style::default().fg(Color::DarkGray)),
];
lines.push(Line::from(spans));

// Approval prompt if pending
if self.status == Status::Pending {
lines.push(render_approval_prompt());
}

// Output if completed
if !self.text.is_empty() {
lines.extend(render_result(&self.text, 10));
}

// Denied message
if self.status == Status::Denied {
lines.push(Line::from(Span::styled(
" Denied by user",
Style::default().fg(Color::DarkGray),
)));
}

lines
let args = vec![Span::styled(task_id.to_string(), Style::default().fg(Color::White))];
render_tool_block(self.status, self.background, "get_background_task", args, &self.text, 10)
}

fn call_id(&self) -> Option<&str> {
Expand Down Expand Up @@ -275,3 +215,160 @@ impl Tool for GetBackgroundTaskTool {
Box::new(GetBackgroundTaskBlock::new(call_id, self.name(), params, background))
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::transcript::lines_to_string;
use serde_json::json;

// =========================================================================
// ListBackgroundTasksBlock render tests
// =========================================================================

#[test]
fn test_list_render_pending() {
let block = ListBackgroundTasksBlock::new(
"call_1",
"mcp_list_background_tasks",
json!({}),
false,
);
let output = lines_to_string(&block.render(80));
assert_eq!(output, "? list_background_tasks()\n [y]es [n]o");
}

#[test]
fn test_list_render_running() {
let mut block = ListBackgroundTasksBlock::new(
"call_1",
"mcp_list_background_tasks",
json!({}),
false,
);
block.status = Status::Running;
let output = lines_to_string(&block.render(80));
assert_eq!(output, "⚙ list_background_tasks()");
}

#[test]
fn test_list_render_complete_with_output() {
let mut block = ListBackgroundTasksBlock::new(
"call_1",
"mcp_list_background_tasks",
json!({}),
false,
);
block.status = Status::Complete;
block.text = "task_1: shell (Complete)\ntask_2: read_file (Running)".to_string();
let output = lines_to_string(&block.render(80));
assert_eq!(output, "✓ list_background_tasks()\n task_1: shell (Complete)\n task_2: read_file (Running)");
}

#[test]
fn test_list_render_denied() {
let mut block = ListBackgroundTasksBlock::new(
"call_1",
"mcp_list_background_tasks",
json!({}),
false,
);
block.status = Status::Denied;
let output = lines_to_string(&block.render(80));
assert_eq!(output, "⊘ list_background_tasks()\n Denied by user");
}

#[test]
fn test_list_render_background() {
let block = ListBackgroundTasksBlock::new(
"call_1",
"mcp_list_background_tasks",
json!({}),
true,
);
let output = lines_to_string(&block.render(80));
assert_eq!(output, "? [bg] list_background_tasks()\n [y]es [n]o");
}

// =========================================================================
// GetBackgroundTaskBlock render tests
// =========================================================================

#[test]
fn test_get_render_pending() {
let block = GetBackgroundTaskBlock::new(
"call_1",
"mcp_get_background_task",
json!({"task_id": "task_123"}),
false,
);
let output = lines_to_string(&block.render(80));
assert_eq!(output, "? get_background_task(task_123)\n [y]es [n]o");
}

#[test]
fn test_get_render_running() {
let mut block = GetBackgroundTaskBlock::new(
"call_1",
"mcp_get_background_task",
json!({"task_id": "task_123"}),
false,
);
block.status = Status::Running;
let output = lines_to_string(&block.render(80));
assert_eq!(output, "⚙ get_background_task(task_123)");
}

#[test]
fn test_get_render_complete_with_output() {
let mut block = GetBackgroundTaskBlock::new(
"call_1",
"mcp_get_background_task",
json!({"task_id": "task_123"}),
false,
);
block.status = Status::Complete;
block.text = "file1.txt\nfile2.txt".to_string();
let output = lines_to_string(&block.render(80));
assert_eq!(output, "✓ get_background_task(task_123)\n file1.txt\n file2.txt");
}

#[test]
fn test_get_render_denied() {
let mut block = GetBackgroundTaskBlock::new(
"call_1",
"mcp_get_background_task",
json!({"task_id": "task_123"}),
false,
);
block.status = Status::Denied;
let output = lines_to_string(&block.render(80));
assert_eq!(output, "⊘ get_background_task(task_123)\n Denied by user");
}

#[test]
fn test_get_render_background() {
let block = GetBackgroundTaskBlock::new(
"call_1",
"mcp_get_background_task",
json!({"task_id": "task_123"}),
true,
);
let output = lines_to_string(&block.render(80));
assert_eq!(output, "? [bg] get_background_task(task_123)\n [y]es [n]o");
}

#[test]
fn test_get_render_error() {
let mut block = GetBackgroundTaskBlock::new(
"call_1",
"mcp_get_background_task",
json!({"task_id": "task_123"}),
false,
);
block.status = Status::Error;
block.text = "Task not found".to_string();
let output = lines_to_string(&block.render(80));
assert_eq!(output, "✗ get_background_task(task_123)\n Task not found");
}
}
Loading