Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs-site/src/content/docs/fr/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ configuration de référence et de repli. Sur l'interface de bouclage, ce fichie
vous pouvez fusionner manuellement si l'injection automatique a été supprimée ; hors bouclage, il contient la
forme avec fournisseur dédié. Le mode de fournisseur externe laisse ce profil intact.

Quand ce fichier est régénéré, les clés racine simples qu'OpenCodex ne gère pas sont conservées : un réglage
que vous ajoutez, comme `stream_idle_timeout_ms` ou `stream_max_retries`, survit à l'injection suivante.
Chaque affectation conservée est copiée telle quelle, y compris les valeurs sur plusieurs lignes et les entiers
64 bits, et placée avant la première table. Les clés à l'intérieur des tables et les clés racine pointées comme
`a.b = 1` ne sont pas conservées. En cas de conflit, OpenCodex l'emporte toujours : les clés racine qu'il gère
(`model_provider`, `model_catalog_json`, `openai_base_url`) sont réécrites pour le mode de routage actif, et
une clé racine portant le nom d'une table écrite par le profil, par exemple un `features = { ... }` en ligne
quand le profil écrit `[features]`, est supprimée. Si le fichier change pendant qu'une injection attend le
verrou d'écriture, l'injection s'arrête avec une erreur réessayable et laisse votre modification en place.

:::caution
Les clés racine telles que `openai_base_url`, `model_provider` et `model_catalog_json` **doivent** précéder le
premier en-tête `[table]`. L'injecteur garantit ce placement, supprime ses propres copies obsolètes ou en double
Expand Down
10 changes: 10 additions & 0 deletions docs-site/src/content/docs/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,16 @@ reference/fallback config. On loopback it contains the root keys you can merge m
injection was removed; on non-loopback it contains the dedicated provider form. External-provider
mode leaves this profile untouched.

Rebuilding that file keeps the plain root keys OpenCodex does not manage, so a setting you add such as
`stream_idle_timeout_ms` or `stream_max_retries` survives the next injection. Each kept assignment is
copied exactly as written, including values that span several lines and 64-bit integers, and is placed
above the first table. Keys inside tables and dotted root keys such as `a.b = 1` are not kept.
OpenCodex wins every collision: the root keys it owns (`model_provider`, `model_catalog_json`,
`openai_base_url`) are rewritten for the routing mode in use, and a root key named like a table the
profile writes, such as an inline `features = { ... }` when the profile writes `[features]`, is
dropped. If the file changes while an injection waits for the write lock, the injection stops with a
retryable error and leaves your edit in place.

:::caution
Root keys such as `openai_base_url`, `model_provider`, and `model_catalog_json` **must** sit before the
first `[table]` header. The injector guarantees that placement, removes its own stale/duplicate
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/ja/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ env_key = "OPENCODEX_API_AUTH_TOKEN"

OpenCodex がルーティングを所有している場合、どちらのモードも参照/フォールバック設定として `$CODEX_HOME/opencodex.config.toml` を書き込みます。ループバックでは、自動挿入が削除された場合に手動でマージできるルート キーが含まれています。非ループバックでは、専用のプロバイダー フォームが含まれます。外部プロバイダー モードでは、このプロファイルは変更されません。

このファイルを再生成しても、OpenCodex が管理しない単純なルート キーは保持されます。そのため、`stream_idle_timeout_ms` や `stream_max_retries` のように追加した設定は次の挿入後も残ります。保持される代入は、複数行にわたる値や 64 ビット整数も含めて書かれたとおりにコピーされ、最初のテーブルより前に置かれます。テーブル内のキーと、`a.b = 1` のようなドット付きルート キーは保持されません。衝突した場合は常に OpenCodex が優先されます。OpenCodex が所有するルート キー(`model_provider`、`model_catalog_json`、`openai_base_url`)は使用中のルーティング モードに合わせて書き直され、プロファイルが書き込むテーブルと同じ名前のルート キー(プロファイルが `[features]` を書き込むときのインライン `features = { ... }` など)は削除されます。挿入が書き込みロックを待っている間にファイルが変更された場合、挿入は再試行可能なエラーで停止し、編集内容はそのまま残ります。

:::caution
`openai_base_url`、`model_provider`、`model_catalog_json` などのルート キーは、最初の `[table]` ヘッダーの前に**なければなりません**。インジェクターはその配置を保証し、それ自身の古い/重複したコピーを削除し、ユーザー所有のルート `openai_base_url` を決して上書きしません。存在する場合、sync はカタログを更新しますが、ルーティングが挿入されなかったことを報告します。
:::
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/ko/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ env_key = "OPENCODEX_API_AUTH_TOKEN"

OpenCodex가 라우팅을 소유할 때는 두 모드 모두 `$CODEX_HOME/opencodex.config.toml`을 참고용/폴백 설정으로 작성합니다. loopback에서는 자동 주입이 사라졌을 때 수동으로 합칠 수 있는 root key가 들어가고, non-loopback에서는 전용 provider 형식이 들어갑니다. 외부 provider 모드는 이 프로필을 건드리지 않습니다.

