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
17 changes: 17 additions & 0 deletions docs-site/src/content/docs/guides/codex-app-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,23 @@ The featured-model list is separate from the Dashboard's **Sub-agent delegation*
controls which overrides Codex offers first; it does not select a model or trigger delegation by
itself.

## Desktop remote servers

Codex Desktop's remote-server mode filters the picker against the client's own
`available_models` allowlist (active when the remote `use_hidden_models` setting is on). Routed
catalog entries are still loaded and served - `model/list` returns them and the bundled CLI reads
them - but the Desktop renderer drops anything that is not on that native-only allowlist before
rendering. opencodex has no hook into that list; the upstream bug is tracked at
[openai/codex#19694](https://github.com/openai/codex/issues/19694).

Until Desktop exposes a control for the allowlist:

- Set the model directly in `~/.codex/config.toml` on the remote machine, for example
`model = "input/grok-4.5"`. The picker may show `Custom`, but requests still use the configured

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use a configured provider in the workaround

When a user copies this workaround without having created a custom provider literally named input, the configured model is unroutable because the shipped registry defines this Grok route under xai (src/providers/registry.ts:879-902) and contains no input provider. Use xai/grok-4.5 or an explicit <configured-provider>/<model> placeholder here and in the translations so the documented workaround does not fail with an unknown provider.

AGENTS.md reference: docs-site/AGENTS.md:L10-L10

Useful? React with 👍 / 👎.

routed model.
- Use Codex CLI or TUI instead of the Desktop picker; they do not apply the allowlist and list
routed models normally.

## Refreshing model state

If the picker still shows stale entries, refresh the catalog and restart the target Codex surface:
Expand Down
9 changes: 9 additions & 0 deletions docs-site/src/content/docs/ja/guides/codex-app-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ Codex は、ピッカーに表示されるカタログ エントリを `priority

注目モデルのリストは、ダッシュボードの **サブエージェント委任** の選択とは別のものです。 Codex が提供するものを最初にオーバーライドするものを制御します。モデルを選択したり、委任をトリガーしたりすることはありません。

## Desktop リモートサーバー

Codex Desktop のリモートサーバーモードでは、クライアント自身の `available_models` 許可リストでピッカーがフィルタリングされます(リモートの `use_hidden_models` 設定が有効な場合)。ルーティングされたカタログエントリは引き続きロードされ提供されます。`model/list` はそれらを返し、バンドルされた CLI も読み取れますが、Desktop レンダラーは表示前にこのネイティブのみの許可リストにないものを破棄します。opencodex はこのリストに介入できません。上流のバグは [openai/codex#19694](https://github.com/openai/codex/issues/19694) で追跡されています。

Desktop が許可リストの制御を提供するまでは:

- リモートマシンの `~/.codex/config.toml` でモデルを直接設定します(例: `model = "input/grok-4.5"`)。ピッカーには `Custom` と表示される場合がありますが、リクエストは設定されたルーティングモデルを使用します。
- Desktop ピッカーの代わりに Codex CLI または TUI を使用します。これらは許可リストを適用せず、ルーティングモデルを通常どおり一覧表示します。

## モデルの状態を更新しています

ピッカーに古いエントリがまだ表示されている場合は、カタログを更新し、ターゲットの Codex サーフェスを再起動します。
Expand Down
16 changes: 16 additions & 0 deletions docs-site/src/content/docs/ko/guides/codex-app-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,22 @@ routed `provider/model` id를 최대 다섯 개 선택하고 저장할 수 있
featured-model 목록은 Dashboard의 **Sub-agent delegation** 선택과 별개입니다. Codex가 먼저 보여 줄
override를 정할 뿐, 모델을 고르거나 delegation을 시작하지는 않습니다.

## Desktop 원격 서버

Codex Desktop의 원격 서버 모드는 클라이언트 자체 `available_models` 허용 목록으로 picker를
필터링합니다(원격 `use_hidden_models` 설정이 켜져 있을 때 적용). 라우팅된 카탈로그 항목은
여전히 로드되고 제공됩니다. `model/list`가 항목을 반환하고 번들 CLI도 읽을 수 있지만, Desktop
렌더러는 표시 전에 이 네이티브 전용 허용 목록에 없는 항목을 버립니다. opencodex는 이 목록에
개입할 수 없습니다. 업스트림 버그는
[openai/codex#19694](https://github.com/openai/codex/issues/19694)에서 추적됩니다.

Desktop이 허용 목록을 제어할 수 있게 될 때까지:

- 원격 머신의 `~/.codex/config.toml`에서 모델을 직접 설정하세요(예: `model = "input/grok-4.5"`).
picker에는 `Custom`으로 표시될 수 있지만, 요청은 설정된 라우팅 모델을 계속 사용합니다.
- Desktop picker 대신 Codex CLI 또는 TUI를 사용하세요. 이들은 허용 목록을 적용하지 않으며
라우팅 모델을 정상적으로 나열합니다.

## 모델 상태 새로고침

picker에 오래된 항목이 계속 보이면 카탈로그를 새로 쓰고 대상 Codex 서피스를 다시 시작합니다:
Expand Down
18 changes: 18 additions & 0 deletions docs-site/src/content/docs/ru/guides/codex-app-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,24 @@ Codex сортирует видимые в picker'е записи каталог
определяет, какие override Codex показывает первыми; он не выбирает модель и не инициирует
делегирование сам по себе.

## Удалённые серверы Desktop

В режиме удалённого сервера Codex Desktop фильтрует picker по собственному списку разрешённых
моделей `available_models` (активируется, когда включена удалённая настройка
`use_hidden_models`). Записи маршрутизированного каталога по-прежнему загружаются и отдаются —
`model/list` возвращает их, и встроенный CLI их читает, — но рендерер Desktop отбрасывает всё,
чего нет в этом списке, ограниченном нативными моделями, ещё до отрисовки. opencodex не может
влиять на этот список; соответствующий upstream-баг отслеживается в
[openai/codex#19694](https://github.com/openai/codex/issues/19694).

Пока Desktop не предоставит управление этим списком:

- Задайте модель напрямую в `~/.codex/config.toml` на удалённой машине, например
`model = "input/grok-4.5"`. Picker может показывать `Custom`, но запросы по-прежнему
используют настроенную маршрутизированную модель.
- Используйте Codex CLI или TUI вместо picker в Desktop; они не применяют этот список и
показывают маршрутизированные модели как обычно.

## Обновление состояния моделей

Если picker всё ещё показывает устаревшие записи, обновите каталог и перезапустите нужную
Expand Down
9 changes: 9 additions & 0 deletions docs-site/src/content/docs/zh-cn/guides/codex-app-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ Codex 会按 `priority` 升序对选择器可见的目录条目排序,并把

精选模型列表与 Dashboard 的 **Sub-agent delegation** 选择彼此独立。它只决定 Codex 先提供哪些 override;它不会自己选择模型,也不会触发委派。

## Desktop 远程服务器

Codex Desktop 的远程服务器模式会针对客户端自己的 `available_models` 白名单过滤模型选择器(当远程 `use_hidden_models` 设置启用时生效)。路由目录条目仍然会被加载并对外提供——`model/list` 会返回它们,内置 CLI 也能读取——但 Desktop 渲染层在显示前会丢弃任何不在这个仅包含原生模型的白名单中的条目。opencodex 无法影响这份白名单;上游问题在 [openai/codex#19694](https://github.com/openai/codex/issues/19694) 跟踪中。

在 Desktop 提供白名单控制之前:

- 在远程机器的 `~/.codex/config.toml` 中直接设置模型,例如 `model = "input/grok-4.5"`。选择器可能显示为 `Custom`,但请求仍会使用所配置的路由模型。
- 改用 Codex CLI 或 TUI,而不是 Desktop 选择器;它们不应用该白名单,会正常列出路由模型。

## 刷新模型状态

如果选择器里仍然显示旧条目,请刷新目录并重启目标 Codex 界面:
Expand Down
53 changes: 51 additions & 2 deletions tests/management-api-logs-metrics.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { afterEach, describe, expect, test } from "bun:test";
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { handleManagementAPI } from "../src/server/management-api";
import { usageLogPath } from "../src/usage/log";
import {
addRequestLog,
clearRequestLogsForTests,
Expand All @@ -10,7 +14,24 @@ import type { OcxConfig } from "../src/types";

const config = { providers: [] } as unknown as OcxConfig;

afterEach(() => clearRequestLogsForTests());
let testDir = "";
let previousHome: string | undefined;

beforeEach(() => {
// addRequestLog persists to usage.jsonl; without a scratch OPENCODEX_HOME a bare
// `bun test <file>` run from outside the repo (no bunfig preload) writes these
// fixture rows into the real ~/.opencodex log and poisons the GUI Usage page.
previousHome = process.env.OPENCODEX_HOME;
testDir = mkdtempSync(join(tmpdir(), "ocx-logs-metrics-"));
process.env.OPENCODEX_HOME = testDir;
});

afterEach(() => {
clearRequestLogsForTests();
if (previousHome === undefined) delete process.env.OPENCODEX_HOME;
else process.env.OPENCODEX_HOME = previousHome;
if (testDir) rmSync(testDir, { recursive: true, force: true });
});

async function readLogs(): Promise<Array<Record<string, any>>> {
const url = new URL("http://localhost/api/logs");
Expand Down Expand Up @@ -154,5 +175,33 @@ describe("GET /api/logs display metrics", () => {
const [dto] = await readLogs();
expect(dto!.displayMetrics.cost).toEqual({ kind: "unavailable", reason: "invalid_cache_breakdown" });
});

test("fixture usage rows land in the scratch home, never the default location", () => {
// Pins the safety property this file's isolation exists for: addRequestLog
// persists to usage.jsonl, so if the scratch-home hook is ever dropped (or a
// future test logs before it runs), a bare `bun test <file>` from outside the
// repo writes fixture rows into the developer's real ~/.opencodex log.
const requestId = "safety-pin-usage-log-target";
addRequestLog(baseEntry({ requestId }));

const resolvedTarget = usageLogPath();
expect(resolvedTarget).toBe(join(testDir, "usage.jsonl"));
expect(readFileSync(resolvedTarget, "utf-8")).toContain(requestId);

// The default location (what the resolver returns with no OPENCODEX_HOME
// override) must never be the write target for this suite.
const previousHome = process.env.OPENCODEX_HOME;
delete process.env.OPENCODEX_HOME;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the fallback-path assertion inside scratch space

When this file is run from outside the repository as described above, the Bun preload is absent and HOME still points at the developer's real home, so deleting OPENCODEX_HOME here makes usageLogPath() resolve to the real ~/.opencodex/usage.jsonl; lines 198-199 then read that user-owned file in full. This defeats the isolation goal, can make the test fail on an unreadable or previously contaminated log, and leaves a sticky failure if the fixed marker was ever written there. Point HOME/USERPROFILE at a second scratch directory for the fallback-path assertion instead of inspecting the real default location.

Useful? React with 👍 / 👎.

try {
const defaultTarget = usageLogPath();
expect(defaultTarget).not.toBe(resolvedTarget);
if (existsSync(defaultTarget)) {
expect(readFileSync(defaultTarget, "utf-8")).not.toContain(requestId);
}
} finally {
if (previousHome === undefined) delete process.env.OPENCODEX_HOME;
else process.env.OPENCODEX_HOME = previousHome;
}
});
});
import { ManagementRequest as Request } from "./helpers/management-auth";
Loading