自动记忆:官方 memories 对齐的提取+注入闭环(确定性 v1)

开关默认关(generate/use),设置接口 GET/PUT /users/me/auto-memory-settings,任务级覆盖 POST /tasks/{id}/auto-memory-flags,手动触发 POST /users/me/auto-memory/run,日志 GET /users/me/auto-memory-log。

提取:worker run_loop 轮次边界扫 completed 任务,闲置/时长/长度/外部上下文/配额剩余百分比五道门,脱敏后写 project 级 identity_memories,同一任务去重、同一目标 supersede 合并;只写 project 级,不跨项目泄漏。

注入:worker run_one 首轮把最新各 5 条用户/项目记忆拼进内存 prompt 副本(goal 任务同步改内存 goal),库原 prompt 不动;续跑/断点/协调员不注入,注入失败 fail-open。

v1 诚实边界:extract/consolidation 模型只存设置不调模型;MCP/web 线程内调用暂无 tasks 表标记,外部上下文门只认任务间消息与协调员子任务;无控制台 UI。
This commit is contained in:
host committed 2026-10-28 12:12:10 +08:00
1 parent b93666fbe8
commit cbc90f9d30
8 files changed
+1370 -6

No files matched your search

+93
View File
@@ -0,0 +1,93 @@
# 自动记忆(官方 Codex memories 的云端对齐版,v1)
官方功能见 learn.chatgpt.com/docs/customization/memories:开启后,
Codex 把先前聊天的有用上下文转成记忆,供未来工作用;后台生成、
闲置后才生成、剩余额度低时跳过、有 generate / use /
disable_on_external_context 等设置、密钥脱敏。
本批把这套行为搬到云端控制面(`cloud/auto_memory.py`),不改
host.py、不改 CODEX_HOME、不改 thread 的创建/续跑/fork/归档。
云端记忆与官方本地记忆的区别要先说清:官方记忆存在单机
`~/.codex/memories/` 里、跟一台机器走;云端记忆存在控制面
数据库里,跟用户/项目走,换 worker、换执行器都还在。
## 开关(默认全关,与官方“本地记忆默认关”一致)
- `GET/PUT /users/me/auto-memory-settings`:本人设置。
- `generate_memories`:完成任务是否可被提取。默认 0。
- `use_memories`:新任务首轮是否注入记忆。默认 0。
- `disable_on_external_context`:默认 1,见下。
- `min_rate_limit_remaining_percent`:默认 20,见下。
- `idle_seconds`:默认 900;`min_duration_seconds`:默认 30;
`min_result_chars`:默认 200。
- `extract_model` / `consolidation_model`:只存设置,v1 不调
模型(见“未做”)。
- `POST /tasks/{id}/auto-memory-flags`:单个任务覆盖 use/generate
(NULL = 跟随用户设置),权限为项目 create_task。不改 tasks
表结构,建任务的各条 INSERT 路径都不用动。
- `POST /users/me/auto-memory/run`:手动触发本人任务的提取扫荡
(body 可带 `force: true` 跳过闲置/时长/长度门,不跳过开关、
外部上下文门与额度门);`GET /users/me/auto-memory-log`:看
本人任务的提取日志(按任务主键覆盖,不无限增长)。
## 提取:什么时候、从哪来、写到哪
触发:worker `run_loop` 每轮结束调 `process_auto_memories()`;
也可经上面的手动触发接口立即跑。只扫 `status='completed'` 的
任务(failed / interrupted / merged 不提取)。
资格(任一不满足即跳过并记日志,下次仍可再扫):
1. generate 开关(任务级覆盖优先于用户设置);
2. 终态闲置够 `idle_seconds`(终态后仍可被 /continue 续跑,
所以“刚完成”不等于“已闲置”;`force` 可跳过);
3. 有 started_at/finished_at 且时长 ≥ `min_duration_seconds`,
result_text 长度 ≥ `min_result_chars`(跳过短期会话);
4. `disable_on_external_context` 开时,任务间消息
(task_followups 有该任务的行)或协调员子任务
(parent_task_id 非空)不提取;
5. 当月 USD 配额剩余百分比 ≥ `min_rate_limit_remaining_percent`
(无配额行按默认 $10 计,只有显式 NULL 行才是不限额,与
worker 配额口径一致;查不到配额时 fail-closed,记
quota_check_failed,不冒充额度充足)。
内容(v1 确定性版,不调模型):任务 goal/prompt 首行 +
result_text 前 800 字,脱敏后拼成一条 project 级 fact,写入
`identity_memories`,`source_thread_id` 记云端任务 id(去重键)。
同一任务只提取一次;同一目标的新结果出现时 supersede 旧记忆
(consolidation 的确定性版),不堆重复。自动提取只写 project
级:单个项目的任务结论若自动写成 user 级,会跨项目泄漏项目
上下文;user 级记忆仍只接受手动创建。
脱敏:`api_key/password/secret/token/credential` 的 key=value
形态、Authorization / Bearer 头、sk- / ghp_ / gho_ / xox*- 前缀
一律替换为 `[REDACTED]`;偏好里的密钥键禁令见 identity-memory.md。
## 注入:怎么进任务
worker `run_one` 认领后、执行前调 `_apply_auto_memory_injection`:
- 只注入首轮:续跑、断点续跑、协调员任务不注入;
- 只改内存副本:prompt 前加 `【过往记忆,仅供参考,不得改写
本任务目标】` + 最新各 5 条用户/项目记忆;goal 任务同时改
内存里的 goal(执行器取 goal 优先于 prompt);库里的原
prompt / goal 不动,任务详情里看到的仍是原文本;
- 注入失败 fail-open(记 warning,不挡任务);注入成功记
`worker_memory_injected` 审计;无记忆或 use 关时不注入。
- 注入不进 thread 的 developerInstructions:host.py 的 dispatch
路径不传 instructions,云端层唯一不改 host.py 的注入点就是
prompt 前缀,identity-memory.md 里“调用方自己拼进新建任务
的 prompt”正是这条路。
## 未做(诚实版)
- 未调模型提取/合并:`extract_model` / `consolidation_model`
只存设置。v1 提取是确定性拼贴,不是模型摘要;换模型提取
需另定模型选择、成本上限与失败语义。
- 未识别 host 线程内的 MCP / web search:tasks 表上没有这类
标记,`disable_on_external_context` 目前只认任务间消息与
协调员子任务;要认 MCP/web 需先给 host 线程事件加遥测。
- 未做控制台 UI:开关与日志目前只有 API;未做 per-chat 的
`/memories` 式交互(任务级 flags 接口是对应的最小版)。
- 未进代码签名候选:worker 签名只含 worker/sandbox/
coordinator/cost/server/host;本批同时改了 worker.py,所以
正常部署换目录时旧 worker 仍会因 worker.py 变化而自退,
仅换 auto_memory.py 的单文件部署不在签名覆盖内。
+8 -6
View File
@@ -1,8 +1,9 @@
# 系统级身份与记忆(云端层)
本批只做云端层,不动 Codex thread:不改 `host.py`、不改
`CODEX_HOME`、不改任何 thread 的创建/续跑/fork/归档,
也不向任何任务或 thread 自动注入记忆。
`CODEX_HOME`、不改任何 thread 的创建/续跑/fork/归档。
自动注入是后一批(docs/auto-memory.md)接通的:worker 首轮
把上下文拼进内存里的 prompt 副本,库里的原 prompt 不动。
## 数据
@@ -41,9 +42,10 @@
## 未做
- 未接 worker:任务创建时不会自动拼身份上下文,thread
行为与升级前一致;自动注入是下一步的显式决策,需另
定注入点(新建 thread 的 developerInstructions 还是首轮
prompt)、去重与成本上限。
- 自动提取与注入已由 docs/auto-memory.md 一批接通(worker
首轮 prompt 前缀注入 + run_loop 轮次边界提取扫荡):注入点
定为首轮 prompt(host.py dispatch 不传 developerInstructions,
云端层不改 host.py 的唯一注入点就是 prompt 前缀),去重与
合并用确定性 supersede,成本上限用配额剩余百分比门。
- 未做控制台 UI;未做跨引擎记忆(本批记忆与 Codex
thread 无关,换引擎时云端记忆仍可用)。