新增: 上下文管理演进 Wave2(T3结构化摘要 + T4工作流DAG占位)

T3: 压缩摘要双格式(向后兼容)
- compress_via_llm 返回类型 Result<String> → Result<CompressedSummary>
- 新增 parse_sections_to_json: 从四段式 Markdown 摘要解析 JSON 卡片
- context_lifecycle: 插入 NL 摘要(向后兼容),预留 WorkingContext 联动
- manual compress IPC (chat.rs): 适配新返回类型

T4: 工作流 DAG 注入(占位)
- workflow_context.rs: 空壳函数,待 PerConvState.workflow_id 落地后接入
- mod.rs: 注入点已就位(日志占位)
- 后续需补: DAG 加载 + 活跃路径裁剪 + system_prompt 注入
This commit is contained in:
lxy
2026-07-20 08:01:34 +08:00
parent faa61a9ba5
commit 3943d68430
5 changed files with 82 additions and 10 deletions
@@ -28,7 +28,7 @@ use std::sync::Arc;
use tauri::{AppHandle, Emitter, Manager};
use tokio::sync::Mutex;
use df_ai::context_helpers::extract_keyword_summary;
use df_ai::context_helpers::{extract_keyword_summary, CompressedSummary};
use df_ai::provider::{ChatMessage, LlmProvider};
use df_storage::models::AiProviderRecord;
@@ -129,7 +129,7 @@ pub(super) async fn maybe_auto_compress(
// 压缩调用(复用 loop 顶部已 build 的 provider,api_key 经 secret 闭环)。
// 成功 → Some(summary);失败 → Err;无 active 可压缩(active_msgs 空)→ 视为 noop。
let compress_outcome: Result<Option<String>, String> = if active_msgs.is_empty() {
let compress_outcome: Result<Option<CompressedSummary>, String> = if active_msgs.is_empty() {
Ok(None)
} else {
compress_via_llm(
@@ -145,15 +145,14 @@ pub(super) async fn maybe_auto_compress(
match compress_outcome {
Ok(Some(summary)) => {
// LLM 成功 → 标 compressed(扣 token)+ 摘要 system 插首位 + set_compressing(false)。
// compress_old_messages 幂等:此时 status 仍是 active(本流程未先标),它会把
// [..protect_start] 内 active 标 compressed 并扣 token。返回的 cloned 与之前读的
// active_msgs 等价(LLM 调用期间 messages 不变,见上方口径决策注)。
{
let mut session = session_arc.lock().await;
let conv = session.conv(&conv_id);
let _compressed = conv.messages.compress_old_messages(protect_start);
conv.messages.insert_at(0, ChatMessage::system(&summary));
// T3: 插入 NL 摘要(向前兼容),JSON 卡片可供后续 WorkingContext(T5)使用
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)
}
tracing::info!(
conv_id = %conv_id,
@@ -166,7 +165,7 @@ pub(super) async fn maybe_auto_compress(
// miniapp 仍插摘要气泡(对端发生压缩告知用户)。
let ev = AiChatEvent::AiAutoCompressed {
conversation_id: Some(conv_id.to_string()),
summary,
summary: summary.nl_summary,
};
let _ = app_handle.emit("ai-chat-event", ev.clone());
// L3 emit 双写:tunnel subscriber(阶段2)透传 miniapp