이 파일을 다시 만들 때 OpenCodex가 관리하지 않는 일반 root key는 그대로 남습니다. 그래서 `stream_idle_timeout_ms`나 `stream_max_retries`처럼 직접 추가한 설정은 다음 주입 뒤에도 유지됩니다. 남는 대입문은 여러 줄에 걸친 값과 64비트 정수까지 작성한 그대로 복사되고, 첫 번째 테이블보다 앞에 놓입니다. 테이블 안의 키와 `a.b = 1` 같은 점 표기 root key는 남지 않습니다. 충돌하면 항상 OpenCodex 쪽이 이깁니다. OpenCodex가 소유한 root key(`model_provider`, `model_catalog_json`, `openai_base_url`)는 현재 라우팅 모드에 맞게 다시 쓰이고, 프로필이 쓰는 테이블과 이름이 같은 root key(프로필이 `[features]`를 쓸 때의 인라인 `features = { ... }` 등)는 버려집니다. 주입이 쓰기 잠금을 기다리는 동안 파일이 바뀌면 주입은 재시도 가능한 오류로 멈추고 수정한 내용은 그대로 둡니다.

:::caution
`openai_base_url`, `model_provider`, `model_catalog_json` 같은 root key는 첫 번째 `[table]` 헤더보다 **반드시** 앞에 있어야 합니다. 인젝터는 그 위치를 보장하고, 자신이 남긴 오래되었거나 중복된 복사본은 지웁니다. 사용자가 소유한 root `openai_base_url`은 덮어쓰지 않습니다. 그런 값이 있으면 sync는 카탈로그만 갱신하고 라우팅은 주입하지 않았다고 알립니다.
:::
Expand Down
10 changes: 10 additions & 0 deletions docs-site/src/content/docs/ru/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ reference/fallback-конфиг. На loopback в нём лежат root key, к
если автоматическое внедрение убрали; на не-loopback — форма с выделенным провайдером. Режим
external-provider этот профиль не трогает.

При пересоздании файла простые root key, которыми OpenCodex не управляет, сохраняются, поэтому
добавленная вами настройка вроде `stream_idle_timeout_ms` или `stream_max_retries` переживает следующее
внедрение. Каждое сохранённое присваивание копируется как есть, включая многострочные значения и 64-битные
целые, и ставится перед первой таблицей. Ключи внутри таблиц и root key с точками вроде `a.b = 1` не
сохраняются. При конфликте всегда побеждает OpenCodex: его root key (`model_provider`,
`model_catalog_json`, `openai_base_url`) переписываются под текущий режим маршрутизации, а root key с
именем таблицы, которую пишет профиль (например, inline `features = { ... }`, когда профиль пишет
`[features]`), отбрасывается. Если файл меняется, пока внедрение ждёт блокировку записи, внедрение
останавливается с ошибкой, которую можно повторить, и ваша правка остаётся на месте.

:::caution
Root key вроде `openai_base_url`, `model_provider` и `model_catalog_json` **обязаны** располагаться
до первого заголовка `[table]`. Injector гарантирует это размещение, удаляет собственные
Expand Down
13 changes: 13 additions & 0 deletions docs-site/src/content/docs/tr/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ döngüde otomatik enjeksiyon kaldırılmışsa manuel olarak birleştirebilece
kök anahtarları içerir; geri döngü olmayanda ise özel sağlayıcı formunu içerir.
Harici sağlayıcı modu bu profile dokunmaz.

Bu dosya yeniden oluşturulurken OpenCodex'in yönetmediği düz kök anahtarlar
korunur; böylece `stream_idle_timeout_ms` veya `stream_max_retries` gibi
eklediğiniz bir ayar sonraki enjeksiyondan sonra da kalır. Korunan her atama,
birden çok satıra yayılan değerler ve 64 bit tamsayılar dahil yazıldığı gibi
kopyalanır ve ilk tablonun önüne yerleştirilir. Tablo içindeki anahtarlar ve
`a.b = 1` gibi noktalı kök anahtarlar korunmaz. Çakışmada her zaman OpenCodex
kazanır: sahip olduğu kök anahtarlar (`model_provider`, `model_catalog_json`,
`openai_base_url`) kullanılan yönlendirme moduna göre yeniden yazılır ve
profilin yazdığı bir tabloyla aynı adı taşıyan kök anahtar (profil `[features]`
yazarken satır içi `features = { ... }` gibi) atılır. Enjeksiyon yazma kilidini
beklerken dosya değişirse enjeksiyon yeniden denenebilir bir hatayla durur ve
düzenlemeniz yerinde kalır.

