修复: 上下文记忆与工作流注入生产侧空壳接通

WorkingContext 写入链落地(用户轮目标钉扎+压缩后 JSON 卡片回填重锚定,含 6 单测);
工作流 DAG 摘要注入生产侧接通(AI 路径启动写入+终态回写,审批调用点透传会话)。
附知识库与记忆走查诊断(「笨/丢历史」根因:消息压缩视图丢失+知识检索四重收口),
todo 登记修复分档(含随批补登 09-28 交互走查索引条目)。
This commit is contained in:
lxy
2026-09-29 13:28:56 +08:00
parent f57e25a277
commit dfa38f6259
9 changed files with 333 additions and 27 deletions
@@ -272,10 +272,10 @@ pub(super) async fn maybe_auto_compress(
}
let conv = session.conv(&conv_id);
let _compressed = conv.messages.compress_old_messages(protect_start);
// T3: 插入 NL 摘要(向前兼容),JSON 卡片可供后续 WorkingContext(T5)使用
// NL 摘要插首位 + JSON 卡片回填 WorkingContext,决策随压缩重锚定
conv.messages.insert_at(0, ChatMessage::system(&summary.nl_summary));
conv.messages.set_compressing(false);
// TODO(T5): 如有 WorkingContext,调用 version.reset_all(summary.json_card, turn)
conv.working_context.sync_after_compress(&summary.json_card);
}
tracing::info!(
conv_id = %conv_id,
@@ -1,19 +1,14 @@
//! 工作流 DAG 上下文注入 — 当会话关联工作流时,将活跃路径注入 system prompt
//!
//! T4 实现。提供两个函数:
//! - `build_dag_summary`: 从 DagDef 构建可读的 DAG 摘要文本
//! - `extract_active_path`: 从完整 DAG 中提取当前活跃路径(简化)
//! T4 实现,完整链路(生产侧已接通):
//! - 生产:`run_workflow_inner`(workflow.rs)AI 路径(conv_id Some)启动时调
//! `build_dag_summary` 产出摘要写入 `PerConvState.workflow_dag_summary`
//! (`workflow_id` 存本次执行 ID,非模板 ID);执行闭包终态(completed/failed)
//! 回写摘要并追加「状态: 已完成/已失败」行。
//! - 消费:`agentic/mod.rs` 的 `build_runtime_prompt` 每轮读该字段注入 system prompt。
//!
//! 调用方(前端/workflow 引擎)在启动工作流时将摘要存入
//! `PerConvState.workflow_dag_summary`,agentic loop 自动注入 system prompt。
//!
//! 预留说明(dead_code):本模块的 3 个函数当前无生产调用方——
//! T4 消费侧已落地(`agentic/mod.rs` 在构建 system prompt 时读
//! `PerConvState.workflow_dag_summary` 并注入),但生产侧尚无人写入该字段
//! (`PerConvState::new` 初始化为 `None`,无代码调用 `build_dag_summary`)。
//! 即完整链路为「工作流启动器 → 调本模块产出摘要 → 写 workflow_dag_summary
//! → agentic loop 注入 system prompt」,中间「生产者」环节待接通。
//! 属为后续工作流上下文注入准备的预留,非真死代码,故 allow 抑制告警。
//! `build_dag_summary` 已有生产调用方;`extract_active_path` 仍无生产调用方
//! (仅单测引用),模块级 allow 为其保留——节点级中间进度刷新属后续扩展。
#![allow(dead_code)]
+6 -2
View File
@@ -647,6 +647,8 @@ pub async fn ai_chat_send(
} else {
conv.messages.push(ChatMessage::user(&user_content));
}
// 新用户轮把本请求钉扎为 WorkingContext 常驻目标(截断 200 字符,与 agentic G1 目标钉扎 GOAL_MAX_CHARS 同量级)
conv.working_context.begin_turn(&user_content, 200);
// F-260619-04 P1:push 后取末条 user 消息 id(本轮 user,原供知识注入 referenced 溯源)。
// DRY(B):知识注入已收敛至 inject_knowledge_into_prompt(helper 内部同消息取 text+id),
// 此处 user_msg_id 不再透传到注入逻辑,保留下划线占用(锁内 push 已发生,语义不变)。
@@ -891,7 +893,7 @@ pub async fn ai_approve(
// 回填 / emit_data_changed / save / try_continue)。workflow 联动任务推进由 run_workflow 内部
// 按 task_id+target_status 自动处理(workflow.rs:270-308),此处不重复推进。
let exec_result: anyhow::Result<serde_json::Value> = if approval.tool_name == "run_workflow" {
super::super::execute_run_workflow_for_tool(&app, &state, &args).await
super::super::execute_run_workflow_for_tool(&app, &state, &args, conv_id.as_deref()).await
} else {
// F-260620 对齐 ai_authorize_dir(:658):ai_approve 执行同样包 60s 超时。
// 防 list_directory 大目录/run_command 慢命令卡死 → 到不了 audit_finalize/emit/try_continue
@@ -1273,7 +1275,7 @@ pub async fn ai_authorize_dir(
// → 到不了 audit_finalize/emit/try_continue → IPC 永挂 → generating 永真。包 60s 超时(对齐
// run_command),超时返 Err → 走 failed 分支 finalize+emit+try_continue,IPC 必返回不卡。
let exec_result: anyhow::Result<serde_json::Value> = if approval.tool_name == "run_workflow" {
super::super::execute_run_workflow_for_tool(&app, &state, &args).await
super::super::execute_run_workflow_for_tool(&app, &state, &args, conv_id.as_deref()).await
} else {
match tokio::time::timeout(
std::time::Duration::from_secs(60),
@@ -1972,6 +1974,8 @@ pub async fn ai_chat_force_send(
} else {
conv.messages.push(ChatMessage::user(&user_content));
}
// 新用户轮把本请求钉扎为 WorkingContext 常驻目标(截断 200 字符,与 agentic G1 目标钉扎 GOAL_MAX_CHARS 同量级)
conv.working_context.begin_turn(&user_content, 200);
// F-260619-04 P1:push 后立即取末条 user 消息 id(供知识注入 referenced 溯源)。
let user_msg_id = conv.messages.last_user_message_id();
// G1 目标钉扎已迁移至 run_agentic_loop 工具调用推理(提取方式同 ai_chat_send)
+5
View File
@@ -1142,10 +1142,14 @@ pub(crate) struct ToolCallDraft {
///
/// 不在此推进任务状态 —— workflow.rs::run_workflow 内部已按 task_id+target_status 自动联动
/// (成功推进到 target / 失败按 regression_target 退回),此处不重复。
///
/// `conv_id`(T4 会话关联)末参透传 run_workflow_inner:调用方带发起会话 ID 时,
/// 启动写 workflow_id/workflow_dag_summary、终态回写摘要,供 agentic loop 注入 system prompt。
pub(crate) async fn execute_run_workflow_for_tool(
app: &tauri::AppHandle,
state: &crate::state::AppState,
args: &serde_json::Value,
conv_id: Option<&str>,
) -> anyhow::Result<serde_json::Value> {
let task_id = args
.get("task_id")
@@ -1178,6 +1182,7 @@ pub(crate) async fn execute_run_workflow_for_tool(
Some(task_id.clone()),
Some(target_status.clone()),
"ai",
conv_id,
)
.await
.map_err(|e| anyhow::anyhow!("工作流执行失败: {}", e))?;