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
8 changes: 5 additions & 3 deletions docs-site/src/content/docs/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,11 @@ Gateway** needs your account + gateway ids filled into the URL.
Cursor is tracked separately as an experimental adapter. `adapter: "cursor"` appears in `ocx init`
and the dashboard Add Provider picker as an experimental local config entry with Cursor's static
fallback model catalog metadata. When a Cursor access token is configured, opencodex uses Cursor's
live HTTP/2 transport. Its v2.7.1 fallback seed includes `gpt-5.6-sol` / `terra` / `luna` (1M context)
plus `grok-4.5` / `grok-4.5-fast` (500K); live discovery decides which remain visible for the
account. Cursor server-driven native read/write/delete/ls/grep/shell/fetch execution
live HTTP/2 transport. Its v2.7.1 fallback seed includes `gpt-5.6-sol` / `terra` / `luna` (1M context),
`grok-4.5` / `grok-4.5-fast` (500K), and `kimi-k3` (262K); live discovery decides which remain
visible for the account. Cursor serves Kimi K3 only as effort-suffixed wire ids, so
`cursor/kimi-k3` exposes a `low` / `high` / `max` ladder and defaults to `max`, matching the

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 Document the synthetic ultra tier

The new documentation says cursor/kimi-k3 exposes only a low / high / max ladder, but applyReasoningLevels always adds ultra to routed reasoning models, and the new catalog test explicitly expects ['low', 'high', 'max', 'ultra']. Users therefore see an undocumented fourth picker option; describe ultra as an alias that resolves to the max wire tier and make the same correction in each translated locale.

AGENTS.md reference: AGENTS.md:L96-L97

Useful? React with 👍 / 👎.

