修复: AI 删项目改软删 + 补回收站三工具 + list_projects 排除回收站
- delete_project 由 repo.delete 物理删改 soft_delete(与 UI 删一致) - 新增 restore_project / purge_project / list_trash 三工具(复用 ProjectRepo 回收站方法) - list_projects 改 list_active 排除回收站,防 LLM 看到已删项目继续操作 Sprint 20 审查 ①② + Workflow A 验证发现 list_projects 泄漏
This commit is contained in:
@@ -85,7 +85,7 @@ pub fn build_ai_tool_registry(db: &Arc<Database>) -> AiToolRegistry {
|
||||
let db = db.clone();
|
||||
Box::pin(async move {
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
let mut items = repo.list_all().await?;
|
||||
let mut items = repo.list_active().await?; // list_active 排除回收站(deleted_at),防 LLM 看到已软删项目
|
||||
items.truncate(50); // 防 LLM context 膨胀
|
||||
Ok(serde_json::to_value(items)?)
|
||||
})
|
||||
@@ -253,18 +253,57 @@ pub fn build_ai_tool_registry(db: &Arc<Database>) -> AiToolRegistry {
|
||||
|
||||
// ── 高风险 (High) ──
|
||||
registry.register(
|
||||
"delete_project", "删除项目及其所有关联数据",
|
||||
"delete_project", "删除项目(移入回收站,可恢复。永久删除用 purge_project)",
|
||||
df_ai::ai_tools::object_schema(vec![("id", "string", true)]), RiskLevel::High,
|
||||
{ let db = db.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let db = db.clone();
|
||||
Box::pin(async move {
|
||||
let id = args["id"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 id"))?;
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
let deleted = repo.delete(id).await?;
|
||||
let deleted = repo.soft_delete(id).await?;
|
||||
Ok(serde_json::json!({ "deleted": deleted, "id": id }))
|
||||
})
|
||||
})},
|
||||
);
|
||||
registry.register(
|
||||
"restore_project", "从回收站恢复已删除项目",
|
||||
df_ai::ai_tools::object_schema(vec![("id", "string", true)]), RiskLevel::High,
|
||||
{ let db = db.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let db = db.clone();
|
||||
Box::pin(async move {
|
||||
let id = args["id"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 id"))?;
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
let restored = repo.restore(id).await?;
|
||||
Ok(serde_json::json!({ "restored": restored, "id": id }))
|
||||
})
|
||||
})},
|
||||
);
|
||||
registry.register(
|
||||
"purge_project", "永久删除项目及关联数据(不可恢复)",
|
||||
df_ai::ai_tools::object_schema(vec![("id", "string", true)]), RiskLevel::High,
|
||||
{ let db = db.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let db = db.clone();
|
||||
Box::pin(async move {
|
||||
let id = args["id"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 id"))?;
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
let purged = repo.purge_with_descendants(id).await?;
|
||||
Ok(serde_json::json!({ "purged": purged, "id": id }))
|
||||
})
|
||||
})},
|
||||
);
|
||||
registry.register(
|
||||
"list_trash", "列出回收站已删除项目",
|
||||
df_ai::ai_tools::object_schema(vec![]), RiskLevel::Low,
|
||||
{ let db = db.clone(); Box::new(move |_args: serde_json::Value| {
|
||||
let db = db.clone();
|
||||
Box::pin(async move {
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
let mut items = repo.list_deleted().await?;
|
||||
items.truncate(50); // 防 LLM context 膨胀
|
||||
Ok(serde_json::to_value(items)?)
|
||||
})
|
||||
})},
|
||||
);
|
||||
registry.register(
|
||||
"run_workflow", "运行指定的工作流 DAG",
|
||||
df_ai::ai_tools::object_schema(vec![("name", "string", true), ("dag", "object", true)]), RiskLevel::High,
|
||||
|
||||
Reference in New Issue
Block a user