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
9 changes: 7 additions & 2 deletions src/adapters/cursor/discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,15 @@ export const CURSOR_STATIC_MODELS: readonly CursorModelInfo[] = normalizeCursorM
{ id: "claude-4.6-opus", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-4.6-sonnet", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-opus-4-7", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
// opus-4-7-fast: effort-suffix tiers unverified -> no tier picker; sent bare like live-only ids.
{ id: "claude-opus-4-7-fast", contextWindow: CONTEXT_200K },
// Opus Fast families: live GetUsableModels (260822) lists ONLY effort-suffixed wire ids
// ({base-without-fast}-{effort}-fast; the bare id returns not_found), so every entry
// carries a tier picker. Live-verified: claude-opus-4-8-high-fast completed a turn.
// Tiers per the 260822 dump (devlog 260822_senpi_cursor_transfer/300).
{ id: "claude-opus-4-7-fast", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-opus-4-8-fast", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-opus-4-8", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-opus-5", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-opus-5-fast", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },
{ id: "claude-fable-5", contextWindow: CONTEXT_200K, supportsReasoningEffort: true },

{ id: "composer-1", contextWindow: CONTEXT_200K },
Expand Down
6 changes: 6 additions & 0 deletions src/adapters/cursor/effort-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ const CURSOR_MODEL_EFFORT_TIERS: Record<string, readonly string[]> = {
// against Anthropic's effort ladder docs and Cursor's live model lineup.
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
"claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"],
// Opus Fast tiers from the 260822 GetUsableModels dump (devlog .../300): the wire
// exposes {base-without-fast}-{effort}-fast only; suffix derivation at the bottom of
// this file produces those ids. opus-5-fast has no xhigh/max (non-thinking) yet.
"claude-opus-4-7-fast": ["low", "medium", "high", "xhigh", "max"],
"claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"],
"claude-opus-4-8-fast": ["low", "medium", "high", "xhigh", "max"],
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
"claude-opus-5-fast": ["low", "medium", "high"],
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
"glm-5.2": ["high", "max"],
// 260814 preemptive: glm-5.3 seeded ahead of Cursor's lineup update. Unlike 5.2, Z.AI folds
Expand Down
31 changes: 31 additions & 0 deletions tests/cursor-static-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,34 @@ describe("Cursor static Codex catalog", () => {
}
});
});

describe("Opus Fast catalog families (devlog 300, live-verified 260822)", () => {
test("all three -fast families are present with tier pickers", async () => {
const { CURSOR_STATIC_MODELS } = await import("../src/adapters/cursor/discovery");
for (const id of ["claude-opus-4-7-fast", "claude-opus-4-8-fast", "claude-opus-5-fast"]) {
const entry = CURSOR_STATIC_MODELS.find(model => model.id === id);
expect(entry, `${id} missing from static catalog`).toBeDefined();
expect(entry?.supportsReasoningEffort, `${id} must carry a tier picker — the bare wire id is not_found`).toBe(true);
}
});

test("tier ladders match the 260822 GetUsableModels dump", async () => {
const { cursorModelEffortLadder } = await import("../src/adapters/cursor/effort-map");
expect(cursorModelEffortLadder("claude-opus-4-7-fast")).toEqual(["low", "medium", "high", "xhigh", "max"]);
expect(cursorModelEffortLadder("claude-opus-4-8-fast")).toEqual(["low", "medium", "high", "xhigh", "max"]);
expect(cursorModelEffortLadder("claude-opus-5-fast")).toEqual(["low", "medium", "high"]);
});

test("wire-id derivation produces the live-verified suffixed forms and never a bare -fast id", async () => {
const { cursorWireModelIdWithEffort, cursorEffortSuffix } = await import("../src/adapters/cursor/effort-map");
expect(cursorWireModelIdWithEffort("claude-opus-4-8-fast", "high")).toBe("claude-opus-4-8-high-fast");
expect(cursorWireModelIdWithEffort("claude-opus-5-fast", "medium")).toBe("claude-opus-5-medium-fast");
expect(cursorWireModelIdWithEffort("claude-opus-4-7-fast", "max")).toBe("claude-opus-4-7-max-fast");
// No-effort requests must still resolve to a suffix (bare id is not_found on the wire).
for (const id of ["claude-opus-4-7-fast", "claude-opus-4-8-fast", "claude-opus-5-fast"]) {
expect(cursorEffortSuffix(id, undefined), `${id} must never send bare`).toBeTruthy();
}
// Out-of-ladder effort clamps within the family ladder (opus-5-fast has no xhigh).
expect(cursorEffortSuffix("claude-opus-5-fast", "xhigh")).toBe("high");
});
});
Loading