修复: B-260617-01 run_workflow审批执行(抽取run_workflow_inner+ai_approve后端分支)

This commit is contained in:
2026-06-17 01:39:28 +08:00
parent f2a56b6982
commit e23b316faf
4 changed files with 129 additions and 17 deletions

View File

@@ -422,3 +422,72 @@ pub(crate) struct ToolCallDraft {
pub(crate) name: String,
pub(crate) args: String,
}
// ============================================================
// B-260617-01 决策 a(方案 a2)run_workflow 工具经审批后的真实执行入口
//
// 背景run_workflow handler(tool_registry.rs)仅持 db:Arc<Database>,无 AppHandle/State
// (registry/event_bus/workflows Repo),经 ai_tools.execute 必然 Err。ai_approve 识别 run_workflow
// 后改调本函数(同 invoke('run_workflow') IPC 入口 workflow.rs::run_workflow,持有完整 State),
// 真正触发工作流引擎执行 + 联动任务推进,把 execution_id 回填 tool_result 让 LLM 收成功结果停止重试。
//
// 选后端分支(a2)而非前端拦截(a1):ai_approve 已持 state+app,后端统一更简,无需新增前端 IPC +
// 不把工作流知识泄漏到前端。本函数仅在 ai_approve 内被调用(单一调用方)。
// ============================================================
/// 把 run_workflow 工具调用的 AI args 转调工作流执行函数,返回 execution_id(供回填 tool_result)。
///
/// 从 args 取 task_id + target_status(两者必填),传空 DagDef(由 workflow.rs 按 target_status
/// 自动选推进链模板,见 task_workflow_templates::template_for),config 传空 Object。
/// 任一参数缺失返 Err(回填 failed tool_result,LLM 据此修参重发)。
///
/// 不在此推进任务状态 —— workflow.rs::run_workflow 内部已按 task_id+target_status 自动联动
/// (成功推进到 target / 失败按 regression_target 退回),此处不重复。
pub(crate) async fn execute_run_workflow_for_tool(
app: &tauri::AppHandle,
state: &crate::state::AppState,
args: &serde_json::Value,
) -> anyhow::Result<serde_json::Value> {
let task_id = args
.get("task_id")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow::anyhow!("缺少 task_id 参数"))?
.to_string();
let target_status = args
.get("target_status")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow::anyhow!("缺少 target_status 参数"))?
.to_string();
// 空 DagDef + target_status:workflow.rs:84-92 自动按 target_status 选推进链模板
// (AiNode 自审 / HumanNode 核对闸门),无需本函数感知模板知识。
let dag = df_workflow::dag_def::DagDef::new();
let config = serde_json::Value::Object(serde_json::Map::new());
let name = format!("AI 推进任务 {}{}", task_id, target_status);
// 转调工作流执行核心(B-260617-01:run_workflow_inner 是 run_workflow 命令的共用核心,
// 同 invoke('run_workflow') IPC 入口的执行逻辑,持 &AppState 非 tauri::State,绕开
// tauri::State 在非命令上下文不可构造的限制)。
// 返回 execution_id 字符串;失败(模板不存在/DAG 校验失败/DB 写入失败)上抛 Err。
let execution_id = crate::commands::workflow::run_workflow_inner(
app,
state,
name,
dag,
config,
Some(task_id.clone()),
Some(target_status.clone()),
)
.await
.map_err(|e| anyhow::anyhow!("工作流执行失败: {}", e))?;
// 回填 tool_result:返回 execution_id + 联动语义说明,让 LLM 知工作流已触发(后台异步执行,
// 完成后自动推进任务状态),不再重试同 tool_call。
Ok(serde_json::json!({
"task_id": task_id,
"target_status": target_status,
"execution_id": execution_id,
"status": "running",
"note": "工作流已触发(后台异步执行,完成后自动推进任务状态,失败按退回态回滚)。前端 workflow-event 跟踪进度。"
}))
}