codex-helper 0.11.0

A Rust-based local helper / proxy for Codex CLI traffic with multi-provider routing, usage-aware switching, filtering, and session helpers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
# codex-helper(Codex CLI 本地助手 / 本地代理)

> 让 Codex CLI 走一层本地“保险杠”:  
> 集中管理所有中转站 / key / 配额,在额度用完或上游挂掉时自动切换,并提供会话与脱敏辅助工具。

当前版本:`v0.11.0`

> English version: `README_EN.md`

---

## 截图


![内置 TUI 面板](https://raw.githubusercontent.com/Latias94/codex-helper/main/screenshots/main.png)

## 为什么需要 codex-helper?


如果你有下面这些情况,codex-helper 会很合适:

- **不想手改 `~/.codex/config.toml`**  
  手工改 `model_provider` / `base_url` 容易写坏,也不好恢复。

- **有多个中转 / 多个 key,要经常切换**  
  想把 OpenAI 官方、Packy 中转、自建中转都集中管理,并一条命令切换“当前在用”的那一个。

- **经常到 401/429 才发现额度用完**  
  希望上游额度用尽时能自动切到备用线路,而不是人工盯着报错。

- **命令行里希望“一键找回 Codex 会话”**  
  例如“给我当前项目最近一次会话,并告诉我怎么 resume”。

- **想给 Codex 加一层本地脱敏和统一日志**  
  请求先本地过滤敏感信息,再发到上游;所有请求写进一个 JSONL 文件,方便排查和统计。

---

## 一分钟上手(TL;DR)


### 1. 安装(推荐:cargo-binstall)


```bash
cargo install cargo-binstall
cargo binstall codex-helper   # 安装 codex-helper,可得到 codex-helper / ch 两个命令
```

安装成功后,`codex-helper` / `ch` 会被放到 Cargo 的 bin 目录(通常是 `~/.cargo/bin`),只要该目录在你的 `PATH` 里,就可以在任意目录直接运行。

> 如果你更习惯从源码构建:  
> `cargo build --release` → 使用 `target/release/codex-helper` / `ch` 即可。

### 2. 一条命令启动 Codex 助手(最推荐)


```bash
codex-helper
# 或更短的:

ch
```

它会自动帮你:

- 启动 Codex 本地代理,监听 `127.0.0.1:3211`- 如果在交互终端运行,会默认显示一个内置 TUI 面板(可用 `--no-tui` 关闭;按 `q` 退出;`1-7` 切页;`7` 查看历史会话;在 Sessions/History 页按 `t` 查看对话记录);
- 对 429/5xx/网络抖动等瞬态错误,以及常见上游认证/路由类错误(例如 401/403/404/408)在**未开始向客户端输出响应**前进行有限次数的自动重试/切换(可配置);
- 在修改前检查 `~/.codex/config.toml`,如已指向本地代理且存在备份,会询问是否先恢复原始配置;
- 必要时修改 `model_provider``model_providers.codex_proxy`,让 Codex 走本地代理,并只在首次写入备份;
- 写入 `model_providers.codex_proxy` 时,默认设置 `request_max_retries = 0` 以避免“Codex 重试 + codex-helper 重试”叠加(你也可以在 `~/.codex/config.toml` 中手动覆盖);
- 如果 `~/.codex-helper/config.toml` / `config.json` 还没初始化,会尝试根据 `~/.codex/config.toml` + `auth.json` 推导一个默认上游(首次自动落盘默认生成 TOML);
- 用 Ctrl+C 或在 TUI 中按 `q` 退出时,尝试从备份恢复原始 Codex 配置。

从此之后,你继续用原来的 `codex` 命令即可,所有请求会自动经过 codex-helper。

---

## 常见配置:多上游自动切换

最常见、也是最“物有所值”的用法,是让 codex-helper 在多个上游之间自动切换:

- 某条线路频繁失败(例如 5xx / 连接失败);
- 或被用量提供商标记为“额度用尽”(`usage_exhausted = true`);
- 在这种情况下,LB 会优先选择同一配置下的其他 upstream 作为备份。

**关键点:主线路 + 备份线路优先放在同一个配置的 `upstreams` 里。**

  > 提示:如果你把每个供应商都拆成一个 config,并且它们的 `level` 都是默认的 `1`(例如 `config list` 全是 `L1 on ...`),codex-helper 仍会**优先**使用 `active`,但同级其他 config 也会参与 failover(避免 `active` 单点)。  
  > 如果你想要明确的“跨配置降级”(例如 `L1=中转优先``L2=官方兜底`),请至少设置两档不同的 `level`(见下文),或把备份线路放回同一 config 的 `upstreams`  >
  > 注意:如果你设置了 **pinned override**(例如 TUI 的 `p`:session provider override/pinned;旧版本也可能存在全局 pinned),路由会进入 `pinned` 模式,只会使用那一个 config,因此**不会跨 config failover**  
  > 想要“首选 + 可 failover”,请使用 `active`(TUI:`P` 选择全局 active,或在 Configs 页 `Enter` 设 active),并清除 pinned override。

### 配置场景速查表

把配置理解成两层就不容易迷路:

1) **分组(routing)**:每个 config 有 `level`(1..=10),`active` 是首选,`enabled=false` 可把它排除出自动路由(但如果它是 active 仍会参与)。
2) **策略(retry)**:决定失败时怎么重试/怎么冷却/是否“回切探测”。

