Files
host cbc90f9d30 自动记忆:官方 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。
2026-10-28 12:12:10 +08:00

94 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 自动记忆(官方 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 的单文件部署不在签名覆盖内。