ocx-cursor 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ocx-cursor",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Use OpenCodex models in Cursor through an authenticated HTTPS gateway",
5
5
  "keywords": [
6
6
  "opencodex",
package/src/catalog.mjs CHANGED
@@ -73,38 +73,30 @@ export function priorityModelIds(catalogFile = configuredCodexCatalogFile()) {
73
73
  }
74
74
  }
75
75
 
76
- export function codexNativeModels(catalogFile = configuredCodexCatalogFile()) {
77
- try {
78
- const payload = JSON.parse(readFileSync(catalogFile, "utf8"));
79
- return payload.models
80
- .filter((model) => typeof model?.slug === "string"
81
- && !model.slug.includes("/")
82
- && model.visibility === "list"
83
- && model.supported_in_api === true
84
- && model.opencodex_capability_provenance === undefined)
85
- .map((model) => ({
86
- id: model.slug,
87
- owned_by: "openai",
88
- capabilities: {
89
- input_modalities: model.input_modalities,
90
- context_length: model.context_window,
91
- max_output_tokens: model.max_output_tokens,
92
- reasoning_effort: model.supported_reasoning_levels?.map(({ effort }) => effort),
93
- },
94
- }));
95
- } catch {
96
- return [];
97
- }
98
- }
99
-
100
76
  export function normalizeActiveCatalog(configured, active, fastModelIds = new Set()) {
101
77
  const configuredById = new Map(configured
102
78
  .filter((model) => typeof model.provider === "string" && typeof model.model === "string")
103
79
  .map((model) => [`${model.provider}/${model.model}`, model]));
104
80
  const models = new Map();
81
+ const activeIds = new Set(active.filter((model) => model?.owned_by !== "opencodex").map((model) => model?.id));
82
+ const configuredIds = new Set(configured.flatMap((model) => [
83
+ `${model.provider}/${model.model}`,
84
+ model.alias,
85
+ ...(model.provider === "openai" ? [model.model] : []),
86
+ ]));
87
+ // OpenCodex publishes synthetic --fast rows for clients without a Fast toggle.
88
+ // Preserve exact configured IDs and real product names ending in a single -fast.
89
+ const fastRows = new Set(active.filter((model) => (
90
+ typeof model?.id === "string"
91
+ && model.owned_by !== "opencodex"
92
+ && model.id.endsWith("--fast")
93
+ && !configuredIds.has(model.id)
94
+ && activeIds.has(model.id.slice(0, -"--fast".length))
95
+ )).map((model) => model.id));
105
96
 
106
97
  for (const model of active) {
107
98
  if (typeof model?.id !== "string" || model.owned_by === "opencodex") continue;
99
+ if (fastRows.has(model.id)) continue;
108
100
  const configuredModel = configuredById.get(model.id);
109
101
  const provider = model.id.includes("/") ? model.id.split("/", 1)[0] : String(model.owned_by || "openai").toLowerCase();
110
102
  if (provider === "cursor") continue;
@@ -123,7 +115,7 @@ export function normalizeActiveCatalog(configured, active, fastModelIds = new Se
123
115
  maxOutputTokens: model.capabilities?.max_output_tokens,
124
116
  inputModalities,
125
117
  reasoningEfforts: sanitizeEfforts(model.id, configuredModel?.reasoningEfforts ?? model.capabilities?.reasoning_effort),
126
- supportsFast: fastModelIds.has(model.id),
118
+ supportsFast: fastModelIds.has(model.id) || fastRows.has(`${model.id}--fast`),
127
119
  });
128
120
  }
129
121
 
@@ -168,7 +160,7 @@ export async function buildActiveCatalog(options = {}) {
168
160
  const codexCatalogFile = options.codexCatalogFile || configuredCodexCatalogFile();
169
161
  return normalizeActiveCatalog(
170
162
  configuredModels(options.ocxBin),
171
- [...await activeModels(options.fetchImpl), ...codexNativeModels(codexCatalogFile)],
163
+ await activeModels(options.fetchImpl),
172
164
  options.fastModelIds || priorityModelIds(codexCatalogFile),
173
165
  );
174
166
  }
@@ -186,6 +186,17 @@ function syncSelectedModel(state, catalog) {
186
186
  const composer = state.aiSettings?.modelConfig?.composer;
187
187
  if (!composer || !Array.isArray(composer.selectedModels)) return;
188
188
  const byAlias = new Map(catalog.map((model) => [model.alias, model]));
189
+ for (const selected of composer.selectedModels) {
190
+ if (typeof selected?.modelId !== "string" || byAlias.has(selected.modelId)
191
+ || !selected.modelId.endsWith("--fast")) continue;
192
+ const base = byAlias.get(selected.modelId.slice(0, -"--fast".length));
193
+ if (!base?.supportsFast) continue;
194
+ selected.modelId = base.alias;
195
+ selected.parameters = [
196
+ ...(Array.isArray(selected.parameters) ? selected.parameters.filter(({ id }) => id !== "fast") : []),
197
+ { id: "fast", value: "true" },
198
+ ];
199
+ }
189
200
  composer.selectedModels = composer.selectedModels.filter((selected) => (
190
201
  typeof selected?.modelId !== "string" || !selected.modelId.startsWith(managedPrefix) || byAlias.has(selected.modelId)
191
202
  ));