新增: AR-11 数据变更联动(AI 工具执行后 emit df-data-changed+store listen 刷新列表)

audit.rs data_change_for_tool 映射(create_project/idea/task→create,update_*→update,delete_*/purge→delete,restore/bind_directory→update)+emit_data_changed(process_tool_calls 已有 app_handle 无需透传);commands.rs ai_approve 成功路径 emit;types.ts DfDataChangedPayload;project.ts barrel listen df-data-changed + start/stopDataChangedListener 单例;App.vue onMounted 全局挂载+onUnmounted 清理。AI 工具(create/update/delete project/task/idea)执行后前端 Projects/Tasks/Ideas 列表自动刷新。批7,cargo+vue-tsc 0
This commit is contained in:
2026-06-15 05:54:15 +08:00
parent b08adcb9da
commit dc27e79fd2
5 changed files with 107 additions and 1 deletions

View File

@@ -230,6 +230,47 @@ pub(crate) async fn audit_finalize(state: &AppState, tool_call_id: &str, status:
let _ = state.ai_tool_executions.update_full(&rec).await;
}
/// AR-11方案A工具名 → (entity, action) 映射,用于数据变更联动刷新。
///
/// 仅数据变更类工具返回 Some其余工具返回 None不 emit df-data-changed
/// 映射规则:
/// - create_project/create_idea/create_task → (project/idea/task, create)
/// - update_project/update_task/update_idea → (..., update)
/// - delete_project/delete_task/delete_idea/purge_project → (..., delete)
/// - restore_project → (project, update)(恢复等同状态变更,前端走 update 刷新)
/// - bind_directory → (project, update)(绑定目录属项目字段更新)
fn data_change_for_tool(name: &str) -> Option<(&'static str, &'static str)> {
let (entity, action) = match name {
"create_project" => ("project", "create"),
"create_task" => ("task", "create"),
"create_idea" => ("idea", "create"),
"update_project" => ("project", "update"),
"update_task" => ("task", "update"),
"update_idea" => ("idea", "update"),
"delete_project" | "purge_project" => ("project", "delete"),
"delete_task" => ("task", "delete"),
"delete_idea" => ("idea", "delete"),
"restore_project" => ("project", "update"),
"bind_directory" => ("project", "update"),
_ => return None,
};
Some((entity, action))
}
/// AR-11方案A工具执行成功后按映射 emit "df-data-changed" { entity, action }。
///
/// 前端 store listen 该事件,按 entity 调 loadProjects/loadTasks/loadIdeas 刷新列表,
/// 取代工具执行后需手动刷新。仅工具名命中 data_change_for_tool 映射才 emit
/// 其余工具run_workflow/list_tasks 等)不 emit。emit 失败不阻断let _ =)。
pub(crate) fn emit_data_changed(app_handle: &AppHandle, tool_name: &str) {
if let Some((entity, action)) = data_change_for_tool(tool_name) {
let _ = app_handle.emit(
"df-data-changed",
serde_json::json!({ "entity": entity, "action": action }),
);
}
}
/// 处理流式接收的工具调用Low 风险并行执行join_allMed/High 进审批门控
/// 返回待审批的工具数量0 = 全部自动执行完成)
pub(crate) async fn process_tool_calls(
@@ -307,6 +348,9 @@ pub(crate) async fn process_tool_calls(
result: val.clone(),
conversation_id: Some(conv_clone),
});
// AR-11方案A数据变更工具执行成功后 emit df-data-changed,
// 前端 store listen 刷新列表(仅命中映射的工具 emit见 emit_data_changed
emit_data_changed(&app_clone, &draft.name);
(draft, Ok(val.to_string()))
}
Err(e) => {

View File

@@ -13,7 +13,7 @@ use crate::state::AppState;
use crate::commands::{err_str, now_millis};
use super::agentic::{run_agentic_loop, try_continue_agent_loop};
use super::audit::audit_finalize;
use super::audit::{audit_finalize, emit_data_changed};
use super::conversation::save_conversation;
use super::knowledge_inject::build_knowledge_context;
use super::prompt::build_system_prompt;
@@ -172,6 +172,12 @@ pub async fn ai_approve(
// 审计:人工审批后无论成败回填(决策者=human
audit_finalize(&state, &tool_call_id, audit_status, Some(result_val.to_string())).await;
// AR-11方案A人工审批通过且工具执行成功(非 failed)后 emit df-data-changed,
// 前端 store listen 刷新列表(仅命中映射的工具 emit见 emit_data_changed
if exec_result.is_ok() {
emit_data_changed(&app, &approval.tool_name);
}
// 重新获取锁,替换占位 tool_result 为真实结果失败时为错误信息LLM 据此决定下一步)
let mut session = state.ai_session.lock().await;
session.messages.replace_tool_result_content(&id, &result_val.to_string());