1import type { ModelSelection as CursorSdkModelSelection, ModelParameterValue } from "@cursor/sdk";
2import type { ModelSelection, ServerProviderModel } from "@t3tools/contracts";
3import { getProviderOptionCurrentValue } from "@t3tools/shared/model";
4
5const CURSOR_SDK_PARAMETER_TO_PROVIDER_OPTION: Readonly<Record<string, string>> = {
6 context: "contextWindow",
7 fast: "fastMode",
8};
9
10const PROVIDER_OPTION_TO_CURSOR_SDK_PARAMETER: Readonly<Record<string, string>> = {
11 contextWindow: "context",
12 fastMode: "fast",
13};
14
15export function cursorSdkProviderOptionId(parameterId: string): string {
16 return CURSOR_SDK_PARAMETER_TO_PROVIDER_OPTION[parameterId] ?? parameterId;
17}
18
19function cursorSdkParameterId(providerOptionId: string): string {
20 return PROVIDER_OPTION_TO_CURSOR_SDK_PARAMETER[providerOptionId] ?? providerOptionId;
21}
22
23export function cursorSdkParameterPriority(parameterId: string): number {
24 switch (parameterId) {
25 case "effort":
26 case "reasoning":
27 return 0;
28 case "context":
29 return 1;
30 case "fast":
31 return 2;
32 case "thinking":
33 return 3;
34 default:
35 return 4;
36 }
37}
38
39export function cursorContextWindowTokens(
40 modelSelection: ModelSelection,
41 models: ReadonlyArray<ServerProviderModel>,
42): number | undefined {
43 // The SDK forwards explicit values even when the catalog does not list them.
44 const explicit = modelSelection.options?.find((option) => option.id === "contextWindow");
45 let value = explicit?.value;
46 if (explicit === undefined) {
47 const descriptor = models
48 .find((model) => model.slug === modelSelection.model)
49 ?.capabilities?.optionDescriptors?.find((option) => option.id === "contextWindow");
50 value = getProviderOptionCurrentValue(descriptor);
51 }
52 const match = /^(\d+)([km])$/i.exec(typeof value === "string" ? value.trim() : "");
53 if (match === null) return undefined;
54 const tokens = Number(match[1]) * (match[2]?.toLowerCase() === "m" ? 1_000_000 : 1_000);
55 return Number.isSafeInteger(tokens) && tokens > 0 ? tokens : undefined;
56}
57
58export function cursorSdkModelSelection(modelSelection: ModelSelection): CursorSdkModelSelection {
59 return {
60 id: modelSelection.model === "auto" ? "default" : modelSelection.model,
61 ...(modelSelection.options === undefined || modelSelection.options.length === 0
62 ? {}
63 : {
64 params: modelSelection.options.map((option): ModelParameterValue => ({
65 id: cursorSdkParameterId(option.id),
66 value: String(option.value),
67 })),
68 }),
69 };
70}