feat(#1095): add wait_seconds to bash_run for inline fast-command completion
This commit is contained in:
parent
60047eb01d
commit
e54c1b84d7
1 changed files with 42 additions and 4 deletions
|
|
@ -416,6 +416,16 @@ pub struct BashRunArgs {
|
||||||
/// `timed_out` when the limit is exceeded.
|
/// `timed_out` when the limit is exceeded.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub timeout_secs: Option<u64>,
|
pub timeout_secs: Option<u64>,
|
||||||
|
/// Optional inline wait: if set, `bash_run` polls for up to
|
||||||
|
/// `wait_seconds` (capped at 30) before returning. When the task
|
||||||
|
/// finishes within the window the full status is returned immediately
|
||||||
|
/// — no separate `bash_status` call needed. When the timeout expires
|
||||||
|
/// before the command finishes, the task keeps running in the
|
||||||
|
/// background and the usual `task started: id=<id>` response is
|
||||||
|
/// returned. Useful for fast commands (< 5 s) that would otherwise
|
||||||
|
/// force an unnecessary round-trip.
|
||||||
|
#[serde(default)]
|
||||||
|
pub wait_seconds: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MCP tool args for `bash_status`.
|
/// MCP tool args for `bash_status`.
|
||||||
|
|
@ -827,15 +837,43 @@ impl AgentServer {
|
||||||
do NOT wait inline. When the command finishes, the harness fires a wake with \
|
do NOT wait inline. When the command finishes, the harness fires a wake with \
|
||||||
`from: \"bash-task-<id>\"` and the exit code + last stdout lines in the body; \
|
`from: \"bash-task-<id>\"` and the exit code + last stdout lines in the body; \
|
||||||
handle it on a future turn. Use `bash_status` to poll the task status within \
|
handle it on a future turn. Use `bash_status` to poll the task status within \
|
||||||
the same turn if needed. `timeout_secs` defaults to 180."
|
the same turn if needed. `timeout_secs` defaults to 180. \
|
||||||
|
Pass `wait_seconds` (capped at 30) to wait inline for fast commands: when the \
|
||||||
|
task finishes within the window the full status is returned immediately and no \
|
||||||
|
wake is fired; when the timeout expires the task keeps running and the normal \
|
||||||
|
`task started: id=<id>` response is returned."
|
||||||
)]
|
)]
|
||||||
async fn bash_run(&self, Parameters(args): Parameters<BashRunArgs>) -> String {
|
async fn bash_run(&self, Parameters(args): Parameters<BashRunArgs>) -> String {
|
||||||
let log = format!("{args:?}");
|
let log = format!("{args:?}");
|
||||||
run_tool_envelope("bash_run", log, async move {
|
run_tool_envelope("bash_run", log, async move {
|
||||||
match crate::bash_runner::submit_task(args.cmd, args.timeout_secs) {
|
let id = match crate::bash_runner::submit_task(args.cmd, args.timeout_secs) {
|
||||||
Ok(id) => format!("task started: id={id}"),
|
Ok(id) => id,
|
||||||
Err(e) => format!("bash_run failed: {e:#}"),
|
Err(e) => return format!("bash_run failed: {e:#}"),
|
||||||
|
};
|
||||||
|
// Inline wait: poll until done or deadline, whichever comes first.
|
||||||
|
if let Some(wait) = args.wait_seconds {
|
||||||
|
const MAX_WAIT_SECS: u64 = 30;
|
||||||
|
const POLL_MS: u64 = 100;
|
||||||
|
let deadline =
|
||||||
|
tokio::time::Instant::now()
|
||||||
|
+ std::time::Duration::from_secs(wait.min(MAX_WAIT_SECS));
|
||||||
|
loop {
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(POLL_MS)).await;
|
||||||
|
if let Some(task) = crate::bash_runner::read_task(&id) {
|
||||||
|
use crate::bash_runner::TaskStatus;
|
||||||
|
if matches!(
|
||||||
|
task.status,
|
||||||
|
TaskStatus::Done | TaskStatus::TimedOut | TaskStatus::Interrupted
|
||||||
|
) {
|
||||||
|
return format_bash_status(&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tokio::time::Instant::now() >= deadline {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
format!("task started: id={id}")
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue