feat(memory): extract on automatic compaction - #2597
likun666661 merged 4 commits into
Conversation
|
I reviewed this PR against the #1615 design trail and the explicit extraction slice in #2117. The safety work here is strong: durable checkpoint identity, user-text-only evidence, repeated policy checks, fail-open dispatch, per-session serialization, and atomic Cursor/Receipt/Item settlement are all good choices. I do think this needs changes before merge, for two architectural reasons and two concrete correctness/privacy issues. 1. Compaction is a useful scheduling point, but not the semantic definition of automatic memoryCompaction correlates with token volume, not future memory value. A short, high-value session may never compact, while a long noisy session may compact repeatedly. Since RuntimeEvents remain durable, Compaction is not a last-chance evidence boundary either; it is a control-plane scheduling choice. That is fine if this slice is described narrowly as a Compaction-triggered coverage safety net. It should not be treated as completing automatic memory coverage or the #1615 user outcome. 2. Coverage boundary and interpretation-context boundary are currently conflatedThe accepted #1615 direction says to process unprocessed RuntimeEvents covered by that Compaction. This implementation instead freezes the last RuntimeEvent before compression:
The Memory Cursor is then advanced through that boundary, including retained tail Events that were not actually compacted. Those are two different boundaries:
Using one boundary for both can process recent retained-tail assertions too early. If later conversation makes their durable meaning clear, those Events are already behind the Cursor and cannot be cited as current incidental-extraction evidence. I suggest storing both boundaries, advancing the Cursor only through the actual Compaction coverage, while optionally exposing a bounded retained tail as context. 3. The model request is not actually boundedThe Evidence JSON is bounded, but the total provider request is not. Automatic recovery rebuilds every model-visible RuntimeEvent from Session start through the checkpoint boundary: The host then sends all of This is contradictory at the exact target condition: the primary request has just required Compaction because its context is too large, then Memory reconstructs the pre-Compaction prefix and sends it again with additional prompt overhead. Repeated Compactions also repeatedly send the full historical prefix even when the Memory Cursor has advanced, so cumulative cost can grow superlinearly. The full auxiliary request needs a hard token/input bound: process the unprocessed coverage in chunks, include only a bounded context neighborhood, and run the same provider-capacity check before generation. 4. Crash recovery is conditional on another triggerThe checkpoint is a durable task identity, but there is no startup recovery scan for Memory Compaction checkpoints. If the process exits after checkpoint persistence and the Session never triggers Memory again, extraction never runs. The PR body accurately says “a later trigger” recovers it, so the current guarantee is next-trigger recovery, not eventual recovery. Either:
A durable identity alone does not provide eventual execution. Concrete implementation blockers
If two durable occurrences reuse the same Tool Call ID, the later result overwrites the earlier one and is attached to the first call. The repository already has replay tests establishing that reused IDs must be handled by durable occurrence, not ID alone. Pairing should be occurrence/step/order aware.
Tool Result output is sanitized, but Tool Call input is serialized directly: An input such as
This looks like a test isolation/accounting race introduced by the new auxiliary request, but it still needs to be fixed before merge. RecommendationI would keep the overall architecture, but request these changes:
The missing recall/quality evaluation does not have to block this infrastructure slice if the scope stays narrow, but it does mean this PR proves pipeline safety—not yet the #1615 user-level memory capability. |
…ory-compaction-extraction # Conflicts: # packages/runtime-host/src/__tests__/execution-model-composition.test.ts # packages/runtime/src/ai-sdk-compaction.ts # packages/runtime/src/mid-turn-capacity-compact.ts
|
Re-reviewed the current head after the bounded-extraction follow-up. The earlier implementation blockers are addressed in a coherent way:
The remaining tradeoffs are explicit and acceptable for this PR's scope: Compaction is a coverage safety net rather than the sole semantic value trigger, and crash recovery is next-trigger recovery rather than startup-driven eventual execution. I do not consider those merge blockers for this infrastructure slice. Overall, this now looks like a mature asynchronous Memory extraction foundation. Extraction quality, recall, semantic deduplication, updates/conflict handling, feedback, and forgetting can be evaluated and developed independently without expanding this already substantial PR. LGTM from me. |
…ory-compaction-extraction # Conflicts: # packages/runtime-host/src/__tests__/execution-model-composition.test.ts # packages/runtime-host/src/server/execution-composition.ts # packages/runtime/src/__tests__/ai-sdk-backend.test.ts # packages/runtime/src/ai-sdk-backend.ts # packages/runtime/src/index.ts
Summary
Implements PR②-B of #1615: automatic long-term-memory extraction when Maka persists an automatic Compaction checkpoint, building on the explicit extraction pipeline merged in #2117.
The three extraction paths now have distinct roles:
memory_remember: the user explicitly asks Maka to remember something;memory_extract: the Agent identifies durable information worth preserving;Automatic extraction is intentionally not the only content-value trigger. A short but important conversation can still use either explicit tool. Conversely, an automatic range with no valuable memory produces a no-op and each segment is capped at three model calls.
The core invariant is:
Automatic trigger and execution order
This PR covers automatic pre-turn Compaction, proactive mid-turn Compaction, and reactive context-overflow Compaction. Manual
compactHistoryremains out of scope.HistoryCompactCheckpoint.There is no async Memory capability read, history scan, message projection, or model call on the primary Compaction path.
Coverage, context, and Evidence
(committed Cursor, frozen boundary].policy_deniedbarrier.Request bounds and splitting
The complete auxiliary request is checked against the frozen model context window, including Messages, Memory prompt, and output reserve.
extractrange with its own operation identity and Event boundary. The second segment retains the original trigger semantics and, formemory_remember, the requested Turn.Failure, retry, and crash recovery
Compaction checkpoints remain the durable task identities; this PR does not add a generic task table, Worker, or Lease.
memory_rememberretry reconstructs the original requested Turn identity.Policy and privacy behavior
policy_denied, never sent to the Memory model, and permanently skipped.unavailableremains eligible and recoverable.memory_rememberormemory_extractPending Failure.Storage
SQLite schema v5 adds durable Compaction policy-denial markers. The earlier v4 changes retain Compaction checkpoint association and explicit
skipped/policy_deniedreceipt semantics. Cursor, Pending Failure, Receipt, denial marker, and Item changes preserve their transactional and idempotency guarantees; existing v3 pending rows migrate without loss.Verification
@maka/core,@maka/storage,@maka/runtime, and@maka/runtime-host;git diff --checkpassed;upstream/mainand resolved/verified all conflicts;This PR intentionally excludes recall, Item updates, semantic deduplication, conflict resolution, Groups, Summaries, feedback, forgetting, and Provider Deferred Tools. Design documents remain local and are intentionally excluded from the commit and PR.
中文说明
概要
这是 #1615 长期记忆方案的 PR②-B,接续已合并的 #2117。
目前有三种提取路径:
memory_remember:用户明确要求记住时调用;memory_extract:Agent 判断对话中存在值得长期保存的信息时调用;因此自动触发不是唯一的“价值判断”入口。短但重要的对话仍可使用两个显式工具;自动范围即使完全没有值得保存的内容,也只会产生 no-op,并且每段最多三次模型请求。
核心不变量:
自动触发与时序
本 PR 覆盖自动 pre-turn Compaction、proactive mid-turn Compaction 和 reactive context-overflow Compaction;手动
compactHistory暂不触发。HistoryCompactCheckpoint;主 Compaction 路径不等待异步 Memory gate,也不扫描历史、不构建完整 Memory 消息、不调用模型。
Coverage、上下文与 Evidence
(已提交 Cursor, 冻结边界];policy_denied隐私屏障;请求上限与两段切分
每次都会按完整辅助请求检查容量,包括 Messages、Memory Prompt 和输出预留。
extract;第二段保留原始触发语义,memory_remember的请求 Turn 也保留在第二段;失败、重试与崩溃恢复
memory_rememberPending Failure 会恢复原请求 Turn 身份;Policy 与隐私语义
policy_denied,不调用 Memory 模型,并永久跳过该范围;unavailable保持 eligible,之后可以恢复;memory_remember或memory_extract的 Pending Failure。Storage 与验证
SQLite schema v5 增加独立的 Compaction policy-denial marker;v4 已加入 Pending Failure 的 checkpoint 关联和
skipped/policy_deniedReceipt 语义。v3 既有 Pending Failure 可以无损迁移。验证结果:
git diff --check通过;upstream/main、解决冲突并重新验证;本 PR 不实现召回、Item 更新、语义去重、冲突消解、Group、Summary、反馈、遗忘或 Provider Deferred Tools。设计文档按约定仅在本地同步,不进入 Commit 或 PR。
Part of #1615. Follows #2117.