use crate::sandbox::Sandbox;
use crate::tools::{ToolCtx, ToolOutcome};
use schemars::JsonSchema;
use serde::Deserialize;
use serde_json::json;
use std::sync::Arc;
use std::time::{Duration, Instant};
const WAIT_WINDOW: Duration = Duration::from_secs(2);
const POLL_INTERVAL: Duration = Duration::from_millis(100);
#[derive(Deserialize, JsonSchema)]
pub struct CheckArgs {
pub id: String,
pub wait_secs: Option<u64>,
}
pub async fn check(
_sandbox: Arc<dyn Sandbox>,
args: CheckArgs,
ctx: ToolCtx,
) -> Result<ToolOutcome, String> {
if let Some(wait_secs) = args.wait_secs {
tokio::time::sleep(Duration::from_secs(wait_secs)).await;
let snap = ctx.tasks.poll(&args.id).ok_or_else(|| {
format!(
"未找到后台任务: {}(可能已被 kill,或进程重启后丢失)",
args.id
)
})?;
return snapshot_to_outcome(snap);
}
let deadline = Instant::now() + WAIT_WINDOW;
loop {
let snap = ctx.tasks.poll(&args.id).ok_or_else(|| {
format!(
"未找到后台任务: {}(可能已被 kill,或进程重启后丢失)",
args.id
)
})?;
if !snap.new_output.is_empty() || snap.finished || Instant::now() >= deadline {
return snapshot_to_outcome(snap);
}
tokio::time::sleep(POLL_INTERVAL).await;
}
}
fn snapshot_to_outcome(snap: crate::tasks::TaskSnapshot) -> Result<ToolOutcome, String> {
if let Some(err) = snap.error {
return Err(err);
}
let status = if snap.finished {
"completed"
} else {
"running"
};
Ok(json!({
"status": status,
"exit_code": snap.exit_code,
"output": snap.new_output,
})
.into())
}