修复: AR-3 审批 reason 查项目名拼对象名(用户再反馈 P0)
build_approval_reason 改 async + 接收 db,对 delete/restore/purge/update/bind/create_task 的 id/project_id 查 ProjectRepo.get_by_id 拼「项目名」(id=x)(原只拼裸 id,用户反馈'只返回 ID 不知道是什么数据') 新增 resolve_project_label helper;process_tool_calls 调用改 await 来源 aichat审查报告 第二章 + 用户 2026-06-14 再反馈;cargo 0 err
This commit is contained in:
@@ -7,7 +7,7 @@ use tauri::{AppHandle, Emitter};
|
|||||||
|
|
||||||
use df_ai::ai_tools::{AiToolRegistry, RiskLevel};
|
use df_ai::ai_tools::{AiToolRegistry, RiskLevel};
|
||||||
use df_ai::provider::ChatMessage;
|
use df_ai::provider::ChatMessage;
|
||||||
use df_storage::crud::AiToolExecutionRepo;
|
use df_storage::crud::{AiToolExecutionRepo, ProjectRepo};
|
||||||
use df_storage::db::Database;
|
use df_storage::db::Database;
|
||||||
use df_storage::models::AiToolExecutionRecord;
|
use df_storage::models::AiToolExecutionRecord;
|
||||||
|
|
||||||
@@ -38,45 +38,79 @@ pub(crate) fn risk_from_str(s: &str) -> Option<RiskLevel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 查项目可读标签:id → "「项目名」(id=x)",查不到回退 "(id=x)",空 id 返回空串。
|
||||||
|
///
|
||||||
|
/// AR-3:审批卡片需显示对象名而非裸 id(用户反馈"只返回 ID 不知道是什么数据")。
|
||||||
|
async fn resolve_project_label(db: &Arc<Database>, id: &str) -> String {
|
||||||
|
if id.is_empty() {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
let repo = ProjectRepo::new(db);
|
||||||
|
match repo.get_by_id(id).await {
|
||||||
|
Ok(Some(p)) => format!("「{}」(id={})", p.name, id),
|
||||||
|
_ => format!("(id={})", id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 拼审批 reason:按工具名 + args 取可读字段,让用户知道"审批要做什么"。
|
/// 拼审批 reason:按工具名 + args 取可读字段,让用户知道"审批要做什么"。
|
||||||
///
|
///
|
||||||
/// 主要审批工具特化(带对象名/标识):
|
/// 主要审批工具特化(带对象名/标识):
|
||||||
/// - delete_project/restore_project/purge_project → "删除/恢复/清除项目"+id
|
/// - delete_project/restore_project/purge_project → 查项目名拼"删除项目「名」(id=x)"
|
||||||
/// - update_project → "修改项目"+field
|
/// - update_project → 查项目名 + field
|
||||||
/// - bind_directory → "绑定目录"+path
|
/// - bind_directory → path + 查项目名
|
||||||
/// - create_task → "创建任务"+title;create_project → "创建项目"+name;create_idea → "捕获灵感"+title
|
/// - create_task → title + 查 project_id 项目名;create_project → name;create_idea → title
|
||||||
/// - run_workflow → "运行工作流"+name
|
/// - run_workflow → name
|
||||||
/// args 无可读字段或工具未特化时,fallback 原 risk 模板(含风险等级提示)。
|
/// args 无可读字段或工具未特化时,fallback 原 risk 模板(含风险等级提示)。
|
||||||
fn build_approval_reason(tool_name: &str, args: &serde_json::Value, risk_level: RiskLevel) -> String {
|
async fn build_approval_reason(
|
||||||
|
tool_name: &str,
|
||||||
|
args: &serde_json::Value,
|
||||||
|
risk_level: RiskLevel,
|
||||||
|
db: &Arc<Database>,
|
||||||
|
) -> String {
|
||||||
let s = |key: &str| args.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
let s = |key: &str| args.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
||||||
let detail = match tool_name {
|
let detail = match tool_name {
|
||||||
"delete_project" => {
|
"delete_project" => {
|
||||||
let id = s("id");
|
let id = s("id");
|
||||||
if !id.is_empty() { format!("删除项目(ID: {})", id) } else { String::new() }
|
if !id.is_empty() { format!("删除项目{}", resolve_project_label(db, id).await) } else { String::new() }
|
||||||
}
|
}
|
||||||
"restore_project" => {
|
"restore_project" => {
|
||||||
let id = s("id");
|
let id = s("id");
|
||||||
if !id.is_empty() { format!("从回收站恢复项目(ID: {})", id) } else { String::new() }
|
if !id.is_empty() { format!("从回收站恢复项目{}", resolve_project_label(db, id).await) } else { String::new() }
|
||||||
}
|
}
|
||||||
"purge_project" => {
|
"purge_project" => {
|
||||||
let id = s("id");
|
let id = s("id");
|
||||||
if !id.is_empty() { format!("永久删除项目及关联数据,不可恢复(ID: {})", id) } else { String::new() }
|
if !id.is_empty() { format!("永久删除项目及关联数据,不可恢复{}", resolve_project_label(db, id).await) } else { String::new() }
|
||||||
}
|
}
|
||||||
"update_project" => {
|
"update_project" => {
|
||||||
|
let id = s("id");
|
||||||
let field = s("field");
|
let field = s("field");
|
||||||
if !field.is_empty() { format!("修改项目字段「{}」", field) } else { String::new() }
|
if !id.is_empty() {
|
||||||
|
format!("修改项目{}字段「{}」", resolve_project_label(db, id).await, field)
|
||||||
|
} else if !field.is_empty() {
|
||||||
|
format!("修改项目字段「{}」", field)
|
||||||
|
} else { String::new() }
|
||||||
}
|
}
|
||||||
"bind_directory" => {
|
"bind_directory" => {
|
||||||
|
let id = s("id");
|
||||||
let path = s("path");
|
let path = s("path");
|
||||||
if !path.is_empty() { format!("绑定目录:{}", path) } else { String::new() }
|
if !path.is_empty() && !id.is_empty() {
|
||||||
|
format!("绑定目录:{}(项目{})", path, resolve_project_label(db, id).await)
|
||||||
|
} else if !path.is_empty() {
|
||||||
|
format!("绑定目录:{}", path)
|
||||||
|
} else { String::new() }
|
||||||
}
|
}
|
||||||
"create_task" => {
|
"create_task" => {
|
||||||
let title = s("title");
|
let title = s("title");
|
||||||
if !title.is_empty() { format!("创建任务:{}", title) } else { String::new() }
|
let pid = s("project_id");
|
||||||
|
if !title.is_empty() && !pid.is_empty() {
|
||||||
|
format!("创建任务:{}(项目{})", title, resolve_project_label(db, pid).await)
|
||||||
|
} else if !title.is_empty() {
|
||||||
|
format!("创建任务:{}", title)
|
||||||
|
} else { String::new() }
|
||||||
}
|
}
|
||||||
"create_project" => {
|
"create_project" => {
|
||||||
let name = s("name");
|
let name = s("name");
|
||||||
if !name.is_empty() { format!("创建项目:{}", name) } else { String::new() }
|
if !name.is_empty() { format!("创建项目:「{}」", name) } else { String::new() }
|
||||||
}
|
}
|
||||||
"create_idea" => {
|
"create_idea" => {
|
||||||
let title = s("title");
|
let title = s("title");
|
||||||
@@ -241,7 +275,7 @@ pub(crate) async fn process_tool_calls(
|
|||||||
recovered: false,
|
recovered: false,
|
||||||
});
|
});
|
||||||
session.messages.push(ChatMessage::tool_result(&draft.id, "需要用户审批,等待确认"));
|
session.messages.push(ChatMessage::tool_result(&draft.id, "需要用户审批,等待确认"));
|
||||||
let reason = build_approval_reason(&draft.name, &args, risk_level);
|
let reason = build_approval_reason(&draft.name, &args, risk_level, db).await;
|
||||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiApprovalRequired {
|
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiApprovalRequired {
|
||||||
id: draft.id.clone(),
|
id: draft.id.clone(),
|
||||||
name: draft.name.clone(),
|
name: draft.name.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user