//! Tool implementations for interacting with background bash jobs: `bash_output` //! and `bash_kill`. Both take a `job_id` produced by `bash` with `run_in_background=true`. use serde_json::{json, Value}; use anyhow::{Result, anyhow}; use super::Tool; use super::ToolCtx; /// Tool: fetch buffered output from a background bash job by `job_id`. pub struct BashOutput; impl Tool for BashOutput { fn name(&self) -> &'static str { "bash_output" } fn description(&self) -> &'static str { "Retrieve output from a background bash job by job_id" } fn parameters(&self) -> Value { json!({ "type": "object", "properties": { "job_id": { "type": "string", "description": "Job ID returned by bash with run_in_background=true" } }, "required": ["job_id"] }) } fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result { let job_id = args.get("job_id") .and_then(|v| v.as_str()) .ok_or_else(|| anyhow!("missing required argument: job_id"))? .to_string(); match crate::app::bgbash::control::bash_output(&job_id) { Some(lines) => Ok(lines.join("\n")), None => Ok(format!("No new output from job '{}'", job_id)), } } } /// Tool: terminate a running background bash job by `job_id`. pub struct BashKill; impl Tool for BashKill { fn name(&self) -> &'static str { "bash_kill" } fn description(&self) -> &'static str { "Kill a background bash job by job_id" } fn parameters(&self) -> Value { json!({ "type": "object", "properties": { "job_id": { "type": "string", "description": "Job ID returned by bash with run_in_background=true" } }, "required": ["job_id"] }) } fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result { let job_id = args.get("job_id") .and_then(|v| v.as_str()) .ok_or_else(|| anyhow!("missing required argument: job_id"))? .to_string(); crate::app::bgbash::control::bash_kill(&job_id)?; Ok(format!("Killed background job '{}'", job_id)) } }