feat(memory): add memory_session_context tool for session-start context injection#1132
feat(memory): add memory_session_context tool for session-start context injection#1132shiloong wants to merge 1 commit into
Conversation
Forrest-ly
left a comment
There was a problem hiding this comment.
PR #1132 Review — feat(memory): add memory_session_context tool for session-start context injection
本 PR 添加 memory_session_context 工具,在 session 启动时注入历史上下文。扫描 facts/summary/ 获取最近 session 摘要,扫描其他 facts// 获取高置信度事实(confidence >= 0.8),输出上限 8KB 的 markdown 文本。
259 行新增,代码质量在最近系列 PR 中最好:正确使用 safe_fs::read_to_string 读文件、frontmatter 解析器支持 YAML unquote、preview 截断是 char-boundary-safe 的。
发现
- src/agent-memory/src/tools/session_context.rs:~85 — WalkDir 扫描整个 mount root 但只需要 facts/ 子目录 (CONFIRMED, 中)
for entry in WalkDir::new(&svc.mount.root) // ← 扫描整棵树
.follow_links(false)
.into_iter()
.filter_entry(|e| !e.path().starts_with(&meta_dir))
{
// ...
if !rel.starts_with("facts/") {
continue; // ← 跳过所有非 facts/ 文件
}
filter_entry 仅排除 meta_dir,不排除 notes/、MEMORY.md 等其他顶级目录。WalkDir 会递归进入 notes/observed/ 的每一层,为每个文件计算 rel_path 后才 continue。对于有 1000 条 notes、50 条 facts 的存储,浪费 95% 的迭代。
此工具定位为 session-start 路径(每次会话启动调用),性能敏感。应改为 WalkDir::new(svc.mount.root.join("facts")) 直接扫描目标目录,或在 filter_entry 中裁剪非 facts/ 子树:
.filter_entry(|e| {
!e.path().starts_with(&meta_dir)
&& (e.depth() == 0 || e.path().starts_with(&facts_dir))
})
- src/agent-memory/src/tools/session_context.rs:~151 — high_confidence.truncate(limit) 与 summaries 共享同一 limit 参数,但文档只提及 summaries (CONFIRMED, 低-中)
summaries.truncate(limit);
// ...
high_confidence.truncate(limit);
工具描述说 "Optional limit (default 5) controls max summaries",但 limit 同样截断 high_confidence。调用 memory_session_context(limit=2) 会同时限制 summaries 和 facts 各为 2 条。如果用户想多看 facts 但少看
summaries,无法做到。应分离为两个参数,或文档明确说明 limit 同时约束两者。
- src/agent-memory/src/tools/session_context.rs:~163 — 空 title 的 summary 生成畸形 markdown (CONFIRMED, 低)
let section = format!(
"## {}\n_session: {} | created: {}_\n\n{}\n\n",
s.title, // ← 可能为空字符串
s.session_id, // ← 可能为空字符串
s.created_at,
take_preview(&s.body)
);
若 summary 文件缺少 title frontmatter 字段,title 默认为 "",生成:
session: | created: 2026-06-25T...
空的 ## 标题在 markdown 渲染中不可见但占据结构位。应 fallback 到文件名:
let title = fm.get("title").cloned()
.filter(|t| !t.is_empty())
.unwrap_or_else(|| rel.clone());
- src/agent-memory/src/tools/session_context.rs:~155 — bytes_used 不包含 section headers("# Recent Sessions\n\n" 等),8KB 上限非精确 (CONFIRMED, 低)
out.push_str("# Recent Sessions\n\n");
// bytes_used 未递增
for s in &summaries {
if bytes_used >= MAX_CONTEXT_BYTES { break; }
实际输出可超过 MAX_CONTEXT_BYTES 约 38 字节(两个 header 总长)。对 8KB 上限来说可忽略不计,但若上限将来调低或上游有严格 budget 检查,可能溢出。
…xt injection Signed-off-by: Shile Zhang <shile.zhang@linux.alibaba.com>
6c2bb60 to
2fb73e2
Compare
Review 修复回复1. 扫描整个 mount root — ✅ 已修复改为 2. limit 共享 —
|
Description
Implement A-7: Session-Start 上下文注入.
Add
memory_session_contexttool that assembles historical context for a new session by combining:facts/summary/*.mdfiles (produced by consolidation Rule 6), sorts bycreated_atdescending, includes top N (default 5)facts/<category>/directories for facts withconfidence >= 0.8, sorted by confidence descendingReturns a markdown-formatted context string (capped at 8KB) suitable for injection into the agent's system prompt at session start.
Usage
Designed to be called by copilot-shell's
autoRecallHook(PR #1121) at session start, or manually by any MCP client:Implementation
src/tools/session_context.rs(272 lines)safe_fs::read_to_stringfor sandbox-safe readsRelated Issue
no-issue: A-7 Session-Start context injection
Type of Change
Scope
memory(agent-memory)Checklist
cargo clippy --all-targets -- -D warningspassescargo fmt --checkpassescargo testpasses (148 tests: 135 lib + 3 profile + 10 integration)