L0 原始对话:忠实记录与增量捕获
L0 不经 LLM,直接旁路记录。核心挑战是「只记新的、不重复、不污染」——位置切片与时间戳游标双重防重,注入标签与代码块被清洗后落盘。
L0 Conversation · l0-recorder.ts
1
位置切片 Position Slice
用 before_prompt_build 时缓存的 originalUserMessageCount 切分 rawMessages,只保留本轮新增消息。对 Gateway 重启后的时间戳漂移免疫,是第一道防重。
2
提取 user / assistant 消息 extractUserAssistantMessages
从 hook 原始数组里抽出 user / assistant 文本;content 为数组时拼接 text 片段;内嵌 base64 图片替换为 [image],避免污染索引。
3
时间戳游标过滤 Incremental Filter
只保留 timestamp > afterTimestamp 的消息(严格大于)。同轮消息共享同一游标、整批进整批出;缺失时间戳的消息以 Date.now() 兜底。
⚠ 安全阀:切片不可用且全部消息通过过滤(>8 条)时告警,提示时间戳漂移
4
还原原始用户输入 Original Prompt Restore
框架会把 prependContext 注入到用户消息里。用缓存的 originalUserText 按时间戳匹配并替换被污染的消息;匹配失败时由 sanitizeText 兜底。
5
清洗与过滤 Sanitize + Filter
sanitizeText 移除注入标签(防反馈回路);assistant 回复剥离代码块(降嵌入噪音);shouldCaptureL0 过滤框架噪音与 / 斜杠命令。
6
双写落盘 JSONL + SQLite
按本地日期分片写入 conversations/YYYY-MM-DD.jsonl(每行一条消息,扁平格式、易于 grep / 流式读取);同步 upsert 到 l0_conversations 表供向量检索。
写文件失败不阻断:过滤后的消息仍返回给 L1 继续处理

落盘记录字段

  • sessionKey / sessionId 会话定位
  • teamId / userId / agentId 三租户隔离,缺省落到 default 兼容桶
  • recordedAt ISO 时间戳
  • id msg_ 前缀消息 ID(供 L1 source_message_ids 追踪)
  • role / content / timestamp 消息本体
{"sessionKey":"sess_001", "sessionId":"sess_001", "teamId":"default", "userId":"default", "agentId":"default", "recordedAt":"2026-09-01T08:00:00Z", "id":"msg_1785...", "role":"user", "content":"别重构旧鉴权模块…", "timestamp":1785657600000}

存储双通道

  • JSONL:conversations/YYYY-MM-DD.jsonl,每日一文件、所有会话合并,行级按 sessionKey 过滤
  • l0_conversations 表:record_id 主键,含 role / message_text / recorded_at / timestamp,可向量化(l0_vec 虚拟表)

下游消费

  • 按 sessionId 分组读取(sessionKey 内不同会话实例独立抽取)
  • L1 抽取以 L0 为输入;tdai_conversation_search 可回溯原始原文
来源:MemoryCore/src/core/conversation/l0-recorder.ts(recordConversation)与 src/core/store/sqlite.ts(l0_conversations DDL)。双保险增量机制:位置切片(免疫重启漂移)+ 时间戳游标(重启兜底)。