model's documented API default. Cursor server-driven native read/write/delete/ls/grep/shell/fetch execution
is disabled by default because it bypasses Codex's approval and sandbox path; set
`unsafeAllowNativeLocalExec: true` on the `providers.cursor` object in `~/.opencodex/config.json`
only for trusted local experiments (or via **Providers → Cursor → Edit JSON** in the dashboard).
Expand Down
8 changes: 5 additions & 3 deletions docs-site/src/content/docs/ja/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ Gateway** は URL にアカウント + ゲートウェイ ID を埋める必要
Cursor は別の実験的アダプターとして追跡します。`adapter: "cursor"` は `ocx init` とダッシュボード Add
Provider ピッカーに実験的 local config 項目として表示され、Cursor の静的フォールバックモデルカタログ
メタデータを保存します。Cursor アクセストークンを設定すると opencodex は Cursor ライブ HTTP/2 トランスポートを
使います。v2.7.1 フォールバックリストには 1M コンテキストの `gpt-5.6-sol` / `terra` / `luna` と 500K コンテキストの
`grok-4.5` / `grok-4.5-fast` が含まれ、ライブ探索結果に基づき現在のアカウントに表示するモデルを
決定します。Cursor サーバーが直接送るネイティブ read/write/delete/ls/grep/shell/fetch 実行は Codex
使います。v2.7.1 フォールバックリストには 1M コンテキストの `gpt-5.6-sol` / `terra` / `luna`、500K コンテキストの
`grok-4.5` / `grok-4.5-fast`、262K コンテキストの `kimi-k3` が含まれ、ライブ探索結果に基づき現在の
アカウントに表示するモデルを決定します。Cursor は Kimi K3 を effort サフィックス付きの wire id
としてのみ提供するため、`cursor/kimi-k3` は `low` / `high` / `max` のラダーを公開し、既定値はモデル
ドキュメントの API 既定値と同じ `max` です。Cursor サーバーが直接送るネイティブ read/write/delete/ls/grep/shell/fetch 実行は Codex
承認とサンドボックス経路をバイパスするためデフォルトで無効です。信頼できるローカル実験でのみ
`~/.opencodex/config.json` の `providers.cursor` に `unsafeAllowNativeLocalExec: true` を設定してください。
ダッシュボードからは **Providers → Cursor → Edit JSON** で設定できます。完全な例は
Expand Down
8 changes: 5 additions & 3 deletions docs-site/src/content/docs/ko/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,11 @@ Gateway**는 URL에 계정 + 게이트웨이 id를 채워야 합니다.
Cursor는 별도의 실험적 어댑터로 추적합니다. `adapter: "cursor"`는 `ocx init`과 dashboard Add
Provider picker에 실험적 local config 항목으로 표시되며, Cursor의 static fallback model catalog
metadata를 저장합니다. Cursor access token이 설정되면 opencodex는 Cursor live HTTP/2 transport를
사용합니다. v2.7.1 폴백 목록에는 1M 컨텍스트의 `gpt-5.6-sol` / `terra` / `luna`와 500K 컨텍스트의
`grok-4.5` / `grok-4.5-fast`가 들어 있으며, 실시간 탐색 결과에 따라 현재 계정에 표시할 모델을
결정합니다. Cursor 서버가 직접 보내는 native read/write/delete/ls/grep/shell/fetch 실행은 Codex
사용합니다. v2.7.1 폴백 목록에는 1M 컨텍스트의 `gpt-5.6-sol` / `terra` / `luna`, 500K 컨텍스트의
`grok-4.5` / `grok-4.5-fast`, 262K 컨텍스트의 `kimi-k3`가 들어 있으며, 실시간 탐색 결과에 따라
현재 계정에 표시할 모델을 결정합니다. Cursor는 Kimi K3를 effort 접미사가 붙은 wire id로만
제공하므로 `cursor/kimi-k3`는 `low` / `high` / `max` 래더를 노출하고 기본값은 모델 문서의 API
기본값과 같은 `max`입니다. Cursor 서버가 직접 보내는 native read/write/delete/ls/grep/shell/fetch 실행은 Codex
승인 및 sandbox 경로를 우회하므로 기본적으로 비활성화되어 있습니다. 신뢰한 로컬 실험에서만
`~/.opencodex/config.json`의 `providers.cursor`에 `unsafeAllowNativeLocalExec: true`를 설정하세요.
대시보드에서는 **Providers → Cursor → Edit JSON**에서 설정할 수 있습니다. 전체 예시는
Expand Down
7 changes: 5 additions & 2 deletions docs-site/src/content/docs/ru/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,11 @@ Cursor отслеживается отдельно как эксперимент
`ocx init` и в селекторе Add Provider дашборда как экспериментальная запись локальной конфигурации
с метаданными статического резервного каталога моделей Cursor. Когда настроен токен доступа Cursor,
opencodex использует живой транспорт HTTP/2 Cursor. Его резервный список версии v2.7.1 включает
`gpt-5.6-sol` / `terra` / `luna` (контекст 1M) плюс `grok-4.5` / `grok-4.5-fast` (500K); живое
обнаружение решает, какие из них останутся видимыми для аккаунта. Управляемое сервером Cursor
`gpt-5.6-sol` / `terra` / `luna` (контекст 1M), `grok-4.5` / `grok-4.5-fast` (500K) и `kimi-k3`
(262K); живое обнаружение решает, какие из них останутся видимыми для аккаунта. Cursor отдаёт
Kimi K3 только через wire id с суффиксом усилия, поэтому `cursor/kimi-k3` предоставляет лестницу
`low` / `high` / `max` и по умолчанию использует `max` — как и задокументированное значение по
умолчанию в API модели. Управляемое сервером Cursor
Comment on lines +224 to +226

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the Russian case/agreement in the Cursor note.

The phrase как и задокументированное значение по умолчанию is grammatically awkward in this construction. Rephrase it so that max is explicitly stated to correspond to the documented API default.

Proposed fix
-`low` / `high` / `max` и по умолчанию использует `max` — как и задокументированное значение по
-умолчанию в API модели.
+`low` / `high` / `max` и по умолчанию использует `max`, что соответствует
+задокументированному в API модели значению по умолчанию.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Kimi K3 только через wire id с суффиксом усилия, поэтому `cursor/kimi-k3` предоставляет лестницу
`low` / `high` / `max` и по умолчанию использует `max` — как и задокументированное значение по
умолчанию в API модели. Управляемое сервером Cursor
Kimi K3 только через wire id с суффиксом усилия, поэтому `cursor/kimi-k3` предоставляет лестницу
`low` / `high` / `max` и по умолчанию использует `max`, что соответствует
задокументированному в API модели значению по умолчанию. Управляемое сервером Cursor
🧰 Tools
🪛 LanguageTool

[uncategorized] ~226-~226: Прилагательное не согласуется с существительным по падежу.
Context: ...ное значение по умолчанию в API модели. Управляемое сервером Cursor нативное выполнение read/write/d...

(Unify_Adj_NN_case)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-site/src/content/docs/ru/guides/providers.md` around lines 224 - 226,
Update the Russian Cursor note near the `cursor/kimi-k3` description to rephrase
the clause after `max`, explicitly stating that `max` corresponds to the
documented default value in the model API. Preserve the existing meaning and the
`low` / `high` / `max` ladder.

Source: Linters/SAST tools

нативное выполнение read/write/delete/ls/grep/shell/fetch по умолчанию отключено, поскольку оно
обходит путь одобрений и песочницу Codex; устанавливайте `unsafeAllowNativeLocalExec: true` в
объекте `providers.cursor` файла `~/.opencodex/config.json` только для доверенных локальных
Expand Down
6 changes: 4 additions & 2 deletions docs-site/src/content/docs/zh-cn/guides/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,10 @@ GPT-5.6 Sol/Terra/Luna 会预置在提供商的回退列表中,因此即使实
Cursor 作为单独的实验性 adapter 进行跟踪。`adapter: "cursor"` 会作为实验性本地配置出现在
`ocx init` 和 dashboard Add Provider picker 中,并保存 Cursor 的静态回退模型目录 metadata。配置
Cursor access token 后,opencodex 会使用 Cursor live HTTP/2 transport。v2.7.1 回退列表包含上下文为
1M 的 `gpt-5.6-sol` / `terra` / `luna`,以及上下文为 500K 的
`grok-4.5` / `grok-4.5-fast`;最终显示哪些模型由账号的实时发现结果决定。Cursor 服务器直接发起的
1M 的 `gpt-5.6-sol` / `terra` / `luna`、上下文为 500K 的 `grok-4.5` / `grok-4.5-fast`,以及上下文为
262K 的 `kimi-k3`;最终显示哪些模型由账号的实时发现结果决定。Cursor 只以带 effort 后缀的 wire id
提供 Kimi K3,因此 `cursor/kimi-k3` 暴露 `low` / `high` / `max` 阶梯,默认值为 `max`,与该模型
文档中的 API 默认值一致。Cursor 服务器直接发起的
native read/write/delete/ls/grep/shell/fetch 执行默认禁用,因为它会绕过 Codex 的 approval 和
sandbox 路径;只有在可信本地实验中,才应在 `~/.opencodex/config.json` 的 `providers.cursor`
对象上设置 `unsafeAllowNativeLocalExec: true`,也可以在仪表盘的 **Providers → Cursor → Edit JSON**
Expand Down
5 changes: 4 additions & 1 deletion src/adapters/cursor/discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export const CURSOR_STATIC_MODELS: readonly CursorModelInfo[] = normalizeCursorM
// the request builder appends the per-model suffix (see effort-map.ts) and reasoning models
// advertise effort so Codex exposes the tier picker. `supportsReasoningEffort` tracks whether the
// model has *selectable effort tiers* (CURSOR_MODEL_EFFORT_TIERS), NOT merely whether it reasons:
// gemini/grok/kimi/gpt-5-mini are reasoning models in the SOT but are sent bare (no tier picker).
// gemini/grok/kimi-k2.7/gpt-5-mini are reasoning models in the SOT but are sent bare (no tier picker).
...CURSOR_ROUTER_MODEL_IDS.map(id => ({ id, contextWindow: CONTEXT_200K, supportsReasoningEffort: false })),

{ id: "claude-sonnet-5", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
Expand Down Expand Up @@ -224,6 +224,9 @@ export const CURSOR_STATIC_MODELS: readonly CursorModelInfo[] = normalizeCursorM
// take PR #73's supportsReasoningEffort for glm-5.2 (its effort-map tiers landed with the PR).
{ id: "glm-5.2", contextWindow: CONTEXT_1M, supportsReasoningEffort: true },
{ id: "kimi-k2.7-code", contextWindow: CONTEXT_262K },
// kimi-k3: cursor.com/docs/models/kimi-k3; account-verified via GetUsableModels (2026-07-28) —
// ships only as effort-suffixed kimi-k3-{low,high,max}, so the tier picker is exposed.
{ id: "kimi-k3", contextWindow: CONTEXT_262K, supportsReasoningEffort: true },

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 Document Kimi K3 in the Cursor catalog

Adding cursor/kimi-k3 with selectable low / high / max tiers changes the user-visible picker and fallback catalog, but the docs-site model coverage table still describes the Cursor fallback without this model or its effort behavior. Update the English Cursor coverage documentation and keep translated locales consistent so users can discover and correctly configure the new route.

AGENTS.md reference: AGENTS.md:L96-L97

Useful? React with 👍 / 👎.

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 Preserve max as Kimi K3's catalog default

When this model is used through the Codex catalog, cursorModelReasoningEfforts supplies low / high / max but the Cursor registry supplies no modelDefaultReasoningEfforts override. Consequently, applyReasoningLevels selects high as default_reasoning_level, so an ordinary picker request explicitly sends high and never reaches the request builder's intended no-effort fallback to kimi-k3-max. Add a max default for this Cursor model, as is already done for Kimi K3 on the other provider routes, and cover the integrated catalog entry.

Useful? React with 👍 / 👎.


{ id: "grok-4.5", contextWindow: 500_000, supportsReasoningEffort: true },
{ id: "grok-4.5-fast", contextWindow: 500_000, supportsReasoningEffort: true },
Expand Down
3 changes: 3 additions & 0 deletions src/adapters/cursor/effort-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const CURSOR_MODEL_EFFORT_TIERS: Record<string, readonly string[]> = {
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
"glm-5.2": ["high", "max"],
// GetUsableModels (2026-07-28) lists kimi-k3 only as effort-suffixed kimi-k3-{low,high,max};
// the bare id returns not_found. Tiers mirror the native Kimi provider's K3 ladder.
"kimi-k3": ["low", "high", "max"],
// GetUsableModels (2026-07-09) lists grok-4.5-{medium,high,xhigh} and grok-4.5-fast-{medium,high,xhigh};
// the bare "grok-4.5-fast" id was removed upstream and now returns not_found.
"grok-4.5": ["medium", "high", "xhigh"],
Expand Down
6 changes: 6 additions & 0 deletions src/providers/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,12 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
modelContextWindows: cursorModelContextWindows(CURSOR_STATIC_MODELS),
modelInputModalities: cursorModelInputModalities(CURSOR_STATIC_MODELS),
modelReasoningEfforts: cursorModelReasoningEfforts(CURSOR_STATIC_MODELS),
// Kimi K3 documents `max` as its API default, and its Cursor ladder has no `medium`
// rung — so applyReasoningLevels' medium->high->first fallback would settle the catalog
// default on `high`, the picker would send `high` explicitly, and the request builder's
// no-effort fallback to `kimi-k3-max` would never be reached. Mirrors the other K3
// routes (kimi, kimi-code, opencode-go).
modelDefaultReasoningEfforts: { "kimi-k3": "max" },

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 Merge the Kimi default into partial Cursor maps

When an existing Cursor configuration already has modelDefaultReasoningEfforts for an unrelated model, this new default never reaches the catalog: enrichProviderFromRegistry only copies that map when the entire field is absent (src/providers/derive.ts), whereas the request router merges it per key. As a result, cursor/kimi-k3 falls back to catalog default high for such configurations even though routing knows the registry default is max. Fresh evidence after the prior finding's fix is that the newly added override remains hidden specifically by a pre-existing partial user map; merge defaults per key and cover that configuration in the catalog regression test.

Useful? React with 👍 / 👎.

// Cursor's wire protocol never forwards image parts (request-builder emits an unsupported-
// content marker), so the vision sidecar covers ALL cursor models regardless of what the
// upstream model could natively do. Live-discovered models outside the static list fall back
Expand Down
28 changes: 28 additions & 0 deletions tests/codex-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,34 @@ describe("Google Gemini catalog metadata", () => {
});
});

describe("Cursor Kimi K3 catalog default effort", () => {
// Regression for the effort-tier ladder added with cursor/kimi-k3: the Cursor ladder is
// low/high/max with NO medium rung, so applyReasoningLevels' medium -> high -> first
// preference would settle default_reasoning_level on "high" unless the registry supplies a
// default. Kimi documents `max` as K3's API default, and a "high" default makes the picker
// send high explicitly so the request builder never falls back to kimi-k3-max.
test("keeps max as the catalog default instead of falling back to high", async () => {
const cursor = {
adapter: "cursor",
authMode: "oauth" as const,
liveModels: false,
};
enrichProviderFromRegistry("cursor", cursor);
const models = await gatherRoutedModels({
port: 0,
defaultProvider: "cursor",
providers: { cursor },
});
const entry = buildCatalogEntries(nativeTemplate(), [], models)
.find(row => row.slug === "cursor/kimi-k3");

expect(entry).toBeDefined();
expect((entry?.supported_reasoning_levels as Array<{ effort: string }>).map(level => level.effort))
.toEqual(["low", "high", "max", "ultra"]);
Comment on lines +721 to +722

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the unsupported ultra tier from this regression expectation.

The Cursor effort map defines kimi-k3 as ["low", "high", "max"] (src/adapters/cursor/effort-map.ts, Line 30), and the updated provider documentation states the same ladder. This test currently asserts an extra ultra level, so it will fail against the intended catalog or conceal a source/catalog contract drift.

Proposed fix
     expect((entry?.supported_reasoning_levels as Array<{ effort: string }>).map(level => level.effort))
-      .toEqual(["low", "high", "max", "ultra"]);
+      .toEqual(["low", "high", "max"]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expect((entry?.supported_reasoning_levels as Array<{ effort: string }>).map(level => level.effort))
.toEqual(["low", "high", "max", "ultra"]);
expect((entry?.supported_reasoning_levels as Array<{ effort: string }>).map(level => level.effort))
.toEqual(["low", "high", "max"]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/codex-catalog.test.ts` around lines 711 - 712, Update the regression
expectation in the supported reasoning levels assertion to remove the
unsupported "ultra" tier, leaving only "low", "high", and "max" for the kimi-k3
effort map.

