Skip to content
Open
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions docs-site/src/content/docs/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,48 @@ The cache remains bounded; this does not extend retention or recover history the
longer has. HTTP clients must handle the error explicitly and resend their full context without
`previous_response_id`. Retrying only the same ID cannot recover missing state.

### Client-side compaction (opt-in)

Authenticated loopback routing normally keeps Codex on its built-in `openai` provider identity.
That preserves native thread identity, but it also makes Codex request native remote compaction.
When a routed provider cannot return a native compaction blob, OpenCodeX stores the summary in its
own `ocx1:` envelope. Native ChatGPT cannot verify that envelope if OpenCodeX is later removed from
the request path.

On an authenticated loopback route, enable client-side compaction to keep V2 sub-agent routing while preventing new `ocx1:` compaction summaries. Non-loopback and API-key routes retain their existing provider and authentication behavior:

```bash
ocx system settings --client-compaction on # or "codexClientCompaction": true in config.json
ocx sync # rewrites the active config (default: ~/.codex/config.toml); restart Desktop
```

The setting defaults to off. For authenticated loopback routing, OpenCodeX selects its existing
dedicated provider form with `requires_openai_auth = true`. If `codexDesktopAuthless` is also
enabled, that stronger compatibility setting takes precedence and writes
`requires_openai_auth = false`:

```toml
model_provider = "opencodex"

[model_providers.opencodex]
name = "OpenCodex Proxy"
base_url = "http://127.0.0.1:10100/v1"
wire_api = "responses"
requires_openai_auth = true
```

Codex then owns compaction and stores a portable plaintext summary rather than a new OpenCodeX
envelope. The compacting request still routes through OpenCodeX and can consume quota on the
selected provider. V2 sub-agent requests keep their existing provider selection and quota
accounting. Client-side compaction does not change plaintext delivery, encrypted task passthrough
through `allowEncryptedV2AgentTasks`, or configured recovery and fallback behavior.

This preference affects future compactions only. It does not rewrite existing `ocx1:` history or
re-tag existing resume-history metadata; use the explicit history recovery workflow for an affected
thread. New threads use the `opencodex` provider identity while the mode is active. Turning the
setting off and syncing restores the default Design B root override unless
`codexDesktopAuthless` or non-loopback admission still requires the provider-table form.

### Authless Codex Desktop (opt-in)

