docs/guides/codex-unified-session-history-guide-zh.md
适用版本:CC Switch v3.16.x 及以上。本文根据当前代码整理,命令与路径均可亲手验证;示例使用去敏数据,不包含真实会话内容或 API Key。
「统一 Codex 会话历史」是 CC Switch v3.16.x 为 Codex 新增的一个开关。它的位置在 设置 → 通用 → 「Codex 应用增强」分组里("Codex 应用增强"是这个分组的标题,开关本身叫"统一 Codex 会话历史")。开启后,官方订阅(ChatGPT 登录 / OpenAI API Key)的会话,会和 CC Switch 管理的所有第三方供应商会话,出现在同一个历史 / 续聊列表里——不再被分隔在两个互相看不见的列表中。
Codex 自己按"供应商标签"(一个叫 model_provider 的字段)给会话分类,而且续聊 / 历史列表只显示和你当前激活的供应商同标签的会话。于是会话天然被分进两个"抽屉":
openai 标签下;custom 标签下。两个抽屉互相看不见。如果你经常在官方与第三方之间切换,就会遇到这种割裂:"刚才用官方聊的会话,切到第三方后在历史列表里找不到了"——它其实没丢,只是被分到了另一个抽屉。这种割裂既容易让人误以为会话丢失,也不方便把所有会话放在一处统一回顾、续聊。
这个开关就是为了消除这种割裂:让官方订阅也以 custom 标签运行,于是官方与第三方会话合并进同一个列表,找起来、续起来都在一处。
✅ 一个贯穿全文的重要前提,请先记住:这个功能(统一 / 迁移 / 还原)全程只改写会话记录里那一个归类标签
model_provider,而且每次改写前都会自动把原文件备份一份。它不会删除、清空或覆盖你的任何一句对话。所以本文后面若提到"某些会话看不到了",几乎都是"被分到了另一个抽屉",而不是"数据没了"——真担心时,直接看 症状对照表 与 亲手验证文件还在。
把它想成 两个抽屉 + 自动备份:
openai 抽屉、第三方会话在 custom 抽屉,互不可见;custom 抽屉,于是两个抽屉合并成一个共享列表;完整机制(注入了什么、为什么可逆、迁移/还原如何保证不丢数据)见下文 核心心智模型 与文末 进阶原理附录。
要理解这个功能,你只需要记住两件事:抽屉和备份。
你每开一个 Codex 会话,Codex 会在会话文件头部记一个标签 model_provider,标记"这条会话是用哪个供应商聊的"。Codex 的续聊 / 历史列表是按当前激活的这个标签精确过滤的——只显示和"你现在这个供应商"同标签的会话。
openai。custom。所以默认情况下,官方会话和第三方会话天生互相看不见——它们在两个不同的抽屉里。这是 Codex 自身的设计,不是 CC Switch 弄丢了什么。
默认状态(没开统一开关):
┌─────────────────┐ ┌─────────────────┐
│ openai 抽屉 │ │ custom 抽屉 │
│ (官方订阅会话) │ │ (第三方供应商会话)│
└─────────────────┘ └─────────────────┘
▲ ▲
用官方时只看到这边 用第三方时只看到这边
(两个抽屉互相看不见)
「统一 Codex 会话历史」开关做的事,就是让官方订阅也以 custom 标签运行,把两个抽屉合并成一个,于是官方会话和第三方会话出现在同一个续聊列表里。注意:认证没变——你的官方订阅照常用你的 ChatGPT 登录、照常走官方后端,只是会话的"归类标签"从 openai 变成了 custom。
开启统一开关后:
┌─────────────────────────────────────────┐
│ custom 共享抽屉 │
│ 官方订阅会话 + 第三方供应商会话 │
│ (出现在同一个历史 / 续聊列表里) │
└─────────────────────────────────────────┘
"合并抽屉"需要把一部分官方会话的标签从 openai 改成 custom(这一步叫迁移,且是可选的、需要你主动勾选)。而任何一次改写之前,CC Switch 都会先把原文件原封不动地复制一份到这里:
~/.cc-switch/backups/codex-official-history-unify-v1/<时间戳>/
这份备份,就是日后"按备份精确还原"的唯一依据。它让整个过程变得可逆:你随时可以关掉开关,把当初迁进来的官方会话精确地翻回 openai 抽屉。
记住这两个词——抽屉(会话只是换了归类)、备份(改前必先复制)——后面所有内容你都能轻松理解。
设置 → 通用 → Codex 应用增强
在"Codex 应用增强"这个区块里有两行开关,第二行(蓝色历史图标)就是本攻略的主角:
统一 Codex 会话历史
它下方有一段说明文字(逐字):
开启后,官方订阅将以共享的 custom 供应商标识运行,官方与第三方会话出现在同一历史列表中,并可选择把现有官方会话一并迁入(迁移前自动备份)。关闭开关时可按备份恢复迁入的会话。注意:跨供应商继续旧会话时,对方后端可能无法解密会话中的 encrypted_content 推理内容,导致继续失败
注意:这一句说明里已经预告了三件事——会出现在同一列表、可选迁入并自动备份、跨供应商续聊"可能继续失败"。这里的"继续失败"指的是续不上、生成不了新回合,不是"记录丢失"。这正是后面要重点拆解的核心误解。
一旦你把开关拨到开,CC Switch 不会立刻保存,而是先弹出一个确认窗口。窗口文案如下(逐字):
标题:统一 Codex 会话历史
正文:
开启后,官方订阅与第三方将共用同一个会话历史列表。注意:跨供应商继续旧会话时,可能因对方后端无法解密 encrypted_content 推理内容而失败。
可选择同时把现有官方会话历史迁入共享列表(迁移前自动备份到 ~/.cc-switch/backups,关闭开关时可选择恢复)。
复选框:同时迁入现有官方会话历史
确认按钮:我已了解,继续开启
取消按钮:取消
这个复选框默认是不勾选的。 这是一个重要的分岔点:
| 你的选择 | 效果 | 此刻你的数据在哪 |
|---|---|---|
| 不勾(默认) | 只切换标识。只有开启之后新建的官方会话才会落进 custom 共享抽屉 | 你开启前的官方老会话,标签仍是 openai,原地未动,仍在 ~/.codex/sessions/ |
| 勾上 | 除了切换标识,还会把现有的官方老会话也从 openai 抽屉迁进 custom 抽屉 | 老会话被复制备份后,标签改写为 custom;原始数据有备份兜底 |
如果你希望"以前的官方会话也出现在统一列表里",必须主动勾选这个复选框。 否则你会遇到下面对照表里的"场景 A"——老会话看起来"不见了",其实只是留在原抽屉里。
点"取消"或点窗口外面:开关直接弹回关闭状态,什么都没发生。 点"我已了解,继续开启":开关保存为开启,CC Switch 在后台落盘配置(如果勾了迁移,就执行迁移)。
如果你勾了"同时迁入现有官方会话历史",CC Switch 会对你的官方老会话做这套流程:
对每个官方(openai 标签)会话文件:
① 先把原文件原样复制一份到备份目录 ← 数据有了第一道保险
② 用「写临时文件 → 整体替换」的原子方式,
只把头部那行 session_meta 里的 model_provider
从 "openai" 改成 "custom" ← 对话正文一个字节都不动
③ 索引数据库 state_5.sqlite 同步在一个事务里把标签改过来
~/.cc-switch/backups/codex-official-history-unify-v1/<时间戳>/,每次迁移生成一个带时间戳的"代际目录",内含 jsonl/(会话副本)、state/(索引库副本)、meta.json(记录这次迁移属于哪个 Codex 目录)。model_provider 这一个字段值。你的对话内容、推理内容、所有正文原样保留。迁移成功后,这些官方老会话就出现在统一列表里了。此刻你的数据:① 原始副本在备份目录;② 活动文件里只有归类标签变了,内容完好。
注意:开启与迁移本身不会弹成功提示。迁移是后端在保存时顺带跑的,UI 上你只会看到开关变成了打开状态。所以"没看到迁移成功的弹窗"是正常的,不代表失败。
关闭时,CC Switch 会先花一瞬间探测有没有迁移备份,然后弹出确认窗口(所以关闭弹窗会有一点点延迟,属正常)。文案如下(逐字):
标题:关闭统一会话历史
正文:
关闭后,官方订阅与第三方将恢复各自独立的会话历史列表。开启期间产生的会话因无法区分来源,将留在第三方历史中,官方订阅将看不到它们。
复选框(条件显示):把开启时迁入的官方会话还原回官方历史(按备份精确还原)
确认按钮:关闭
取消按钮:取消
划重点:正文说的是"官方订阅将看不到它们"——是看不到,不是删除。开启期间你新聊的会话仍然完整地在
custom抽屉里,只是关闭后官方那一侧看不到而已。
这个还原复选框默认是勾选的。 也就是说,默认行为就是"关闭的同时,把当初迁入的官方会话精确还原回官方历史"。你只要保持勾选、点"关闭"即可。
如果复选框没有出现,说明系统判断当前没有需要还原的备份(要么你从没勾过迁移、要么探测不到备份)——这种情况下你的官方老会话从没被改动过,关掉开关它们自己就回到 openai 抽屉了。
如果你保持勾选并点"关闭",CC Switch 的还原流程是这样的:
① 先把当前现场再复制一份到独立的还原备份目录
~/.cc-switch/backups/codex-official-history-unify-restore-v1/<时间戳>/
(还原本身也先备份,所以还原也不会丢数据)
② 翻遍所有迁移备份代际,找出"当初标签是 openai"的会话 id,组成一份"账本"
③ 只对【既在账本里、当前又仍是 custom】的会话,把标签改回 "openai"
注意第 ③ 步的双重条件——既要在账本里(证明它当初确实是官方迁来的),又要当前仍是 custom(说明你没手动改过它)。两个条件都满足才翻回。这保证了还原既精确又不会误伤。
此刻你的数据:被迁回的官方会话标签改回 openai,重新出现在官方列表;同时迁移备份和还原备份两份副本都还在硬盘上。
只有"关闭 + 勾选还原"这条路径会弹结果提示。可能看到的提示(逐字):
| 你看到的提示 | 含义 |
|---|---|
| 已按备份还原官方会话历史({{files}} 个会话文件、{{rows}} 条索引记录) | 还原成功。{{files}} / {{rows}} 处会显示实际数字 |
| 当前 Codex 目录没有可恢复的迁移备份 | 没有可还原的内容(不等于数据丢了,详见对照表场景 E) |
| 统一会话历史开关已重新开启,已跳过还原 | 还原排队期间你又把开关打开了,系统主动放弃还原(详见对照表场景 F) |
| 还原官方会话历史失败,请重试 | 还原过程报错,重试即可,数据未被破坏 |
| 保存失败,请重试 | 关闭这一步保存本身就失败了;此时绝不会触发还原,开关弹回原位 |
一个贴心的安全设计:如果"关闭开关"这一步保存失败,CC Switch 绝不会去执行还原。否则就会出现"开关还开着、会话却被翻回 openai 桶"的撕裂状态。保存失败时开关会自动弹回原来的位置,你不会停留在一个"看起来已关、实则没保存"的假状态里。
下面六个场景,是用户最容易误以为"会话丢了"的情形。每一个的真相都是:数据完好,只是换了抽屉或暂时看不到。 先用这张表按症状定位,再看下面的详细说明。
| 场景 | 你看到的 | 数据真相 | 一句话解法 |
|---|---|---|---|
| A 没勾迁移 | 官方老会话不在统一列表 | 全在,仍带 openai 标签 | 重开并勾迁移,或关开关 |
| B 跨供应商续聊失败 | 续不上 / 报错 | 文件完好,只是密文跨后端解不开 | 回原供应商续;只看内容直接读 jsonl |
| C 代理接管 / 注入被拒 | 没迁也没还原 | 迁移被安全跳过,文件没动 | 退出接管 → 重启重试;或直接关开关 |
| D 还原后新会话没回官方 | 开启期间新会话不在官方 | 在 custom 抽屉,设计上不动 | 切第三方供应商即可见 |
| E 提示"没有可恢复备份" | 还原"失败" | 通常压根没迁移过,会话在原抽屉 | 关开关官方会话自动复现 |
| F 提示"开关已重新开启,跳过还原" | 还原被拒 | 防数据撕裂,啥也没改 | 先彻底关开关再还原 |
现象:你开了统一开关,但开启弹窗里那个"同时迁入现有官方会话历史"没勾(它默认就不勾)。开启后一看,以前的官方老会话好像都不在列表里了。
真相:数据 100% 都在,一行都没动。开关只对"开启之后新建"的官方会话生效,你开启前的官方老会话标签仍是 openai,原封不动地躺在 ~/.codex/sessions/ 里。你现在激活的是 custom 抽屉,自然看不到留在 openai 抽屉里的老会话——这就是"看起来消失"的全部原因。
怎么办(任选其一):
custom 抽屉,它们立刻出现在统一列表(改写前自动备份)。openai 抽屉运行,老会话原地复现。现象:统一之后列表里能看到一条用"另一家供应商"聊出来的旧会话,你切到现在的供应商点"继续",结果报错或接不上。
真相:会话文件完好无损,丢的不是数据,是"跨后端解密能力"。Codex 会话里保存了一段加密的推理内容 encrypted_content,这段密文只有当初生成它的那个后端能解密。你用 B 供应商去续 A 供应商生成的会话,B 解不开 A 的密文 → 续聊失败。这是上游 Codex 的设计限制(by design),与 CC Switch 是否动过文件无关。会话里的文字内容你随时能读到。
这是整篇攻略里唯一一个"看起来真出了问题"的真实例外——但请注意:它只是无法续聊(生成不了新回合),原始文件依然完整存在,对话文字随时可读。
怎么办:
.jsonl 文件(文末有命令)。现象:你开启并勾了迁移,但官方老会话既没进统一列表、关开关想还原也提示没东西可还原(或者关闭弹窗里压根没出现还原复选框,参见场景 E)。你怀疑迁移过程中把会话搞丢了。
真相:迁移根本没执行,所以也不可能弄丢——你的会话一个字都没被改。CC Switch 在迁移前有一道安全闸门:它会检查 Codex 的 live 配置(~/.codex/config.toml)此刻是否真的路由到了共享 custom 抽屉,只有真路由过去了才迁移。以下两种情况会判定"还没统一"(内部原因码 live_not_unified),于是主动跳过迁移、保留你的开关和迁移意愿、等条件满足后再迁:
config.toml 已有手工指定的 model_provider,或已存在一张形态不同的 [model_providers.custom] 表(可能带第三方地址)。为避免把官方流量错误路由到第三方后端,CC Switch 宁可不注入、不迁移。跳过迁移 = 不碰任何会话文件。没迁,等于没动,谈不上丢。 这是"安全延后",不是"失败丢数据"。
怎么办:
~/.codex/config.toml:若有你手工写的冲突路由,整理掉冲突后再开开关。openai 抽屉正常显示,毫发无损。现象:你开启统一期间,用官方又聊了几条新会话。后来关开关、勾了还原,还原完发现那几条新会话没回到官方抽屉。
真相:这是有意为之的设计,新会话好端端在 custom 抽屉里,能看见、能续。还原的依据是"迁移时的备份账本"——只有当初从 openai 抽屉迁进来的会话,备份里有据可查,才会被精确翻回 openai。你开启期间新建的会话不在任何备份账本里;而且统一之后官方和第三方都用 custom 标签,CC Switch 无法分辨这条新会话到底是官方聊的还是第三方聊的。为了不把第三方会话误塞进官方历史,产品决策是:这些新会话一律留在 custom(第三方)历史里,绝不自动搬动。关闭弹窗的文案也明示了这一点——"开启期间产生的会话因无法区分来源,将留在第三方历史中"。
怎么办:
custom 抽屉),就能在历史列表里看到这些会话。.jsonl;想续聊遵循场景 B 的规则(回到当初生成它的后端)。.jsonl 第一行 session_meta 里的 model_provider 从 custom 改回 openai(属高阶操作,改前务必复制一份)。现象:关开关时勾了还原,结果弹出提示"当前 Codex 目录没有可恢复的迁移备份"。你慌了:还原都失败了,是不是数据彻底没了?
真相:"没有可还原的东西"≠"数据丢了"。恰恰相反,通常是因为根本没有需要还原的迁移。常见原因:
openai 抽屉,关开关后直接复现(同场景 A)。(这种情况下,关闭弹窗甚至可能根本不显示还原复选框——因为系统探测不到任何备份。)openai,再点一次自然"没有仍是 custom 的目标可还原"——这是幂等保护,不是失败。这三种情况下,没有任何会话被删除。
怎么办:用文末命令统计 ~/.codex/sessions/ 里的会话文件总数,确认文件都在;再看 ~/.cc-switch/backups/ 里有没有 codex-official-history-unify-v1 目录——如果连这个目录都没有,说明你从没触发过迁移,会话一直在原抽屉。
现象:关开关 → 勾还原 → 你手很快,紧接着又把开关重新打开了,然后看到提示"统一会话历史开关已重新开启,已跳过还原"。
真相:这是一道防护,防止把数据弄成"撕裂"状态,会话同样没丢。还原的动作是"把会话标签从 custom 翻回 openai",但如果此刻开关又开着,live 配置正路由到 custom——一边把历史翻回 openai、一边新会话往 custom 落,会话会被人为撕成两半。所以 CC Switch 检测到"开关又开了",主动放弃这次还原、什么都不改。会话维持现状,没有任何删除或破坏。
怎么办:想真正还原,就先把开关稳定地关掉(别再立刻打开),再执行关闭 + 勾还原;想保持统一,就别还原,让会话留在 custom 共享抽屉正常使用。
总原则:CC Switch 的统一 / 迁移 / 还原全程只改会话的一个标签字段,并且每次改写前都自动备份。它不会删你的对话。看不见 ≠ 丢了——换个抽屉看,或用下面的命令亲眼确认。
文字再多,不如亲眼看见。下面给出真实路径(取自 CC Switch 源码)和在不同系统下查看会话文件、备份目录的方法。全程只读不改,强烈建议你亲手试一遍。
Cmd + Shift + G,粘贴 ~/.codex/sessions 回车,就能看到一堆 .jsonl 会话文件和它们的修改时间;备份目录粘贴 ~/.cc-switch/backups。%USERPROFILE%\.codex\sessions 回车,就能看到会话文件夹和里面的 .jsonl;备份目录粘贴 %USERPROFILE%\.cc-switch\backups。只要你能在这里看到一批 .jsonl 文件,就证明会话数据完好无损地在硬盘上。 文件数量、修改时间,比任何文字都直观。
| 内容 | 真实路径 | 说明 |
|---|---|---|
| 会话正文(核心) | ~/.codex/sessions/(含按日期分的子目录,递归) | 每个会话一个 .jsonl 文本文件,这就是你的对话内容 |
| 归档会话 | ~/.codex/archived_sessions/ | 同为 .jsonl |
| 会话索引数据库 | ~/.codex/state_5.sqlite | threads 表的 model_provider 列就是"抽屉标签",它才是续聊列表真正读取的归类来源 |
| 迁移备份(开启迁移时自动产生) | ~/.cc-switch/backups/codex-official-history-unify-v1/<时间戳>/ | 内含 jsonl/、state/、meta.json |
| 还原备份(点还原时自动产生) | ~/.cc-switch/backups/codex-official-history-unify-restore-v1/<时间戳>/ | 还原前的安全副本 |
注意:如果你在 CC Switch 里改过 Codex 目录,或在
config.toml里设了sqlite_home,请把上面的~/.codex换成你的实际目录。下文~= 你的用户主目录。
1. 数会话文件总数(这才是"没丢"的硬证据)
# 统计会话文件总数 —— 只要这个数字符合你的预期,数据就都在
find ~/.codex/sessions ~/.codex/archived_sessions -name '*.jsonl' 2>/dev/null | wc -l
# 看最近修改的 10 个会话文件
find ~/.codex/sessions -name '*.jsonl' 2>/dev/null -print0 \
| xargs -0 ls -lt 2>/dev/null | head -10
2. (辅助)看每个"抽屉"各有多少会话
# 官方抽屉(openai)会话文件数
grep -rlE '"model_provider"[[:space:]]*:[[:space:]]*"openai"' ~/.codex/sessions 2>/dev/null | wc -l
# 统一抽屉(custom)会话文件数
grep -rlE '"model_provider"[[:space:]]*:[[:space:]]*"custom"' ~/.codex/sessions 2>/dev/null | wc -l
# 看各标签分布一目了然
grep -rhoE '"model_provider"[[:space:]]*:[[:space:]]*"[^"]*"' ~/.codex/sessions 2>/dev/null | sort | uniq -c
重要提示,别被这一步吓到:早期版本的 Codex 不在
.jsonl里写model_provider字段,这些旧官方会话用上面的 grep 是数不到的,但它们在索引库state_5.sqlite里仍然归类为openai、续聊列表照样能看到。所以判断"会话没丢"请以第 1 步的文件总数为准——分桶 grep 只是帮你理解归类,数出来比文件总数少完全正常,绝不代表"丢了一批"。
3. (进阶)查索引库 state_5.sqlite——续聊列表真正读的归类
# 需要已安装 sqlite3;没装可跳过
sqlite3 ~/.codex/state_5.sqlite \
"SELECT COALESCE(model_provider,'<空>'), COUNT(*) FROM threads GROUP BY 1;"
这张
threads表才是 Codex 续聊列表真正读取的归类来源,openai行数 ≈ 你官方抽屉里能看到的会话数。它和第 2 步的 jsonl grep 可能对不上数——原因就是上面说的"旧会话不写 jsonl 字段,但索引库里仍是 openai"。两边对不上不是异常。
4. 直接读某条会话的内容(确认对话文字还在)
# 把 <文件名> 换成上面 ls 列出的某个 .jsonl 路径
python3 -m json.tool < "<文件名>.jsonl" 2>/dev/null | head -50
# 或者直接用编辑器打开看(纯文本)
open -e "<文件名>.jsonl" # macOS
5. 看 CC Switch 的备份目录(证明迁移 / 还原前都留了副本)
ls -la ~/.cc-switch/backups/codex-official-history-unify-v1/ 2>/dev/null
ls -la ~/.cc-switch/backups/codex-official-history-unify-restore-v1/ 2>/dev/null
会话目录通常在 C:\Users\<你的用户名>\.codex\,备份在 C:\Users\<你的用户名>\.cc-switch\backups\。
# 1. 会话文件总数("没丢"的硬证据)
(Get-ChildItem "$env:USERPROFILE\.codex\sessions","$env:USERPROFILE\.codex\archived_sessions" -Recurse -Filter *.jsonl -ErrorAction SilentlyContinue).Count
# 2. 最近修改的 10 个会话
Get-ChildItem "$env:USERPROFILE\.codex\sessions" -Recurse -Filter *.jsonl |
Sort-Object LastWriteTime -Descending | Select-Object -First 10 FullName,LastWriteTime
# 3. (辅助)官方(openai) / 统一(custom) 抽屉各多少会话文件
(Get-ChildItem "$env:USERPROFILE\.codex\sessions" -Recurse -Filter *.jsonl |
Select-String -Pattern 'model_provider"\s*:\s*"openai"' -List).Count
(Get-ChildItem "$env:USERPROFILE\.codex\sessions" -Recurse -Filter *.jsonl |
Select-String -Pattern 'model_provider"\s*:\s*"custom"' -List).Count
# 4. 看备份目录
Get-ChildItem "$env:USERPROFILE\.cc-switch\backups\codex-official-history-unify-v1" -ErrorAction SilentlyContinue
Get-ChildItem "$env:USERPROFILE\.cc-switch\backups\codex-official-history-unify-restore-v1" -ErrorAction SilentlyContinue
同样提醒:第 3 步的 grep 数会少于文件总数属正常(旧会话不写该字段),请以第 1 步的文件总数作为"会话没丢"的判断依据。
Codex 的续聊 / 历史列表按当前激活的 model_provider id 精确字符串过滤。会话文件 .jsonl 的第一行是一条 type:"session_meta" 记录,其 payload.model_provider 即该会话所属抽屉(grep -rl 只要文件里出现一次该标签就计入该文件,因此无需逐行解析;旧版本未写该字段的会话则数不到)。真正驱动续聊列表的是索引库 state_5.sqlite 的 threads.model_provider 列。官方订阅在 config.toml 没有显式 model_provider 时落进内建默认 id openai;CC Switch 的所有第三方供应商统一用 custom。
开启后,CC Switch 对官方 live config.toml 注入如下内容:
model_provider = "custom"
[model_providers.custom]
name = "OpenAI"
requires_openai_auth = true
supports_websockets = true
wire_api = "responses"
每个字段都有作用:requires_openai_auth = true 让认证继续走 auth.json 里的 ChatGPT 登录、base_url 缺省回落官方 Codex 后端;name = "OpenAI" 让 Codex 的官方特性门控(web search、远程压缩等)继续命中;supports_websockets = true 补回 custom 条目默认丢失的能力;wire_api = "responses" 用官方 responses 协议。净效果是:认证没变,只是桶名变了。
关键不变量:这段注入只能存在于 live config.toml,绝不写进数据库的存储配置。 切换离开官方供应商、把 live 回写数据库时,CC Switch 会把这段注入精确剥离(只在形态与注入产物完全一致时才剥,第三方自定义的 custom 表原样保留)。正因如此,"关掉开关 + 切换一次"就能彻底还原 live,数据库里始终是你原本干净的官方配置——这是整个开关可逆性的基石。
config.toml 已有显式 model_provider → 不覆盖用户路由;[model_providers.custom] 表(可能带第三方 base_url)→ 拒绝注入,否则会把 ChatGPT OAuth 流量路由到错误后端。拒绝注入时 live 不统一,迁移闸门(检查 live 的 model_provider 是否 trim 后等于 custom)判定 live_not_unified → 跳过迁移、保留意愿、等下次启动重试时再做。这是"安全延后",不是"失败丢数据"。
openai;custom);四层设计共同保证:在正常与异常的所有路径下,原始会话数据都不会被真正删除。
model_provider 值在 openai 与 custom 之间切换,对话内容、response_item、encrypted_content 一律原样保留。codex-official-history-unify-v1/,还原备份在独立的 codex-official-history-unify-restore-v1/,两者分开以保持账本纯净。UPDATE,全程没有任何删除会话或索引的动作。文件在任一时刻都是完整的。live_not_unified)宁可不迁;一把进程锁串行化迁移与还原,避免"启动重试 / 保存后台任务 / 关闭还原"并发对同批文件双向改写;完成标记按 Codex 目录绑定、条件写入,防漏迁;还原用"在账本 + 当前仍 custom"双重条件,防误改。还原扫描全部备份代际取并集,多次开关循环后仍能还原早期迁入的会话;重复还原返回 nothing_to_restore,是幂等保护而非失败。会话内的推理密文只能被生成它的后端解密,上游 Codex by design 不支持跨后端解密。这是"续聊失败"的根因,与文件完整性无关——会话 .jsonl 完整躺在磁盘上、encrypted_content 也完好无损。换回原供应商续聊,或开新会话,都正常。
给你的最后一句话:你看到的"会话不见了 / 续聊失败",本质是会话被换到了另一个历史列表(抽屉)里、或对方后端无法解密旧推理内容,文件始终原封不动地躺在 ~/.codex/sessions/(及 state_5.sqlite)里。关闭开关时勾选"按备份还原"即可把当初迁入的官方会话精确翻回官方列表;即便不还原,原始 .jsonl 文件和 ~/.cc-switch/backups/codex-official-history-unify-*/ 下的备份副本也都在——数据绝不会真正丢失。