2026-07-12 11:28:39 +07:00
|
|
|
//! 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`.
|
|
|
|
|
|
2026-07-11 20:21:59 +07:00
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
use anyhow::{Result, anyhow};
|
|
|
|
|
use super::Tool;
|
|
|
|
|
use super::ToolCtx;
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Tool: fetch buffered output from a background bash job by `job_id`.
|
2026-07-11 20:21:59 +07:00
|
|
|
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<String> {
|
|
|
|
|
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)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Tool: terminate a running background bash job by `job_id`.
|
2026-07-11 20:21:59 +07:00
|
|
|
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<String> {
|
|
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
}
|