@oh-my-pi/pi-catalog 18.0.11 → 18.1.0

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.
Files changed (198) hide show
  1. package/CHANGELOG.md +42 -8
  2. package/README.md +9 -8
  3. package/dist/types/build.d.ts +13 -8
  4. package/dist/types/cline-pass-model-id.d.ts +4 -0
  5. package/dist/types/compat/anthropic.d.ts +10 -4
  6. package/dist/types/compat/axes.d.ts +50 -0
  7. package/dist/types/compat/behavior.d.ts +69 -0
  8. package/dist/types/compat/cascade.d.ts +37 -0
  9. package/dist/types/{variant-collapse.d.ts → compat/collapse.d.ts} +40 -35
  10. package/dist/types/compat/openai.d.ts +7 -26
  11. package/dist/types/compat/resolve.d.ts +15 -0
  12. package/dist/types/compat/revision.d.ts +41 -0
  13. package/dist/types/compat/taxonomy.d.ts +93 -0
  14. package/dist/types/compat/types.d.ts +338 -0
  15. package/dist/types/discovery/antigravity.d.ts +1 -1
  16. package/dist/types/discovery/cursor-proto.d.ts +6 -6
  17. package/dist/types/discovery/cursor.d.ts +5 -3
  18. package/dist/types/discovery/devin-proto.d.ts +363 -0
  19. package/dist/types/discovery/gemini-cli.d.ts +1 -1
  20. package/dist/types/identity/id.d.ts +1 -0
  21. package/dist/types/identity/index.d.ts +3 -3
  22. package/dist/types/identity/reference.d.ts +0 -10
  23. package/dist/types/index.d.ts +1 -1
  24. package/dist/types/model-thinking.d.ts +6 -24
  25. package/dist/types/provider-models/cline-pass.d.ts +22 -0
  26. package/dist/types/provider-models/descriptors.d.ts +10 -0
  27. package/dist/types/provider-models/models-dev-policies.d.ts +2 -1
  28. package/dist/types/provider-models/openai-compat.d.ts +33 -46
  29. package/dist/types/provider-models/special.d.ts +21 -1
  30. package/dist/types/types.d.ts +156 -9
  31. package/dist/types/wire/cline-pass.d.ts +21 -0
  32. package/dist/types/wire/devin-proto.d.ts +14 -0
  33. package/dist/types/wire/devin.d.ts +36 -0
  34. package/package.json +10 -8
  35. package/src/build.ts +158 -48
  36. package/src/cline-pass-model-id.ts +11 -0
  37. package/src/compat/anthropic.ts +15 -136
  38. package/src/compat/axes.ts +277 -0
  39. package/src/compat/behavior.ts +207 -0
  40. package/src/compat/cascade.ts +230 -0
  41. package/src/{variant-collapse.ts → compat/collapse.ts} +200 -749
  42. package/src/compat/openai.ts +17 -848
  43. package/src/compat/resolve.ts +1219 -0
  44. package/src/compat/revision.ts +154 -0
  45. package/src/compat/rules/README.md +258 -0
  46. package/src/compat/rules/classes/amazon.kdl +21 -0
  47. package/src/compat/rules/classes/anthropic.kdl +242 -0
  48. package/src/compat/rules/classes/baidu.kdl +9 -0
  49. package/src/compat/rules/classes/bytedance.kdl +9 -0
  50. package/src/compat/rules/classes/cohere.kdl +7 -0
  51. package/src/compat/rules/classes/deepseek.kdl +80 -0
  52. package/src/compat/rules/classes/gemini.kdl +91 -0
  53. package/src/compat/rules/classes/gemma.kdl +14 -0
  54. package/src/compat/rules/classes/glm.kdl +83 -0
  55. package/src/compat/rules/classes/gpt-oss.kdl +16 -0
  56. package/src/compat/rules/classes/kimi.kdl +113 -0
  57. package/src/compat/rules/classes/meta.kdl +13 -0
  58. package/src/compat/rules/classes/mimo.kdl +32 -0
  59. package/src/compat/rules/classes/minimax.kdl +79 -0
  60. package/src/compat/rules/classes/mistral.kdl +19 -0
  61. package/src/compat/rules/classes/openai.kdl +42 -0
  62. package/src/compat/rules/classes/qwen.kdl +72 -0
  63. package/src/compat/rules/classes/stepfun.kdl +10 -0
  64. package/src/compat/rules/classes/xai.kdl +45 -0
  65. package/src/compat/rules/providers/aiand.kdl +19 -0
  66. package/src/compat/rules/providers/aimlapi.kdl +24 -0
  67. package/src/compat/rules/providers/alibaba-coding-plan.kdl +20 -0
  68. package/src/compat/rules/providers/alibaba-token-plan.kdl +35 -0
  69. package/src/compat/rules/providers/amazon-bedrock.kdl +36 -0
  70. package/src/compat/rules/providers/anthropic.kdl +24 -0
  71. package/src/compat/rules/providers/azure.kdl +19 -0
  72. package/src/compat/rules/providers/baseten.kdl +19 -0
  73. package/src/compat/rules/providers/bedrock-mantle.kdl +15 -0
  74. package/src/compat/rules/providers/cerebras.kdl +19 -0
  75. package/src/compat/rules/providers/cline-pass.kdl +8 -0
  76. package/src/compat/rules/providers/cloudflare-ai-gateway.kdl +26 -0
  77. package/src/compat/rules/providers/coreweave.kdl +16 -0
  78. package/src/compat/rules/providers/cursor.kdl +47 -0
  79. package/src/compat/rules/providers/deepseek.kdl +21 -0
  80. package/src/compat/rules/providers/firepass.kdl +15 -0
  81. package/src/compat/rules/providers/fireworks.kdl +43 -0
  82. package/src/compat/rules/providers/github-copilot.kdl +62 -0
  83. package/src/compat/rules/providers/gitlab-duo.kdl +24 -0
  84. package/src/compat/rules/providers/gmi-cloud.kdl +8 -0
  85. package/src/compat/rules/providers/google-antigravity.kdl +53 -0
  86. package/src/compat/rules/providers/google-vertex.kdl +25 -0
  87. package/src/compat/rules/providers/google.kdl +17 -0
  88. package/src/compat/rules/providers/groq.kdl +8 -0
  89. package/src/compat/rules/providers/huggingface.kdl +24 -0
  90. package/src/compat/rules/providers/kilo.kdl +51 -0
  91. package/src/compat/rules/providers/kimi-code.kdl +37 -0
  92. package/src/compat/rules/providers/llama.cpp.kdl +6 -0
  93. package/src/compat/rules/providers/lm-studio.kdl +6 -0
  94. package/src/compat/rules/providers/meta.kdl +10 -0
  95. package/src/compat/rules/providers/minimax-code-cn.kdl +13 -0
  96. package/src/compat/rules/providers/minimax-code.kdl +13 -0
  97. package/src/compat/rules/providers/minimax.kdl +6 -0
  98. package/src/compat/rules/providers/mistral.kdl +8 -0
  99. package/src/compat/rules/providers/moonshot.kdl +36 -0
  100. package/src/compat/rules/providers/nanogpt.kdl +100 -0
  101. package/src/compat/rules/providers/novita.kdl +34 -0
  102. package/src/compat/rules/providers/nvidia.kdl +27 -0
  103. package/src/compat/rules/providers/ollama-cloud.kdl +20 -0
  104. package/src/compat/rules/providers/ollama.kdl +12 -0
  105. package/src/compat/rules/providers/openai-codex.kdl +121 -0
  106. package/src/compat/rules/providers/openai.kdl +82 -0
  107. package/src/compat/rules/providers/opencode-go.kdl +97 -0
  108. package/src/compat/rules/providers/opencode-zen.kdl +103 -0
  109. package/src/compat/rules/providers/openrouter.kdl +66 -0
  110. package/src/compat/rules/providers/qianfan.kdl +8 -0
  111. package/src/compat/rules/providers/sakana.kdl +10 -0
  112. package/src/compat/rules/providers/synthetic.kdl +16 -0
  113. package/src/compat/rules/providers/together.kdl +22 -0
  114. package/src/compat/rules/providers/umans.kdl +28 -0
  115. package/src/compat/rules/providers/venice.kdl +46 -0
  116. package/src/compat/rules/providers/vercel-ai-gateway.kdl +73 -0
  117. package/src/compat/rules/providers/vllm.kdl +8 -0
  118. package/src/compat/rules/providers/wafer-serverless.kdl +35 -0
  119. package/src/compat/rules/providers/xai-oauth.kdl +48 -0
  120. package/src/compat/rules/providers/xai.kdl +50 -0
  121. package/src/compat/rules/providers/xiaomi-token-plan-ams.kdl +9 -0
  122. package/src/compat/rules/providers/xiaomi-token-plan-cn.kdl +9 -0
  123. package/src/compat/rules/providers/xiaomi-token-plan-sgp.kdl +9 -0
  124. package/src/compat/rules/providers/xiaomi.kdl +22 -0
  125. package/src/compat/rules/providers/yolo-auto.kdl +16 -0
  126. package/src/compat/rules/providers/zai.kdl +32 -0
  127. package/src/compat/rules/providers/zenmux.kdl +108 -0
  128. package/src/compat/rules/providers/zhipu-coding-plan.kdl +49 -0
  129. package/src/compat/rules/runtime/behavior.kdl +240 -0
  130. package/src/compat/rules/taxonomy/_collapse.kdl +767 -0
  131. package/src/compat/rules/taxonomy/_discovery.kdl +60 -0
  132. package/src/compat/rules/taxonomy/ai21.kdl +6 -0
  133. package/src/compat/rules/taxonomy/amazon.kdl +8 -0
  134. package/src/compat/rules/taxonomy/anthropic.kdl +17 -0
  135. package/src/compat/rules/taxonomy/baidu.kdl +5 -0
  136. package/src/compat/rules/taxonomy/bytedance.kdl +5 -0
  137. package/src/compat/rules/taxonomy/cohere.kdl +6 -0
  138. package/src/compat/rules/taxonomy/deepseek.kdl +18 -0
  139. package/src/compat/rules/taxonomy/gemini.kdl +9 -0
  140. package/src/compat/rules/taxonomy/gemma.kdl +3 -0
  141. package/src/compat/rules/taxonomy/glm.kdl +14 -0
  142. package/src/compat/rules/taxonomy/gpt-oss.kdl +11 -0
  143. package/src/compat/rules/taxonomy/kimi.kdl +20 -0
  144. package/src/compat/rules/taxonomy/meta.kdl +7 -0
  145. package/src/compat/rules/taxonomy/mimo.kdl +7 -0
  146. package/src/compat/rules/taxonomy/minimax.kdl +9 -0
  147. package/src/compat/rules/taxonomy/mistral.kdl +7 -0
  148. package/src/compat/rules/taxonomy/openai.kdl +43 -0
  149. package/src/compat/rules/taxonomy/qwen.kdl +33 -0
  150. package/src/compat/rules/taxonomy/stepfun.kdl +5 -0
  151. package/src/compat/rules/taxonomy/unknown.kdl +3 -0
  152. package/src/compat/rules/taxonomy/xai.kdl +12 -0
  153. package/src/compat/rules.d.json.ts +5 -0
  154. package/src/compat/rules.json +14486 -0
  155. package/src/compat/taxonomy.ts +427 -0
  156. package/src/compat/types.ts +358 -0
  157. package/src/discovery/antigravity.ts +5 -6
  158. package/src/discovery/codex.ts +12 -7
  159. package/src/discovery/cursor-proto.ts +7 -7
  160. package/src/discovery/cursor.ts +47 -58
  161. package/src/discovery/devin-proto.ts +613 -0
  162. package/src/discovery/devin.ts +358 -52
  163. package/src/discovery/gemini-cli.ts +14 -11
  164. package/src/discovery/gemini.ts +2 -0
  165. package/src/identity/dialect.ts +2 -2
  166. package/src/identity/id.ts +12 -0
  167. package/src/identity/index.ts +3 -3
  168. package/src/identity/reference.ts +30 -4
  169. package/src/index.ts +1 -1
  170. package/src/model-manager.ts +4 -4
  171. package/src/model-thinking.ts +6 -810
  172. package/src/model-tokenizer.ts +37 -44
  173. package/src/models.json +75591 -19664
  174. package/src/models.ts +6 -1
  175. package/src/provider-models/bundled-references.ts +3 -1
  176. package/src/provider-models/cline-pass.ts +226 -0
  177. package/src/provider-models/descriptors.ts +9 -0
  178. package/src/provider-models/google.ts +8 -4
  179. package/src/provider-models/models-dev-policies.ts +4 -29
  180. package/src/provider-models/ollama.ts +15 -2
  181. package/src/provider-models/openai-compat.ts +570 -460
  182. package/src/provider-models/special.ts +182 -1
  183. package/src/types.ts +171 -8
  184. package/src/wire/cline-pass.ts +35 -0
  185. package/src/wire/devin-proto.ts +30 -0
  186. package/src/wire/devin.ts +72 -0
  187. package/dist/types/compat/bedrock.d.ts +0 -3
  188. package/dist/types/compat/devin.d.ts +0 -9
  189. package/dist/types/identity/classify.d.ts +0 -69
  190. package/dist/types/identity/family.d.ts +0 -243
  191. package/dist/types/identity/markers.d.ts +0 -4
  192. package/dist/types/openai-pricing.d.ts +0 -17
  193. package/src/compat/bedrock.ts +0 -153
  194. package/src/compat/devin.ts +0 -12
  195. package/src/identity/classify.ts +0 -242
  196. package/src/identity/family.ts +0 -496
  197. package/src/identity/markers.ts +0 -49
  198. package/src/openai-pricing.ts +0 -29
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.1.0] - 2026-09-01
6
+
7
+ ### Added
8
+
9
+ - Added GitLab Duo model support.
10
+ - Added provider support for Llama.cpp, LM Studio, and Minimax.
11
+ - Added catalog entries for Qwen 3.8 27B, Granite 4.2 8B, Abliterated variants, GLM 5.3, and Qwen 3.8 Flash Next.
12
+ - Added compatibility metadata for context management and reasoning summaries on supported provider-compatible model endpoints.
13
+ - Added the native ClinePass provider with live model discovery, subscription and free-tier model listings, current limits and pricing, model modalities, and per-model reasoning controls. Subscription models display API-equivalent pricing while free-tier models display as free.
14
+ - Added native Devin provider discovery with current Cascade model capabilities, pricing, limits, reasoning controls, selector aliases, and model descriptions and recommendation/beta metadata. Added static SWE-1.6 defaults so the provider can resolve a default model before account-scoped discovery completes.
15
+ - Added per-tier model pricing and long-context pricing support, along with expanded catalog metadata for model limits, API routes, input modalities, and provider-specific model aliases.
16
+
17
+ ### Changed
18
+
19
+ - Updated pricing data across the catalog to reflect current provider rates.
20
+ - Standardized model display names for greater consistency.
21
+ - Improved model compatibility classification and variant selection using structured model identities, providing more reliable detection of model families, revisions, reasoning variants, and provider-specific capabilities.
22
+
23
+ ### Fixed
24
+
25
+ - Fixed compatibility detection for vendor-prefixed GLM models on Mistral and Cerebras, restoring the appropriate tokenizer and reasoning-history behavior.
26
+ - Removed an obsolete OpenCode provider entry that exposed unavailable Zen models in the model picker.
27
+ - Fixed model revision detection for parameterized model IDs, including correct classification of Qwen, Fireworks Kimi, and Cursor-wrapped Grok models.
28
+ - Fixed Kimi K3 reasoning-effort handling on OpenAI-compatible hosts such as LiteLLM and vLLM.
29
+ - Fixed pricing for Codex Daybreak aliases, including worker variants.
30
+ - Fixed reasoning-effort variants for local Ollama models and DeepSeek V4, and corrected prompt-cache support for applicable Bedrock Nova deployments.
31
+ - Fixed Devin model variants with separate thinking and context-size options so all supported routing combinations and context limits are preserved.
32
+ - Corrected Devin SWE-1.6 and SWE-1.6 Fast capability metadata so image attachments use the appropriate text-only fallback instead of being silently discarded.
33
+ - Devin discovery now warns when the service returns an empty native model catalog, helping identify stale or incompatible CLI credentials.
34
+
35
+ ### Removed
36
+
37
+ - Removed legacy DeepSeek V3 variants from the Novita catalog.
38
+
5
39
  ## [18.0.11] - 2026-08-29
