修复: spawn panic 兜底 + namespace 淘汰提示 + run_command 超时与破坏命令信任门控

This commit is contained in:
lxy
2026-08-01 11:10:28 +08:00
parent 468950616b
commit c4ba920cf5
7 changed files with 145 additions and 11 deletions
+21 -5
View File
@@ -139,17 +139,33 @@ async fn execute_with_heartbeat(
let _guard = HeartbeatGuard { stop, handle: heartbeat };
// tools.execute 无 timeout 时,卡死工具(run_command 长命令/read_file 大文件/同步
// 阻塞工具)永久挂起 → process_tool_calls 持 session lock 永久 → guard.reset 等 lock → AiCompleted
// 永不发 → 前端"回答完卡住/超时清空"。60s timeout 兜底:超时返错误 tool_result,锁释放,loop 续跑。
// 心跳 30s 续命前端 watchdog,60s timeout 覆盖绝大多数工具(run_command 已自带 10s 子超时)
match tokio::time::timeout(Duration::from_secs(60), tools.execute(name, args)).await {
// 永不发 → 前端"回答完卡住/超时清空"。外层 timeout 兜底:超时返错误 tool_result,锁释放,loop 续跑。
// 心跳 30s 续命前端 watchdog。
//
// 外层 timeout 取值(BUF-run-cmd-timeout):原硬编码 60s 会先于 run_command 自带 timeout_secs
// (上限 600s)drop,致 run_command 跑长构建(cargo/npm)永远到不了用户配的 timeout_secs。
// run_command 分支从 args.timeout_secs 取值(clamp [60,600],默认 60,与 tool_registry.rs:2707
// run_command 内部 clamp 同源),其余工具仍 60s。run_command 内部还有自己的子 timeout,
// 外层只需 >= 内部 timeout 即不抢断(run_command 内部超时会返带语义的 tool_result,优于外层裸中止)。
let outer_secs: u64 = if name == "run_command" {
args.get("timeout_secs")
.and_then(|v| v.as_u64())
.unwrap_or(60)
.clamp(60, 600)
} else {
60
};
match tokio::time::timeout(Duration::from_secs(outer_secs), tools.execute(name, args)).await {
Ok(result) => result,
Err(_elapsed) => {
tracing::error!(
conv_id = %conv_id,
tool = %name,
"[ai] 工具执行超时(60s),返回错误 tool_result(防 process_tool_calls 持 session lock 永久卡死)"
outer_secs,
"[ai] 工具执行超时({}s),返回错误 tool_result(防 process_tool_calls 持 session lock 永久卡死)",
outer_secs
);
Err(anyhow::anyhow!("工具执行超时(60s),已中止(防死锁)"))
Err(anyhow::anyhow!("工具执行超时({}s),已中止(防死锁)", outer_secs))
}
}
}