@oh-my-pi/pi-catalog 16.3.0 → 16.3.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 CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.3.2] - 2026-07-02
6
+
7
+ ### Fixed
8
+
9
+ - Fixed ZenMux model discovery to run without a `ZENMUX_API_KEY`, so newly published ZenMux models (for example `anthropic/claude-fable-5-free`) auto-update into the runtime `models.db` cache instead of waiting on a regenerated `models.json`.
10
+ - Fixed ZenMux runtime discovery to query the `/api/v1/models` endpoint even when the resolved provider base URL points at the Anthropic-compatible route, so discovery no longer requests a non-existent `/api/anthropic/models` path.
11
+
12
+ ## [16.3.1] - 2026-07-02
13
+
14
+ ### Removed
15
+
16
+ - Removed reasoning suppression prompt logic for GPT-5 models
17
+
5
18
  ## [16.3.0] - 2026-07-02
6
19
 
7
20
  ### Breaking Changes
@@ -20,8 +20,6 @@ interface OpenAIResponsesSpecLike {
20
20
  * as well as URL — bundled `azure` models carry no baseUrl (the deployment host
21
21
  * is per-resource, resolved at runtime) — while OpenAI/Copilot developer-role
22
22
  * and prompt-cache detection stay URL-keyed, as the historical call sites were.
23
- * The GPT-5 reasoning-suppression prompt keys on the model name, matching the
24
- * historical request-time check.
25
23
  */
26
24
  export declare function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): ResolvedOpenAIResponsesCompat;
27
25
  export declare function buildOpenRouterCompat(spec: ModelSpec<"openrouter">): ResolvedOpenRouterCompat;
