@oh-my-pi/pi-catalog 15.12.2 → 15.12.4
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 +19 -0
- package/dist/types/provider-models/openai-compat.d.ts +2 -1
- package/dist/types/types.d.ts +2 -2
- package/dist/types/utils.d.ts +3 -0
- package/package.json +4 -4
- package/src/discovery/antigravity.ts +1 -1
- package/src/discovery/codex.ts +1 -1
- package/src/discovery/cursor.ts +1 -1
- package/src/discovery/gemini.ts +6 -5
- package/src/discovery/openai-compatible.ts +3 -4
- package/src/identity/equivalence.ts +2 -2
- package/src/identity/reference.ts +2 -2
- package/src/model-cache.ts +9 -5
- package/src/model-manager.ts +7 -5
- package/src/models.json +3184 -2696
- package/src/provider-models/bundled-references.ts +2 -2
- package/src/provider-models/openai-compat.ts +174 -54
- package/src/types.ts +2 -2
- package/src/utils.ts +9 -1
- package/src/variant-collapse.ts +7 -2
- package/dist/types/provider-models/discovery-constants.d.ts +0 -11
- package/src/provider-models/discovery-constants.ts +0 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.12.4] - 2026-06-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added bundled Fireworks models `deepseek-v4-flash`, `kimi-k2.7-code`, `minimax-m2.5`, `minimax-m3`, `nemotron-3-ultra-nvfp4`, `qwen3.6-plus`, and `qwen3.7-plus`
|
|
10
|
+
- Changed
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Model `contextWindow`/`maxTokens` are now `number | null`; discovery emits `null` when a provider reports no limit, replacing the `222222`/`8888` (`UNK_CONTEXT_WINDOW`/`UNK_MAX_TOKENS`) sentinels (now removed). Bundled `models.json` unknown limits are `null`.
|
|
15
|
+
- Changed the `github-copilot` model context window to `524288` tokens
|
|
16
|
+
- Changed Fireworks model discovery to source the control-plane `List Models` API (`GET /v1/accounts/fireworks/models?filter=supports_serverless=true`) instead of the OpenAI-compatible `/v1/models` inference listing. The inference endpoint returns a sparse, account-specific subset that omits on-demand serverless models (e.g. `kimi-k2.7-code`), so newly published serverless models stayed invisible in the picker until hand-added to the bundled catalog. The control-plane catalog enumerates every serverless model with capability metadata (`supportsServerless`/`supportsTools`/`supportsImageInput`/`contextLength`/`displayName`), paginated and filtered to tool-capable `READY` entries, then merged with bundled/models.dev references — the Kimi K2 max-output clamp and DeepSeek V4 thinking-toggle strip are preserved, and unbundled models default to reasoning so `buildModel` derives the Fireworks effort map. New serverless releases now surface automatically with no catalog edits.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Filled missing `contextWindow` and `maxTokens` in generated `models.json` for proxy/reseller variants by inheriting limits from canonical-family and segment-reference models
|
|
21
|
+
- Ignored zero-cost `x-ai` subscription entries as reference sources when backfilling limits so inflated values are not propagated
|
|
22
|
+
- Fixed the model cache opening with `PRAGMA journal_mode=WAL` before `PRAGMA busy_timeout`, so concurrent omp startups could crash inside `getDb()` on `SQLITE_BUSY` during WAL recovery instead of waiting through the transient lock. The busy handler is now installed before the first lock-taking statement ([#2421](https://github.com/can1357/oh-my-pi/issues/2421)).
|
|
23
|
+
|
|
5
24
|
## [15.11.8] - 2026-06-12
|
|
6
25
|
|
|
7
26
|
### Fixed
|
|
@@ -165,6 +165,7 @@ export declare function isFireworksKimiK2ModelId(modelId: string): boolean;
|
|
|
165
165
|
* on Fireworks-backed providers, leaving every other model untouched.
|
|
166
166
|
*/
|
|
167
167
|
export declare function clampFireworksKimiMaxTokens(modelId: string, candidate: number): number;
|
|
168
|
+
export declare function clampFireworksKimiMaxTokens(modelId: string, candidate: number | null): number | null;
|
|
168
169
|
/**
|
|
169
170
|
* Fireworks DeepSeek V4 accepts effort via `reasoning_effort` but rejects the
|
|
170
171
|
* DeepSeek-native binary `thinking` toggle when both are present.
|
|
@@ -343,7 +344,6 @@ export interface AnthropicModelManagerConfig {
|
|
|
343
344
|
fetch?: FetchImpl;
|
|
344
345
|
}
|
|
345
346
|
export declare function anthropicModelManagerOptions(config?: AnthropicModelManagerConfig): ModelManagerOptions<"anthropic-messages">;
|
|
346
|
-
export { UNK_CONTEXT_WINDOW, UNK_MAX_TOKENS } from "./discovery-constants";
|
|
347
347
|
/** Describes how to map models.dev API data for a single provider. */
|
|
348
348
|
export interface ModelsDevProviderDescriptor {
|
|
349
349
|
/** Key in the models.dev API response JSON (e.g., "anthropic", "amazon-bedrock") */
|
|
@@ -386,3 +386,4 @@ export interface ModelsDevProviderDescriptor {
|
|
|
386
386
|
export declare function mapModelsDevToModels(data: Record<string, unknown>, descriptors: readonly ModelsDevProviderDescriptor[]): ModelSpec<Api>[];
|
|
387
387
|
/** All provider descriptors for models.dev data mapping in generate-models.ts. */
|
|
388
388
|
export declare const MODELS_DEV_PROVIDER_DESCRIPTORS: readonly ModelsDevProviderDescriptor[];
|
|
389
|
+
export {};
|
package/dist/types/types.d.ts
CHANGED
|
@@ -373,8 +373,8 @@ export interface Model<TApi extends Api = Api> {
|
|
|
373
373
|
};
|
|
374
374
|
/** Premium Copilot requests charged per user-initiated request (defaults to 1). */
|
|
375
375
|
premiumMultiplier?: number;
|
|
376
|
-
contextWindow: number;
|
|
377
|
-
maxTokens: number;
|
|
376
|
+
contextWindow: number | null;
|
|
377
|
+
maxTokens: number | null;
|
|
378
378
|
/**
|
|
379
379
|
* When `true`, providers MUST omit `max_output_tokens` (Responses) /
|
|
380
380
|
* `max_tokens` / `max_completion_tokens` (Completions) from the outbound
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { isRecord } from "@oh-my-pi/pi-utils";
|
|
2
2
|
export declare function toNumber(value: unknown): number | undefined;
|
|
3
3
|
export declare function toPositiveNumber(value: unknown, fallback: number): number;
|
|
4
|
+
export declare function toPositiveNumber(value: unknown, fallback: number | null): number | null;
|
|
5
|
+
/** Positive finite number, or `null` when the value is missing/non-positive. */
|
|
6
|
+
export declare function toPositiveNumberOrNull(value: unknown): number | null;
|
|
4
7
|
export declare function toBoolean(value: unknown): boolean | undefined;
|
|
5
8
|
export declare function isAnthropicOAuthToken(key: string): boolean;
|
|
6
9
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-catalog",
|
|
4
|
-
"version": "15.12.
|
|
4
|
+
"version": "15.12.4",
|
|
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,11 +34,11 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@bufbuild/protobuf": "^2.12.0",
|
|
37
|
-
"@oh-my-pi/pi-utils": "15.12.
|
|
38
|
-
"zod": "4
|
|
37
|
+
"@oh-my-pi/pi-utils": "15.12.4",
|
|
38
|
+
"zod": "^4"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@oh-my-pi/pi-ai": "15.12.
|
|
41
|
+
"@oh-my-pi/pi-ai": "15.12.4",
|
|
42
42
|
"@types/bun": "^1.3.14"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
package/src/discovery/codex.ts
CHANGED
package/src/discovery/cursor.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as http2 from "node:http2";
|
|
2
2
|
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
3
|
-
import
|
|
3
|
+
import { z } from "zod/v4";
|
|
4
4
|
import { getBundledModels } from "../models";
|
|
5
5
|
import { toModelSpec } from "../provider-models/bundled-references";
|
|
6
6
|
import type { Model, ModelSpec } from "../types";
|
package/src/discovery/gemini.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
2
|
import { getBundledModels } from "../models";
|
|
3
3
|
import { toModelSpec } from "../provider-models/bundled-references";
|
|
4
|
-
import { UNK_CONTEXT_WINDOW, UNK_MAX_TOKENS } from "../provider-models/discovery-constants";
|
|
5
4
|
import type { FetchImpl, Model, ModelSpec } from "../types";
|
|
6
5
|
|
|
7
6
|
const GOOGLE_GENERATIVE_AI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
@@ -148,7 +147,9 @@ function normalizeBaseUrl(baseUrl?: string): string {
|
|
|
148
147
|
return value.replace(/\/+$/, "");
|
|
149
148
|
}
|
|
150
149
|
|
|
151
|
-
function normalizePositiveInt(value: number | undefined, fallback: number): number
|
|
150
|
+
function normalizePositiveInt(value: number | undefined, fallback: number): number;
|
|
151
|
+
function normalizePositiveInt(value: number | undefined, fallback: number | null): number | null;
|
|
152
|
+
function normalizePositiveInt(value: number | undefined, fallback: number | null): number | null {
|
|
152
153
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
153
154
|
return fallback;
|
|
154
155
|
}
|
|
@@ -178,8 +179,8 @@ function normalizeModel(
|
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
const reference = bundledById.get(id);
|
|
181
|
-
const contextWindow = normalizePositiveInt(item.inputTokenLimit, reference?.contextWindow ??
|
|
182
|
-
const maxTokens = normalizePositiveInt(item.outputTokenLimit, reference?.maxTokens ??
|
|
182
|
+
const contextWindow = normalizePositiveInt(item.inputTokenLimit, reference?.contextWindow ?? null);
|
|
183
|
+
const maxTokens = normalizePositiveInt(item.outputTokenLimit, reference?.maxTokens ?? null);
|
|
183
184
|
const name = normalizeModelName(item.displayName, reference?.name ?? id);
|
|
184
185
|
|
|
185
186
|
if (reference) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { UNK_CONTEXT_WINDOW, UNK_MAX_TOKENS } from "../provider-models/discovery-constants";
|
|
1
|
+
import { z } from "zod/v4";
|
|
3
2
|
import type { Api, FetchImpl, ModelSpec, Provider } from "../types";
|
|
4
3
|
|
|
5
4
|
const MODELS_PATH = "/models";
|
|
@@ -165,8 +164,8 @@ export async function fetchOpenAICompatibleModels<TApi extends Api>(
|
|
|
165
164
|
reasoning: false,
|
|
166
165
|
input: ["text"],
|
|
167
166
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
168
|
-
contextWindow:
|
|
169
|
-
maxTokens:
|
|
167
|
+
contextWindow: null,
|
|
168
|
+
maxTokens: null,
|
|
170
169
|
};
|
|
171
170
|
|
|
172
171
|
// `mapModel` returning null skips the entry (documented contract); only a
|
|
@@ -61,10 +61,10 @@ const FAMILY_EXTRACTION_PATTERNS = [
|
|
|
61
61
|
function shouldReplaceReference(existing: Model<Api> | undefined, candidate: Model<Api>): boolean {
|
|
62
62
|
if (!existing) return true;
|
|
63
63
|
if (candidate.contextWindow !== existing.contextWindow) {
|
|
64
|
-
return candidate.contextWindow > existing.contextWindow;
|
|
64
|
+
return (candidate.contextWindow ?? 0) > (existing.contextWindow ?? 0);
|
|
65
65
|
}
|
|
66
66
|
if (candidate.maxTokens !== existing.maxTokens) {
|
|
67
|
-
return candidate.maxTokens > existing.maxTokens;
|
|
67
|
+
return (candidate.maxTokens ?? 0) > (existing.maxTokens ?? 0);
|
|
68
68
|
}
|
|
69
69
|
return existing.provider !== "openai" && candidate.provider === "openai";
|
|
70
70
|
}
|
|
@@ -34,10 +34,10 @@ export function isZeroCostXaiOAuthReference(candidate: Model<Api>): boolean {
|
|
|
34
34
|
function shouldReplaceReference(existing: Model<Api> | undefined, candidate: Model<Api>): boolean {
|
|
35
35
|
if (!existing) return true;
|
|
36
36
|
if (candidate.contextWindow !== existing.contextWindow) {
|
|
37
|
-
return candidate.contextWindow > existing.contextWindow;
|
|
37
|
+
return (candidate.contextWindow ?? 0) > (existing.contextWindow ?? 0);
|
|
38
38
|
}
|
|
39
39
|
if (candidate.maxTokens !== existing.maxTokens) {
|
|
40
|
-
return candidate.maxTokens > existing.maxTokens;
|
|
40
|
+
return (candidate.maxTokens ?? 0) > (existing.maxTokens ?? 0);
|
|
41
41
|
}
|
|
42
42
|
const existingHasCachePricing = existing.cost.cacheRead > 0 || existing.cost.cacheWrite > 0;
|
|
43
43
|
const candidateHasCachePricing = candidate.cost.cacheRead > 0 || candidate.cost.cacheWrite > 0;
|
package/src/model-cache.ts
CHANGED
|
@@ -7,10 +7,12 @@ import { getModelDbPath } from "@oh-my-pi/pi-utils";
|
|
|
7
7
|
import type { Api, Model, ModelSpec } from "./types";
|
|
8
8
|
|
|
9
9
|
// Rows persist ModelSpec JSON (sparse `compat`, never the resolved record);
|
|
10
|
-
// the model manager rebuilds via `buildModel` on load.
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
10
|
+
// the model manager rebuilds via `buildModel` on load. v6 invalidates rows
|
|
11
|
+
// that may contain the retired unknown-limit sentinels (222222/8888); v5
|
|
12
|
+
// invalidated rows predating effort-tier variant collapsing (raw
|
|
13
|
+
// `-low`/`-high`/`-thinking` member ids); v4 dropped the pre-efforts
|
|
14
|
+
// ThinkingConfig shape.
|
|
15
|
+
const CACHE_SCHEMA_VERSION = 6;
|
|
14
16
|
|
|
15
17
|
interface CacheRow {
|
|
16
18
|
provider_id: string;
|
|
@@ -51,8 +53,10 @@ function getDb(dbPath?: string): Database {
|
|
|
51
53
|
sharedDb.close();
|
|
52
54
|
}
|
|
53
55
|
const db = new Database(resolvedPath, { create: true });
|
|
54
|
-
|
|
56
|
+
// Install the busy handler BEFORE any lock-taking statement. See
|
|
57
|
+
// https://github.com/can1357/oh-my-pi/issues/2421.
|
|
55
58
|
db.run("PRAGMA busy_timeout = 3000");
|
|
59
|
+
db.run("PRAGMA journal_mode = WAL");
|
|
56
60
|
db.run(`
|
|
57
61
|
CREATE TABLE IF NOT EXISTS model_cache (
|
|
58
62
|
provider_id TEXT PRIMARY KEY,
|
package/src/model-manager.ts
CHANGED
|
@@ -363,11 +363,13 @@ function preferDiscoveryName(discoveryName: string, fallbackName: string, modelI
|
|
|
363
363
|
return normalizedDiscoveryName;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
function preferDiscoveryLimit(discoveryLimit: number, fallbackLimit: number): number
|
|
367
|
-
|
|
366
|
+
function preferDiscoveryLimit(discoveryLimit: number, fallbackLimit: number): number;
|
|
367
|
+
function preferDiscoveryLimit(discoveryLimit: number | null, fallbackLimit: number | null): number | null;
|
|
368
|
+
function preferDiscoveryLimit(discoveryLimit: number | null, fallbackLimit: number | null): number | null {
|
|
369
|
+
if (discoveryLimit === null || !Number.isFinite(discoveryLimit) || discoveryLimit <= 0) {
|
|
368
370
|
return fallbackLimit;
|
|
369
371
|
}
|
|
370
|
-
if (discoveryLimit === 4096 && fallbackLimit > discoveryLimit) {
|
|
372
|
+
if (discoveryLimit === 4096 && fallbackLimit !== null && fallbackLimit > discoveryLimit) {
|
|
371
373
|
return fallbackLimit;
|
|
372
374
|
}
|
|
373
375
|
return discoveryLimit;
|
|
@@ -428,11 +430,11 @@ function isModelLike(value: unknown): value is ModelSpec<Api> {
|
|
|
428
430
|
}
|
|
429
431
|
// Finite positive: NaN > 0 is false, +Infinity < Infinity is false.
|
|
430
432
|
const cw = v.contextWindow;
|
|
431
|
-
if (typeof cw !== "number" || !(cw > 0 && cw < Infinity)) {
|
|
433
|
+
if (cw !== null && (typeof cw !== "number" || !(cw > 0 && cw < Infinity))) {
|
|
432
434
|
return false;
|
|
433
435
|
}
|
|
434
436
|
const mt = v.maxTokens;
|
|
435
|
-
if (typeof mt !== "number" || !(mt > 0 && mt < Infinity)) {
|
|
437
|
+
if (mt !== null && (typeof mt !== "number" || !(mt > 0 && mt < Infinity))) {
|
|
436
438
|
return false;
|
|
437
439
|
}
|
|
438
440
|
return true;
|