- 模型停用无效根因: get_active_provider 两条路径均不校验 enabled(显式活跃直返/默认只挑 is_default) → 收敛为启用集合解析,无启用 provider 明确报错 - 压缩/标题兜底模型不校验 enabled → 新增 resolve_fallback_model 纯函数(title 复用同一实现,单一源无双轨) - 上下文多夹层归位修复: gather_tool_responses 聚拢该头全部响应(此前第二个夹层之后的响应仍被判未闭合剥除) - 压缩后台任务加内容版本哨兵(取首条消息 id,否掉 len:压缩期间 loop 正常 append 会致守卫永不生效) + panic 兜底复位标志 - 902 超时类失败与其它 Fatal 区分停靠文案(点继续可续跑) - 子代理事件按 conv 改挂(route_scope) + 运行期事件推父会话视图 - 飞书 13a 真根因: run_stream_refresher 死代码(提前 drop)+静默钟被心跳重置 → 帧通道+仅内容事件重置 - 项目详情文件查看: F22 目录不存在误显非 Git 仓库 / F24 模块为仓库子目录时 git 徽标全失效(scope_git_path 按 show-prefix 剥前缀) - 更新徽章通道错配(Tauri 事件 vs window CustomEvent 同名不同通道,徽章此前永不触发) - ProjectCard 卡片根 keydown 顶替内嵌按钮(补 e.target 守卫) - i18n 坏键 ai.aiTool.rejectedHint → aiTool.rejectedHint(双缺会渲染裸 key) - miniapp 三处: 会话列表刷新漏网/看门狗节流致新一轮无兜底/newConversation 漏清看门狗
51 lines
2.5 KiB
Rust
51 lines
2.5 KiB
Rust
//! 审批后审计记录状态回填(audit_finalize)
|
||
//!
|
||
//! `audit_tool_call` 已移至 record.rs(审计记录写入操作归 audit record 子模块)。
|
||
//! re-export 经 audit/mod.rs `pub(crate) use finalize::audit_finalize;` 保持
|
||
//! `commands::ai::audit::*` 路径透明(调用方零变更)。
|
||
|
||
use crate::commands::ai::tool_result_offload;
|
||
use crate::commands::now_millis;
|
||
use crate::state::AppState;
|
||
|
||
/// 审批后更新审计记录状态(按 tool_call_id 定位 pending 记录,回填 status/decided_by=human/executed_at/result)
|
||
///
|
||
/// 走专用 find_by_tool_call_id —— 通用 query 宏硬编码 ORDER BY created_at DESC,
|
||
/// 而 ai_tool_executions 无该列,调用会报 "no such column: created_at" 被 unwrap_or_default 吞掉,
|
||
/// 导致审批后审计记录永久卡 pending。
|
||
pub(crate) async fn audit_finalize(
|
||
state: &AppState,
|
||
tool_call_id: &str,
|
||
status: &str,
|
||
result: Option<String>,
|
||
duration_ms: Option<i64>,
|
||
) {
|
||
// 区分 Err(DB 故障)与 Ok(None)(真无记录):原 unwrap_or_default 把 Err 压成 None,
|
||
// DB 故障被「未找到」日志掩盖,审批后审计记录卡 pending 无确诊线索。
|
||
let mut rec = match state.ai_tool_executions.find_by_tool_call_id(tool_call_id).await {
|
||
Ok(Some(rec)) => rec,
|
||
Ok(None) => {
|
||
tracing::warn!("audit_finalize: 未找到 tool_call_id={} 的审计记录", tool_call_id);
|
||
return;
|
||
}
|
||
Err(e) => {
|
||
tracing::error!("audit_finalize: 查询 tool_call_id={} 审计记录失败(DB 故障,状态未回填): {}", tool_call_id, e);
|
||
return;
|
||
}
|
||
};
|
||
rec.status = status.to_string();
|
||
rec.decided_by = Some("human".to_string());
|
||
rec.executed_at = Some(now_millis());
|
||
// V50 纯执行耗时:审批路径由调用方(ai_approve/ai_authorize_dir)在真执行窗口测量后传入,
|
||
// 与「requested_at→executed_at」(含等待人工批准)解耦。拒绝/超时未执行传 None。
|
||
rec.duration_ms = duration_ms;
|
||
if let Some(r) = result {
|
||
// 与 audit_tool_call 的写侧一致:超阈值结果外置落盘,DB 只留句柄,防审批路径大结果
|
||
// 绕过外置直接内联落库(工具真正执行发生在审批通过之后,这条才是大结果主入口)。
|
||
rec.result = Some(tool_result_offload::offload_result(tool_call_id, &rec.tool_name, &r));
|
||
}
|
||
if let Err(e) = state.ai_tool_executions.update_full(&rec).await {
|
||
tracing::error!("audit_finalize: 回填 tool_call_id={} 审计状态失败: {}", tool_call_id, e);
|
||
}
|
||
}
|