如果你已经用 `codex-helper config overwrite-from-codex --yes` 同步过账号信息(最常见),通常不需要手写 `[[...upstreams]]`;你只需要:

- 分组:`codex-helper config set-level <name> <level>` + `codex-helper config set-active <name>`
- 策略:`codex-helper config set-retry-profile <balanced|same-upstream|aggressive-failover|cost-primary>`

> 注意:`set-retry-profile` 会覆盖整个 `[retry]` 段;如果你要高级微调(例如 `retry.upstream.max_attempts``retry.provider.on_status``transport_cooldown_secs`,以及用于兜底的 `never_on_status` / `never_on_class`),可以在执行 profile 后再手改配置文件(旧版扁平字段仍兼容,但建议迁移到两层配置)。

| 场景目标 | 你只需要怎么“分组”(导入后) | 建议策略(profile) | 备注 |
| --- | --- | --- | --- |
| 单账号多 endpoint 自动切换 | 需要把多个 endpoint 合并到同一个 config 的 `upstreams`(见模板 A) | `balanced` | 最简单、最稳定;优先推荐 |
| 多供应商同级互为备份(避免 active 单点) | 让多个 config 都是同一个 `level`(默认就是 1),并设置一个 `active`(见模板 B) | `balanced` | 同级会优先 `active`,但其他同级也会参与 failover |
| 中转优先,官方/直连兜底 | 把中转设 `level=1`,把直连/官方设 `level=2`(见模板 C) | `balanced` | 失败时跨 level 降级;有其他候选时会跳过处于 cooldown 的 config |
| 包月中转为主,按量备选为从(省钱+回切探测) | 同上(`L1=包月中转``L2=按量直连`),并把包月中转设为 `active`(见模板 D) | `cost-primary` | 主线路不稳会降级到备选,并通过冷却/退避“隔一段时间探测回切” |

#### 模板 A:单账号多 endpoint(同一个 config 多 upstream)

适合你希望“同一类账号/同一中转商”的多个 endpoint 自动切换(最快最稳)。这需要你手动把多个 endpoint 放进同一个 config 的 `upstreams`:

```toml
version = 1

[codex]
active = "codex-main"

[codex.configs.codex-main]
name = "codex-main"
enabled = true
level = 1

[[codex.configs.codex-main.upstreams]]
base_url = "https://codex-api.packycode.com/v1"
auth = { auth_token_env = "PACKYCODE_API_KEY" }
tags = { provider_id = "packycode", source = "codex-config" }

[[codex.configs.codex-main.upstreams]]
base_url = "https://co.yes.vg/v1"
auth = { auth_token_env = "YESCODE_API_KEY" }
tags = { provider_id = "yes", source = "codex-config" }
```

说明:

- `active` 指向这个 config,LB 会在多个 upstream 之间自动切换。
- 当某个 upstream 失败/被标记为 `usage_exhausted` 时,会尽量选择其他 upstream;全部不可用时会兜底返回第一个,避免硬断流。

#### 模板 B:多供应商同级互备(导入后只改 active)

```bash
codex-helper config overwrite-from-codex --yes

# 选择一个首选(但仍允许同级 failover)
codex-helper config set-active right

# 同级互备一般用默认 profile 即可
codex-helper config set-retry-profile balanced
```

如果你更想直接改 `config.toml`,等价写法是:

```toml
[codex]
active = "right"

[retry]
profile = "balanced"
```

