Skip to content

Commit edbeb8e

Browse files
committed
feat(model): per-model output limits for high-output frontier models
1 parent 02a5d6a commit edbeb8e

2 files changed

Lines changed: 46 additions & 1 deletion

File tree

‎src/plugin/model-v2.ts‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,38 @@ export function resolveCost(modelId: string): {
146146
return best ?? DEFAULT_COST;
147147
}
148148

149+
/**
150+
* Per-model output token limits, keyed by model id prefix. The Cursor SDK
151+
* doesn't expose output limits, so these are best-known values. 32K default
152+
* (the previous hardcoded value); 64K for frontier models known to support
153+
* higher output. Low priority — the TUI doesn't display output limit.
154+
*/
155+
const MODEL_OUTPUT_LIMITS: Record<string, number> = {
156+
"claude-opus-4-7": 64_000,
157+
"claude-opus-4-8": 64_000,
158+
"claude-opus-5": 64_000,
159+
"claude-fable-5": 64_000,
160+
"gpt-5.5": 64_000,
161+
"gpt-5.6-sol": 64_000,
162+
};
163+
164+
const DEFAULT_OUTPUT_LIMIT = 32_000;
165+
166+
/**
167+
* Resolve a model's output limit by longest-prefix match. Falls back to 32K.
168+
*/
169+
export function resolveOutputLimit(modelId: string): number {
170+
let best: number | undefined;
171+
let bestLen = 0;
172+
for (const [prefix, limit] of Object.entries(MODEL_OUTPUT_LIMITS)) {
173+
if (modelId.startsWith(prefix) && prefix.length > bestLen) {
174+
best = limit;
175+
bestLen = prefix.length;
176+
}
177+
}
178+
return best ?? DEFAULT_OUTPUT_LIMIT;
179+
}
180+
149181
/**
150182
* Build opencode's rich runtime `Model` objects from discovered Cursor models.
151183
* Used by the auth-aware `provider.models()` hook. Fields opencode does not get
@@ -174,7 +206,7 @@ export function buildModelV2Map(items: ModelListItem[]): Record<string, ModelV2>
174206
const c = resolveCost(item.id);
175207
return { input: c.input, output: c.output, cache: { read: c.cacheRead, write: c.cacheWrite } };
176208
})(),
177-
limit: { context: resolveContextLimit(item.id), output: 32_000 },
209+
limit: { context: resolveContextLimit(item.id), output: resolveOutputLimit(item.id) },
178210
status: "active",
179211
options: Object.keys(params).length > 0 ? { params } : {},
180212
headers: {},

‎test/model-v2.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ describe("buildModelV2Map", () => {
7676
});
7777
});
7878

79+
it("sets output limit from per-model map for known models", () => {
80+
const map = buildModelV2Map([
81+
{ id: "claude-opus-5", displayName: "Claude Opus 5" },
82+
{ id: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6" },
83+
{ id: "gpt-5.5", displayName: "GPT-5.5" },
84+
{ id: "composer-2.5", displayName: "Composer 2.5" },
85+
]);
86+
expect(map["claude-opus-5"]!.limit.output).toBe(64_000);
87+
expect(map["claude-sonnet-4-6"]!.limit.output).toBe(32_000);
88+
expect(map["gpt-5.5"]!.limit.output).toBe(64_000);
89+
expect(map["composer-2.5"]!.limit.output).toBe(32_000);
90+
});
91+
7992
it("uses $0 cost for Cursor Models pool models", () => {
8093
const map = buildModelV2Map([
8194
{ id: "composer-2.5", displayName: "Composer 2.5" },

0 commit comments

Comments
 (0)