6
40
 
7
41
  ### Fixed
@@ -869,7 +903,7 @@
869
903
 
870
904
  ### Fixed
871
905
 
872
- - Fixed direct Anthropic Claude Sonnet/Haiku 4.5 advisor/agent turns crashing every call with HTTP 400 `This model does not support the effort parameter.` The catalog classified the whole Claude 4.5 family on `anthropic-messages` (and `bedrock-converse-stream`) as `anthropic-budget-effort`, which made the Anthropic provider serialize `output_config.effort` alongside `thinking.budget_tokens`. Anthropic only honors `output_config.effort` on Opus 4.5 and adaptive (4.6+) Messages-API models, so Sonnet 4.5 / Haiku 4.5 rejected the field. `inferThinkingControlMode` now gates `anthropic-budget-effort` to `parsedModel.kind === "opus" && semverGte(version, "4.5")` on both Anthropic-routed APIs, so Sonnet 4.5 / Haiku 4.5 on direct Anthropic + Cloudflare-AI-Gateway + Vertex + GitLab-Duo + Copilot + Bedrock fall through to plain `mode: "budget"` (thinking budget still scales with the selected effort tier). Opus 4.5 keeps `anthropic-budget-effort`. `anthropic-budget-effort` also stays in use for Anthropic-compatible third-party backends that natively support the field (Umans GLM 5.2). ([#3497](https://github.com/can1357/oh-my-pi/issues/3497))
906
+ - Fixed direct Anthropic Claude Sonnet/Haiku 4.5 advisor/agent turns crashing every call with HTTP 400 `This model does not support the effort parameter.` The catalog classified the whole Claude 4.5 family on `anthropic-messages` (and `bedrock-converse-stream`) as `anthropic-budget-effort`, which made the Anthropic provider serialize `output_config.effort` alongside `thinking.budget_tokens`. Anthropic only honors `output_config.effort` on Opus 4.5 and adaptive (4.6+) Messages-API models, so Sonnet 4.5 / Haiku 4.5 rejected the field. `inferThinkingControlMode` now gates `anthropic-budget-effort` to the structured Opus family at revision 4.5+ on both Anthropic-routed APIs, so Sonnet 4.5 / Haiku 4.5 on direct Anthropic + Cloudflare-AI-Gateway + Vertex + GitLab-Duo + Copilot + Bedrock fall through to plain `mode: "budget"` (thinking budget still scales with the selected effort tier). Opus 4.5 keeps `anthropic-budget-effort`. `anthropic-budget-effort` also stays in use for Anthropic-compatible third-party backends that natively support the field (Umans GLM 5.2). ([#3497](https://github.com/can1357/oh-my-pi/issues/3497))
873
907
 
874
908
  ## [16.1.17] - 2026-06-24
875
909
 
@@ -1004,7 +1038,7 @@
1004
1038
  - Fixed local Ollama (`provider: "ollama"`) reasoning turns still failing with HTTP 400 `invalid reasoning value: "minimal"` when the model was selected from a stale `~/.omp/models.db` cache row or a hand-written config: the `minimal → low` / `xhigh → max` remap was only stamped during fresh discovery, so cached and custom specs reached the wire unmapped. The remap now lives in the OpenAI chat-completions and Responses compat builders, so every `buildModel` (including cache loads, custom specs, and the `whenThinking` variant) backfills it — no `omp models refresh` required. Custom OpenAI-compatible providers registered under a non-`ollama` provider id still need their own `compat.reasoningEffortMap`.
1005
1039
  - Advertised Ollama Cloud GLM-5.2 reasoning efforts as high/xhigh-only and mapped `xhigh` to native max effort ([#2911](https://github.com/can1357/oh-my-pi/pull/2911) by [@serverinspector](https://github.com/serverinspector))
1006
1040
  - Fixed OpenRouter pseudo-API model construction so bundled OpenRouter models resolve shared OpenAI compatibility metadata instead of an undefined compat record.
1007
- - Fixed custom/direct `xai-oauth` Responses model specs (e.g. `grok-build`) emitting `reasoning.effort` and hitting xAI's HTTP 400: `buildOpenAIResponsesCompat` now defaults `supportsReasoningEffort` to `false` for `xai-oauth` Grok models that are off the effort-capable allowlist (`grok-3-mini`/`grok-4.20-multi-agent`/`grok-4.3`), matching the curated discovery path; explicit `compat.supportsReasoningEffort` still overrides. The allowlist moved to a shared `isGrokReasoningEffortCapable` identity helper consumed by both the compat builder and provider-model curation so the two cannot drift.
1041
+ - Fixed custom/direct `xai-oauth` Responses model specs (e.g. `grok-build`) emitting `reasoning.effort` and hitting xAI's HTTP 400: `buildOpenAIResponsesCompat` now defaults `supportsReasoningEffort` to `false` for `xai-oauth` Grok models that are off the effort-capable allowlist (`grok-3-mini`/`grok-4.20-multi-agent`/`grok-4.3`), matching the curated discovery path; explicit `compat.supportsReasoningEffort` still overrides. The reviewed allowlist moved into shared compat rules consumed by both the compat builder and provider-model curation so the two cannot drift.
1008
1042
 
1009
1043
  ## [16.0.5] - 2026-06-17
1010
1044
 
@@ -1094,13 +1128,13 @@
1094
1128
  ### Changed
1095
1129
 
1096
1130
  - Kept non-tool-capable Fireworks serverless models in discovery results and marked them with `supportsTools: false` for fallback-aware handling
1097
- - Extended `modelFamilyToken(modelId)` to classify Claude/OpenAI ids the structured parser misses (older dated forms such as `claude-3-5-sonnet-20241022` and `gpt-4o`), returning `anthropic`/`openai` instead of an empty token.
1131
+ - Extended structured classification to cover older Claude/OpenAI forms such as `claude-3-5-sonnet-20241022` and `gpt-4o`.
1098
1132
 
1099
1133
  ## [15.13.1] - 2026-06-15
1100
1134
 
1101
1135
  ### Added
1102
1136
 
1103
- - Added `modelFamilyToken(modelId)` to `@oh-my-pi/pi-catalog/identity`: a coarse vendor-lineage token (`anthropic`/`openai`/`gemini`/`kimi`/…) for "are two models the same family?" comparisons, backed by `parseKnownModel` canonical-id normalization. Opaque and comparison-only; kind/variant collapsed onto the vendor token ([#2406](https://github.com/can1357/oh-my-pi/issues/2406))
1137
+ - Added coarse vendor-lineage classification (`anthropic`/`openai`/`gemini`/`kimi`/…) to `@oh-my-pi/pi-catalog/identity` for "are two models the same family?" comparisons, with namespace normalization and kind/variant collapse ([#2406](https://github.com/can1357/oh-my-pi/issues/2406))
1104
1138
 
1105
1139
  ### Changed
1106
1140
 
@@ -1124,7 +1158,7 @@
1124
1158
  ### Changed
1125
1159
 
1126
1160
  - Pinned zai `glm-5.2` to 1M context during catalog generation so endpoint discovery and older fallbacks cannot regress it to 200k.
1127
- - Replaced the hand-maintained `zhipu-coding-plan` GLM reasoning allowlist and vision regex with a `parseGlmModel` family classifier in `identity/classify.ts` (variant + vision + version), surfaced as `isReasoningGlmModelId` / `isGlmVisionModelId`. Discovery now derives reasoning/vision capability from the GLM family instead of a per-id list, so newly-bumped integers (`glm-5.3`, `glm-6`, …) are covered automatically while `-flash`/`-preview` and the vision `…v` shape stay correctly classified.
1161
+ - Replaced the hand-maintained `zhipu-coding-plan` GLM reasoning allowlist and vision regex with structured GLM class, family, and revision facts. Discovery now derives reasoning/vision capability from the GLM family instead of a per-id list, so newly-bumped integers (`glm-5.3`, `glm-6`, …) are covered automatically while `-flash`/`-preview` and the vision `…v` shape stay correctly classified.
1128
1162
 
1129
1163
  ## [15.12.4] - 2026-06-13
1130
1164
 
@@ -1237,7 +1271,7 @@
1237
1271
  - Added `ResolvedAnthropicCompat.supportsSamplingParams` (Opus 4.7+/Fable/Mythos reject `temperature`/`top_p`/`top_k` with a 400), baked at build time from model identity so the request path stops re-parsing model ids.
1238
1272
  - Compat detection gained model-time flags so handlers stop sniffing baseUrl: completions `supportsReasoningParams`, `alwaysSendMaxTokens`, `isOpenRouterHost`, `isVercelGatewayHost`, `streamIdleTimeoutMs`, and a precomputed `whenThinking` alternate view (OpenCode `reasoning_content` gating, #1071/#1484); responses `strictResponsesPairing`, `supportsLongPromptCacheRetention`, `supportsReasoningEffort`; anthropic `officialEndpoint`, `requiresToolResultId`, `replayUnsignedThinking`.
1239
1273
  - New `@oh-my-pi/pi-catalog` package: the model catalog extracted from `@oh-my-pi/pi-ai`. Owns the bundled `models.json` and its generation pipeline (`scripts/generate-models.ts`), the core model data types (`Model`, `Api`, `ThinkingConfig`, `Effort`, `Usage`, compat interfaces), thinking metadata enrichment and generated policies (`model-thinking.ts`), the SQLite model cache and model manager, per-provider discovery factories (`provider-models/`), the discovery protocol clients (`discovery/`), and the new `CATALOG_PROVIDERS` table — the single source of truth for provider ids, default models, and discovery wiring (`KnownProvider`, `PROVIDER_DESCRIPTORS`, and `DEFAULT_MODEL_PER_PROVIDER` are derived from it).
1240
- - New `identity/` module centralizing model-identity concerns that were previously duplicated across packages: family classification and version parsing (`identity/classify.ts`, extracted from pi-ai's `model-thinking` internals), canonical model equivalence with injected reference data (`identity/equivalence.ts`, from coding-agent's `model-equivalence`), proxy/reseller reference lookup (`identity/reference.ts`, from coding-agent's `model-registry`), bracket-affix and id-segment helpers (`identity/id.ts`), a single trailing-marker vocabulary with canonical vs reference flavors (`identity/markers.ts` — `search` stays reference-only so Perplexity's `sonar-pro-search` remains canonical-distinct), and provider priority ordering (`identity/priority.ts`).
1274
+ - New `identity/` module centralizing model-identity concerns that were previously duplicated across packages: structured taxonomy classification and revisions, proxy/reseller reference lookup (`identity/reference.ts`), bracket-affix and id-segment helpers (`identity/id.ts`), and provider priority ordering (`identity/priority.ts`).
1241
1275
  - Memoized bundled-reference accessors (`getBundledCanonicalReferenceData` / `getBundledModelReferenceIndex` in `identity/bundled.ts`): one lazy walk of the bundled catalog feeds both canonical equivalence and proxy-reference lookup, so consumers no longer hand-roll the glue.
1242
1276
  - `identity/selection.ts`: pure canonical-variant selection (`resolveCanonicalVariant`, `buildCanonicalModelOrder`, `CanonicalVariantPreferences`) extracted from the coding-agent registry — provider rank, then exact-id match, variant source, id length, and candidate order.
1243
1277
 
@@ -1249,14 +1283,14 @@
1249
1283
  - `Model`'s api parameter now defaults to `Api` instead of `any` (`Model<TApi extends Api = Api>`), so bare `Model` no longer behaves as `Model<any>` at call sites.
1250
1284
  - `ThinkingConfig` is now explicit and total: an ordered `efforts` array replaces the `minLevel`/`maxLevel`/`levels` range encoding, and the wire facts are baked alongside it — `effortMap` (anthropic-adaptive 4-tier vs 5-tier scale, shared with the OpenRouter completions remap) and `supportsDisplay` (adaptive `display` field support). Explicit spec thinking owns the capability surface (`mode`/`efforts`/`defaultLevel`) and wins over inference; missing wire facts are backfilled from identity so configs never need to know Anthropic's tier tables. Reasoning models that reject the wire effort param (`compat.supportsReasoningEffort: false` on openai-responses*) are encoded as `thinking: undefined` ("thinks, no control surface") instead of the removed `modelOmitsReasoningEffort` special case. `models.json` was re-baked in the new vocabulary behind a 3196-model behavioral parity gate, and the model cache schema bumped to v4 to invalidate old-shape rows.
1251
1285
  - `mapEffortToGoogleThinkingLevel(effort)` is now a static map (model parameter dropped — validation stays at the `requireSupportedEffort` call sites), and `mapEffortToAnthropicAdaptiveEffort` reads the baked `thinking.effortMap` instead of re-classifying the model id per request.
1252
- - Generator-only policy code moved out of the runtime bundle into `scripts/generated-policies.ts`: `applyGeneratedModelPolicies` (now policy fixups + thinking re-bake via the shared deriver), `linkOpenAIPromotionTargets`, the Copilot context-window table, minimax/opencode-go compat fixups, and `CLOUDFLARE_FALLBACK_MODEL`. The anthropic id predicates (`hasOpus47ApiRestrictions`, `supportsMidConversationSystemMessages`, `isAnthropicFableOrMythosModel`) moved to `identity/family` for build-time use by the compat/thinking derivers only.
1286
+ - Generator-only policy code moved out of the runtime bundle into `scripts/generated-policies.ts`: `applyGeneratedModelPolicies` (now policy fixups + thinking re-bake via the shared deriver), `linkOpenAIPromotionTargets`, the Copilot context-window table, minimax/opencode-go compat fixups, and `CLOUDFLARE_FALLBACK_MODEL`. Anthropic generation checks moved to structured class, family, and revision facts for build-time use by the compat/thinking derivers only.
1253
1287
 
1254
1288
  ### Fixed
1255
1289
 
1256
1290
  - Fixed Anthropic official-endpoint detection to require strict HTTPS hostname matching so non-official or lookalike URLs are no longer treated as official Anthropic hosts
1257
1291
  - Fixed Ollama Cloud dynamic discovery so same-id matches from other providers no longer supply context-window or max-output-token limits for discovered models.
1258
1292
  - Wired `@oh-my-pi/pi-catalog` into the release publish package list, tarball install smoke test, and root `bun generate-models` script.
1259
- - Fixed `supportsAdaptiveThinkingDisplay` only matching dash-form version ids: dotted ids (`claude-opus-4.7`) now classify through `identity/classify` like every other anthropic predicate, so six bundled dotted Opus 4.7/4.8 entries (github-copilot, vercel-ai-gateway, zenmux) regain adaptive `display` support; bare dated ids (`claude-opus-4-20250514` = Opus 4.0) stay excluded.
1293
+ - Fixed adaptive-display classification only matching dash-form version ids: dotted ids (`claude-opus-4.7`) now classify through the structured taxonomy, so six bundled dotted Opus 4.7/4.8 entries (github-copilot, vercel-ai-gateway, zenmux) regain adaptive `display` support; bare dated ids (`claude-opus-4-20250514` = Opus 4.0) stay excluded.
1260
1294
  - Fixed the OpenRouter anthropic adaptive-effort map misclassifying bare dated Opus ids (`claude-opus-4-20250514` parsed as version 4.20 → wrongly adaptive); the map now derives from the shared classifier and the shared 4-/5-tier tables.
1261
1295
 
1262
1296
  ### Removed
package/README.md CHANGED
@@ -9,25 +9,26 @@ Model catalog for [oh-my-pi](https://github.com/can1357/oh-my-pi): bundled model
9
9
  | `models.json` + `models` | Bundled model database (pricing, context windows, modalities, thinking support) |
10
10
  | `provider-models` | Provider catalog descriptors (`CATALOG_PROVIDERS`), per-provider model resolution rules |
11
11
  | `discovery` | Runtime model discovery for OpenAI-compatible endpoints, Gemini, Codex, Cursor, Antigravity, Ollama |
12
- | `identity` | Model id parsing and classification (family/version), reference resolution, equivalence, selection priority |
13
- | `model-thinking` | Thinking/reasoning metadata and generated per-model policies |
12
+ | `compat/rules` | Checked-in KDL policy tree: taxonomy (classes/families/revisions), class/provider cascade rules, runtime behavior vocabulary; compiled by `bun run gen:compat` into the committed `rules.json` |
13
+ | `compat` | The rule engine: `classifyModel` (taxonomy), `resolveModelPolicy` (cascade), behavior accessors (`api-routes`, `model-limits`, `exclude-models`, `pricing-peer`), collapse, and OpenAI/Anthropic wire builders that consume resolved records |
14
+ | `identity` | Mechanical id utilities: reference resolution against the bundled index, dialects, selection priority, tokenizer families |
15
+ | `model-thinking` | Runtime thinking helpers (`getSupportedEfforts`, effort clamping/mapping, wire-id routing) over resolved model records |
14
16
  | `model-manager` / `model-cache` | Runtime model registry with discovery refresh and on-disk caching |
15
- | `variant-collapse` | Collapsing provider-specific variants of the same underlying model |
16
- | `compat` | Request/response compatibility fixups for OpenAI- and Anthropic-shaped APIs |
17
17
  | `wire` | Wire-level helpers: Codex, Gemini headers, GitHub Copilot |
18
18
  | `effort` | Reasoning-effort level definitions |
19
19
 
20
20
  Import from subpaths (`@oh-my-pi/pi-catalog/<module>`) or the root barrel.
21
21
 
22
- ## models.json is generated
22
+ ## models.json and rules.json are generated
23
23
 
24
- Never edit `src/models.json` by hand it is produced from upstream sources (stencil.so, provider catalog discovery, OpenCode docs) by `scripts/generate-models.ts` and the resolvers in `src/provider-models/`. Regenerate with:
24
+ Never edit `src/models.json` or `src/compat/rules.json` by hand. `models.json` is produced from upstream sources (stencil.so, provider catalog discovery, OpenCode docs) by `scripts/generate-models.ts`; `rules.json` is compiled from the KDL tree in `src/compat/rules/`. Regenerate with:
25
25
 
26
26
  ```sh
27
- bun run gen:models
27
+ bun run gen:compat # src/compat/rules/**/*.kdl -> src/compat/rules.json
28
+ bun run gen:models # upstream sources + rules -> src/models.json
28
29
  ```
29
30
 
30
- To change an entry, fix the source: resolver overrides in `provider-models/openai-compat.ts`, provider entries in `provider-models/descriptors.ts`, generator fixups in `scripts/generate-models.ts`, or thinking policies in `model-thinking.ts`.
31
+ Model- or provider-conditional policy (identity, effort ladders, wire quirks, modality/limit/pricing corrections, API routing, roster exclusions) lives in the KDL tree — see `src/compat/rules/README.md` for the grammar and axis vocabulary. TypeScript changes are only for transport mechanics: provider entries in `provider-models/descriptors.ts`, discovery/request plumbing in `provider-models/openai-compat.ts`, and generator wiring in `scripts/generate-models.ts`. Commit `rules.json` (and a rebaked `models.json` when values change) alongside the `.kdl` edit.
31
32
 
32
33
  ## Install
33
34
 
@@ -1,19 +1,24 @@
1
1
  /**
2
- * The single Model constructor. Resolution order is a dependency chain, each
3
- * step materialized exactly once per spec:
4
- *
5
- * 1. compat — URL/provider/id detection resolved into a complete record;
6
- * 2. thinking — derived from identity + resolved compat (or trusted verbatim
7
- * when the spec carries explicit metadata);
2
+ * The single Model constructor. Resolution runs through the compat engine
3
+ * (`compat/resolve`): identity classification, cascade-rule axes, host
4
+ * detection, and spec overrides materialize exactly once per spec.
8
5
  *
9
6
  * Request handlers read fields — they never detect, parse ids, or allocate
10
7
  * compat per request.
11
8
  */
12
- import type { Api, CompatOf, Model, ModelSpec } from "./types.js";
9
+ import type { Api, Model, ModelSpec } from "./types.js";
10
+ /**
11
+ * Applies reviewed catalog-data value corrections (`cost-patch`,
12
+ * `limits-patch`, `long-context-cost`, `context-window-floor`,
13
+ * `input-modalities`) onto an upstream-sourced spec. Applied by
14
+ * `buildModel` to every upstream-sourced spec; user-authored overrides are
15
+ * recomposed after building by the override applicators, so explicit user
16
+ * limits and pricing still win.
17
+ */
18
+ export declare function applyCatalogCorrections(model: Pick<ModelSpec<Api>, "cost" | "contextWindow" | "maxTokens" | "input">, catalog: Record<string, unknown>): void;
13
19
  /**
14
20
  * Build one model from an authored spec. Bundled models.json rows are fully
15
21
  * materialized by the generator and consumed directly (see `models.ts`), so
16
22
  * this only runs for discovered/custom/override specs.
17
23
  */
18
24
  export declare function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi>;
19
- export declare function buildCompat(spec: ModelSpec<Api>): CompatOf<Api>;
@@ -0,0 +1,4 @@
1
+ /** Convert a public ClinePass catalog id to the gateway's wire id. */
2
+ export declare function toClinePassWireModelId(modelId: string): string;
3
+ /** Convert a gateway ClinePass wire id to the public catalog id. */
4
+ export declare function toClinePassPublicModelId(modelId: string): string;
@@ -1,4 +1,3 @@
1
- import type { ModelSpec, ResolvedAnthropicCompat } from "../types.js";
2
1
  /**
3
2
  * Official first-party Anthropic API. A missing baseUrl is official on purpose:
4
3
  * request dispatch falls back to `https://api.anthropic.com`. This is the one
@@ -8,11 +7,18 @@ import type { ModelSpec, ResolvedAnthropicCompat } from "../types.js";
8
7
  */
9
8
  export declare function isOfficialAnthropicApiUrl(baseUrl?: string): boolean;
10
9
  /**
11
- * Known non-official URLs that enforce Anthropic thinking signatures on replay.
10
+ * Azure AI Inference / Foundry Anthropic route
11
+ * (`<resource>.inference.ai.azure.com`, `<resource>.services.ai.azure.com`).
12
+ * Fronts Claude behind Azure identity and enforces Anthropic signatures on
13
+ * replay; it also rejects the top-level `strict` tool field.
14
+ */
15
+ export declare function isAzureAnthropicRoute(baseUrl?: string): boolean;
16
+ /**
17
+ * Known non-official URLs that enforce Anthropic thinking signatures on replay
18
+ * (GitHub Copilot, ZenMux, Cloudflare AI Gateway `/anthropic`, Google Vertex
19
+ * `publishers/anthropic`, AWS Bedrock, Azure Foundry).
12
20
  *
13
21
  * Runtime routing calls this with the effective URL because a model's resolved
14
22
  * compat can be stale after Foundry or a provider base-URL override reroutes it.
15
23
  */
16
24
  export declare function isAnthropicSigningProxyUrl(baseUrl?: string): boolean;
17
- /** Build the resolved anthropic-messages compat record for a model spec. */
18
- export declare function buildAnthropicCompat(spec: ModelSpec<"anthropic-messages">): ResolvedAnthropicCompat;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The closed compat-axis vocabulary: every KDL cascade directive, the resolved
3
+ * camelCase field it assigns, its value shape, and — for wire axes — the
4
+ * compat records it applies to.
5
+ *
6
+ * Single source of truth shared by the compile-time rule compiler
7
+ * (`scripts/compat-compiler`) and the runtime engine (`./resolve`). The
8
+ * compiler rejects any directive absent from this table; the runtime assigns
9
+ * a wire axis onto a model's compat record only when the model's API maps to
10
+ * one of the axis's declared records.
11
+ */
12
+ import type { Effort } from "../effort.js";
13
+ import type { ThinkingControlMode } from "../types.js";
14
+ /** Value shape a directive accepts (see `rules/README.md`). */
15
+ export type AxisShape = "scalar" | "array" | "object";
16
+ /** Axis namespace: request-wire compat, thinking control surface, or catalog metadata. */
17
+ export type AxisSet = "wire" | "thinking" | "catalog";
18
+ /** Resolved compat record families a wire axis may be assigned onto. */
19
+ export type CompatRecordName = "openai" | "openai-responses" | "anthropic" | "bedrock" | "devin" | "google";
20
+ /** One axis definition: resolved key, namespace, shape, and applicability. */
21
+ export interface AxisDef {
22
+ /** Resolved camelCase field the directive assigns. */
23
+ key: string;
24
+ set: AxisSet;
25
+ shape: AxisShape;
26
+ /** Wire axes only: records this key exists on. */
27
+ records?: readonly CompatRecordName[];
28
+ /** Closed value vocabulary for string scalars / string arrays. */
29
+ values?: readonly string[];
30
+ /**
31
+ * Object axes only: payload child names are literal wire JSON keys copied
32
+ * verbatim (`extra-body`). Default object payloads author kebab-case names
33
+ * that compile to camelCase resolved keys.
34
+ */
35
+ verbatimKeys?: true;
36
+ }
37
+ /** Effort tiers accepted by taxonomy collapse/override vocabulary (`Effort` ∪ `"off"`). */
38
+ export declare const EFFORT_TIERS: readonly string[];
39
+ /** Narrow a KDL string to an effort tier (`Effort` ∪ `"off"`). */
40
+ export declare function isEffortTier(value: string): value is Effort | "off";
41
+ /** Narrow a KDL string to a thinking control mode. */
42
+ export declare function isThinkingMode(value: string): value is ThinkingControlMode;
43
+ /**
44
+ * KDL directive → axis definition. Keys are the kebab-case directive
45
+ * spellings accepted inside `classes/*.kdl` and `providers/*.kdl` rule
46
+ * blocks.
47
+ */
48
+ export declare const AXES: Readonly<Record<string, AxisDef>>;
49
+ /** Records applicable to each API family; used by `resolve.ts` when applying wire axes. */
50
+ export declare const API_COMPAT_RECORDS: Readonly<Record<string, readonly CompatRecordName[]>>;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Conservative heuristic for a normalized, lowercase discovered model id with
3
+ * no exact bundled record: whether it likely rides the OpenAI Responses API.
4
+ */
5
+ export declare function isLikelyOpenAIResponsesId(model: string): boolean;
6
+ /**
7
+ * Additional catalog-declared operations for a discovered provider/model pair
8
+ * (e.g. `generate_image`), augmenting provider discovery metadata.
9
+ */
10
+ export declare function modelOperationOverrides(provider: string, model: string): readonly string[];
11
+ /**
12
+ * Splits a Cursor effort-suffixed OpenAI sibling id into its base id and
13
+ * declared effort tier. The family gate requires the declared marker
14
+ * (`gpt-`) followed immediately by an ASCII digit; matching stays
15
+ * case-sensitive to preserve Cursor wire-id behavior.
16
+ */
17
+ export declare function cursorEffortSuffix(model: string): {
18
+ base: string;
19
+ tier: string;
20
+ } | undefined;
21
+ /** Fixed Cursor `requestedModel` parameters declared for an exact wire model. */
22
+ export declare function cursorModelParameters(model: string): readonly {
23
+ id: string;
24
+ value: string;
25
+ }[];
26
+ /**
27
+ * The catalog-declared quota scope or display tier for a provider model id.
28
+ * Exact authored memberships win; provider-authored substring fallbacks
29
+ * preserve quota semantics for newly discovered ids.
30
+ */
31
+ export declare function quotaTierFor(provider: string, model: string): string | undefined;
32
+ /** Whether a provider has catalog-authored model quota scopes. */
33
+ export declare function hasQuotaTierPolicy(provider: string): boolean;
34
+ /** The provider-default wire model for a model-less hosted operation. */
35
+ export declare function hostedDefaultModel(provider: string): string | undefined;
36
+ /** One resolved API route for a provider model id. */
37
+ export interface ApiRouteMatch {
38
+ /** Transport API the id rides. */
39
+ api: string;
40
+ /** Wire id after prefix stripping, when the route declares `strip-prefix`. */
41
+ requestModelId?: string;
42
+ }
43
+ /**
44
+ * Resolves the declared API route for a provider model id. Routes match in
45
+ * declaration order; a `strip-prefix` route with a prefix matcher strips the
46
+ * matched prefix off the wire id. Falls back to the node's `default` API.
47
+ */
48
+ export declare function apiRouteFor(provider: string, model: string): ApiRouteMatch | undefined;
49
+ /** Exact model ids named by a provider's api-routes rules (cache-migration drop lists). */
50
+ export declare function apiRouteExactModelIds(provider: string): string[];
51
+ /** Declared context-window / max-token pins for a provider model id. */
52
+ export declare function modelLimitsFor(provider: string, model: string): {
53
+ context?: number;
54
+ maxTokens?: number;
55
+ } | undefined;
56
+ /** Whether a provider roster entry is a declared non-chat/unsupported SKU. */
57
+ export declare function isExcludedModel(provider: string, model: string): boolean;
58
+ /**
59
+ * Whether a provider is retired: its entire roster is excluded from the
60
+ * generated bundle and must never be resurrected from the previous snapshot.
61
+ */
62
+ export declare function isRetiredProvider(provider: string): boolean;
63
+ /** The declared subscription tier required to use a provider model id, if any. */
64
+ export declare function planRequirementFor(provider: string, model: string): string | undefined;
65
+ /** Cross-provider pricing-peer resolution for one provider model id. */
66
+ export declare function pricingPeerFor(provider: string, model: string): {
67
+ peers: readonly string[];
68
+ peerId: string;
69
+ } | undefined;
@@ -0,0 +1,37 @@
1
+ import type { CompiledCascade, ResolvedAxes, ResolveTarget } from "./types.js";
2
+ /**
3
+ * Two equal-rank rules contest one axis for a target. CI-time for bundled
4
+ * targets (the parity sweep exercises every catalog row); fix with an
5
+ * explicit `priority=` in the KDL, never in code.
6
+ */
7
+ export declare class AmbiguousOverlapError extends Error {
8
+ readonly provider: string;
9
+ readonly model: string;
10
+ readonly axis: string;
11
+ readonly first: string;
12
+ readonly second: string;
13
+ constructor(provider: string, model: string, axis: string, first: string, second: string);
14
+ }
15
+ /**
16
+ * Anchored `*`-wildcard match; both sides must be pre-lowercased. `*` spans
17
+ * any substring; non-wildcard text stays anchored in order.
18
+ */
19
+ export declare function globMatch(pattern: string, value: string): boolean;
20
+ /**
21
+ * Resolves wire, thinking, and catalog assignments for one structured target.
22
+ *
23
+ * Thinking axes are gated on `target.reasoning`, except that an exact model
24
+ * selector declaring `thinking-efforts` upgrades the target (a reviewed
25
+ * correction to stale capability metadata). Family and revision selectors
26
+ * never match targets missing that identity rank. Unmatched targets resolve
27
+ * to empty maps.
28
+ *
29
+ * @throws AmbiguousOverlapError when two equal-rank rules contest one axis.
30
+ */
31
+ export declare function resolveCascade(target: ResolveTarget): ResolvedAxes;
32
+ /**
33
+ * Resolves a target against an arbitrary compiled cascade (test seam and
34
+ * scratch evaluations); `resolveCascade` delegates here with the bundled
35
+ * rule index.
36
+ */
37
+ export declare function resolveCascadeRules(cascade: CompiledCascade, target: ResolveTarget): ResolvedAxes;
@@ -1,5 +1,5 @@
1
- import { Effort } from "./effort.js";
2
- import type { Api, Model, ModelSpec, Provider, ThinkingConfig } from "./types.js";
1
+ import { Effort } from "../effort.js";
2
+ import type { Api, Model, ModelSpec, Provider, ThinkingConfig } from "../types.js";
3
3
  /**
4
4
  * Structural bound for collapse inputs: both raw `ModelSpec`s and built
5
5
  * `Model`s qualify. (`Model.compat` is the resolved record, not the sparse
@@ -45,8 +45,14 @@ export interface EffortVariantFamily {
45
45
  * efforts fall back to `requestModelId ?? id`.
46
46
  */
47
47
  routing: Readonly<Partial<Record<Effort | "off", string>>>;
48
- /** Explicit capability surface for the collapsed spec — no inference. */
49
- thinking: Readonly<Omit<ThinkingConfig, "effortRouting" | "suppressWhenOff">>;
48
+ /**
49
+ * Explicit capability surface for the collapsed spec — no inference. Omit
50
+ * for single-wire-id renames on providers where effort is encoded in the
51
+ * upstream id itself (Devin): with one member and no routing there is no
52
+ * controllable surface, and the collapsed spec must carry no thinking
53
+ * rather than an effort ladder whose every tier resolves to one wire id.
54
+ */
55
+ thinking?: Readonly<Omit<ThinkingConfig, "effortRouting" | "suppressWhenOff">>;
50
56
  /** Thinking-off requests must explicitly suppress thinking on the wire. */
51
57
  suppressWhenOff?: boolean;
52
58
  /**
@@ -61,16 +67,21 @@ export interface EffortVariantFamily {
61
67
  }
62
68
  export interface VariantCollapseTable {
63
69
  families: readonly EffortVariantFamily[];
70
+ /**
71
+ * Provider-scoped selector aliases: short native-CLI names and dotted
72
+ * upstream spellings → logical model id. Unlike family members and
73
+ * `extraAliases` these are deliberately invisible to the bare-id lookup
74
+ * ({@link resolveBareVariantSelector}) and to the reverse index — a generic
75
+ * label like `gpt` or `opus` only means something once a provider is
76
+ * named, and must never hijack an unqualified selector or re-key config.
77
+ */
78
+ providerAliases?: Readonly<Record<string, string>>;
64
79
  }
65
- /** `google-antigravity` Gemini families, using each generation's native transport. */
66
- export declare const ANTIGRAVITY_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
67
- /** `google-gemini-cli` Gemini families on the official CLI's level transport. */
68
- export declare const GEMINI_CLI_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
69
- export declare const DEVIN_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
70
- /** `cursor` per-effort sibling families collapsed per service-tier lane: Grok 4.5/4.6 plus GPT-5.6 Luna/Sol/Terra. */
71
- export declare const CURSOR_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
72
- /** Provider id → hand collapse table. The CCA providers diverge on thinking transport. */
73
- export declare const VARIANT_COLLAPSE_TABLES: Readonly<Record<string, VariantCollapseTable>>;
80
+ /**
81
+ * Return the reviewed collapse table compiled for `provider`, when declared.
82
+ * Discovery uses this accessor to preserve injectable table seams.
83
+ */
84
+ export declare function reviewedCollapseTable(provider: string): VariantCollapseTable | undefined;
74
85
  /**
75
86
  * The global automatic rule: derive an `X` + `X-thinking` family for every
76
87
  * pair where both ids are live in `specs` (trailing or infix token). Gates:
@@ -78,35 +89,31 @@ export declare const VARIANT_COLLAPSE_TABLES: Readonly<Record<string, VariantCol
78
89
  * - known pricing must match — all-zero cost rows count as unknown
79
90
  * (aggregators routinely ship them), but twins that BOTH carry real,
80
91
  * differing prices are distinct SKUs and never merge,
81
- * - ids claimed by the provider's hand `table` are skipped (curation wins).
92
+ * - ids claimed by the provider's reviewed table are skipped (curation wins).
82
93
  * The capability surface prefers the thinking member's metadata, then the
83
94
  * bare member's, then the canonical deriver (aggregators often ship
84
95
  * `reasoning: false` and no thinking config on the twin), then a budget
85
96
  * default. `off` routes to the bare id; every supported effort routes to the
86
97
  * thinking id.
87
98
  */
88
- export declare function deriveThinkingPairFamilies<TSpec extends VariantSpecLike>(specs: readonly TSpec[], table?: VariantCollapseTable): EffortVariantFamily[];
99
+ export declare function deriveThinkingPairFamilies<TSpec extends VariantSpecLike>(specs: readonly TSpec[], table?: VariantCollapseTable, provider?: string): EffortVariantFamily[];
89
100
  /**
90
101
  * True when `spec` is the output of collapsing rather than a raw upstream
91
102
  * member. `thinking.effortRouting` is written only by collapsing; the
92
- * `requestModelId` arm is scoped to the provider's hand-table family ids so
103
+ * `requestModelId` arm is scoped to the provider's reviewed-table family ids so
93
104
  * unrelated carriers (GitHub Copilot `-1m` context variants) never match.
94
105
  */
95
- export declare function isVariantCollapsedSpec(spec: VariantSpecLike): boolean;
96
- /**
97
- * Collapse every family in `table` found in `specs`. Non-member specs pass
98
- * through verbatim (by reference), order preserved; the collapsed spec
99
- * replaces the first occurrence of its family.
100
- */
101
- export declare function collapseEffortVariants<TSpec extends VariantSpecLike>(specs: readonly TSpec[], table: VariantCollapseTable): TSpec[];
106
+ export declare function isCollapsedVariantSpec(spec: VariantSpecLike): boolean;
102
107
  /**
103
- * Collapse a full mixed-provider list: per provider, the hand table, Cursor's
108
+ * Collapse a full mixed-provider list: per provider, the compiled reviewed table, Cursor's
104
109
  * conservative live effort-sibling rule, and the automatic `X`/`X-thinking`
105
110
  * pair rule. Used by the catalog generator; the runtime equivalent lives at
106
111
  * the model-manager merge point. Output is regrouped by provider — callers
107
112
  * re-sort.
108
113
  */
109
- export declare function collapseEffortVariantsAcrossProviders<TSpec extends VariantSpecLike>(specs: readonly TSpec[]): TSpec[];
114
+ export declare function collapseVariants<TSpec extends VariantSpecLike>(specs: readonly TSpec[], opts?: {
115
+ table?: VariantCollapseTable;
116
+ }): TSpec[];
110
117
  /**
111
118
  * Runtime entry point for already-built `Model` lists (the model-manager
112
119
  * merge point, coding-agent registry custom providers): collapses hand
@@ -114,16 +121,14 @@ export declare function collapseEffortVariantsAcrossProviders<TSpec extends Vari
114
121
  * logical specs so thinking wire defaults stay resolved. Untouched entries
115
122
  * pass through by reference.
116
123
  */
117
- export declare function collapseBuiltModelVariants<TApi extends Api>(models: readonly Model<TApi>[]): Model<TApi>[];
124
+ export declare function collapseBuiltVariants<TApi extends Api>(models: readonly Model<TApi>[]): Model<TApi>[];
118
125
  /**
119
- * Resolve a retired effort-tier variant id (collapsed member, recycled id) to
120
- * its replacement model id for `provider` via hand-table or registered live
121
- * aliases. Returns `undefined` when the id is not a known alias; derived
122
- * `X-thinking` members also resolve through `stripThinkingVariantToken`.
123
- * Callers must try an exact model lookup first — a live model always wins over
124
- * an alias.
126
+ * Resolve a retired effort-tier variant id, registered live alias, or
127
+ * provider-scoped native alias to its replacement model id for `provider`.
128
+ * Returns `undefined` when the id is unknown. Callers must try an exact model
129
+ * lookup first because a live model always wins over an alias.
125
130
  */
126
- export declare function resolveVariantAlias(provider: Provider, modelId: string): string | undefined;
131
+ export declare function resolveVariantSelector(provider: Provider, modelId: string): string | undefined;
127
132
  /** Bare-id alias hit: replacement id plus the providers declaring it. */
128
133
  export interface BareVariantAliasHit {
129
134
  id: string;
@@ -136,10 +141,10 @@ export interface BareVariantAliasHit {
136
141
  * on unrelated providers too (e.g. a retired Cursor tier id must not resolve
137
142
  * to `openai/gpt-5.4`).
138
143
  */
139
- export declare function resolveBareVariantAlias(modelId: string): BareVariantAliasHit | undefined;
144
+ export declare function resolveBareVariantSelector(modelId: string): BareVariantAliasHit | undefined;
140
145
  /**
141
146
  * Reverse alias lookup: the retired ids that resolve to `modelId` for
142
- * `provider` via hand-table or registered live aliases. Used to re-key config
147
+ * `provider` via reviewed-table or registered live aliases. Used to re-key config
143
148
  * keyed by raw member ids (models.yml `modelOverrides`, suppressed selectors)
144
149
  * onto the collapsed model.
145
150
  */
@@ -1,28 +1,9 @@
1
- import type { ModelSpec, OpenAICompat, ResolvedOpenAICompat, ResolvedOpenAIResponsesCompat, ResolvedOpenRouterCompat } from "../types.js";
2
- /** Wire effort remap for first-party xAI Responses. */
3
- export declare function xaiResponsesReasoningEffortMap(modelId: string): NonNullable<OpenAICompat["reasoningEffortMap"]>;
4
- /**
5
- * Build the resolved chat-completions compat record for a model spec.
6
- * Provider takes precedence over URL-based detection since it's explicitly configured.
7
- */
8
- export declare function buildOpenAICompat(spec: ModelSpec<"openai-completions">): ResolvedOpenAICompat;
9
- interface OpenAIResponsesSpecLike {
10
- id?: string;
11
- provider: string;
12
- name: string;
13
- baseUrl: string;
14
- reasoning?: boolean;
15
- compat?: OpenAICompat;
16
- }
17
1
  /**
18
- * Build the resolved Responses-API compat record. Most shared OpenAI-compatible
19
- * capability defaults intentionally mirror chat-completions, while Responses-
20
- * only behavior (developer role, prompt cache, pairing strictness, image detail)
21
- * keeps endpoint-specific detection. Azure is detected by provider id as well
22
- * as URL — bundled `azure` models carry no baseUrl (the deployment host is per-
23
- * resource, resolved at runtime) — while OpenAI/Copilot developer-role and
24
- * prompt-cache detection stay URL-keyed, as the historical call sites were.
2
+ * OpenAI-side compat residue: the first-party xAI Responses effort remap used
3
+ * by the xai-oauth discovery mapper when curating sparse rows. Everything else
4
+ * that lived here (the chat-completions/Responses compat builders) moved into
5
+ * the compat engine (`./resolve`) and the KDL rules.
25
6
  */
26
- export declare function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): ResolvedOpenAIResponsesCompat;
27
- export declare function buildOpenRouterCompat(spec: ModelSpec<"openrouter">): ResolvedOpenRouterCompat;
28
- export {};
7
+ import type { OpenAICompat } from "../types.js";
8
+ /** Wire effort remap for first-party xAI Responses. */
9
+ export declare function xaiResponsesReasoningEffortMap(modelId: string): NonNullable<OpenAICompat["reasoningEffortMap"]>;
@@ -0,0 +1,15 @@
1
+ import type { Api, CompatOf, ModelSpec, ThinkingConfig } from "../types.js";
2
+ import type { ModelIdentity } from "./types.js";
3
+ /** Result of resolving one model spec through the compat engine. */
4
+ export interface ResolvedModelPolicy<TApi extends Api = Api> {
5
+ identity: ModelIdentity;
6
+ compat: CompatOf<TApi>;
7
+ thinking: ThinkingConfig | undefined;
8
+ /** Catalog-data axis assignments (longContext, priority, …) for generation. */
9
+ catalog: Record<string, unknown>;
10
+ }
11
+ /**
12
+ * Resolves the full policy surface for one model spec: structured identity,
13
+ * complete compat record, thinking metadata, and catalog-data corrections.
14
+ */
15
+ export declare function resolveModelPolicy<TApi extends Api>(spec: ModelSpec<TApi>): ResolvedModelPolicy<TApi>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Revision triples (`major.minor.patch`) extracted from model identifiers.
3
+ *
4
+ * The compat engine compares revisions as three unsigned 8-bit components;
5
+ * omitted components are zero (`4.6` ≡ `4.6.0`). Shared by the compile-time
6
+ * rule compiler and the runtime taxonomy/cascade.
7
+ */
8
+ /** A parsed `major.minor.patch` revision. */
9
+ export type Revision = readonly [number, number, number];
10
+ /**
11
+ * Parses an explicit revision literal: one to three components separated by
12
+ * `.` or `-` (`"4.6"`, `"4-6-1"`). Returns undefined on malformed input.
13
+ */
14
+ export declare function parseRevision(value: string): Revision | undefined;
15
+ /**
16
+ * Extracts a leading revision from an identifier tail that begins with a
17
+ * digit: up to three components separated by `.` or by `-` followed by a
18
+ * digit (`"4-6-turbo"` → `[4, 6, 0]`). Mirrors o2 `parse_revision_prefix`.
19
+ * A component whose digits run directly into a letter is a parameter-count
20
+ * or size token (`qwen3-32b`, `llama-3.3-70b`), never a revision component.
21
+ */
22
+ export declare function parseRevisionPrefix(value: string): Revision | undefined;
23
+ /** Lexicographic triple comparison: negative, zero, or positive. */
24
+ export declare function compareRevision(a: Revision, b: Revision): number;
25
+ /** Renders a revision as its canonical `major.minor.patch` string. */
26
+ export declare function formatRevision(revision: Revision): string;
27
+ /** Comparison operator inside a `revision ">=2.5 <4"` cascade constraint. */
28
+ export type RevisionOp = ">=" | ">" | "<=" | "<" | "=";
29
+ /** One comparison term of a revision constraint conjunction. */
30
+ export interface RevisionTerm {
31
+ op: RevisionOp;
32
+ revision: Revision;
33
+ }
34
+ /** Whether `revision` satisfies every term of the conjunction. */
35
+ export declare function revisionSatisfies(revision: Revision, terms: readonly RevisionTerm[]): boolean;
36
+ /**
37
+ * Parses a whitespace-separated conjunction of comparisons
38
+ * (`">=2.5 <3.8"`). Operands allow one to three dot-separated components.
39
+ * Returns undefined when empty or malformed.
40
+ */
41
+ export declare function parseRevisionConstraint(expression: string): RevisionTerm[] | undefined;