feat: enhance subagent context with abort flag and implement tool call timeout

This commit is contained in:
asepharyana
2026-07-13 04:59:16 +07:00
parent 3b711bbf3b
commit 2856dd78b8
9 changed files with 272 additions and 131 deletions
+23
View File
@@ -36,6 +36,11 @@ impl Tool for BashOutput {
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("missing required argument: job_id"))?
.to_string();
// Validate that job_id looks like a UUID to prevent injection
// into the global job registry.
if !is_valid_job_id(&job_id) {
anyhow::bail!("invalid job_id format: expected UUID");
}
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)),
@@ -73,7 +78,25 @@ impl Tool for BashKill {
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("missing required argument: job_id"))?
.to_string();
if !is_valid_job_id(&job_id) {
anyhow::bail!("invalid job_id format: expected UUID");
}
crate::app::bgbash::control::bash_kill(&job_id)?;
Ok(format!("Killed background job '{}'", job_id))
}
}
/// Validate that a job_id matches UUID v4 format (hex with dashes).
fn is_valid_job_id(id: &str) -> bool {
// UUID v4 format: 8-4-4-4-12 hex digits
let parts: Vec<&str> = id.split('-').collect();
if parts.len() != 5 {
return false;
}
parts.iter().all(|p| !p.is_empty() && p.chars().all(|c| c.is_ascii_hexdigit()))
&& parts[0].len() == 8
&& parts[1].len() == 4
&& parts[2].len() == 4
&& parts[3].len() == 4
&& parts[4].len() == 12
}