@@ -407,8 +407,10 @@ export declare const CATALOG_PROVIDERS: readonly [{
407
407
  readonly defaultModel: "anthropic/claude-opus-4.8";
408
408
  readonly envVars: readonly ["ZENMUX_API_KEY"];
409
409
  readonly createModelManagerOptions: (config: ModelManagerConfig) => import("..").ModelManagerOptions<import("..").Api, unknown>;
410
+ readonly allowUnauthenticated: true;
410
411
  readonly catalogDiscovery: {
411
412
  readonly label: "ZenMux";
413
+ readonly allowUnauthenticated: true;
412
414
  };
413
415
  }, {
414
416
  readonly id: "zhipu-coding-plan";
@@ -286,14 +286,6 @@ export interface OpenAICompat {
286
286
  strictResponsesPairing?: boolean;
287
287
  /** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
288
288
  supportsImageDetailOriginal?: boolean;
289
- /**
290
- * Append a trailing no-reasoning developer item when the caller did not
291
- * request reasoning, suppressing default reasoning on models that cannot
292
- * disable it via request params (Responses APIs only; see
293
- * https://community.openai.com/t/need-reasoning-false-option-for-gpt-5/1351588/7).
294
- * The prompt must not look like an execution or tool budget. Default: auto-detected (GPT-5-family model names).
295
- */
296
- requiresReasoningSuppressionPrompt?: boolean;
297
289
  /** Whether streamed reasoning deltas for the same field may repeat the full cumulative text snapshot. Default: false. */
298
290
  reasoningDeltasMayBeCumulative?: boolean;
299
291
  /** Strip leaked DeepSeek chat-template special tokens from visible content deltas. Default: auto-detected. */
@@ -463,7 +455,7 @@ export interface ResolvedOpenAISharedCompat {
463
455
  * `buildModel`; request handlers read fields and never detect, resolve, or
464
456
  * allocate.
465
457
  */
466
- export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "thinkingFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "replayReasoningContent" | "qwenPreserveThinking" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamIdleTimeoutMs" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "requiresReasoningSuppressionPrompt" | "enableGeminiThinkingLoopGuard" | "whenThinking">> & {
458
+ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "thinkingFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "replayReasoningContent" | "qwenPreserveThinking" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamIdleTimeoutMs" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "enableGeminiThinkingLoopGuard" | "whenThinking">> & {
467
459
  vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
468
460
  extraBody?: OpenAICompat["extraBody"];
469
461
  cacheControlFormat?: OpenAICompat["cacheControlFormat"];
@@ -482,7 +474,6 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
482
474
  supportsLongPromptCacheRetention: boolean;
483
475
  strictResponsesPairing: boolean;
484
476
  supportsImageDetailOriginal: boolean;
485
- requiresReasoningSuppressionPrompt: boolean;
486
477
  supportsObfuscationOptOut: boolean;
487
478
  streamIdleTimeoutMs?: number;
488
479
  }
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.0",
4
+ "version": "16.3.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.0",
37
- "@oh-my-pi/pi-utils": "16.3.0",
37
+ "@oh-my-pi/pi-utils": "16.3.2",
38
38
  "arktype": "^2.2.0",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.3.0",
42
+ "@oh-my-pi/pi-ai": "16.3.2",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -593,8 +593,6 @@ interface OpenAIResponsesSpecLike {
593
593
  * as well as URL — bundled `azure` models carry no baseUrl (the deployment host
594
594
  * is per-resource, resolved at runtime) — while OpenAI/Copilot developer-role
595
595
  * and prompt-cache detection stay URL-keyed, as the historical call sites were.
596
- * The GPT-5 reasoning-suppression prompt keys on the model name, matching the
597
- * historical request-time check.
598
596
  */
599
597
  export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): ResolvedOpenAIResponsesCompat {
600
598
  const baseUrl = spec.baseUrl ?? "";
@@ -626,7 +624,6 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
626
624
  // or base-URL host (mirroring the Anthropic compat builder) so a model
627
625
  // pointed at the Copilot host under a different provider id still clamps.
628
626
  supportsImageDetailOriginal: !modelMatchesHost({ provider: spec.provider, baseUrl }, "githubCopilot"),
629
- requiresReasoningSuppressionPrompt: spec.name.toLowerCase().startsWith("gpt-5"),
630
627
  reasoningEffortMap: {},
631
628
  supportsReasoningParams: true,
632
629
  thinkingFormat,
@@ -693,7 +690,6 @@ function pickResponsesOnly(compat: ResolvedOpenAIResponsesCompat): ResponsesOnly
693
690
  supportsLongPromptCacheRetention: compat.supportsLongPromptCacheRetention,
694
691
  strictResponsesPairing: compat.strictResponsesPairing,
695
692
  supportsImageDetailOriginal: compat.supportsImageDetailOriginal,
696
- requiresReasoningSuppressionPrompt: compat.requiresReasoningSuppressionPrompt,
697
693
  supportsObfuscationOptOut: compat.supportsObfuscationOptOut,
698
694
  } satisfies ResponsesOnlyCompat;
699
695
  }
@@ -453,7 +453,8 @@ export const CATALOG_PROVIDERS = [
453
453
  defaultModel: "anthropic/claude-opus-4.8",
454
454
  envVars: ["ZENMUX_API_KEY"],
455
455
  createModelManagerOptions: (config: ModelManagerConfig) => zenmuxModelManagerOptions(config),
456
- catalogDiscovery: { label: "ZenMux" },
456
+ allowUnauthenticated: true,
457
+ catalogDiscovery: { label: "ZenMux", allowUnauthenticated: true },
457
458
  },
458
459
  {
459
460
  id: "zhipu-coding-plan",
@@ -2035,7 +2035,11 @@ function normalizeZenMuxOpenAiBaseUrl(baseUrl?: string): string {
2035
2035
  if (!value) {
2036
2036
  return ZENMUX_OPENAI_BASE_URL;
2037
2037
  }
2038
- return value.endsWith("/") ? value.slice(0, -1) : value;
2038
+ const normalized = value.endsWith("/") ? value.slice(0, -1) : value;
2039
+ if (normalized.endsWith("/api/anthropic")) {
2040
+ return normalized.replace("/api/anthropic", "/api/v1");
2041
+ }
2042
+ return normalized;
2039
2043
  }
2040
2044
 
2041
2045
  function toZenMuxAnthropicBaseUrl(openAiBaseUrl: string): string {
@@ -2103,37 +2107,35 @@ export function zenmuxModelManagerOptions(config?: ZenMuxModelManagerConfig): Mo
2103
2107
  const anthropicBaseUrl = toZenMuxAnthropicBaseUrl(openAiBaseUrl);
2104
2108
  return {
2105
2109
  providerId: "zenmux",
2106
- ...(apiKey && {
2107
- fetchDynamicModels: () =>
2108
- fetchOpenAICompatibleModels<Api>({
2109
- api: "openai-completions",
2110
- provider: "zenmux",
2111
- baseUrl: openAiBaseUrl,
2112
- apiKey,
2113
- mapModel: (entry, defaults) => {
2114
- const pricings = isRecord(entry.pricings) ? entry.pricings : undefined;
2115
- const capabilities = isRecord(entry.capabilities) ? entry.capabilities : undefined;
2116
- const isAnthropicModel = isZenMuxAnthropicModel(entry, defaults.id);
2117
- return {
2118
- ...defaults,
2119
- name: toModelName(entry.display_name, defaults.name),
2120
- api: isAnthropicModel ? "anthropic-messages" : "openai-completions",
2121
- baseUrl: isAnthropicModel ? anthropicBaseUrl : openAiBaseUrl,
2122
- reasoning: capabilities?.reasoning === true || defaults.reasoning,
2123
- input: toInputCapabilities(entry.input_modalities),
2124
- cost: {
2125
- input: getZenMuxPricingValue(pricings, "prompt"),
2126
- output: getZenMuxPricingValue(pricings, "completion"),
2127
- cacheRead: getZenMuxPricingValue(pricings, "input_cache_read"),
2128
- cacheWrite: getZenMuxCacheWritePrice(pricings),
2129
- },
2130
- contextWindow: toPositiveNumber(entry.context_length, defaults.contextWindow),
2131
- maxTokens: toPositiveNumber(entry.max_completion_tokens, defaults.maxTokens),
2132
- };
2133
- },
2134
- fetch: config?.fetch,
2135
- }),
2136
- }),
2110
+ fetchDynamicModels: () =>
2111
+ fetchOpenAICompatibleModels<Api>({
2112
+ api: "openai-completions",
2113
+ provider: "zenmux",
2114
+ baseUrl: openAiBaseUrl,
2115
+ apiKey,
2116
+ mapModel: (entry, defaults) => {
2117
+ const pricings = isRecord(entry.pricings) ? entry.pricings : undefined;
2118
+ const capabilities = isRecord(entry.capabilities) ? entry.capabilities : undefined;
2119
+ const isAnthropicModel = isZenMuxAnthropicModel(entry, defaults.id);
2120
+ return {
2121
+ ...defaults,
2122
+ name: toModelName(entry.display_name, defaults.name),
2123
+ api: isAnthropicModel ? "anthropic-messages" : "openai-completions",
2124
+ baseUrl: isAnthropicModel ? anthropicBaseUrl : openAiBaseUrl,
2125
+ reasoning: capabilities?.reasoning === true || defaults.reasoning,
2126
+ input: toInputCapabilities(entry.input_modalities),
2127
+ cost: {
2128
+ input: getZenMuxPricingValue(pricings, "prompt"),
2129
+ output: getZenMuxPricingValue(pricings, "completion"),
2130
+ cacheRead: getZenMuxPricingValue(pricings, "input_cache_read"),
2131
+ cacheWrite: getZenMuxCacheWritePrice(pricings),
2132
+ },
2133
+ contextWindow: toPositiveNumber(entry.context_length, defaults.contextWindow),
2134
+ maxTokens: toPositiveNumber(entry.max_completion_tokens, defaults.maxTokens),
2135
+ };
2136
+ },
2137
+ fetch: config?.fetch,
2138
+ }),
2137
2139
  };
2138
2140
  }
2139
2141
 
package/src/types.ts CHANGED
@@ -324,14 +324,6 @@ export interface OpenAICompat {
324
324
  strictResponsesPairing?: boolean;
325
325
  /** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
326
326
  supportsImageDetailOriginal?: boolean;
327
- /**
328
- * Append a trailing no-reasoning developer item when the caller did not
329
- * request reasoning, suppressing default reasoning on models that cannot
330
- * disable it via request params (Responses APIs only; see
331
- * https://community.openai.com/t/need-reasoning-false-option-for-gpt-5/1351588/7).
332
- * The prompt must not look like an execution or tool budget. Default: auto-detected (GPT-5-family model names).
333
- */
334
- requiresReasoningSuppressionPrompt?: boolean;
335
327
  /** Whether streamed reasoning deltas for the same field may repeat the full cumulative text snapshot. Default: false. */
336
328
  reasoningDeltasMayBeCumulative?: boolean;
337
329
  /** Strip leaked DeepSeek chat-template special tokens from visible content deltas. Default: auto-detected. */
@@ -557,7 +549,6 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
557
549
  | "thinkingKeep"
558
550
  | "strictResponsesPairing"
559
551
  | "supportsImageDetailOriginal"
560
- | "requiresReasoningSuppressionPrompt"
561
552
  | "enableGeminiThinkingLoopGuard"
562
553
  | "whenThinking"
563
554
  >
@@ -581,7 +572,6 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
581
572
  supportsLongPromptCacheRetention: boolean;
582
573
  strictResponsesPairing: boolean;
583
574
  supportsImageDetailOriginal: boolean;
584
- requiresReasoningSuppressionPrompt: boolean;
585
575
  supportsObfuscationOptOut: boolean;
586
576
  streamIdleTimeoutMs?: number;
587
577
  }