@oh-my-pi/pi-catalog 18.1.19 → 18.1.21

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.
@@ -89,10 +89,14 @@ export function resolveModelCacheProviderId(providerId: string, options: ModelCa
89
89
  }
90
90
  case "litellm": {
91
91
  const baseUrl = options.baseUrl ?? getDefaultModelDiscoveryBaseUrl(providerId)!;
92
- // rich-v8 invalidates rows whose `compatConfig` retained a colliding
93
- // bundled model's provider-specific transport (e.g. Fireworks
94
- // `wireModelIdMode`) before that leak was fixed (issue #9938).
95
- return `litellm:rich-v8:${Bun.hash(baseUrl).toString(36)}`;
92
+ // rich-v9 unions compat across the management endpoints and keys the
93
+ // deployment's `supports_vision` declaration into it, so a warm
94
+ // rich-v8 row would keep retracting axes an earlier endpoint reported
95
+ // (issue #11982). rich-v8 invalidated rows whose `compatConfig`
96
+ // retained a colliding bundled model's provider-specific transport
97
+ // (e.g. Fireworks `wireModelIdMode`) before that leak was fixed
98
+ // (issue #9938).
99
+ return `litellm:rich-v9:${Bun.hash(baseUrl).toString(36)}`;
96
100
  }
97
101
  case "opencode-go":
98
102
  case "opencode-zen": {
@@ -5726,6 +5726,19 @@ function mapLiteLLMRichEntry<TApi extends Api>(
5726
5726
  ...(referenceCompat?.omitReasoningEffort !== undefined
5727
5727
  ? { omitReasoningEffort: referenceCompat.omitReasoningEffort }
5728
5728
  : {}),
5729
+ // The deployment is authoritative about its own groups. When its
5730
+ // `model_info.supports_vision` says the group reads images, the derived
5731
+ // opt-out has to outrank the class-wide text-only guard
5732
+ // (`classes/deepseek.kdl`), which keys on the model id alone and would
5733
+ // otherwise replace the attachment with `[image omitted: model does not
5734
+ // support vision]` for a group the endpoint reads. LiteLLM cannot take a
5735
+ // reviewed model list the way OpenRouter or OpenCode Go can — its aliases
5736
+ // are chosen per deployment — so the declaration decides.
5737
+ // `applyCompatOverrides` runs after the cascade, so this beats the class
5738
+ // default; `supports_vision: false` or absent metadata leaves the guard
5739
+ // in place. `mergeLiteLLMCompat` keeps it when another endpoint wins the
5740
+ // compat merge (issue #11982).
5741
+ ...(supportsVision === true ? { stripImageInput: false } : {}),
5729
5742
  };
5730
5743
  return {
5731
5744
  id,
@@ -5749,6 +5762,43 @@ function mapLiteLLMRichEntry<TApi extends Api>(
5749
5762
  };
5750
5763
  }
5751
5764
 
5765
+ /**
5766
+ * Field-wise compat union for the management endpoints describing one group.
5767
+ *
5768
+ * The endpoints are complementary, not ranked: `/model_group/info` reports the
5769
+ * gateway's view while `/model/info` and its `/v1` twin report the operator's
5770
+ * own `model_info`, and any of them may answer partially. Picking one side
5771
+ * wholesale dropped every axis the other had reported — a later endpoint that
5772
+ * merely listed `supported_openai_params` erased what an earlier one declared.
5773
+ * Merge per axis instead: a later endpoint overrides the axes it reports and
5774
+ * leaves the rest alone, so an absent axis means "no news", never "retract".
5775
+ */
5776
+ function mergeLiteLLMCompat<TApi extends Api>(
5777
+ existing: ModelSpec<TApi>["compat"],
5778
+ next: ModelSpec<TApi>["compat"],
5779
+ evidence: { existingReportedParams: boolean; nextReportedParams: boolean },
5780
+ ): ModelSpec<TApi>["compat"] {
5781
+ if (!existing) return next;
5782
+ if (!next) return existing;
5783
+ const merged: Record<string, unknown> = { ...(existing as Record<string, unknown>) };
5784
+ for (const axis in next as Record<string, unknown>) {
5785
+ const value = (next as Record<string, unknown>)[axis];
5786
+ if (value !== undefined) merged[axis] = value;
5787
+ }
5788
+ // `supportsReasoningEffort` is the one axis with two sources: the endpoint's
5789
+ // own `supported_openai_params` list, and the models.dev reference it falls
5790
+ // back to when no list was reported. Only the list is evidence, so an
5791
+ // inferred value must not override the other endpoint's verdict — a fallback
5792
+ // `true` would send `reasoning_effort` to a group whose own metadata omitted
5793
+ // it (#11985 review).
5794
+ if (!evidence.nextReportedParams) {
5795
+ const reported = (existing as Record<string, unknown>).supportsReasoningEffort;
5796
+ if (reported === undefined) delete merged.supportsReasoningEffort;
5797
+ else merged.supportsReasoningEffort = reported;
5798
+ }
5799
+ return merged as unknown as ModelSpec<TApi>["compat"];
5800
+ }
5801
+
5752
5802
  function mergeLiteLLMRichEndpointModels<TApi extends Api>(
5753
5803
  existing: LiteLLMRichEndpointModel<TApi>,
5754
5804
  next: LiteLLMRichEndpointModel<TApi>,
@@ -5769,7 +5819,10 @@ function mergeLiteLLMRichEndpointModels<TApi extends Api>(
5769
5819
  input: next.supportsVision === true || next.supportsVision === false ? next.model.input : existing.model.input,
5770
5820
  reasoning: typeof next.supportsReasoning === "boolean" ? next.model.reasoning : existing.model.reasoning,
5771
5821
  cost: { ...existing.model.cost, ...existing.reportedCost, ...next.reportedCost },
5772
- compat: next.hasSupportedOpenAIParams ? next.model.compat : existing.model.compat,
5822
+ compat: mergeLiteLLMCompat(existing.model.compat, next.model.compat, {
5823
+ existingReportedParams: existing.hasSupportedOpenAIParams,
5824
+ nextReportedParams: next.hasSupportedOpenAIParams,
5825
+ }),
5773
5826
  };
5774
5827
  if (next.hasToolMetadata) {
5775
5828
  model.supportsTools = next.model.supportsTools;
@@ -5950,8 +6003,11 @@ export function litellmModelManagerOptions(config?: LiteLLMModelManagerConfig):
5950
6003
  const baseUrl = config?.baseUrl ?? getDefaultModelDiscoveryBaseUrl("litellm")!;
5951
6004
  return {
5952
6005
  providerId: "litellm",
5953
- // rich-v8 invalidates rows whose `compatConfig` retained a colliding
5954
- // bundled model's provider-specific transport (e.g. Fireworks
6006
+ // rich-v9 keys the deployment's `supports_vision` declaration into the
6007
+ // cached compat and unions compat across management endpoints instead of
6008
+ // letting a later one retract what an earlier one reported (issue
6009
+ // #11982). rich-v8 invalidated rows whose `compatConfig` retained a
6010
+ // colliding bundled model's provider-specific transport (e.g. Fireworks
5955
6011
  // `wireModelIdMode`) before that leak was fixed. Earlier versions added
5956
6012
  // bundled reference fallback, moved OpenAI models to Responses, continued
5957
6013
  // past incomplete vision/API metadata and endpoints omitting cache