Skip to content

Add TaskOutput tool for retrieving background task results #79

@evansenter

Description

@evansenter

Summary

Add a task_output tool to retrieve stdout/stderr from background tasks spawned via the task or bash tools.

Current State (as of PR #87)

  • BACKGROUND_TASKS: HashMap<String, tokio::process::Child> lives in bash.rs
  • task.rs imports it from bash.rs (tight coupling)
  • Background tasks use Stdio::null() - no output capture
  • Foreground tasks have kill_on_drop(true) for proper cleanup
  • kill_shell tool works for both bash and task background processes

Proposed Design (Revised)

Step 1: Extract Background Registry Module

First, extract shared state to src/tools/background.rs:

// src/tools/background.rs
use std::collections::HashMap;
use std::sync::{Arc, LazyLock, Mutex};
use std::sync::atomic::{AtomicUsize, AtomicBool, AtomicI32};
use tokio::process::Child;

pub static NEXT_TASK_ID: AtomicUsize = AtomicUsize::new(1);

pub struct BackgroundTask {
    pub child: Child,
    pub stdout_buffer: Arc<Mutex<String>>,
    pub stderr_buffer: Arc<Mutex<String>>,
    pub completed: AtomicBool,
    pub exit_code: AtomicI32,
}

pub static BACKGROUND_TASKS: LazyLock<Mutex<HashMap<String, BackgroundTask>>> =
    LazyLock::new(|| Mutex::new(HashMap::new()));

This cleans up the bash→task coupling and prepares for output capture.

Step 2: Async Output Collection

When spawning background tasks, create collection tasks:

let (stdout_tx, stdout_buffer) = create_output_collector();
let (stderr_tx, stderr_buffer) = create_output_collector();

let child = Command::new(&cmd)
    .args(&args)
    .stdout(Stdio::piped())
    .stderr(Stdio::piped())
    .spawn()?;

// Spawn collectors
let stdout = child.stdout.take().unwrap();
tokio::spawn(collect_output(stdout, stdout_tx));

let stderr = child.stderr.take().unwrap();
tokio::spawn(collect_output(stderr, stderr_tx));

Step 3: TaskOutput Tool

struct TaskOutputTool;

// Parameters
{
    "task_id": "string",     // Required
    "wait": "boolean",       // Wait for completion (default: false)
    "timeout": "integer"     // Max wait time in seconds (default: 30)
}

// Returns
{
    "task_id": "abc123",
    "status": "running" | "completed",
    "exit_code": 0,          // Only if completed
    "stdout": "output...",
    "stderr": "errors..."
}

Implementation Order

  1. Extract background.rs - Move registry, clean up imports in bash.rs and task.rs
  2. Add output capture - Modify background spawning in both tools
  3. Implement TaskOutput tool - New tool that reads from buffers
  4. Add integration tests (per comments below)

Complexity

Medium - requires:

  • New module extraction (straightforward refactor)
  • Registry structure change
  • Async output collection tasks
  • New tool implementation
  • Integration tests

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions