Skip to content

feat(memo): 引入 user/project 双层 Scope 分层存储并解耦 TUI slash 命令#354

Merged
phantom5099 merged 11 commits into1024XEngineer:mainfrom
Yumiue:feat-memo-scope-layering
Apr 18, 2026
Merged

feat(memo): 引入 user/project 双层 Scope 分层存储并解耦 TUI slash 命令#354
phantom5099 merged 11 commits into1024XEngineer:mainfrom
Yumiue:feat-memo-scope-layering

Conversation

@Yumiue
Copy link
Copy Markdown
Collaborator

@Yumiue Yumiue commented Apr 18, 2026

Summary

  • memo 双层 Scope 存储:引入 Scope(user/project/all)类型,Store 接口所有方法加入 scope 参数,FileStore 改为双层目录布局(user 层全局共享,project 层按工作区哈希隔离)
  • 新增 memo_list / memo_remove 工具:支持按 scope 过滤列出和删除记忆
  • TUI slash 命令去耦合:新增 runtime.ExecuteSystemTool 统一入口,/memo/remember/forget 改为通过 runtime 执行,TUI 不再直接依赖 memo.Service
  • 配置细化MaxIndexLines 拆分为 MaxEntries + MaxIndexBytes + ExtractTimeoutSec + ExtractRecentMessages,校验从严
  • 提取器可配置化AutoExtractor 加入超时控制,LLMExtractorrecentMessageLimit 从硬编码改为构造参数注入
  • 安全增强nearestExistingPath 检查父路径类型防止文件占位攻击
  • 代码简化:导出 ScopeForType 消除重复映射,提取 normalizeToolName/normalizeKeyword 去重,scopeDir 去除冗余分支

Test plan

  • go build ./... 编译通过
  • go test ./... 全量测试通过
  • gofmt -w ./cmd ./internal 格式化通过
  • internal/memo 覆盖率 87.4%
  • internal/tools/memo 覆盖率 90.8%
  • internal/runtime 覆盖率 95.3%(新增 system_tool.go 98%)
  • 新增文件均有完整测试:list_test.go(9 个测试)、remove_test.go(9 个测试 + 11 子用例)、system_tool_test.go(11 个测试)

🤖 Generated with Claude Code

fennoai[bot]

This comment was marked as outdated.

核心变更:
- 新增 Scope 类型(user/project/all),Store 接口所有方法加入 scope 参数
- FileStore 改为双层目录布局:user 层全局共享,project 层按工作区隔离
- Service 的 List/Remove/Search/Recall 支持 scope 过滤,自动按 Type 路由到对应分层
- 配置从 MaxIndexLines 拆分为 MaxEntries + MaxIndexBytes + ExtractTimeoutSec + ExtractRecentMessages
- AutoExtractor 加入 context.WithTimeout 超时控制
- LLMExtractor 的 recentMessageLimit 从硬编码改为构造参数注入

新增工具:
- memo_list:按 scope 列出持久记忆
- memo_remove:按关键词 + scope 删除记忆

TUI 去耦合:
- 新增 runtime.ExecuteSystemTool 统一系统工具执行入口
- /memo、/remember、/forget 命令改为通过 runtime 执行,TUI 不再直接依赖 memo.Service
- prompt 注入从单一 "Memo" section 拆分为 "User Memo" + "Project Memo"

安全增强:
- nearestExistingPath 检查父路径类型,防止文件占位攻击

代码简化(simplify 轮):
- 导出 ScopeForType 消除 list.go 的重复映射
- 提取 normalizeToolName 去重 system_tool ID 生成逻辑
- 提取 normalizeKeyword 统一关键词标准化
- scopeDir 去除冗余 default 分支

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Yumiue Yumiue force-pushed the feat-memo-scope-layering branch from 31284f5 to 9951cfc Compare April 18, 2026 07:14
@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

已按你的要求完成:先检查历史评论并评估未解决项,再修复值得修复的问题,最后执行了 code-simplifier 复核、提交并推送到当前 PR 分支。

已处理内容

  1. 已修复 review 评论 1(internal/config/loader.go):
  • fromPersistedMemoConfig 之前仅在 >0 时才应用数值字段,导致显式非法值(如 -1)被静默吞掉。
  • 现在 memo 数值项改为指针反序列化(*int),只要字段在配置中出现就保留原值,交给校验报错。
  • 同时把 MemoConfig.ApplyDefaults 改为仅对 ==0 补默认值,避免负值被默认值覆盖。
  1. 已修复 review 评论 2(兼容性):
  • 增加 memo.max_index_lines 过渡兼容字段,映射到 memo.max_entries,避免升级后因 KnownFields(true) 直接启动失败。
  1. 补充/调整测试:
  • internal/config/loader_test.go
    • TestLoaderSupportsLegacyMemoMaxIndexLinesField
    • TestLoaderRejectsExplicitInvalidMemoNumbers(覆盖四个 memo 数值字段)
  • internal/config/config_test.go
    • TestMemoConfigApplyDefaults 增加“保留负值用于后续校验”子用例
  1. code-simplifier 复核结果:
  • 已调用简化代理复核本次改动,结论为无额外必要简化,不再追加改动。

验证结果

  • go test ./internal/config:通过
  • go build ./...:通过
  • go test ./...:存在既有失败(与本次改动无关)
    • internal/subagent 包:TestSchedulerRunCancellationWriteback 失败

提交与推送

  • Commit: 273a031
  • 已推送到 PR 头分支:Yumiue/feat-memo-scope-layering

View job run

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/review

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
fennoai[bot]

This comment was marked as outdated.

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/review

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

完成结果

已按触发指令完成:先检查历史评论并修复值得修复项,再执行代码简化并推送到当前 PR 分支。

已修复项

  1. 修复未解决高优先级评论(internal/memo/store.go
  • project scope 增加旧路径兼容读取:优先新路径,缺失时回退旧路径。
  • 为写入路径增加迁移:在 SaveIndex/SaveTopic/DeleteTopic 前将旧目录数据迁移到新目录,避免升级后历史 memo 不可见。
  • 在简化阶段抽取通用辅助函数(如首个存在文件读取、仅在目标缺失时迁移文件),减少重复分支。
  1. 补充回归测试(internal/memo/store_test.go
  • 覆盖旧索引回退读取。
  • 覆盖旧 topic 回退读取与列表回退。
  • 覆盖写入触发迁移后的新旧路径状态断言。
  • 抽取测试初始化辅助函数,降低重复。
  1. 修复低优先级文档一致性(docs/tools-and-tui-integration.md
  • 更新工具列表,补充 memo_list / memo_remove
  • 同步 slash 命令经 Runtime.ExecuteSystemTool 执行的链路说明。

验证

  • gofmt -w internal/memo/store.go internal/memo/store_test.go
  • go test ./internal/memo
  • go test ./internal/tools/memo
  • go test ./...

提交与推送

  • Commit: 9cb4ce3
  • 已推送到 PR 头分支:Yumiue/feat-memo-scope-layering

未执行项

View job run

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/review

Generated with [codeagent](https://github.com/qbox/codeagent)

Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
fennoai[bot]

This comment was marked as outdated.

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

完成结果

已按触发指令执行完毕:检查历史评论中的未解决 review 点、修复值得修复项、执行 code-simplifier 复核,并完成提交推送。

已处理内容

  1. 修复 review 评论:internal/memo/service.go(去重索引污染)
  • 问题:条目在 trimIndexEntries 后可能已被裁掉,但仍会无条件执行 trackAutoExtractEntryLocked
  • 修复:新增 indexContainsEntryID 判定,仅当条目最终仍在索引中时才更新自动提取去重索引。
  1. 修复 review 评论:internal/memo/service.go(字节裁剪 O(n^2))
  • 问题:按 max_index_bytes 裁剪时每轮调用 RenderIndex 造成重复全量渲染。
  • 修复:新增 trimIndexEntriesByBytes,改为二分定位最小前缀移除量,显著减少重复渲染次数。
  1. 修复 review 评论:internal/tools/memo/recall.go(Schema 文案不一致)
  • keyword 描述更新为包含 content 匹配,和实际 matchesKeyword 行为一致。
  1. 补充回归测试
  • internal/memo/service_test.go
    • TestServiceAutoExtractTrimmedEntryDoesNotPolluteDedupIndex
    • TestTrimIndexEntriesByBytesRemovesMinimalPrefix
  • 同步保留并通过现有相关测试。
  1. code-simplifier 复核
  • 已调用子 agent 进行简化复核,并并入等价简化(不改变行为):
    • listLocked 返回浅拷贝写法简化
    • trimIndexEntries 去除不必要中间变量
    • recall.Execute 反序列化错误分支变量命名简化

验证

  • gofmt -w internal/memo/service.go internal/memo/service_test.go internal/tools/memo/recall.go
  • go test ./internal/memo
  • go test ./internal/tools/memo
  • go test ./...

提交与推送

未执行项

View job run

xgopilot and others added 2 commits April 18, 2026 07:47
Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
fix(memo): avoid stale auto-extract dedup and optimize byte trimming
@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

处理结果

已按触发要求完成:先检查历史评论中的未解决 code review 项,再执行 code-simplifier 简化,并在有改动后提交推送。

评论检查结论

  • 已读取 /tmp/codeagent/comments/codeagent-comments-1776498818-d12de50b15013ca4.log
  • 日志中的 3 条 code review 问题(internal/memo/service.go 两条、internal/tools/memo/recall.go 一条)在当前分支代码中已落地修复;本轮未发现需继续修复的新未解决项。

本轮代码简化(行为不变)

修改文件:

  • internal/tools/memo/common.go
  • internal/tools/memo/list.go
  • internal/tools/memo/recall.go
  • internal/tools/memo/remove.go
  • internal/tools/memo/remember.go

简化内容:

  • 抽取统一参数反序列化错误包装:invalidArgumentsError
  • 抽取统一 scope schema:memoScopePropertySchema
  • 将复用的 parseMemoScope 收敛到 common.go,移除 remove.go 重复实现。

验证

  • go test ./internal/tools/memo 通过。
  • go test ./... 通过。

提交与推送

未完成项

View job run

xgopilot and others added 2 commits April 18, 2026 07:58
Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
refactor(memo): simplify memo tool argument/scope helpers
@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/review 请作为资深 Go 审查助手,对 PR #354纯风险导向审查。仅输出问题,不要表扬,不要泛泛总结。

审查背景(必须纳入判断):

  • PR 主题:memo user/project 双层 Scope 分层存储新增 memo_list/memo_removeTUI slash 命令改为 runtime.ExecuteSystemToolmemo 配置项拆分并从严校验自动提取器可配置化workspace 安全检查增强
  • 关键变更目录:
    • internal/memo/*(store/service/auto_extractor/llm_extractor/types)
    • internal/tools/memo/*(list/remove/recall)
    • internal/runtime/system_tool.go
    • internal/tui/core/app/update.gointernal/tui/services/runtime_service.go
    • internal/config/{memo.go,loader.go}
    • internal/security/workspace.go

审查目标(按优先级):

  1. 正确性与回归风险
  • Scope 语义是否一致:Type -> ScopeForTypeNormalizeScopeparseMemoScopescopesForQuery
  • all/user/project 查询与删除是否会误删、漏删、跨 scope 污染。
  • memo_list/memo_remove 参数解析、默认值、错误路径是否与 schema 一致。
  • runtime.ExecuteSystemTool 是否与主链路工具执行结果一致(tool start/result、错误映射、session/run 关联)。
  1. 存储一致性与迁移风险
  • FileStore 新旧路径兼容(新路径优先、旧路径回退)是否导致读写分叉或覆盖顺序问题。
  • legacy project 路径迁移是否幂等、并发安全、失败可恢复。
  • SaveIndex/SaveTopic 原子替换逻辑在异常路径下是否产生脏文件或数据丢失。
  • topic 删除与索引删除是否始终一致。
  1. 并发与状态一致性
  • memo.Service 锁粒度是否可能导致竞态/死锁/长时间阻塞。
  • 自动提取去重索引(autoExtractIndex*)在 replace/trim/remove 下是否会残留脏引用。
  • AutoExtractor 的 debounce/tail-run/idle 回收状态机是否可能丢任务或重复执行。
  1. 性能与可扩展性
  • 索引裁剪逻辑(尤其按字节阈值)是否存在 O(n^2) 热路径。
  • 读取/列举 topics 时的 IO 放大风险。
  • 大量 memo 下 list/recall/remove 的复杂度和可接受性。
  1. 配置与兼容性风险
  • memo 新字段(max_entries/max_index_bytes/extract_timeout_sec/extract_recent_messages)默认值、显式非法值、序列化/反序列化是否正确。
  • 兼容字段 max_index_lines 的优先级与回退行为是否符合预期。
  • ApplyDefaultsValidate 是否存在“非法值被默认值吞掉”的路径。
  1. 安全风险
  • nearestExistingPath 父路径类型检查是否完全阻断“文件占位父路径”绕过。
  • topicPath(filepath.Base) 是否仍有路径穿越或同名覆盖风险。
  • system tool 执行是否完整复用 runtime 权限/沙箱链路,无旁路执行。
  1. TUI 解耦后的行为风险
  • /memo /remember /forget 改为 runtime 执行后,错误文案、状态更新、事件订阅是否回归。
  • command 失败时是否正确透传 ToolResult.Content 与 error,避免 UI 误报成功。
  1. 测试有效性
  • 检查新增测试是否覆盖:
    • scope 过滤与 all 模式
    • 迁移与回退读取
    • system tool 事件与错误分支
    • 配置非法值/兼容字段
    • 并发与竞态敏感路径
  • 指出缺失的失败分支用例。

输出格式要求(严格遵守):

  • 按严重级别分组:High / Medium / Low
  • 每条问题必须包含:
    • 文件:行号
    • 触发条件
    • 实际影响
    • 建议修复方向
  • 若未发现阻断问题,明确写:未发现阻断问题,并列出剩余测试盲区。

fennoai[bot]

This comment was marked as outdated.

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

完成情况

已按本次触发指令执行:读取历史评论并评估未解决 review comments,修复值得修复项,调用 code-simplifier agent 复核,并完成提交推送。

评论评估结论

  • 已检查历史日志与 PR 评论列表(含 review comments)。
  • 先前多条 review 问题(config 兼容、legacy 路径迁移、service 去重/性能、recall 文案)已在当前分支落地,不再重复修改。
  • 本轮确认仍值得修复的问题:ListTopics 在新旧目录并存时只返回首个非空目录,存在漏列风险。

本轮修复

  • internal/memo/store.go
    • ListTopics 改为聚合 topicsDirs(scope) 的所有候选目录结果。
    • 对 topic 名称去重后统一排序返回,避免兼容期漏列。
  • internal/memo/store_test.go
    • 新增 TestFileStoreListTopicsMergesScopedAndLegacyProjectTopics,覆盖“新旧目录并存 + 重名文件去重”。
  • code-simplifier 子代理复核并吸收等价简化:去掉 collectTopicNames 内的冗余排序,仅保留最终排序。

验证

  • gofmt -w internal/memo/store.go internal/memo/store_test.go
  • go test ./internal/memo
  • go test ./...

提交与推送

未执行项

  • 未新增与本次问题无关的额外重构或覆盖率补齐。

View job run

xgopilot and others added 2 commits April 18, 2026 08:18
Generated with [codeagent](https://github.com/qbox/codeagent)

Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
fix(memo): merge scoped and legacy topics in ListTopics
@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/review

Copy link
Copy Markdown

@fennoai fennoai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completed four passes (code quality, performance, security, docs). I found one noteworthy issue after deduplication.

var (
state *runState
loaded agentsession.Session
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExecuteSystemTool keeps the per-session mutex locked for the entire tool execution path (including permission wait and actual tool runtime). This can block other same-session operations for a long time and creates avoidable contention. Consider narrowing the lock scope to session load/snapshot only, then releasing it before executeToolCallWithPermission.

@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

完成结果

已按你的要求完成:读取评论日志、筛选未解决 review 意见、修复值得修复项、执行 code-simplifier 简化复核,并完成提交推送。

已处理

  1. 已检查未解决 review 评论
  • 发现并处理的有效问题:internal/runtime/system_tool.go:43 会话锁持有范围过大,会覆盖权限等待与工具执行路径,导致同 session 竞争阻塞。
  1. 已实施修复
  • internal/runtime/system_tool.go
    • ExecuteSystemTool 的会话锁范围收敛为“仅加载会话快照”阶段。
    • 工具执行前释放锁,避免长时间持锁。
  1. 已补充回归测试
  • internal/runtime/system_tool_test.go
    • 新增 TestExecuteSystemToolReleasesSessionLockBeforeToolExecution,验证工具执行期间同会话锁可被再次获取。
  1. code-simplifier 复核并合入等价简化
  • internal/runtime/system_tool.go
    • 抽取 formatSystemToolID,统一 runID/callID 构造逻辑。
  • internal/runtime/system_tool_test.go
    • 抽取 assertGeneratedIDWithPrefix,去重 ID 格式断言。

验证

  • go test ./internal/runtime 通过
  • go test ./... 全量通过

提交与推送

未执行项

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com>
@phantom5099
Copy link
Copy Markdown
Collaborator

@xgopilot 先确认当前总体方案设计,再确认有没有存在风险点

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

风险审查结果

  1. internal/memo/store.go:164, internal/memo/store.go:267, internal/memo/store.go:328, internal/memo/store.go:350
    project 分层在“新旧目录同时存在同名 topic”场景下,DeleteTopic 只删除新路径文件,旧路径同名文件会继续被 LoadTopic/ListTopics 兜底读到,导致“删除后仍可见/被召回”的幽灵数据回归。触发路径是:迁移逻辑 moveFileIfDstMissing 在目标已存在时保留 legacy 文件,后续删除只删 scoped 路径。

  2. internal/runtime/events.go:126, internal/runtime/system_tool.go:97, internal/runtime/toolexec.go:114
    事件语义不一致:EventToolResult 注释语义是“执行完成并写回会话”,但 ExecuteSystemTool 路径会发出 EventToolResult,却未执行 appendToolMessageAndSave 持久化写回;与主 ReAct 工具链路行为不同。依赖事件语义做审计/回放/状态同步的上层会出现认知偏差。

  3. internal/tui/core/app/update.go:1914, internal/tui/core/app/update.go:2118, internal/app/bootstrap.go:154
    /memo /remember /forget 改走 runtime 后,移除了 memoSvc == nil 的显式兜底;当 memo.enabled=false(工具未注册)时,命令会落入运行期“未知工具”错误,而不是明确“memo 未启用”。这是用户可见回归,且当前用例未覆盖该分支。

  4. internal/tui/core/app/update.go:1914, internal/runtime/system_tool.go:45
    memo slash 命令没有 busy 态保护,可在主 run 进行中触发系统工具;该路径会争用同一 session 锁并串行阻塞,结果可能延后回到 UI,形成与用户预期不一致的交互时序(看起来像命令“卡住”或“晚到”)。

已完成/未完成

已完成:按 origin/main...HEAD 对总体方案与风险点做纯风险导向审查。
未完成:未做代码修改与本地修复验证(本轮为审查请求)。

View job run

fix(runtime): release session lock during system tool execution
@Yumiue
Copy link
Copy Markdown
Collaborator Author

Yumiue commented Apr 18, 2026

/simplify

@fennoai
Copy link
Copy Markdown

fennoai Bot commented Apr 18, 2026

完成结果

已按本次触发要求执行完毕:先读评论日志定位未解决审查项,逐条评估是否需修复,再执行 code-simplifier 流程并验证。

处理详情

  1. 未解决 review comment 检查
  • 已读取 /tmp/codeagent/comments/codeagent-comments-1776503008-bd3640e9216d70ad.log
  • 当前唯一 code review comment 为 internal/runtime/system_tool.go:43(会话锁粒度过大),该问题已在当前分支历史提交 5b0bcfd 修复。
  • 复核当前代码后未发现新的未解决审查项。
  1. 验证
  • 已执行 go test ./...,全量通过。
  1. code-simplifier 执行结果
  • 已两次调用子代理执行代码简化复核,但均因上游 502 Bad Gateway 失败(非代码问题)。
  • 已补做本地等价简化检查(仅审查,不改行为),当前工作区无可提交改动。
  1. 提交与推送
  • 本轮未产生文件变更(git status --short 为空),因此无需新增 commit / push。

未完成项

  • 无(简化代理调用失败已按要求重试并给出本地兜底检查结果)。

View job run

@phantom5099 phantom5099 merged commit 9b1d4d5 into 1024XEngineer:main Apr 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants