@oh-my-pi/pi-catalog 16.3.9 → 16.3.10

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 CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.3.10] - 2026-07-06
6
+
7
+ ### Fixed
8
+
9
+ - Fixed LiteLLM rich discovery to ignore unusable sentinel placeholders and continue to `/v2/model/info` for real models. ([#4655](https://github.com/can1357/oh-my-pi/issues/4655))
10
+
5
11
  ## [16.3.9] - 2026-07-06
6
12
 
7
13
  ### Fixed
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.3.9",
4
+ "version": "16.3.10",
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.0",
37
- "@oh-my-pi/pi-utils": "16.3.9",
37
+ "@oh-my-pi/pi-utils": "16.3.10",
38
38
  "arktype": "^2.2.0",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.3.9",
42
+ "@oh-my-pi/pi-ai": "16.3.10",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -3037,6 +3037,11 @@ const LITELLM_RICH_ENDPOINTS = ["/model_group/info", "/v2/model/info", "/model/i
3037
3037
  export const OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW = 128_000;
3038
3038
  export const OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS = 32_768;
3039
3039
  const UNKNOWN_PROXY_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } as const;
3040
+ const LITELLM_UNUSABLE_SENTINEL_IDS: Record<string, true> = {
3041
+ "all-team-models": true,
3042
+ "all-proxy-models": true,
3043
+ "no-default-models": true,
3044
+ };
3040
3045
 
3041
3046
  export function normalizeLiteLLMManagementBaseUrl(baseUrl: string): string {
3042
3047
  const trimmed = baseUrl.trim().replace(/\/+$/g, "");
@@ -3142,11 +3147,59 @@ function getSupportedOpenAIParams(entry: LiteLLMRichModelEntry): string[] | unde
3142
3147
  return value.flatMap(item => (typeof item === "string" ? [item] : []));
3143
3148
  }
3144
3149
 
3150
+ function isLiteLLMUnusableSentinelPlaceholder(entry: LiteLLMRichModelEntry): boolean {
3151
+ const modelGroup = toNonEmptyString(entry.model_group);
3152
+ const id = toNonEmptyString(entry.id);
3153
+ if (
3154
+ (modelGroup === undefined || LITELLM_UNUSABLE_SENTINEL_IDS[modelGroup] !== true) &&
3155
+ (id === undefined || LITELLM_UNUSABLE_SENTINEL_IDS[id] !== true)
3156
+ ) {
3157
+ return false;
3158
+ }
3159
+ const providers = entry.providers;
3160
+ if (providers !== undefined && (!Array.isArray(providers) || providers.length > 0)) {
3161
+ return false;
3162
+ }
3163
+ const modelName = toNonEmptyString(entry.model_name);
3164
+ if (modelName && LITELLM_UNUSABLE_SENTINEL_IDS[modelName] !== true) {
3165
+ return false;
3166
+ }
3167
+ if (id && LITELLM_UNUSABLE_SENTINEL_IDS[id] !== true) {
3168
+ return false;
3169
+ }
3170
+ const backendModel = toNonEmptyString(getLiteLLMParams(entry)?.model);
3171
+ if (backendModel && LITELLM_UNUSABLE_SENTINEL_IDS[backendModel] !== true) {
3172
+ return false;
3173
+ }
3174
+ if (
3175
+ toPositiveNumber(getLiteLLMMetadataValue(entry, "max_input_tokens"), null) !== null ||
3176
+ toPositiveNumber(getLiteLLMMetadataValue(entry, "max_output_tokens"), null) !== null
3177
+ ) {
3178
+ return false;
3179
+ }
3180
+ if (
3181
+ getLiteLLMMetadataValue(entry, "supports_vision") === true ||
3182
+ getLiteLLMMetadataValue(entry, "supports_reasoning") === true ||
3183
+ getLiteLLMMetadataValue(entry, "supports_function_calling") === true ||
3184
+ getLiteLLMMetadataValue(entry, "supports_tools") === true
3185
+ ) {
3186
+ return false;
3187
+ }
3188
+ const supportedOpenAIParams = getSupportedOpenAIParams(entry);
3189
+ if (supportedOpenAIParams && supportedOpenAIParams.length > 0) {
3190
+ return false;
3191
+ }
3192
+ return true;
3193
+ }
3194
+
3145
3195
  function mapLiteLLMRichEntry<TApi extends Api>(
3146
3196
  entry: LiteLLMRichModelEntry,
3147
3197
  options: FetchLiteLLMRichModelsOptions<TApi>,
3148
3198
  runtimeBaseUrl: string,
3149
3199
  ): ModelSpec<TApi> | null {
3200
+ if (isLiteLLMUnusableSentinelPlaceholder(entry)) {
3201
+ return null;
3202
+ }
3150
3203
  const id = getLiteLLMRichModelId(entry);
3151
3204
  if (!id) {
3152
3205
  return null;
@@ -3286,11 +3339,11 @@ export function litellmModelManagerOptions(
3286
3339
  const baseUrl = config?.baseUrl ?? Bun.env.LITELLM_BASE_URL ?? "http://localhost:4000/v1";
3287
3340
  return {
3288
3341
  providerId: "litellm",
3289
- // rich-v2 invalidates rows cached before reseller usage-suffix stripping
3290
- // (stale display names like `MiniMax-M3 (3x usage)`); bump the version
3291
- // whenever the mappers below change, or warm authoritative caches keep
3292
- // serving pre-change rows for the full TTL.
3293
- cacheProviderId: `litellm:rich-v2:${Bun.hash(baseUrl).toString(36)}`,
3342
+ // rich-v3 invalidates rows cached before reseller usage-suffix stripping
3343
+ // and placeholder-only `all-team-models` filtering; bump the version whenever
3344
+ // the mappers below change, or warm authoritative caches keep serving
3345
+ // pre-change rows for the full TTL.
3346
+ cacheProviderId: `litellm:rich-v3:${Bun.hash(baseUrl).toString(36)}`,
3294
3347
  // litellm is a local-only proxy and is never bundled in models.json (that
3295
3348
  // would leak the machine's localhost catalog). Prefer the proxy's richer
3296
3349
  // management metadata, then fall back to /v1/models and enrich bare ids