> 想缩小候选集:把你不希望参与自动路由的 config `disable` 掉(active 除外)。例如:`codex-helper config disable some-provider`
#### 模板 C:中转优先,直连/官方兜底(level 分级)

> 下面的 `right/packyapi/yescode/openai` 仅为示例,请以 `codex-helper config list` 输出的真实名称替换。

```bash
codex-helper config overwrite-from-codex --yes

# L1:各类中转
codex-helper config set-level right 1
codex-helper config set-level packyapi 1
codex-helper config set-level yescode 1

# L2:直连/官方兜底
codex-helper config set-level openai 2

# 首选一个中转(仍允许跨 level 降级)
codex-helper config set-active right
codex-helper config set-retry-profile balanced
```

等价的 `config.toml`(示例):

```toml
[codex]
active = "right"

[codex.configs.right]
level = 1

[codex.configs.openai]
level = 2

[retry]
profile = "balanced"
```

#### 模板 D:包月中转主、按量直连从(省钱 + 回切探测)

> 下面的 `right/openai` 仅为示例,请以 `codex-helper config list` 输出的真实名称替换。

```bash
codex-helper config overwrite-from-codex --yes

# L1:包月中转(便宜但可能不稳)
codex-helper config set-level right 1
codex-helper config set-active right

# L2:按量直连(贵但稳)
codex-helper config set-level openai 2

# 开启 cost-primary:失败越多,冷却越久;冷却到期会“探测回切”
codex-helper config set-retry-profile cost-primary
```

等价的 `config.toml`(示例):

```toml
[codex]
active = "right"

[codex.configs.right]
level = 1

[codex.configs.openai]
level = 2

[retry]
profile = "cost-primary"
```

> 注意:如果 config 名称包含 `-` 等字符,请在 TOML 里用引号,例如:`[codex.configs."openai-main"]`
### Level 分组(跨配置降级,可选)

如果你更希望把不同供应商/通道拆成多个 config,codex-helper 也支持 **按 level 分组的跨配置降级**(推荐用于“中转优先,直连兜底”等场景):

- 每个 config 有一个 `level`(1..=10,越小优先级越高)。
- 如果存在 **多个不同的 level**,会按 level 从小到大路由/降级(低 level 优先)。
- 如果所有 config 都是同一个 level,则视为“同级候选”:仍会优先 `active`,但同级其他 config 也会参与 failover(避免 active 单点)。
- 同一 level 内会优先使用 `active` 配置。
- `enabled = false` 可把该 config 排除出自动路由(除非它是 active)。
- 实操建议:把“同一类线路”放同一 level(例如 `L1=各类中转``L2=官方/直连兜底`),并把 `retry.provider.max_attempts` 设到足够覆盖你希望每次请求尝试的候选数量(而 `retry.upstream.max_attempts` 控制单个候选内的重试次数)。

一个常见成本优化策略是“包月中转为主,按量备选为从”:把包月中转设为 `active` 且 `level=1`,把按量直连设为 `level=2`;当主线路不稳定时会自动降级到备选,同时通过冷却(以及可选的冷却退避)“隔一段时间探测回切”,避免一直按量计费。

例如:让 `L1` 优先使用中转(`right/packyapi/yescode/...`),失败时再降级到 `L2` 的直连 OpenAI:

```bash
codex-helper config set-level right 1
codex-helper config set-level packyapi 1
codex-helper config set-level yescode 1

codex-helper config set-level openai 2
```

---

## 常用命令速查表


### 日常使用


- 启动 Codex 助手(推荐):
  - `codex-helper` / `ch`
- 显式启动 Codex 代理:
  - `codex-helper serve`(默认端口 3211)
  - `codex-helper serve --no-tui`(关闭内置 TUI 面板)

### 开关 Codex


- 一次性让 Codex 指向本地代理:

  ```bash
  codex-helper switch on

  ```

- 从备份恢复原始配置:

  ```bash
  codex-helper switch off

  ```

- 查看当前开关状态:

  ```bash
  codex-helper switch status

  ```

### 配置管理(上游 / 中转)


- 列出配置:

  ```bash
  codex-helper config list

  ```

- 添加新配置:

  ```bash
  codex-helper config add openai-main \

    --base-url https://api.openai.com/v1 \

    --auth-token-env OPENAI_API_KEY \

    --alias "OpenAI 主额度"

  ```

