修复: AI工具调用健壮性+审批卡片可读化+任务工具补全

- AC1/AC2 anthropic_compat tool_use_id None/空时跳过或占位(防GLM端500卡死)
- AR-3 审批卡片 id→项目名回显(前端白名单特化) + 后端查不到友好提示
- FR-D6 补 delete_task/update_task 工具(防误用 delete_project 清理孤儿任务)
- FR-D7 抽 bind_dir_to_project 消除 create_project/bind_directory 重复
- FR-D8 create_idea schema 补 priority 契约对齐
- FR-S4 SKILL.md 注入加头尾隔离标注防 prompt injection 混淆
- FR-R4 complete() 加 60s 单请求超时(不影响 stream)
This commit is contained in:
2026-06-14 22:48:04 +08:00
parent 49ac0601e1
commit 36d68ddb26
8 changed files with 207 additions and 70 deletions

View File

@@ -3,6 +3,8 @@
//! 覆盖: OpenAI / GLM (open.bigmodel.cn) / DeepSeek / Claude OpenAI 兼容模式
//! 支持: 同步调用 + SSE 流式 + Function Calling / Tool Use
use std::time::Duration;
use async_trait::async_trait;
use eventsource_stream::Eventsource;
use futures::StreamExt;
@@ -392,14 +394,26 @@ impl LlmProvider for OpenAICompatProvider {
debug!(model = %openai_req.model, "OpenAI 同步调用");
// 同步路径整体超时(FR-R4)client 仅配 connect_timeout无总 timeout防误砍流式长生成
// complete 为一次性请求,挂死会让整轮对话静默卡住,此处用 RequestBuilder 的单请求 timeout 兜底,
// 超时返回 is_timeout 错误(不静默挂),且不影响 stream() 流式路径。
let resp = self
.client
.post(self.chat_url())
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Content-Type", "application/json")
.timeout(Duration::from_secs(60))
.json(&openai_req)
.send()
.await?;
.await
.map_err(|e| {
if e.is_timeout() {
error!(model = %openai_req.model, "OpenAI 同步调用超时(60s)");
anyhow::anyhow!("LLM 同步调用超时(60s),请检查网络或模型可用性: {}", e)
} else {
anyhow::anyhow!(e)
}
})?;
if !resp.status().is_success() {
let status = resp.status();