:::caution
`openai_base_url`, `model_provider` ve `model_catalog_json` gibi kök anahtarlar
ilk `[tablo]` başlığından önce **bulunmalıdır**. Enjektör bu yerleşimi garanti
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ env_key = "OPENCODEX_API_AUTH_TOKEN"
在 loopback 情况下,它包含可在自动注入被移除后手动合并的 root keys;在非 loopback 情况下,
它包含专用 provider 形式。外部 provider 模式会保持这个 profile 不变。

重新生成这个文件时,会保留 OpenCodex 不管理的普通 root keys,所以你添加的 `stream_idle_timeout_ms` 或
`stream_max_retries` 这类设置在下一次注入后仍然存在。保留的赋值按原样复制,包括跨多行的值和 64 位整数,
并放在第一个表之前。表内的键以及 `a.b = 1` 这样的点分 root key 不会保留。发生冲突时总是以 OpenCodex
为准:它拥有的 root keys(`model_provider`、`model_catalog_json`、`openai_base_url`)会按当前路由模式
重写;与 profile 写入的表同名的 root key(例如 profile 写入 `[features]` 时的内联 `features = { ... }`)
会被丢弃。如果在注入等待写锁期间文件发生变化,注入会以可重试的错误停止,并保留你的修改。

:::caution
像 `openai_base_url`、`model_provider` 和 `model_catalog_json` 这样的 root keys **必须** 位于第一个
`[table]` 头之前。注入器会保证这一点,移除自己留下的陈旧/重复副本,并且绝不会覆盖用户拥有的 root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ env_key = "OPENCODEX_API_AUTH_TOKEN"
設定。loopback 模式下,其中包含自動注入被移除時可手動合併的根級鍵;non-loopback 模式下,其中包含
專用 provider 形式。外部 provider 模式不會修改此 profile。

重新產生此檔案時,會保留 OpenCodex 不管理的一般根級鍵,因此你新增的 `stream_idle_timeout_ms` 或
`stream_max_retries` 等設定在下一次注入後仍會存在。保留的賦值會照原樣複製,包括跨多行的值與 64 位元
整數,並放在第一個表之前。表內的鍵以及 `a.b = 1` 這類點分根級鍵不會保留。發生衝突時一律以 OpenCodex
為準:它擁有的根級鍵(`model_provider`、`model_catalog_json`、`openai_base_url`)會依目前的路由模式
重寫;與 profile 寫入的表同名的根級鍵(例如 profile 寫入 `[features]` 時的內嵌 `features = { ... }`)
會被捨棄。若注入等待寫入鎖期間檔案有變動,注入會以可重試的錯誤停止,並保留你的修改。

:::caution
`openai_base_url`、`model_provider`、`model_catalog_json` 等根級鍵**必須**位於第一個 `[table]`
標頭之前。注入器會保證此位置、移除自己留下的舊值或重複項,而且絕不覆寫使用者自有的根級
Expand Down
3 changes: 2 additions & 1 deletion scripts/test-layout/layout-codex-collision.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@
"codex-stored-main-duplicate.test.ts": "codex-integration",
"codex-account-slot-identity.test.ts": "codex-integration",
"codex-pool-caller-fallback-policy.test.ts": "codex-integration",
"codex-windows-current-sid.test.ts": "codex-integration"
"codex-windows-current-sid.test.ts": "codex-integration",
"codex-profile-preservation.test.ts": "codex-integration"
}
11 changes: 11 additions & 0 deletions src/codex/inject-coordination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ export function captureCodexPreImages(): CodexPreImages {
};
}

/** The profile bytes one injection published, set just before it writes them. */
export interface CodexProfilePublish { published?: string }

/**
* How many transactions of evidence the ledger keeps.
*
Expand Down Expand Up @@ -366,10 +369,16 @@ export function recordCodexNativeTransactionProvenance(
*
* Every surface is attempted even after one fails: a second failure is worth
* knowing about, and stopping early would leave more unrestored than necessary.
*
* `profilePublish`, when given, limits the profile surface to bytes this
* operation wrote: it is reverted only if `published` is set and the file still
* holds exactly those bytes. A refusal before the publish, or a profile another
* writer replaced since, is left as it is.
*/
export function restoreCodexPreImages(
pre: CodexPreImages,
heldConfigWriteLock?: LockHandle,
profilePublish?: CodexProfilePublish,
): { complete: boolean; unrestored: readonly string[] } {
const locked = withConfigWriteLockHeld(CODEX_CONFIG_PATH, heldConfigWriteLock, held => {
const unrestored: string[] = [];
Expand All @@ -382,6 +391,8 @@ export function restoreCodexPreImages(
// The current journal remains recovery authority until both artifacts are restored.
if (name === "journal" && unrestored.length > 0) { unrestored.push(name); continue; }
try {
if (name === "profile" && profilePublish
&& (profilePublish.published === undefined || readOrNull(path) !== profilePublish.published)) continue;
publishCodexArtifact(path, held, (destination, hooks) => {
if (bytes === null) {
hooks.validateBeforeRename?.(destination);
Expand Down
Loading
Loading