- 切换当前 active 配置:

  ```bash
  codex-helper config set-active openai-main
  ```

- 设置重试策略预设(写入 `[retry]` 段,适合“只选策略,不想调一堆参数”的用法):

  ```bash
  codex-helper config set-retry-profile balanced
  codex-helper config set-retry-profile cost-primary
  ```

- 调整 Level 分组 / 启用禁用(用于跨配置降级):
  
  ```bash
  codex-helper config set-level openai-main 1
  codex-helper config disable packy-main
  codex-helper config enable packy-main

  ```

- 从 Codex CLI 覆盖导入账号/配置(重置为默认分组):
  
  ```bash
  # 覆盖 codex-helper 的 Codex 配置(active/enabled/level 等回到默认)

  codex-helper config overwrite-from-codex --dry-run

  codex-helper config overwrite-from-codex --yes

  ```

### TUI 设置页(运行态)


- `R`:立即重载运行态配置(用于确认手动修改已生效;下一次请求将使用新配置)

### 会话、用量与诊断


- 会话助手(Codex):

  ```bash
  codex-helper session list
  codex-helper session last
  codex-helper session transcript <ID> --tail 40
  ```

- 请求用量 / 日志:

  ```bash
  codex-helper usage summary

  codex-helper usage tail --limit 20 --raw

  ```

- 状态与诊断:

  ```bash
  codex-helper status

  codex-helper doctor


  # JSON 输出,方便脚本 / UI 集成

  codex-helper status --json | jq .

  codex-helper doctor --json | jq '.checks[] | select(.status != "ok")'

  ```

---

## 典型场景示例


### 场景 1:多中转 / 多 key 集中管理 + 快速切换


```bash
# 1. 为不同供应商添加配置

codex-helper config add openai-main \
  --base-url https://api.openai.com/v1 \
  --auth-token-env OPENAI_API_KEY \
  --alias "OpenAI 主额度"

codex-helper config add packy-main \
  --base-url https://codex-api.packycode.com/v1 \
  --auth-token-env PACKYCODE_API_KEY \
  --alias "Packy 中转"

codex-helper config list

# 2. 全局选择当前使用的供应商(active 配置)

codex-helper config set-active openai-main   # 使用 OpenAI
codex-helper config set-active packy-main    # 使用 Packy

# 3. 一次性让 Codex 使用本地代理(只需执行一次)

codex-helper switch on

# 4. 在当前 active 配置下启动代理

codex-helper
```

### 场景 2:按项目快速恢复 Codex 会话


```bash
cd ~/code/my-app

codex-helper session list   # 列出与当前项目相关的最近会话
codex-helper session last   # 给出最近一次会话 + 对应 resume 命令
codex-helper session transcript <ID> --tail 40   # 查看最近对话,用于辨认某个 session
```

`session list` 会额外展示每个会话的轮数(rounds)与最后更新时间(last_update,优先取最后一次 assistant 响应时间)。

你也可以从任意目录查询指定项目的会话:

```bash
codex-helper session list --path ~/code/my-app
codex-helper session last --path ~/code/my-app
```

这在你有多个 side project 时尤其方便:不需要记忆 session ID,只要告诉 codex-helper 你关心的目录,它会优先匹配该目录及其父/子目录下的会话,并给出 `codex resume <ID>` 命令。

---

## 进阶配置(可选)


大部分用户只需要前面的命令即可。如果你想做更细粒度的定制,可以关注这几个文件:

- 主配置:`~/.codex-helper/config.toml`(优先)或 `~/.codex-helper/config.json`(兼容)
- 请求过滤:`~/.codex-helper/filter.json`
- 用量提供商:`~/.codex-helper/usage_providers.json`
- 请求日志:`~/.codex-helper/logs/requests.jsonl`
- 详细调试日志(可选):`~/.codex-helper/logs/requests_debug.jsonl`(仅在启用 `http_debug` 拆分时生成)
- 会话统计缓存(自动生成):`~/.codex-helper/cache/session_stats.json`(用于加速 `session list/search` 的轮数/时间统计;以 session 文件 `mtime+size` 作为失效条件,如怀疑不准可直接删除该文件强制重建)

如果你希望快速生成一个带注释的 TOML 默认模板:

```bash
codex-helper config init
```

> 说明:
> - 模板注释默认是中文;
> - 如果检测到 `~/.codex/config.toml`,会 best-effort 自动把 Codex providers 导入到生成的 `config.toml`> - 只想生成纯模板(不导入)可用:`codex-helper config init --no-import`
Codex 官方文件:

