Skip to content

fix(relay-config): fix TOML merge and model catalog sync - #2006

Open
ViceEye wants to merge 2 commits into
BigPizzaV3:mainfrom
ViceEye:fix/toml-header-dedup-semantic-merge
Open

fix(relay-config): fix TOML merge and model catalog sync#2006
ViceEye wants to merge 2 commits into
BigPizzaV3:mainfrom
ViceEye:fix/toml-header-dedup-semantic-merge

Conversation

@ViceEye

@ViceEye ViceEye commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix two relay configuration issues:

  1. Prevent invalid config.toml after repeated MCP/plugin merges.
  2. Keep absolute context and auto-compaction limits synchronized with generated model catalogs.

TOML Semantic Merge

Replace line-based duplicate removal with semantic TOML merging.

  • Split duplicate TOML content into parseable blocks.
  • Merge blocks with merge_toml_table_like.
  • Recursively merge child tables.
  • Later scalar/root values override earlier values.
  • Fall back to the previous cleanup path when block parsing fails.

Fixes cases involving:

  • [mcp_servers.node_repl]
  • [mcp_servers.node_repl.env]
  • duplicate or empty [mcp_servers]
  • repeated headers with different fields
  • duplicate root keys

Prevents invalid transport errors caused by malformed MCP/plugin configuration.

Context Configuration

Support absolute token values from the profile:

model_context_window = 1000000
model_auto_compact_token_limit = 900000

Model window priority:

per-model model_windows
> profile.context_window
> existing catalog value
> Codex fallback

When copying an external catalog into a Codex++ managed catalog:

  • Update context_window.
  • Update max_context_window.
  • Preserve existing capability metadata.
  • Set use_responses_lite = false for custom Responses providers.
  • Leave the original external catalog unchanged.

model_auto_compact_token_limit uses the absolute token value from the profile.

Regression Coverage

Covered:

  • Child tables merged with later empty parent headers.
  • Repeated table headers merged without losing fields.
  • Later duplicate root keys winning.
  • External catalog capability preservation.
  • Absolute context window propagation.
  • Absolute auto-compaction limit propagation.
  • Original external catalog preservation.
  • Model suffix parsing and catalog generation.

Validation

  • cargo test -p codex-plus-core --test model_suffix
    • 15 passed
  • cargo test -p codex-plus-core --test relay_config
    • 137 passed
  • git diff --check

Tests ran in rust:latest Docker because no local Rust toolchain is installed.

cargo fmt --check was unavailable because the Docker image does not include rustfmt.

normalize_duplicate_toml_text 之前按整行字符串去重表头/根键, 遇到第二次
出现的表头就整段丢弃表体。这在语义上是错的: [mcp_servers.node_repl]
(带正确的 .env 子表) 和其后一个裸的空 [mcp_servers] 表头是两个不同的
字符串, 行级去重看不出它们是同一棵 TOML 树的父子关系, 也看不出同一
表头出现两次、各自只写了部分字段时应该合并而不是丢弃后者。

真实故障: Codex config.toml 反复复现 invalid transport, 根因是
split_relay_context_config_sections 迁移 common/context 配置段时纯
文本拼接无去重, 让裸 env 变量和 .env 子表的历史残留一起原样保留进了
最终文件。

改为按顶层表头/根键切块, 每块单独 parse 成 DocumentMut, 用已有的
merge_toml_table_like 做语义合并(标量后写覆盖前写, 子表递归合并、
不清空)。任一块解析失败则退回原逐行丢弃策略, 保证不比修复前更差。

新增 3 个回归测试覆盖: 子表与后出现空父表头合并、同表头两次出现各写
部分字段的合并、根键重复后写覆盖前写。codex-plus-core 全量 300 个测试
+ codex-plus-data 10 个测试通过(cargo test, rust:latest docker 镜像)。
@ViceEye
ViceEye force-pushed the fix/toml-header-dedup-semantic-merge branch from f1a7fd6 to cd1eba2 Compare August 27, 2026 20:23
@ViceEye

ViceEye commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

摘要

修复两个 relay 配置问题:

  1. 修复 MCP/plugin 配置重复合并后生成非法 config.toml
  2. 保证绝对值 context window 和自动压缩阈值与生成的 model catalog 同步。

TOML 语义合并

用 TOML 语义合并替代原来的按文本行去重。

  • 将重复 TOML 内容拆分成可独立解析的区块。
  • 使用 merge_toml_table_like 合并区块。
  • 递归合并子表。
  • 后出现的标量值和根键覆盖先出现的值。
  • 区块解析失败时回退到原有清理逻辑。

修复以下场景:

  • [mcp_servers.node_repl]
  • [mcp_servers.node_repl.env]
  • 重复或空的 [mcp_servers]
  • 同一表头多次出现且字段不同
  • 重复根键

避免 MCP/plugin 配置损坏导致 invalid transport

Context 配置

支持 profile 中的绝对 token 配置:

model_context_window = 1000000
model_auto_compact_token_limit = 900000

模型窗口优先级:

单模型 model_windows
> profile.context_window
> 原有 catalog 值
> Codex 默认 fallback

复制外部 catalog 到 Codex++ 管理的 catalog 时:

  • 更新 context_window
  • 更新 max_context_window
  • 保留原有能力字段。
  • custom Responses provider 设置 use_responses_lite = false
  • 不修改原始外部 catalog。

model_auto_compact_token_limit 使用 profile 中的绝对 token 值。

回归测试

覆盖:

  • 子表与后出现的空父表头合并。
  • 重复表头字段合并且不丢字段。
  • 后出现的重复根键覆盖先前值。
  • 外部 catalog 能力字段保留。
  • 绝对 context window 传递。
  • 绝对 auto-compaction limit 传递。
  • 原始外部 catalog 不被修改。
  • 模型后缀解析和 catalog 生成。

验证结果

  • cargo test -p codex-plus-core --test model_suffix
    • 15 个通过
  • cargo test -p codex-plus-core --test relay_config
    • 137 个通过
  • git diff --check 通过

测试在 rust:latest Docker 环境中运行,因为本机未安装 Rust 工具链。

cargo fmt --check 未运行,因为 Docker 镜像未安装 rustfmt 组件。

@ViceEye ViceEye changed the title fix(relay-config): merge duplicate TOML blocks semantically fix(relay-config): fix TOML merge and model catalog sync Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant