use crate::sandbox::Sandbox;
use crate::tools::{ToolCtx, ToolOutcome, merge_tool_result};
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);
}
if snap.finished {
return Ok(merge_tool_result(
"completed",
snap.new_output,
snap.result.unwrap_or_else(|| json!({})),
)
.into());
}
Ok(json!({
"status": "running",
"tool_name": snap.tool_name,
"output": snap.new_output,
})
.into())
}