- `~/.codex/auth.json`:由 `codex login` 维护,codex-helper 只读取,不写入;
- `~/.codex/config.toml`:由 Codex CLI 维护,codex-helper 仅在 `switch on/off` 时有限修改。

### 配置文件简要结构(推荐 TOML)


codex-helper 支持 `config.toml` 与 `config.json`,字段结构基本一致;如同时存在,以 `config.toml` 为准。

```toml
version = 1

[codex]
active = "openai-main"

[codex.configs.openai-main]
name = "openai-main"
alias = "主 OpenAI 额度"
enabled = true
level = 1

[[codex.configs.openai-main.upstreams]]
base_url = "https://api.openai.com/v1"
auth = { auth_token_env = "OPENAI_API_KEY" }
tags = { source = "codex-config", provider_id = "openai" }
```

关键点:

- `active`:当前生效的配置名;
- `configs`:按名称索引的配置集合;
- `level`:用于跨配置分组路由(1..=10,越小优先级越高;默认 1);
- `enabled`:该配置是否参与自动路由(默认 true);
- 每个 `upstream` 表示一个上游 endpoint,顺序 = 优先级(primary → backup...)。

### 用量提供商(Usage Providers)


路径:`~/.codex-helper/usage_providers.json`,示例:

```jsonc
{
  "providers": [
    {
      "id": "packycode",
      "kind": "budget_http_json",
      "domains": ["packycode.com"],
      "endpoint": "https://www.packycode.com/api/backend/users/info",
      "token_env": null,
      "poll_interval_secs": 60
    }
  ]
}
```

行为简述:

- upstream 的 `base_url` host 匹配 `domains` 中任一项,即视为该 provider 的管理对象;
- 调用 `endpoint` 的认证 token 优先来自 `token_env`,否则尝试使用绑定 upstream 的 `auth.auth_token` / `auth.auth_token_env`(运行时从环境变量解析);
- 请求结束后,codex-helper 按需调用 `endpoint` 查询额度,解析 `monthly_budget_usd` / `monthly_spent_usd`- 当额度用尽时,对应 upstream 在 LB 中被标记为 `usage_exhausted = true`,优先避开该线路。

### 请求过滤与日志


- 过滤规则:`~/.codex-helper/filter.json`,例如:

  ```jsonc
  [
    { "op": "replace", "source": "your-company.com", "target": "[REDACTED_DOMAIN]" },
    { "op": "remove",  "source": "super-secret-token" }
  ]
  ```

  请求 body 在发出前会按规则进行字节级替换 / 删除,规则根据文件 mtime 约 1 秒内自动刷新。

- 请求日志:`~/.codex-helper/logs/requests.jsonl`,每行一个 JSON,字段包括:
  - `service`(目前为 `codex`)、`method``path``status_code``duration_ms`  - `config_name``upstream_base_url`  - `usage`(input/output/total_tokens 等)。
  - (可选)`retry`:发生重试/切换上游时记录重试次数与尝试链路(便于回溯问题)。
  - (可选)`http_debug`:用于排查 4xx/5xx 时记录更完整的请求/响应信息(请求头、请求体预览、上游响应头/响应体预览等)。
  - (可选)`http_debug_ref`:当启用拆分写入时,主日志只保存引用,详细内容写入 `requests_debug.jsonl`
  你可以通过环境变量启用该调试日志(默认关闭):

  - `CODEX_HELPER_HTTP_DEBUG=1`:仅当上游返回非 2xx 时写入 `http_debug`  - `CODEX_HELPER_HTTP_DEBUG_ALL=1`:对所有请求都写入 `http_debug`(更容易产生日志膨胀);
  - `CODEX_HELPER_HTTP_DEBUG_BODY_MAX=65536`:请求/响应 body 预览的最大字节数(会截断)。
  - `CODEX_HELPER_HTTP_DEBUG_SPLIT=1`:将 `http_debug` 大对象拆分写入 `requests_debug.jsonl`,主 `requests.jsonl` 仅保留 `http_debug_ref`(推荐在 `*_ALL=1` 时开启)。

  另外,你也可以让代理在终端直接输出更完整的非 2xx 调试信息(同样默认关闭):

  - `CODEX_HELPER_HTTP_WARN=1`:当上游返回非 2xx 时,以 `warn` 级别输出一段裁剪后的 `http_debug` JSON;
  - `CODEX_HELPER_HTTP_WARN_ALL=1`:对所有请求都输出(不建议,容易泄露/刷屏);
  - `CODEX_HELPER_HTTP_WARN_BODY_MAX=65536`:终端输出里 body 预览的最大字节数(会截断)。

  注意:敏感请求头会自动脱敏(例如 `Authorization`/`Cookie` 等);如需进一步控制请求体中的敏感信息,建议配合 `~/.codex-helper/filter.json` 使用。

### 两层重试与切换(默认:每个 upstream 2 次尝试;最多尝试 2 个 config/provider;同一 config 内会在多个 upstream 间切换)

有些上游错误(例如网络抖动、429 限流、5xx/524、或看起来像 Cloudflare/WAF 的拦截页)可能是瞬态的;codex-helper 在**未开始向客户端输出响应**前按“两层模型”执行:先在当前 provider/config 内做 upstream 级重试,仍失败再做 provider/config 级 failover(例如 401/403/404/408 等路由/认证类错误也会触发切换)。

- 强烈建议将 Codex 侧 `model_providers.codex_proxy.request_max_retries = 0`,让“重试与切换”主要由 codex-helper 负责,避免 Codex 默认 5 次重试把同一个 502 反复打满(`switch on` 会在该字段不存在时写入 0;如你手动改过,则不会覆盖)。
- 主配置(`~/.codex-helper/config.toml` / `config.json`)的 `[retry]` 段用于设置全局默认值(从 `v0.8.0` 起不再支持通过环境变量覆盖 retry 参数)。

配置示例(TOML,两层可分别覆盖;profile 默认 `balanced`):

```toml
[retry]
profile = "balanced"

[retry.upstream]
max_attempts = 2
strategy = "same_upstream"
backoff_ms = 200
backoff_max_ms = 2000
jitter_ms = 100
on_status = "429,500-599,524"
on_class = ["upstream_transport_error", "cloudflare_timeout", "cloudflare_challenge"]

[retry.provider]
max_attempts = 2
strategy = "failover"
on_status = "401,403,404,408,429,500-599,524"
on_class = ["upstream_transport_error"]

never_on_status = "413,415,422"
never_on_class = ["client_error_non_retryable"]
cloudflare_challenge_cooldown_secs = 300
cloudflare_timeout_cooldown_secs = 60
transport_cooldown_secs = 30
cooldown_backoff_factor = 1
cooldown_backoff_max_secs = 600

# 兼容说明:旧版扁平字段(max_attempts/on_status/strategy/...)仍可解析,默认映射到 retry.upstream.*```

注意:重试可能导致 **POST 请求重放**(例如重复计费/重复写入)。建议仅在你明确接受这一风险、且错误大多是瞬态的场景下开启,并将尝试次数控制在较小范围内。

### 日志文件大小控制(推荐)

`requests.jsonl` 默认会持续追加,为避免长期运行导致文件过大,codex-helper 支持自动轮转(默认开启):

- `CODEX_HELPER_REQUEST_LOG_MAX_BYTES=52428800`:单个日志文件最大字节数,超过会自动轮转(`requests.jsonl` → `requests.<timestamp_ms>.jsonl`;`requests_debug.jsonl` → `requests_debug.<timestamp_ms>.jsonl`)(默认 50MB);
- `CODEX_HELPER_REQUEST_LOG_MAX_FILES=10`:最多保留多少个历史轮转文件(默认 10);
- `CODEX_HELPER_REQUEST_LOG_ONLY_ERRORS=1`:只记录非 2xx 请求(可显著减少日志量,默认关闭)。

这些字段是稳定契约,后续版本只会在此基础上追加字段,不会删除或改名,方便脚本长期依赖。

---

## 与 cli_proxy / cc-switch 的关系

- [cli_proxy](https://github.com/guojinpeng/cli_proxy):多服务守护进程 + Web UI,看板 + 管理功能很全面;
- [cc-switch](https://github.com/farion1231/cc-switch):桌面 GUI 级供应商 / MCP 管理器,主打“一处管理、按需应用到各客户端”。

codex-helper 借鉴了它们的设计思路,但定位更轻量:

- 专注 Codex CLI;
- 单一二进制,无守护进程、无 Web UI;
- 更适合作为你日常使用的“命令行小助手”,或者集成进你自己的脚本 / 工具链中。