In **Dashboard → Overview**, **Open Codex without signing in** controls this existing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ runs helper features around provider requests.
| `codexAutoStart?` | `boolean` | `true` | Let the Codex shim run `ocx ensure` before launching Codex. False makes ensure a no-op. |
| `codexShimAutoRestore?` | `boolean` | `true` | Restore an installed shim after a completed external Codex update replaces it. Environment opt-out: `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0`. |
| `codexDesktopAuthless?` | `boolean` | `false` | Opt-in authless Codex Desktop routing on a loopback bind: inject the dedicated `opencodex` provider with `requires_openai_auth = false` so Desktop opens without a ChatGPT login. Ignored on non-loopback binds. `ocx system settings --desktop-authless on`. See [Codex integration](/guides/codex-integration/#authless-codex-desktop-opt-in). |
| `codexClientCompaction?` | `boolean` | `false` | Opt into Codex client-side compaction on an authenticated loopback bind. Uses the dedicated `opencodex` provider identity with `requires_openai_auth = true`, preventing new routed compactions from storing OpenCodeX-owned `ocx1:` state. `codexDesktopAuthless` takes precedence when both are enabled and keeps `requires_openai_auth = false`. V2 sub-agent routing is unchanged. `ocx system settings --client-compaction on`. See [Codex integration](/guides/codex-integration/#client-side-compaction-opt-in). |
| `resetCreditAutoRedeem?` | `{ enabled?: boolean; leadTimeMinutes?: number }` | off | Opt-in: redeem the main Codex account's soonest-expiring reset credit `leadTimeMinutes` (1–60, default 10) before it expires. Every attempt re-reads the upstream credit list first and skips when the credit is gone (for example, redeemed by hand); the `redeem_request_id` is journaled in `$OPENCODEX_HOME/reset-credit-auto-redeem.json` before the call so a crash replays the same idempotent request instead of spending a second credit. Servers sharing this configuration directory coordinate reservations and settlements so one process does not replace another's request record. Logs carry a hashed account key only. |
| `syncResumeHistory?` | `boolean` | `true` | Reversible Codex App history compatibility. Original metadata is backed up and restored by `ocx stop` / `ocx restore`. |
| `shadowCallIntercept?` | `{ enabled?: boolean; model?: string; sourceModels?: string[] }` | off | Redirect recognized Codex helper/shadow calls to a chosen model while preserving the request's configured reasoning effort. The default source prefix is `gpt-5.6-luna`; older clients through 0.144.x used `gpt-5.4-mini`, which `sourceModels` can restore. |
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,8 @@ export const de: Record<TKey, string> = {
"dash.visionAdvancedPopover": "Erweiterte Vision-Einstellungen",
"dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen",
"dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.",
"dash.codexClientCompaction": "Clientseitige Komprimierung verwenden",
"dash.codexClientCompactionHint": "Standardmäßig aus; nur für authentifiziertes Loopback-Routing. Künftige Komprimierungen speichern portable Klartext-Zusammenfassungen, während OpenCodeX- und V2-Provider-Routing aktiv bleiben; der konfigurierte Anbieter kann sie verarbeiten und Kontingent verbrauchen. Vorhandene ocx1-Verläufe müssen weiterhin wiederhergestellt werden. Codex nach einer Änderung neu starten.",
"models.newPolicyGlobal": "Neue Modelle zunächst deaktivieren", "models.newPolicyProvider": "Richtlinie für neue Modelle",
"models.newPolicy_inherit": "Übernehmen", "models.newPolicy_off": "Aus", "models.newPolicy_on": "An", "models.newBadge": "NEU", "models.newCount": "{count} neu, aus",
"models.aliases": "Aliase",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,8 @@ export const en = {
"dash.multiAgent": "Sub-agent",
"dash.codexDesktopAuthless": "Open Codex without signing in",
"dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.",
"dash.codexClientCompaction": "Use client-side compaction",
"dash.codexClientCompactionHint": "Off by default; authenticated loopback only. Future compactions store portable plaintext summaries while OpenCodeX and V2 provider routing stay active; the configured provider may process them and consume quota. Existing ocx1 history still needs recovery. Restart Codex after changing this setting.",
"models.v2Conflict": "[agents] max_threads is set — codex will refuse to start; remove it from config.toml",
"models.v2Applied": "Sub-agent mode updated — applies to new sessions (restart the Codex app to refresh the picker)",
"models.v2ThreadsLabel": "Max threads",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@ export const fr: Record<TKey, string> = {
"dash.multiAgent": "Sous-agent",
"dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter",
"dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.",
"dash.codexClientCompaction": "Utiliser la compaction côté client",
"dash.codexClientCompactionHint": "Désactivé par défaut, uniquement pour le routage loopback authentifié. Les compactages futurs stockent des résumés portables en texte clair tout en conservant le routage OpenCodeX/V2 ; le fournisseur configuré peut les traiter et consommer son quota. L'historique ocx1 existant doit toujours être restauré. Redémarrez Codex après modification.",
"models.v2Conflict": "[agents] max_threads est défini — codex refusera de démarrer ; supprimez-le de config.toml",
"models.v2Applied": "Mode sous-agent mis à jour — s’applique aux nouvelles sessions (redémarrez l’application Codex pour actualiser le sélecteur)",
"models.v2ThreadsLabel": "Nombre maximal de fils",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2506,6 +2506,8 @@ export const ja: Record<TKey, string> = {
"dash.visionAdvancedPopover": "詳細なビジョン設定",
"dash.codexDesktopAuthless": "ログインせずに Codex を開く",
"dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。",
"dash.codexClientCompaction": "クライアント側コンパクションを使用",
"dash.codexClientCompactionHint": "既定ではオフで、認証済みループバックルーティング専用です。今後のコンパクションは、OpenCodeX と V2 プロバイダーのルーティングを維持したまま移植可能な平文要約を保存します。設定済みプロバイダーが要約を処理し、割り当てを消費する場合があります。既存の ocx1 履歴は別途復旧が必要です。変更後は Codex を再起動してください。",
"models.newPolicyGlobal": "新しいモデルを無効で追加", "models.newPolicyProvider": "新しいモデルのポリシー",
"models.newPolicy_inherit": "継承", "models.newPolicy_off": "オフ", "models.newPolicy_on": "オン", "models.newBadge": "新着", "models.newCount": "新着 {count} 件、オフ",
"models.aliases": "エイリアス",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2507,6 +2507,8 @@ export const ko: Record<TKey, string> = {
"dash.visionAdvancedPopover": "고급 비전 설정",
"dash.codexDesktopAuthless": "로그인 없이 Codex 열기",
"dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.",
"dash.codexClientCompaction": "클라이언트 측 컴팩션 사용",
"dash.codexClientCompactionHint": "기본값은 꺼짐이며 인증된 루프백 라우팅에만 적용됩니다. 향후 컴팩션은 OpenCodeX 및 V2 제공자 라우팅을 유지하면서 이식 가능한 평문 요약을 저장합니다. 설정된 제공자가 요약을 처리하고 할당량을 사용할 수 있습니다. 기존 ocx1 기록은 별도로 복구해야 합니다. 변경 후 Codex를 다시 시작하세요.",
"models.newPolicyGlobal": "새 모델을 비활성화 상태로 추가", "models.newPolicyProvider": "새 모델 정책",
"models.newPolicy_inherit": "상속", "models.newPolicy_off": "끔", "models.newPolicy_on": "켬", "models.newBadge": "신규", "models.newCount": "신규 {count}개, 꺼짐",
"models.aliases": "별칭",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2508,6 +2508,8 @@ export const ru: Record<TKey, string> = {
"dash.visionAdvancedPopover": "Дополнительные настройки изображений",
"dash.codexDesktopAuthless": "Открывать Codex без входа",
"dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.",
"dash.codexClientCompaction": "Использовать сжатие на стороне клиента",
"dash.codexClientCompactionHint": "По умолчанию выключено; только для аутентифицированной loopback-маршрутизации. Будущие сжатия сохраняют переносимые текстовые сводки, а маршрутизация OpenCodeX и V2 остаётся активной; настроенный провайдер может обрабатывать сводки и расходовать квоту. Существующую историю ocx1 всё равно нужно восстановить. После изменения перезапустите Codex.",
"models.newPolicyGlobal": "Добавлять новые модели выключенными", "models.newPolicyProvider": "Политика новых моделей",
"models.newPolicy_inherit": "Наследовать", "models.newPolicy_off": "Выкл.", "models.newPolicy_on": "Вкл.", "models.newBadge": "НОВАЯ", "models.newCount": "Новых: {count}, выкл.",
"models.aliases": "Псевдонимы",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2508,6 +2508,8 @@ export const tr: Record<TKey, string> = {
"dash.visionAdvancedPopover": "Gelişmiş görsel ayarları",
"dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat",
"dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.",
"dash.codexClientCompaction": "İstemci tarafı sıkıştırmayı kullan",
"dash.codexClientCompactionHint": "Varsayılan olarak kapalıdır ve yalnızca kimliği doğrulanmış geri döngü yönlendirmesinde geçerlidir. Gelecekteki sıkıştırmalar, OpenCodeX ve V2 sağlayıcı yönlendirmesi etkin kalırken taşınabilir düz metin özetleri kaydeder; yapılandırılmış sağlayıcı bunları işleyip kotasını tüketebilir. Mevcut ocx1 geçmişi yine ayrıca kurtarılmalıdır. Değişiklikten sonra Codex’i yeniden başlatın.",
"models.newPolicyGlobal": "Yeni modeller devre dışı başlasın", "models.newPolicyProvider": "Yeni model ilkesi",
"models.newPolicy_inherit": "Devral", "models.newPolicy_off": "Kapalı", "models.newPolicy_on": "Açık", "models.newBadge": "YENİ", "models.newCount": "{count} yeni, kapalı",
"models.aliases": "Takma adlar",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2470,6 +2470,8 @@ export const zhTW: Record<TKey, string> = {
"dash.visionAdvancedPopover": "進階視覺設定",
"dash.codexDesktopAuthless": "無需登入即可開啟 Codex",
"dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。",
"dash.codexClientCompaction": "使用用戶端壓縮",
"dash.codexClientCompactionHint": "預設關閉,僅適用於已驗證的 loopback 路由。未來壓縮會儲存可攜的純文字摘要,同時保留 OpenCodeX 與 V2 提供方路由;已設定的提供方可能處理摘要並消耗其額度。既有 ocx1 歷程仍須另行復原。變更後請重新啟動 Codex。",
"models.newPolicyGlobal": "新模型預設停用", "models.newPolicyProvider": "新模型策略",
"models.newPolicy_inherit": "繼承", "models.newPolicy_off": "關閉", "models.newPolicy_on": "開啟", "models.newBadge": "新增", "models.newCount": "{count} 個新增,已關閉",
"models.aliases": "別名",
Expand Down
2 changes: 2 additions & 0 deletions gui/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2506,6 +2506,8 @@ export const zh: Record<TKey, string> = {
"dash.visionAdvancedPopover": "高级视觉设置",
"dash.codexDesktopAuthless": "无需登录即可打开 Codex",
"dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。",
"dash.codexClientCompaction": "使用客户端压缩",
"dash.codexClientCompactionHint": "默认关闭,仅适用于已认证的 loopback 路由。未来压缩会保存可移植的明文摘要,同时保留 OpenCodeX 与 V2 提供方路由;已配置的提供方可能处理摘要并消耗其额度。已有 ocx1 历史仍需单独恢复。更改后请重启 Codex。",
"models.newPolicyGlobal": "新模型默认停用", "models.newPolicyProvider": "新模型策略",
"models.newPolicy_inherit": "继承", "models.newPolicy_off": "关闭", "models.newPolicy_on": "开启", "models.newBadge": "新增", "models.newCount": "{count} 个新增,已关闭",
"models.aliases": "别名",
Expand Down
21 changes: 21 additions & 0 deletions gui/src/pages/dashboard-overview-sections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ function VisionAdvancedPopover({ t, open, triggerRef, onClose, maxValue, maxInva
export function DashboardSidecarPanels({ d }: { d: Dash }) {
const {
t, settings, settingsSaving, syncing, toggleCodexAutoStart, toggleCodexDesktopAuthless,
toggleCodexClientCompaction,
sidecar, sidecarSaving, sidecarModels, visionModels, models, saveSidecar,
shadowCall, shadowCallSaving, shadowCallHelpTriggerRef, shadowCallHelpOpen, setShadowCallHelpOpen, saveShadowCall,
} = d;
Expand Down Expand Up @@ -525,6 +526,26 @@ export function DashboardSidecarPanels({ d }: { d: Dash }) {
</div>
</div>

<div className="panel">
<div className="spread">
<div style={{ flex: 1, minWidth: 0 }}>
<div className="font-semibold">{t("dash.codexClientCompaction")}</div>
<div className="muted setting-hint">{t("dash.codexClientCompactionHint")}</div>
{settings?.catalogRefreshPending && <div className="muted setting-hint" role="status">{t("codexAuth.catalogRefreshPending")}</div>}
</div>
<button
type="button"
className={`switch ${settings?.codexClientCompaction ?? false ? "on" : ""}`}
onClick={toggleCodexClientCompaction}
disabled={!settings || settingsSaving || syncing}
aria-label={t("dash.codexClientCompaction")}
aria-pressed={settings?.codexClientCompaction ?? false}
>
<span className="knob" />
</button>
</div>
</div>

Comment thread
cb8010d6 marked this conversation as resolved.
<div className="dash-sidecar-grid">
{/* Both sidecar cards wear the DashboardInjectionPanel shell: the PANEL is
the flex row, copy left, controls right. */}
Expand Down
1 change: 1 addition & 0 deletions gui/src/pages/dashboard-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface ModelInfo { id: string; provider: string; namespaced: string; o
export interface SettingsData {
codexAutoStart: boolean;
codexDesktopAuthless?: boolean;
codexClientCompaction?: boolean;
catalogRefreshPending?: boolean;
/** Whether a login may open a browser on the machine running the proxy. */
oauthOpenBrowser?: boolean;
Expand Down
Loading
Loading