新增: AE-2025-04会话级授权(TrustKey目录级+同会话同类自动放行)
This commit is contained in:
@@ -560,6 +560,59 @@ pub(crate) async fn process_tool_calls(
|
||||
match risk_level {
|
||||
RiskLevel::Low => low_risk.push((draft, args)),
|
||||
RiskLevel::Medium | RiskLevel::High => {
|
||||
// AE-2025-04 会话级信任(Session Trust):首批 write_file / run_command,
|
||||
// 同会话已批准过同工具+同目录 → TrustKey 命中 → 自动放行(跳过 pending + 二次确认)。
|
||||
// 命中后走与 F-05 去重命中相似的「直接执行 + Completed + 审计 decided_by=auto_trust」路径,
|
||||
// 但与 F-05 不同:F-05 复用缓存 tool_result 跳过执行;trust 放行**真实执行工具**
|
||||
// (用户信任同目录同类操作,但仍要看每次的真实结果)。
|
||||
let trust_hit = super::trust_key_for(&draft.name, &args)
|
||||
.and_then(|key| {
|
||||
if session.session_trust.contains(&key) {
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if let Some(key) = trust_hit {
|
||||
let dir_label = match &key {
|
||||
super::TrustKey::Write { dir } | super::TrustKey::Execute { dir } => dir.clone(),
|
||||
};
|
||||
tracing::info!(
|
||||
tool = %draft.name,
|
||||
dir = %dir_label,
|
||||
new_tool_call_id = %draft.id,
|
||||
"[AE-2025-04] 会话信任命中: 同会话已批准同类操作,自动放行(跳过审批+二次确认)"
|
||||
);
|
||||
// emit 轻量 toast 事件(前端 AiChat.vue 显示"🔓 自动放行: tool(dir)")
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiToolAutoApproved {
|
||||
id: draft.id.clone(),
|
||||
tool: draft.name.clone(),
|
||||
dir: dir_label,
|
||||
conversation_id: Some(conv_id.to_string()),
|
||||
});
|
||||
// 真实执行工具(在 session 锁外,与 Low risk 并行执行闭包同款不持锁)
|
||||
let exec_args = args.clone();
|
||||
let exec_tool = draft.name.clone();
|
||||
let exec_result = tools_arc.execute(&exec_tool, exec_args).await;
|
||||
let (status, content) = match &exec_result {
|
||||
Ok(val) => ("completed", val.to_string()),
|
||||
Err(e) => ("failed", e.to_string()),
|
||||
};
|
||||
session.messages.push(ChatMessage::tool_result(&draft.id, content.clone()));
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiToolCallCompleted {
|
||||
id: draft.id.clone(),
|
||||
result: serde_json::Value::String(content.clone()),
|
||||
conversation_id: Some(conv_id.to_string()),
|
||||
});
|
||||
// AR-11:数据变更类工具执行成功后 emit df-data-changed 联动刷新
|
||||
// (write_file/run_command 不在 data_change_for_tool 映射内,emit_data_changed 内部 None 即 noop)
|
||||
if exec_result.is_ok() {
|
||||
emit_data_changed(app_handle, &draft.name);
|
||||
}
|
||||
// 审计:trust 放行仍记一条(decided_by=auto_trust),留痕可追溯
|
||||
audit_tool_call(&audit_repo, conv_id, &draft.id, &draft.name, &draft.args, status, risk_level, Some(content), Some("auto_trust")).await;
|
||||
continue;
|
||||
}
|
||||
// F-05:仅 High 查去重缓存;Med 保持原审批流程
|
||||
if matches!(risk_level, RiskLevel::High) {
|
||||
if let Some(cached) = find_cached_high_risk_result(session, &draft.name, &args) {
|
||||
|
||||
Reference in New Issue
Block a user