@oh-my-pi/pi-catalog 16.5.0 → 16.5.2
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/CHANGELOG.md +14 -0
- package/dist/types/provider-models/descriptors.d.ts +2 -0
- package/dist/types/types.d.ts +2 -0
- package/package.json +3 -3
- package/src/discovery/cursor.ts +3 -0
- package/src/model-manager.ts +22 -7
- package/src/model-thinking.ts +8 -4
- package/src/models.json +2 -5
- package/src/provider-models/descriptors.ts +2 -0
- package/src/provider-models/openai-compat.ts +12 -0
- package/src/provider-models/special.ts +3 -0
- package/src/types.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.5.2] - 2026-07-14
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed OpenCode Zen and Go discovery to replace stale bundled models with each provider's live model catalog.
|
|
10
|
+
|
|
11
|
+
## [16.5.1] - 2026-07-14
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Fixed reasoning effort mapping for Z.ai GLM-5.2 on the Anthropic messages endpoint to correctly use the two-tier scale (high, max) and emit output_config.effort.
|
|
16
|
+
- Fixed an issue where stale cached model limits would override updated static catalog limits after a catalog fingerprint mismatch.
|
|
17
|
+
- Fixed Cursor discovery to correctly preserve GetUsableModels max-mode metadata for premium models and invalidate stale cache entries.
|
|
18
|
+
|
|
5
19
|
## [16.4.3] - 2026-07-11
|
|
6
20
|
|
|
7
21
|
### Fixed
|
|
@@ -264,11 +264,13 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
264
264
|
readonly defaultModel: "kimi-k2.7-code";
|
|
265
265
|
readonly envVars: readonly ["OPENCODE_API_KEY"];
|
|
266
266
|
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<import("../index.js").Api, unknown>;
|
|
267
|
+
readonly dynamicModelsAuthoritative: true;
|
|
267
268
|
}, {
|
|
268
269
|
readonly id: "opencode-zen";
|
|
269
270
|
readonly defaultModel: "claude-opus-4-8";
|
|
270
271
|
readonly envVars: readonly ["OPENCODE_API_KEY"];
|
|
271
272
|
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<import("../index.js").Api, unknown>;
|
|
273
|
+
readonly dynamicModelsAuthoritative: true;
|
|
272
274
|
}, {
|
|
273
275
|
readonly id: "openrouter";
|
|
274
276
|
readonly defaultModel: "openai/gpt-5.5";
|
package/dist/types/types.d.ts
CHANGED
|
@@ -590,6 +590,8 @@ export interface Model<TApi extends Api = Api> {
|
|
|
590
590
|
supportsTools?: boolean;
|
|
591
591
|
/** GitLab Duo Workflow root namespace selected during catalog discovery. */
|
|
592
592
|
gitlabDuoWorkflowRootNamespaceId?: string;
|
|
593
|
+
/** Cursor `max_mode` request flag returned by `GetUsableModels` for premium models that require max mode. */
|
|
594
|
+
cursorMaxMode?: boolean;
|
|
593
595
|
cost: {
|
|
594
596
|
input: number;
|
|
595
597
|
output: number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-catalog",
|
|
4
|
-
"version": "16.5.
|
|
4
|
+
"version": "16.5.2",
|
|
5
5
|
"description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@bufbuild/protobuf": "^2.12.1",
|
|
37
|
-
"@oh-my-pi/pi-utils": "16.5.
|
|
37
|
+
"@oh-my-pi/pi-utils": "16.5.2",
|
|
38
38
|
"arktype": "2.2.3",
|
|
39
39
|
"zod": "^4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@oh-my-pi/pi-ai": "16.5.
|
|
42
|
+
"@oh-my-pi/pi-ai": "16.5.2",
|
|
43
43
|
"@types/bun": "^1.3.14"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
package/src/discovery/cursor.ts
CHANGED
|
@@ -35,6 +35,7 @@ const CursorModelDetailsSchema = type({
|
|
|
35
35
|
displayModelId: OptionalDisplayNameSchema.default(undefined),
|
|
36
36
|
aliases: CursorAliasesSchema.default(() => []),
|
|
37
37
|
"thinkingDetails?": "unknown",
|
|
38
|
+
maxMode: "boolean = false",
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
const CursorModelsInnerSchema = type("unknown[]");
|
|
@@ -290,6 +291,7 @@ function normalizeCursorModel(
|
|
|
290
291
|
name,
|
|
291
292
|
baseUrl: baseUrlOverride ?? reference.baseUrl,
|
|
292
293
|
reasoning,
|
|
294
|
+
cursorMaxMode: details.maxMode,
|
|
293
295
|
};
|
|
294
296
|
}
|
|
295
297
|
return {
|
|
@@ -303,6 +305,7 @@ function normalizeCursorModel(
|
|
|
303
305
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
304
306
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
|
305
307
|
maxTokens: DEFAULT_MAX_TOKENS,
|
|
308
|
+
cursorMaxMode: details.maxMode,
|
|
306
309
|
};
|
|
307
310
|
}
|
|
308
311
|
|
package/src/model-manager.ts
CHANGED
|
@@ -152,8 +152,9 @@ export async function resolveProviderModels<TApi extends Api = Api, TModelsDevPa
|
|
|
152
152
|
const dynamicFetchSucceeded = fetchedDynamicModels !== null;
|
|
153
153
|
const cacheModels = dynamicFetchSucceeded
|
|
154
154
|
? []
|
|
155
|
-
:
|
|
155
|
+
: prepareCacheModelsForStaticMismatch(
|
|
156
156
|
normalizeModelList<TApi>(cache?.models ?? []),
|
|
157
|
+
staticModels,
|
|
157
158
|
cacheFingerprintMatches,
|
|
158
159
|
options.dropCachedModelIdsOnStaticMismatch,
|
|
159
160
|
);
|
|
@@ -188,8 +189,9 @@ export async function resolveProviderModels<TApi extends Api = Api, TModelsDevPa
|
|
|
188
189
|
collapseBuiltModelVariants(
|
|
189
190
|
mergeDynamicModels(
|
|
190
191
|
mergeModelSources(staticModels, modelsDevModels),
|
|
191
|
-
|
|
192
|
+
prepareCacheModelsForStaticMismatch(
|
|
192
193
|
normalizeModelList<TApi>(latestCache?.models ?? cache?.models ?? []),
|
|
194
|
+
staticModels,
|
|
193
195
|
cacheFingerprintMatches,
|
|
194
196
|
options.dropCachedModelIdsOnStaticMismatch,
|
|
195
197
|
),
|
|
@@ -260,16 +262,29 @@ function shouldFetchRemoteSources(
|
|
|
260
262
|
return false;
|
|
261
263
|
}
|
|
262
264
|
|
|
263
|
-
function
|
|
265
|
+
function prepareCacheModelsForStaticMismatch<TApi extends Api>(
|
|
264
266
|
models: readonly Model<TApi>[],
|
|
267
|
+
staticModels: readonly Model<TApi>[],
|
|
265
268
|
cacheFingerprintMatches: boolean,
|
|
266
269
|
ids: readonly string[] | undefined,
|
|
267
270
|
): Model<TApi>[] {
|
|
268
|
-
if (
|
|
269
|
-
return
|
|
271
|
+
if (models.length === 0) {
|
|
272
|
+
return [];
|
|
273
|
+
}
|
|
274
|
+
if (cacheFingerprintMatches) {
|
|
275
|
+
return [...models];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const droppedIds = ids && ids.length > 0 ? new Set(ids) : undefined;
|
|
279
|
+
const staticIds = staticModels.length > 0 ? new Set(staticModels.map(model => model.id)) : undefined;
|
|
280
|
+
const sanitizedModels: Model<TApi>[] = [];
|
|
281
|
+
for (const model of models) {
|
|
282
|
+
if (droppedIds?.has(model.id)) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
sanitizedModels.push(staticIds?.has(model.id) ? { ...model, contextWindow: null, maxTokens: null } : model);
|
|
270
286
|
}
|
|
271
|
-
|
|
272
|
-
return models.filter(model => !droppedIds.has(model.id));
|
|
287
|
+
return sanitizedModels;
|
|
273
288
|
}
|
|
274
289
|
|
|
275
290
|
function mergeModelSources<TApi extends Api>(...sources: readonly (readonly Model<TApi>[])[]): Model<TApi>[] {
|
package/src/model-thinking.ts
CHANGED
|
@@ -318,7 +318,7 @@ function getModelDefinedEfforts<TApi extends Api>(
|
|
|
318
318
|
}
|
|
319
319
|
if (
|
|
320
320
|
isZaiThinkingFormat(compat) ||
|
|
321
|
-
|
|
321
|
+
isAnthropicMessagesGlm52ReasoningEffortModel(spec) ||
|
|
322
322
|
isOllamaCloudGlm52ReasoningEffortModel(spec) ||
|
|
323
323
|
spec.provider === "baseten"
|
|
324
324
|
) {
|
|
@@ -394,8 +394,12 @@ function isOllamaCloudGlm52ReasoningEffortModel<TApi extends Api>(spec: ModelSpe
|
|
|
394
394
|
return spec.api === "ollama-chat" && spec.provider === "ollama-cloud" && isGlm52ReasoningEffortModelId(spec.id);
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
function
|
|
398
|
-
return
|
|
397
|
+
function isAnthropicMessagesGlm52ReasoningEffortModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
398
|
+
return (
|
|
399
|
+
spec.api === "anthropic-messages" &&
|
|
400
|
+
(spec.provider === "umans" || spec.provider === "zai") &&
|
|
401
|
+
isGlm52ReasoningEffortModelId(spec.id)
|
|
402
|
+
);
|
|
399
403
|
}
|
|
400
404
|
|
|
401
405
|
function isMinimaxReasoningModelOnAnthropicEndpoint<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
@@ -617,7 +621,7 @@ function inferThinkingControlMode<TApi extends Api>(
|
|
|
617
621
|
if (isMinimaxReasoningModelOnAnthropicEndpoint(spec)) {
|
|
618
622
|
return "anthropic-adaptive";
|
|
619
623
|
}
|
|
620
|
-
if (
|
|
624
|
+
if (isAnthropicMessagesGlm52ReasoningEffortModel(spec)) {
|
|
621
625
|
return "anthropic-budget-effort";
|
|
622
626
|
}
|
|
623
627
|
if (parsedModel.family === "anthropic") {
|
package/src/models.json
CHANGED
|
@@ -88484,13 +88484,10 @@
|
|
|
88484
88484
|
"contextWindow": 1000000,
|
|
88485
88485
|
"maxTokens": 131072,
|
|
88486
88486
|
"thinking": {
|
|
88487
|
-
"mode": "budget",
|
|
88487
|
+
"mode": "anthropic-budget-effort",
|
|
88488
88488
|
"efforts": [
|
|
88489
|
-
"minimal",
|
|
88490
|
-
"low",
|
|
88491
|
-
"medium",
|
|
88492
88489
|
"high",
|
|
88493
|
-
"
|
|
88490
|
+
"max"
|
|
88494
88491
|
]
|
|
88495
88492
|
}
|
|
88496
88493
|
},
|
|
@@ -311,12 +311,14 @@ export const CATALOG_PROVIDERS = [
|
|
|
311
311
|
defaultModel: "kimi-k2.7-code",
|
|
312
312
|
envVars: ["OPENCODE_API_KEY"],
|
|
313
313
|
createModelManagerOptions: (config: ModelManagerConfig) => opencodeGoModelManagerOptions(config),
|
|
314
|
+
dynamicModelsAuthoritative: true,
|
|
314
315
|
},
|
|
315
316
|
{
|
|
316
317
|
id: "opencode-zen",
|
|
317
318
|
defaultModel: "claude-opus-4-8",
|
|
318
319
|
envVars: ["OPENCODE_API_KEY"],
|
|
319
320
|
createModelManagerOptions: (config: ModelManagerConfig) => opencodeZenModelManagerOptions(config),
|
|
321
|
+
dynamicModelsAuthoritative: true,
|
|
320
322
|
},
|
|
321
323
|
{
|
|
322
324
|
id: "openrouter",
|
|
@@ -2036,6 +2036,16 @@ function openCodeBaseUrlForApi(api: Api, basePath: string): string {
|
|
|
2036
2036
|
return api === "anthropic-messages" ? basePath : `${basePath}/v1`;
|
|
2037
2037
|
}
|
|
2038
2038
|
|
|
2039
|
+
function openCodeModelCacheProviderId(
|
|
2040
|
+
providerId: "opencode-go" | "opencode-zen",
|
|
2041
|
+
apiKey: string | undefined,
|
|
2042
|
+
discoveryBaseUrl: string,
|
|
2043
|
+
): string {
|
|
2044
|
+
// OpenCode catalogs are entitlement-scoped; isolate authoritative rows by credential and endpoint.
|
|
2045
|
+
const scope = `${apiKey ?? ""}\u0000${discoveryBaseUrl}`;
|
|
2046
|
+
return `${providerId}:models-v1:${Bun.hash(scope).toString(36)}`;
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2039
2049
|
function openCodeModelManagerOptions(
|
|
2040
2050
|
providerId: "opencode-go" | "opencode-zen",
|
|
2041
2051
|
defaultBasePath: string,
|
|
@@ -2047,6 +2057,8 @@ function openCodeModelManagerOptions(
|
|
|
2047
2057
|
const references = createBundledReferenceMap<Api>(providerId);
|
|
2048
2058
|
return {
|
|
2049
2059
|
providerId,
|
|
2060
|
+
cacheProviderId: openCodeModelCacheProviderId(providerId, apiKey, discoveryBaseUrl),
|
|
2061
|
+
dynamicModelsAuthoritative: true,
|
|
2050
2062
|
...(apiKey && {
|
|
2051
2063
|
fetchDynamicModels: () =>
|
|
2052
2064
|
fetchOpenAICompatibleModels<Api>({
|
|
@@ -42,10 +42,13 @@ export interface CursorModelManagerConfig {
|
|
|
42
42
|
clientVersion?: string;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
const CURSOR_CACHE_PROVIDER_ID = "cursor:max-mode-v2";
|
|
46
|
+
|
|
45
47
|
export function cursorModelManagerOptions(config: CursorModelManagerConfig = {}): ModelManagerOptions<"cursor-agent"> {
|
|
46
48
|
const { apiKey, baseUrl, clientVersion } = config;
|
|
47
49
|
return {
|
|
48
50
|
providerId: "cursor",
|
|
51
|
+
cacheProviderId: CURSOR_CACHE_PROVIDER_ID,
|
|
49
52
|
...(apiKey
|
|
50
53
|
? {
|
|
51
54
|
fetchDynamicModels: async () => {
|
package/src/types.ts
CHANGED
|
@@ -718,6 +718,8 @@ export interface Model<TApi extends Api = Api> {
|
|
|
718
718
|
supportsTools?: boolean;
|
|
719
719
|
/** GitLab Duo Workflow root namespace selected during catalog discovery. */
|
|
720
720
|
gitlabDuoWorkflowRootNamespaceId?: string;
|
|
721
|
+
/** Cursor `max_mode` request flag returned by `GetUsableModels` for premium models that require max mode. */
|
|
722
|
+
cursorMaxMode?: boolean;
|
|
721
723
|
cost: {
|
|
722
724
|
input: number; // $/million tokens
|
|
723
725
|
output: number; // $/million tokens
|