新增: namespace淘汰治理与可恢复会话分组
- namespace 淘汰治理: pin 机制(关键产出 LRU 永不淘汰, 超池 50% 最旧降级) + EvictionLog 留档富提示(原工具名+内容摘要+重调指引) + owner 软隔离(无主最旧先淘); 子代理报告出口 pin 收编 - 错误路径广播 AiAgentFinished(status=error): 错误任务有终态, watcher/任务卡可收敛 - 桌面侧栏可恢复分组: parked 会话独立分组+点击恢复, 断点续跑读侧闭环 - 验收: cargo check 零 error + vue-tsc EXIT 0
This commit is contained in:
@@ -152,7 +152,10 @@ pub(super) async fn maybe_auto_compress(
|
||||
path = %path,
|
||||
"[namespace] 引用已淘汰,替换为提示文案"
|
||||
);
|
||||
m.content = df_ai::namespace_store::EVICTED_PLACEHOLDER.to_string();
|
||||
m.content = session
|
||||
.namespace_store
|
||||
.eviction_rich_notice(&path)
|
||||
.unwrap_or_else(|| df_ai::namespace_store::EVICTED_PLACEHOLDER.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1835,7 +1835,10 @@ async fn prepare_round_inputs(
|
||||
path = %path,
|
||||
"[namespace] 引用已淘汰,替换为提示文案"
|
||||
);
|
||||
m.content = df_ai::namespace_store::EVICTED_PLACEHOLDER.to_string();
|
||||
m.content = session
|
||||
.namespace_store
|
||||
.eviction_rich_notice(&path)
|
||||
.unwrap_or_else(|| df_ai::namespace_store::EVICTED_PLACEHOLDER.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2704,6 +2707,21 @@ pub(crate) async fn emit_fatal_error(app_handle: &AppHandle, conv_id: &str, erro
|
||||
error_type: Some(error_type),
|
||||
conversation_id: Some(conv_id.to_string()),
|
||||
});
|
||||
// #23 修复:错误路径也广播 AiAgentFinished(status=error)——原只发 AiError,飞书
|
||||
// completion_watcher 只消费 AiAgentFinished → 错误任务永不收敛(watcher 空等到二次
|
||||
// 超时弃守,且无失败终态)。单一事实源在引擎层,订阅方(飞书 watcher/桌面任务卡)各自消费。
|
||||
app_handle.state::<AppState>().ai_event_bus.publish_event(
|
||||
AiChatEvent::AiAgentFinished {
|
||||
agent_id: conv_id.to_string(),
|
||||
conversation_id: Some(conv_id.to_string()),
|
||||
summary: format!("任务失败: {}", error.chars().take(300).collect::<String>()),
|
||||
status: "error".to_string(),
|
||||
rounds: 0,
|
||||
tokens: 0,
|
||||
rejected_tools: None,
|
||||
stop_kind: Some("error".to_string()),
|
||||
},
|
||||
);
|
||||
// P1 bg 化:失败系统通知(条件发送,失败静默)。正文截断防长堆栈撑爆系统气泡。
|
||||
let brief: String = error.chars().take(160).collect();
|
||||
crate::commands::ai::notify::notify_session_event(
|
||||
|
||||
@@ -532,7 +532,7 @@ pub(crate) async fn run_sub_agent_loop(
|
||||
// 统一出口:挂父会话 emit 终态(前端展示二期消费;报告本体经父 tool_result 返回值交付)
|
||||
emit_ai_chat_event(&app_handle, AiChatEvent::AiAgentFinished {
|
||||
agent_id: child_conv_id.clone(),
|
||||
conversation_id: Some(parent_conv_id),
|
||||
conversation_id: Some(parent_conv_id.clone()),
|
||||
summary: outcome.summary.clone(),
|
||||
status: outcome.status.as_str().to_string(),
|
||||
rounds: outcome.rounds,
|
||||
@@ -566,8 +566,16 @@ pub(crate) async fn run_sub_agent_loop(
|
||||
}
|
||||
|
||||
// 清理子会话内存条目(轨迹已持久化或已随级联丢弃;origin 标记随 per_conv 一并回收)
|
||||
// + namespace 治理:报告若经工具结果入库(namespace 引用路径),统一出口 pin 保护
|
||||
// (store hash 去重:已入库条目原地升级 pinned;未入库则 store_pinned 收编,
|
||||
// 超大报告也不因父会话 LRU 淘汰丢报告)。owner=父会话,软隔离归当前主。
|
||||
{
|
||||
let mut session = session_arc.lock().await;
|
||||
if df_ai::namespace_store::should_use_namespace(&outcome.summary, "sub_agent_report") {
|
||||
session.namespace_store.store_pinned(
|
||||
"sub_agent_report", &outcome.summary, Some(&parent_conv_id),
|
||||
);
|
||||
}
|
||||
session.per_conv.remove(&child_conv_id);
|
||||
session.save_locks.remove(&child_conv_id);
|
||||
session.conv_origins.remove(&child_conv_id);
|
||||
@@ -744,7 +752,12 @@ async fn run_sub_agent_loop_inner(
|
||||
match session.namespace_store.read_only(&path) {
|
||||
Some(original) => m.content = original.to_string(),
|
||||
None => {
|
||||
m.content = df_ai::namespace_store::EVICTED_PLACEHOLDER.to_string();
|
||||
// 淘汰治理富提示:Log 命中给原工具名+内容 hint+重调指引,
|
||||
// 未命中(跨会话残留/未知 key)落回既有占位
|
||||
m.content = session
|
||||
.namespace_store
|
||||
.eviction_rich_notice(&path)
|
||||
.unwrap_or_else(|| df_ai::namespace_store::EVICTED_PLACEHOLDER.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +361,11 @@ async fn save_conversation_inner(
|
||||
let session = session_arc.lock().await;
|
||||
for m in &mut persist_msgs {
|
||||
if df_ai::namespace_store::is_namespace_ref(&m.content) {
|
||||
if let Some(original) = session.namespace_store.read_only(&m.content) {
|
||||
// 淘汰治理富提示:Log 命中给原工具名+hint,未命中原样保留引用
|
||||
// (落库持久化路径,不落占位文案——占位只在请求组装视图层替换)
|
||||
if let Some(notice) = session.namespace_store.eviction_rich_notice(&m.content) {
|
||||
m.content = notice;
|
||||
} else if let Some(original) = session.namespace_store.read_only(&m.content) {
|
||||
m.content = original.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user