expect(entry?.default_reasoning_level).toBe("max");
});
});

describe("configured CatalogModel displayName -> catalog display_name", () => {
test("a routed CatalogModel displayName becomes the catalog display_name", () => {
const model = { provider: "deepseek", id: "deepseek-v4", displayName: "DeepSeek V4", owned_by: "deepseek" };
Expand Down
1 change: 1 addition & 0 deletions tests/cursor-discovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe("Cursor discovery metadata", () => {
expect(ids).toContain("gpt-5.5");
expect(ids).toContain("glm-5.2");
expect(ids).toContain("kimi-k2.7-code");
expect(ids).toContain("kimi-k3");
expect(ids).toContain("claude-opus-4-7-fast");
// 260709 refresh: stale ids dropped from the static seed (cursor.com docs); gpt-5.5-extra
// stays — it survives the live GetUsableModels filter (004_live_snapshot.md).
Expand Down
10 changes: 10 additions & 0 deletions tests/cursor-effort-suffix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ describe("Cursor per-model reasoning-effort suffix", () => {
expect(modelIdFor("cursor/grok-4.5-fast", "xhigh")).toBe("grok-4.5-fast-xhigh");
});

test("kimi-k3 maps to its live effort-suffixed variants", () => {
expect(modelIdFor("cursor/kimi-k3", "low")).toBe("kimi-k3-low");
expect(modelIdFor("cursor/kimi-k3", "medium")).toBe("kimi-k3-high");
expect(modelIdFor("cursor/kimi-k3", "high")).toBe("kimi-k3-high");
expect(modelIdFor("cursor/kimi-k3", "max")).toBe("kimi-k3-max");
// Bare id (no requested effort) resolves to the model's top tier; upstream rejects the bare id.
expect(modelIdFor("cursor/kimi-k3")).toBe("kimi-k3-max");
expect(cursorModelEffortLadder("kimi-k3")).toEqual(["low", "high", "max"]);
});

test("model ladders are deduped and sorted in canonical Codex order", () => {
expect(cursorModelEffortLadder("claude-opus-4-8")).toEqual(["low", "medium", "high", "xhigh", "max"]);
expect(cursorModelEffortLadder("glm-5.2")).toEqual(["high", "max"]);
Expand Down
Loading