新增: 上下文管理演进 Wave1(契约定义 + T1动态阈值 + T2命名空间)
Agent 3: 共享契约类型定义 - CompressedSummary(T3输出格式) - WorkflowContextBlock(T4工作流DAG上下文) - WorkingContext + GoalItem/DecisionItem/StepInfo(T5常驻上下文) - 脏标记版本追踪 + reset_all 压缩联动 T1: 动态压缩阈值 - maybe_auto_compress 加 sys_tokens 参数,触发条件从 budget*0.6 改为 available*0.6 - 调用处传 sys_tokens(loop顶部已缓存) - 3 行核心改动 T2: 工具命名空间存储 - crates/df-ai/src/namespace_store.rs: 完整实现 + 单元测试 - process_tool_calls: Low/Med/High 路径 namespace 路由 - save_conversation: namespace 引用展开为原文再落 DB - AiSession 新增 namespace_store 字段
This commit is contained in:
@@ -69,6 +69,7 @@ pub(super) async fn maybe_auto_compress(
|
||||
provider_config: &AiProviderRecord,
|
||||
llm_concurrency: &LlmConcurrency,
|
||||
iteration: usize,
|
||||
sys_tokens: u32,
|
||||
) -> bool {
|
||||
let prev_compressing = session_arc.lock().await.conv_read(&conv_id).map(|c| c.messages.is_compressing()).unwrap_or(false);
|
||||
if !prev_compressing {
|
||||
@@ -85,10 +86,10 @@ pub(super) async fn maybe_auto_compress(
|
||||
let mgr = &mgr.messages;
|
||||
let protect_start = mgr.len().saturating_sub(PROTECT_COUNT);
|
||||
let history_tokens = mgr.history_tokens();
|
||||
let budget = mgr.budget_limit();
|
||||
// 触发阈值 0.6*budget(整数比避免浮点):budget*6/10 < history_tokens
|
||||
let available = mgr.budget_limit().saturating_sub(sys_tokens);
|
||||
// 触发阈值 0.6*available(可用预算=budget-sys_tokens):available*6/10 < history_tokens
|
||||
let should = protect_start > 0
|
||||
&& (budget as u64) * 6 / 10 < history_tokens as u64
|
||||
&& (available as u64) * 6 / 10 < history_tokens as u64
|
||||
&& mgr.has_compressible_messages(protect_start);
|
||||
(should, protect_start, history_tokens)
|
||||
};
|
||||
|
||||
@@ -1122,6 +1122,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
&provider_config,
|
||||
&llm_concurrency,
|
||||
iteration,
|
||||
sys_tokens,
|
||||
).await {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -486,7 +486,13 @@ pub(crate) async fn process_tool_calls(
|
||||
// 短 lock 段:push tool_result(纯写,无 await)
|
||||
{
|
||||
let mut session = session_arc.lock().await;
|
||||
session.conv(conv_id).messages.push(ChatMessage::tool_result(&draft.id, content.clone()));
|
||||
// T2: 大工具结果进 namespace
|
||||
let msg_content = if df_ai::namespace_store::should_use_namespace(&content, &draft.name) {
|
||||
session.namespace_store.store(&draft.name, &content)
|
||||
} else {
|
||||
content.clone()
|
||||
};
|
||||
session.conv(conv_id).messages.push(ChatMessage::tool_result(&draft.id, &msg_content));
|
||||
}
|
||||
// 锁外:审计(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"), current_message_id).await;
|
||||
@@ -599,7 +605,13 @@ pub(crate) async fn process_tool_calls(
|
||||
// 短 lock 段:写 per_conv.messages(纯写,无 await)
|
||||
{
|
||||
let mut session = session_arc.lock().await;
|
||||
session.conv(conv_id).messages.push(ChatMessage::tool_result(&draft.id, content.clone()));
|
||||
// T2: 大工具结果进 namespace,主队列只留引用
|
||||
let msg_content = if df_ai::namespace_store::should_use_namespace(&content, &draft.name) {
|
||||
session.namespace_store.store(&draft.name, &content)
|
||||
} else {
|
||||
content.clone()
|
||||
};
|
||||
session.conv(conv_id).messages.push(ChatMessage::tool_result(&draft.id, &msg_content));
|
||||
}
|
||||
// F-#97 审计留痕:low_risk 向量中 risk_level != Low 即 mode 放行(Med 仅 medium/all、High 仅 all 才进)。
|
||||
// decided_by 区分接管来源,审计表可追溯 all 模式执行了多少高危命令(治 securityReview blocker:
|
||||
|
||||
@@ -222,6 +222,17 @@ async fn save_conversation_inner(
|
||||
eprintln!("[LOCK-DIAG] save clone 段持锁 {:?} (含等待,>50ms 报告,定位 session lock 长持有者)", __lock_total);
|
||||
}
|
||||
// truncate 在锁外(clone 副本上操作,不影响 session 真相源)
|
||||
// T2: 展开 namespace 引用为原文再落库
|
||||
{
|
||||
let session = session_arc.lock().await;
|
||||
for m in &mut msgs {
|
||||
if df_ai::namespace_store::is_namespace_ref(&m.content) {
|
||||
if let Some(original) = session.namespace_store.read_only(&m.content) {
|
||||
m.content = original.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for m in &mut msgs {
|
||||
// P0-2:tool result 是结构化 JSON(provider 读工具返回原样),
|
||||
// 中段截断会插裸换行+中文省略标记破坏 JSON 结构致 reload/重发 parse FAIL。
|
||||
|
||||
@@ -530,6 +530,8 @@ pub struct AiSession {
|
||||
/// conversation.rs save + title.rs + knowledge_inject.rs + lib.rs L0)读写
|
||||
/// `session.conv(conv_id).*` / `session.conv_read(conv_id)`。顶层单例会话级字段已全部删除。
|
||||
pub per_conv: HashMap<String, PerConvState>,
|
||||
/// T2 工具命名空间存储(运行时缓存,大工具结果不进主队列)
|
||||
pub namespace_store: df_ai::namespace_store::NamespaceStore,
|
||||
}
|
||||
|
||||
impl AiSession {
|
||||
@@ -540,6 +542,7 @@ impl AiSession {
|
||||
active_conv_created_at: None,
|
||||
pending_approvals: HashMap::new(),
|
||||
per_conv: HashMap::new(),
|
||||
namespace_store: df_ai::namespace_store::NamespaceStore::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user