@linxiraos/pi-catalog 1.1.26 → 1.2.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 (128) hide show
  1. package/CHANGELOG.md +4 -6
  2. package/dist/types/compat/auth-ids.d.ts +2 -2
  3. package/dist/types/compat/collapse.d.ts +7 -0
  4. package/dist/types/compat/image-tokenization.d.ts +52 -0
  5. package/dist/types/compat/judgment-questions.d.ts +7 -0
  6. package/dist/types/compat/prompt-cache-lookback.d.ts +7 -0
  7. package/dist/types/compat/provider-ids.d.ts +1 -1
  8. package/dist/types/compat/reasoning-carry.d.ts +21 -0
  9. package/dist/types/compat/request-size.d.ts +7 -0
  10. package/dist/types/compat/taxonomy.d.ts +0 -10
  11. package/dist/types/compat/types.d.ts +4 -0
  12. package/dist/types/discovery/antigravity.d.ts +13 -3
  13. package/dist/types/hosts.d.ts +4 -0
  14. package/dist/types/model-cache.d.ts +6 -0
  15. package/dist/types/model-manager.d.ts +16 -0
  16. package/dist/types/provider-models/account-access.d.ts +11 -0
  17. package/dist/types/provider-models/google.d.ts +23 -1
  18. package/dist/types/provider-models/openai-compat.d.ts +19 -1
  19. package/dist/types/provider-models/special.d.ts +8 -0
  20. package/dist/types/types.d.ts +134 -23
  21. package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -10
  22. package/dist/types/wire/cloudflare.d.ts +10 -0
  23. package/dist/types/wire/factory-droid.d.ts +1 -1
  24. package/dist/types/wire/gemini-headers.d.ts +6 -3
  25. package/package.json +4 -4
  26. package/src/build.ts +39 -35
  27. package/src/compat/auth-ids.ts +6 -0
  28. package/src/compat/axes.ts +43 -5
  29. package/src/compat/cascade.ts +6 -1
  30. package/src/compat/collapse.d.ts +7 -0
  31. package/src/compat/collapse.ts +11 -0
  32. package/src/compat/image-tokenization.ts +166 -0
  33. package/src/compat/judgment-questions.ts +12 -0
  34. package/src/compat/prompt-cache-lookback.ts +23 -0
  35. package/src/compat/provider-ids.d.ts +1 -1
  36. package/src/compat/provider-ids.ts +3 -0
  37. package/src/compat/reasoning-carry.ts +64 -0
  38. package/src/compat/request-size.ts +25 -0
  39. package/src/compat/resolve.ts +36 -25
  40. package/src/compat/rules/README.md +13 -3
  41. package/src/compat/rules/auth/_order.kdl +2 -2
  42. package/src/compat/rules/auth/cloudflare-workers-ai.kdl +9 -0
  43. package/src/compat/rules/auth/coralbricks.kdl +13 -0
  44. package/src/compat/rules/auth/minimax-code-cn.kdl +1 -1
  45. package/src/compat/rules/auth/minimax-code.kdl +1 -1
  46. package/src/compat/rules/auth/openai-codex.kdl +1 -1
  47. package/src/compat/rules/auth/snowflake.kdl +11 -0
  48. package/src/compat/rules/auth/stencil.kdl +1 -1
  49. package/src/compat/rules/classes/anthropic.kdl +188 -7
  50. package/src/compat/rules/classes/deepseek.kdl +11 -3
  51. package/src/compat/rules/classes/gemini.kdl +12 -0
  52. package/src/compat/rules/classes/glm.kdl +17 -8
  53. package/src/compat/rules/classes/kimi.kdl +15 -0
  54. package/src/compat/rules/classes/meta.kdl +4 -4
  55. package/src/compat/rules/classes/minimax.kdl +31 -1
  56. package/src/compat/rules/classes/openai.kdl +114 -4
  57. package/src/compat/rules/classes/qwen.kdl +2 -1
  58. package/src/compat/rules/providers/abliteration.kdl +7 -0
  59. package/src/compat/rules/providers/amazon-bedrock.kdl +0 -7
  60. package/src/compat/rules/providers/anthropic.kdl +13 -0
  61. package/src/compat/rules/providers/apple.kdl +1 -0
  62. package/src/compat/rules/providers/cloudflare-workers-ai.kdl +34 -0
  63. package/src/compat/rules/providers/coralbricks.kdl +62 -0
  64. package/src/compat/rules/providers/cursor.kdl +28 -8
  65. package/src/compat/rules/providers/devin.kdl +2 -2
  66. package/src/compat/rules/providers/factory-droid.kdl +77 -13
  67. package/src/compat/rules/providers/github-copilot.kdl +29 -0
  68. package/src/compat/rules/providers/google-antigravity.kdl +8 -1
  69. package/src/compat/rules/providers/groq.kdl +21 -0
  70. package/src/compat/rules/providers/image-tokenization.kdl +42 -0
  71. package/src/compat/rules/providers/judgment-questions.kdl +53 -0
  72. package/src/compat/rules/providers/litellm.kdl +4 -1
  73. package/src/compat/rules/providers/meta.kdl +3 -3
  74. package/src/compat/rules/providers/minimax-code-cn.kdl +10 -5
  75. package/src/compat/rules/providers/minimax-code.kdl +10 -5
  76. package/src/compat/rules/providers/mistral.kdl +25 -1
  77. package/src/compat/rules/providers/moonshot.kdl +11 -0
  78. package/src/compat/rules/providers/muse-code.kdl +7 -0
  79. package/src/compat/rules/providers/ollama.kdl +3 -0
  80. package/src/compat/rules/providers/openai-codex.kdl +18 -13
  81. package/src/compat/rules/providers/openai.kdl +22 -0
  82. package/src/compat/rules/providers/opencode-go.kdl +11 -0
  83. package/src/compat/rules/providers/opencode-zen.kdl +20 -0
  84. package/src/compat/rules/providers/openrouter.kdl +6 -0
  85. package/src/compat/rules/providers/snowflake.kdl +135 -0
  86. package/src/compat/rules/providers/tool-result-images.kdl +16 -0
  87. package/src/compat/rules/providers/zhipu-coding-plan.kdl +10 -0
  88. package/src/compat/rules/runtime/behavior.kdl +8 -5
  89. package/src/compat/rules/taxonomy/_collapse.kdl +52 -2
  90. package/src/compat/rules/taxonomy/deepseek.kdl +4 -0
  91. package/src/compat/rules/taxonomy/kimi.kdl +5 -0
  92. package/src/compat/rules.json +1 -1
  93. package/src/compat/taxonomy.d.ts +0 -10
  94. package/src/compat/taxonomy.ts +3 -3
  95. package/src/compat/types.d.ts +4 -0
  96. package/src/compat/types.ts +4 -0
  97. package/src/discovery/antigravity.d.ts +13 -3
  98. package/src/discovery/antigravity.ts +33 -17
  99. package/src/discovery/cursor.ts +28 -4
  100. package/src/discovery/devin.ts +20 -2
  101. package/src/hosts.d.ts +4 -0
  102. package/src/hosts.ts +2 -0
  103. package/src/model-cache.d.ts +6 -0
  104. package/src/model-cache.ts +123 -47
  105. package/src/model-manager.d.ts +16 -0
  106. package/src/model-manager.ts +107 -41
  107. package/src/model-tokenizer.ts +3 -0
  108. package/src/models.json +1 -1
  109. package/src/provider-models/account-access.d.ts +11 -0
  110. package/src/provider-models/account-access.ts +30 -0
  111. package/src/provider-models/cache-provider-id.ts +13 -6
  112. package/src/provider-models/cline-pass.ts +33 -0
  113. package/src/provider-models/descriptors.ts +4 -0
  114. package/src/provider-models/google.d.ts +23 -1
  115. package/src/provider-models/google.ts +72 -14
  116. package/src/provider-models/openai-compat.d.ts +19 -1
  117. package/src/provider-models/openai-compat.ts +281 -42
  118. package/src/provider-models/special.d.ts +8 -0
  119. package/src/provider-models/special.ts +26 -22
  120. package/src/types.d.ts +134 -23
  121. package/src/types.ts +183 -20
  122. package/src/wire/cloudflare-ai-gateway.d.ts +0 -10
  123. package/src/wire/cloudflare-ai-gateway.ts +0 -36
  124. package/src/wire/cloudflare.ts +40 -0
  125. package/src/wire/factory-droid.d.ts +1 -1
  126. package/src/wire/factory-droid.ts +1 -1
  127. package/src/wire/gemini-headers.d.ts +6 -3
  128. package/src/wire/gemini-headers.ts +39 -21
@@ -107,11 +107,12 @@ class IdentityFacts {
107
107
  return this.is("kimi") && this.family("k2.7-code", "k3");
108
108
  }
109
109
 
110
- /** Adaptive-thinking Claude generation floor (Opus ≥ min; Sonnet/Fable/Mythos ≥ 5). */
110
+ /** Adaptive-thinking Claude generation floor (Opus ≥ min; Sonnet/Fable/Mythos ≥ 5; Haiku ≥ 5.5). */
111
111
  anthropicAdaptiveGenAtLeast(opusMin: string): boolean {
112
112
  if (!this.is("anthropic")) return false;
113
113
  if (this.family("opus")) return this.revGte(opusMin);
114
114
  if (this.family("sonnet", "fable", "mythos")) return this.revGte("5");
115
+ if (this.family("haiku")) return this.revGte("5.5");
115
116
  return false;
116
117
  }
117
118
  }
@@ -179,7 +180,7 @@ function overlayEffortMapAxis(
179
180
  }
180
181
 
181
182
  function effortList(value: unknown): readonly Effort[] | undefined {
182
- if (!Array.isArray(value) || value.length === 0) return undefined;
183
+ if (!Array.isArray(value)) return undefined;
183
184
  const out: Effort[] = [];
184
185
  for (const entry of value) {
185
186
  const effort = THINKING_EFFORTS.find(candidate => candidate === entry);
@@ -502,10 +503,11 @@ function detectOpenAICompat(
502
503
  supportsDeveloperRole: isOpenAIHost || isAzureHost,
503
504
  supportsMultipleSystemMessages: supportsMultipleSystemMessagesDefault,
504
505
  supportsReasoningEffort: !isGrok && !d.isXiaomiMimo && (!(d.isZai || d.isZhipu) || supportsZaiReasoningEffort),
506
+ trustExplicitThinkingOnly: undefined,
505
507
  // API-conditional: this completions-only Copilot exclusion cannot be a
506
508
  // provider rule without changing Copilot Responses rows.
507
509
  supportsReasoningParams: provider !== "github-copilot",
508
- supportsSamplingParams: !(facts.is("openai") && (facts.family("o-series") || facts.revGte("5"))),
510
+ supportsSamplingParams: true,
509
511
  supportsPenaltyAndStopParams: !(isGrok && reasoningCapable),
510
512
  reasoningEffortMap: {},
511
513
  supportsUsageInStreaming: !isCerebrasHost,
@@ -598,26 +600,12 @@ function detectOpenAICompat(
598
600
  };
599
601
  }
600
602
 
601
- const DSML_HEALING_PROVIDERS: Record<string, true> = {
602
- ollama: true,
603
- "ollama-cloud": true,
604
- nvidia: true,
605
- deepseek: true,
606
- fireworks: true,
607
- nanogpt: true,
608
- "opencode-go": true,
609
- openrouter: true,
610
- // Transparent gateways / user-configured hosts forward the upstream model's
611
- // native chat template unchanged, so a deepseek-classed model behind them
612
- // still emits DSML tool-call envelopes and needs the DSML healer.
613
- litellm: true,
614
- nous: true,
615
- };
616
-
617
603
  /**
618
604
  * Default leaked-markup healer. Kimi/DeepSeek dedicated grammars are keyed on
619
605
  * identity class; official OpenAI heals nothing; everything else defaults to
620
- * the generic `thinking` healer.
606
+ * the generic `thinking` healer. DSML is DeepSeek's own tool-call grammar, so
607
+ * every host serving a DeepSeek model gets it — gateways, local backends, and
608
+ * custom providers alike.
621
609
  */
622
610
  function detectStreamMarkupHealing(
623
611
  provider: string,
@@ -628,7 +616,7 @@ function detectStreamMarkupHealing(
628
616
  // Kimi ids keep the generic healer, matching the census.
629
617
  const isKimiK2 = facts.is("kimi") && facts.identity.family?.startsWith("k2") === true;
630
618
  if (provider === "kimi-code" || provider === "moonshot" || isKimiK2) return "kimi";
631
- if (facts.is("deepseek") && DSML_HEALING_PROVIDERS[provider] === true) return "dsml";
619
+ if (facts.is("deepseek")) return "dsml";
632
620
  if (isOfficialOpenAIEndpoint(provider, baseUrl)) return undefined;
633
621
  return "thinking";
634
622
  }
@@ -745,12 +733,20 @@ function resolveOpenAIResponsesPolicy(
745
733
  hostMatchesUrl(baseUrl, "openrouter") ||
746
734
  hostMatchesUrl(baseUrl, "deepseekFamily"),
747
735
  supportsReasoningEffort: !isXaiHost,
736
+ trustExplicitThinkingOnly: undefined,
748
737
  supportsLongPromptCacheRetention: isOpenAIUrl,
749
738
  supportsPromptCacheBreakpoints,
750
739
  promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : undefined,
751
740
  strictResponsesPairing: isAzure || provider === "github-copilot",
752
- supportsImageDetailOriginal: !isXaiHost && !modelMatchesHost(hostModel, "githubCopilot"),
741
+ // Azure's provider id alone only implies support while its endpoint is
742
+ // resolved at runtime; an explicit non-Azure baseUrl is a proxy, like Codex.
743
+ supportsImageDetailOriginal:
744
+ isOpenAIUrl ||
745
+ hostMatchesUrl(baseUrl, "azureOpenAI") ||
746
+ (isAzure && !baseUrl) ||
747
+ hostMatchesUrl(baseUrl, "openaiCodex"),
753
748
  supportsReasoningSummary: !isXaiHost,
749
+ statefulResponses: undefined,
754
750
  supportsAllTurnsReasoningContext: false,
755
751
  supportsConfigurationUpdate: false,
756
752
  supportsSteering: false,
@@ -759,7 +755,7 @@ function resolveOpenAIResponsesPolicy(
759
755
  thinkingLoopGuard: undefined,
760
756
  reasoningEffortMap: {},
761
757
  supportsReasoningParams: true,
762
- supportsSamplingParams: !(facts.is("openai") && (facts.family("o-series") || facts.revGte("5"))),
758
+ supportsSamplingParams: true,
763
759
  supportsPenaltyAndStopParams: !isXaiHost,
764
760
  thinkingFormat,
765
761
  reasoningDisableMode: resolveReasoningDisableMode(thinkingFormat),
@@ -798,6 +794,8 @@ function resolveOpenAIResponsesPolicy(
798
794
  PROXY_OPENAI_COMPAT_PROVIDERS[backendProvider] !== true &&
799
795
  (LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl)),
800
796
  supportsObfuscationOptOut: isOpenAIUrl || provider === "openai",
797
+ storeResponses: false,
798
+ connectionBoundNativeHistory: false,
801
799
  officialEndpoint: isOfficialOpenAIEndpoint(provider, baseUrl),
802
800
  harmonyLeakMitigation: false,
803
801
  rejectRootObjectUnion: false,
@@ -859,6 +857,8 @@ function pickResponsesOnly(compat: ResolvedOpenAIResponsesCompat): ResponsesOnly
859
857
  strictResponsesPairing: compat.strictResponsesPairing,
860
858
  supportsImageDetailOriginal: compat.supportsImageDetailOriginal,
861
859
  supportsObfuscationOptOut: compat.supportsObfuscationOptOut,
860
+ storeResponses: compat.storeResponses,
861
+ connectionBoundNativeHistory: compat.connectionBoundNativeHistory,
862
862
  supportsAllTurnsReasoningContext: compat.supportsAllTurnsReasoningContext,
863
863
  supportsConfigurationUpdate: compat.supportsConfigurationUpdate,
864
864
  supportsSteering: compat.supportsSteering,
@@ -867,6 +867,7 @@ function pickResponsesOnly(compat: ResolvedOpenAIResponsesCompat): ResponsesOnly
867
867
  cacheControlFormat: compat.cacheControlFormat,
868
868
  requiresReasoningOffJuiceInstruction: compat.requiresReasoningOffJuiceInstruction,
869
869
  supportsReasoningSummary: compat.supportsReasoningSummary,
870
+ statefulResponses: compat.statefulResponses,
870
871
  isVercelGatewayHost: compat.isVercelGatewayHost,
871
872
  } satisfies ResponsesOnlyCompat;
872
873
  }
@@ -906,7 +907,7 @@ function resolveAnthropicPolicy(
906
907
  supportsThinkingBindingControls: false,
907
908
  supportsBetweenToolsThinking: false,
908
909
  supportsForcedToolChoice: !requiresThinkingEnabled && !facts.family("fable", "mythos"),
909
- supportsSamplingParams: !facts.anthropicAdaptiveGenAtLeast("4.7"),
910
+ supportsSamplingParams: true,
910
911
  requiresToolResultId: false,
911
912
  requiresThinkingEnabled,
912
913
  replayUnsignedThinking:
@@ -914,6 +915,11 @@ function resolveAnthropicPolicy(
914
915
  escapeBuiltinToolNames: false,
915
916
  injectClaudeCodeInstruction: true,
916
917
  stripImageInput: false,
918
+ // Unset means "canonical Anthropic image contract"; the request builder
919
+ // owns those numbers. The keys must exist for a KDL rule or a
920
+ // user-authored `compat` block to override them.
921
+ maxImageDimension: undefined,
922
+ maxImagePayloadBytes: undefined,
917
923
  thinkingLoopGuard: undefined,
918
924
  // Present as keys so models.yml `compat` can set them; unset unless a rule assigns them.
919
925
  stripThinkingHistory: undefined,
@@ -936,6 +942,9 @@ function resolveBedrockPolicy(spec: ModelSpec<"bedrock-converse-stream">, axes:
936
942
  promptCacheMinimumTokens: 0,
937
943
  promptCacheMaximumCheckpoints: 0,
938
944
  supportsForcedToolChoice: true,
945
+ // Opt-out: every prefix-bound Claude line on Converse takes the controls,
946
+ // including custom Bedrock-wire providers; KDL or models.yml sets `false`.
947
+ supportsThinkingBindingControls: true,
939
948
  };
940
949
  // Reasoning capability is a mechanism gate; adaptive-lineage duration is rule-owned.
941
950
  compat.streamIdleTimeoutMs = compatReasoning(spec, axes) ? BEDROCK_REASONING_STREAM_IDLE_TIMEOUT_MS : undefined;
@@ -1013,7 +1022,8 @@ function defaultThinkingMode<TApi extends Api>(spec: ModelSpec<TApi>, facts: Ide
1013
1022
  return "anthropic-budget-effort";
1014
1023
  }
1015
1024
  if (facts.is("anthropic")) {
1016
- if (facts.revGte("4.6") && !facts.family("haiku")) return "anthropic-adaptive";
1025
+ // Haiku stays on budget thinking until 5.5, its first adaptive generation.
1026
+ if (facts.revGte(facts.family("haiku") ? "5.5" : "4.6")) return "anthropic-adaptive";
1017
1027
  if (facts.family("opus") && facts.revGte("4.5")) return "anthropic-budget-effort";
1018
1028
  }
1019
1029
  return "budget";
@@ -1162,6 +1172,7 @@ function resolveThinkingPolicy<TApi extends Api>(
1162
1172
  if (compat !== undefined && "trustExplicitThinkingOnly" in compat && compat.trustExplicitThinkingOnly === true) {
1163
1173
  return undefined;
1164
1174
  }
1175
+ if (rule.efforts?.length === 0) return undefined;
1165
1176
  const config: ThinkingConfig = {
1166
1177
  mode: rule.mode ?? defaultThinkingMode(spec, facts),
1167
1178
  efforts: rule.efforts ?? fallbackEfforts(spec, compat),
@@ -209,14 +209,20 @@ The directive vocabulary is closed and lives in **`src/compat/axes.ts`** — one
209
209
  The three value shapes are:
210
210
 
211
211
  - **Scalar**: exactly one KDL boolean, integer, float, or string argument and no children. `#null` is rejected.
212
- - **Array**: one or more scalar arguments and no children; it resolves to a JSON array. Axes marked `emptyArray` in `axes.ts` also accept a bare directive, which assigns an explicit empty list (`region-upstreams-eu` with no arguments: the region never serves the model).
212
+ - **Array**: one or more scalar arguments and no children; it resolves to a JSON array. Axes marked `emptyArray` in `axes.ts` also accept a bare directive, which assigns an explicit empty list (`region-upstreams-eu` with no arguments: the region never serves the model). Bare `thinking-efforts` keeps a reasoning-capable deployment without selectable effort tiers off the effort dial.
213
213
  - **Object**: no arguments and a child block, including an empty block. Child names are kebab-case: an axis-directive spelling compiles to its resolved axis key (`template-reasoning-effort` → `qwenTemplateReasoningEffort`), anything else converts mechanically (`input-threshold` → `inputThreshold`); camelCase names are a compile error. `extra-body` payloads (top-level or nested) are the exception — their child names are literal wire JSON keys copied verbatim (`enable_thinking`). Each child is either one scalar or another object; arrays are not representable inside an object payload.
214
214
 
215
215
  A rule cannot assign the same resolved axis twice in one block.
216
- One object axis carries a computed form: `long-context-cost` accepts either the absolute rates (`input-threshold` + `input`/`output`/`cache-read`/`cache-write`) or `input-threshold` + `multiplier` (with optional `input-threshold-inclusive`), which derives the tier from the row's live base price at build time so the rule tracks upstream list-price updates (xAI's SuperGrok 200K tier). Rows without a token price carry no tier.
216
+ One object axis carries a computed form: `long-context-cost` accepts either the absolute rates (`input-threshold` + `input`/`output`/`cache-read`/`cache-write`) or `input-threshold` + `multiplier` (with optional `input-threshold-inclusive`), which derives the tier from the row's base price at build time, after `cost-patch` and `cost-fallback`, so the rule tracks upstream list-price updates (xAI's SuperGrok 200K tier). Rows without a token price carry no tier. An empty `long-context-cost {}` adds no tier; a more specific rule uses it to opt a host out of a broader rule's band (GitHub Copilot's Haiku 5.5 rows, whose long tier is the `-1m` sibling).
217
217
 
218
218
  `context-window-authoritative #true` preserves a host's supplied context window through runtime model selection instead of applying inferred expansion or reference-price-tier caps. Explicit user context overrides still apply afterward. It applies to rows materialized through `buildModel` (discovery and regenerated bundles). See [`providers/factory-droid.kdl`](providers/factory-droid.kdl).
219
219
 
220
+ `inline-image-byte-budget` caps retained base64 image characters for a deployment's request body. It leaves room for tool schemas and text beneath the provider's body-size limit; the coding agent reads it through `resolveInlineImageByteBudget` before sending live history. The budget applies only while `compat.officialEndpoint` holds: a custom `baseUrl` imposes its own body limit.
221
+
222
+ `judgment-questions-max` is the most questions one System One judgment request may carry (razorback16/openjev: 256; Cloudflare Clef on Workers AI and through OpenRouter Decisions: 64; unidentified `*openjev*` deployments: 16). The coding agent reads it through `resolveJudgmentQuestionsMax` and `NativeJudge` splits larger requests into parallel chunks; unassigned means the endpoint takes any batch size. [`providers/judgment-questions.kdl`](providers/judgment-questions.kdl) lists the servers verified uncapped or not isolatable.
223
+
224
+ `prompt-cache-lookback` is how many block positions back from a cache breakpoint the model's prompt cache looks for an earlier request's entry (Claude: 20, counting the breakpoint; a run of consecutive `tool_use` or `tool_result` blocks is one position). The coding agent reads it through `resolvePromptCacheLookback` and keeps warm-cache tool-result pruning inside the window; unassigned means no known bound.
225
+
220
226
  The routed-subscription registry axes (`upstream-rotation`, `region-upstreams-global|us|eu`, `region-limits-eu`, `credit-rates`, `list-price-from`, `routing-family`, `policy-aliases`, `entitlement`, `default-reasoning-off`) describe a gateway whose proxy fans one model out to several upstreams. They are read through `src/compat/factory-droid.ts` by Factory Droid discovery and its request provider, not materialized by `buildModel`. A provider-wide `region-upstreams-*` rule is the upstream serving table and a model rule replaces it for that region. `list-price-from "<provider>" ["<id>"]` shows a bundled row's list price beside the subscription's own billing; unlike seed values it is resolved at runtime and degrades to the seed's zero cost when the row is gone. See [`providers/factory-droid.kdl`](providers/factory-droid.kdl), whose wire and billing pool per model are `api-routes` and `quota-tiers` rules in `runtime/behavior.kdl`.
221
227
 
222
228
  ### Time-based pricing
@@ -468,11 +474,15 @@ provider "muse-code" {
468
474
 
469
475
  Only `discovery` enrolls a provider in `generate-models.ts`; providers without it are never fetched at generation time (see the `charm-hyper` entry for why a live gateway deliberately omits it).
470
476
 
477
+ `automatic-default #false` keeps a provider available for explicit selection but excludes it from startup fallback and automatic model presets. The default is `#true`; `apple` opts out because its on-device context cannot accommodate the standard coding-agent prompt in many projects.
478
+
479
+ `kind-apis { <kind> "<api>" }` maps each non-chat kind (`image`, `tts`, `stt`, `embedding`, `rerank`, `video`) to the API discovery assigns rows of that kind. A runner API must sit under the kind it serves (`RUNNER_API_KINDS` in `src/types.ts`); chat APIs, which serve hosted image generation, and multi-kind `local-inference` may back any kind.
480
+
471
481
  ### Seed rows
472
482
 
473
483
  A `seed` _defines_ bundled rows for providers whose catalog cannot be discovered at generation time — credential-scoped rosters, unauthenticated regens, or models ahead of upstream catalogs. Every other stratum patches rows; this one authors them. Runtime model managers hand the rows to `staticModels` through `seedModels(provider)`; the generator bundles them per the seed's `bundle` policy. Values are literal — a seed never derives from another provider's row, and pricing is never borrowed.
474
484
 
475
- `seed` properties: `api` and `base-url` are per-row defaults (a `model` may override either with the same property names); `bundle` defaults to `always`; `precedence="seed"` is optional. `model` takes the wire id positionally, requires `name=`, and its body MUST declare `reasoning`, `input` (`"text"` and/or `"image"`), `cost` (all four per-million rates), and `limits` (`context=` / `max-tokens=`, an omitted limit is `null`); `supports-tools #true` is optional. Any other directive is an axis from the cascade vocabulary: thinking axes become the row's explicit `thinking` (then `thinking-mode` and `thinking-efforts` are both required), wire axes become its explicit `compat` and must apply to the row's API, and catalog axes are rejected because they stay rule-owned in the cascade block. Explicit `thinking`/`compat` on a seed row win over the cascade exactly as they do for any authored spec.
485
+ `seed` properties: `api` and `base-url` are per-row defaults (a `model` may override either with the same property names); `bundle` defaults to `always`; `precedence="seed"` is optional. `model` takes the row id positionally, requires `name=`, and its body MUST declare `reasoning`, `input` (`"text"` and/or `"image"`), `cost` (all four per-million rates), and `limits` (`context=` / `max-tokens=`, an omitted limit is `null`); `supports-tools #true` is optional, and `request-model-id "<wire id>"` sets the row's `requestModelId` when the upstream id differs from the row id (an OpenAI Decisions judge row beside the same-id chat model). Any other directive is an axis from the cascade vocabulary: thinking axes become the row's explicit `thinking` (then `thinking-mode` and `thinking-efforts` are both required), wire axes become its explicit `compat` and must apply to the row's API, and catalog axes are rejected because they stay rule-owned in the cascade block. Explicit `thinking`/`compat` on a seed row win over the cascade exactly as they do for any authored spec.
476
486
 
477
487
  `bundle` decides when the generator includes the rows:
478
488
 
@@ -8,6 +8,6 @@ login-order "openai-codex" "anthropic" "zai" "zai-coding-plan" "kimi-code" "open
8
8
  "xiaomi-token-plan-ams" "xiaomi-token-plan-cn" "firepass" "cline-pass" "factory-droid" "commandcode" "charm-hyper" "deepseek" "stepfun" "muse-code" "meta" "moonshot" \
9
9
  "cerebras" "baseten" "helmcode" "fireworks" "together" "nvidia" "novita" "deepinfra" "huggingface" "perplexity" \
10
10
  "qianfan" "venice" "siliconflow" "siliconflow-cn" "synthetic" "nanogpt" "wafer-serverless" "coreweave" \
11
- "vercel-ai-gateway" "cloudflare-ai-gateway" "litellm" "kilo" "zenmux" "opencode-zen" "opencode-go" \
11
+ "vercel-ai-gateway" "cloudflare-ai-gateway" "cloudflare-workers-ai" "snowflake" "litellm" "kilo" "zenmux" "opencode-zen" "opencode-go" \
12
12
  "yolo-auto" "tavily" "kagi" "exa" "parallel" "typesafe" "ollama" "ollama-cloud" "lm-studio" "llama.cpp" "vllm" \
13
- "gmi-cloud" "stencil" "singularityapi-dev" "singularityapi-tech"
13
+ "gmi-cloud" "stencil" "singularityapi-dev" "singularityapi-tech" "coralbricks"
@@ -0,0 +1,9 @@
1
+ // Cloudflare Workers AI runs the Clef decision models under
2
+ // `/client/v4/accounts/{account_id}/ai/run`. Login stores the API token with
3
+ // the account id (the shared Cloudflare credential); an env-supplied token
4
+ // takes its account from `CLOUDFLARE_ACCOUNT_ID`.
5
+ auth "cloudflare-workers-ai" {
6
+ name "Cloudflare Workers AI"
7
+ env "CLOUDFLARE_API_TOKEN" "CLOUDFLARE_AUTH_TOKEN"
8
+ login "custom" hook="cloudflare-workers-ai"
9
+ }
@@ -0,0 +1,13 @@
1
+ // `/v1/models` is key-protected — it answers `401 missing_api_key` without a
2
+ // bearer key and `401 invalid_api_key` to a rejected one (verified
3
+ // 2026-10-02) — so login validates the pasted key there. The probe bills
4
+ // nothing, unlike a chat-completions ping against a prepaid balance.
5
+ auth "coralbricks" {
6
+ name "CoralBricks"
7
+ login "api-key" {
8
+ auth-url "https://www.coralbricks.ai/api-keys"
9
+ instructions "Create or copy your API key from the CoralBricks dashboard (keys look like cb_...)"
10
+ prompt "Paste your CoralBricks API key" placeholder="cb_..."
11
+ validate "models-endpoint" label="CoralBricks" url="https://inference.coralbricks.ai/v1/models"
12
+ }
13
+ }
@@ -4,6 +4,6 @@ auth "minimax-code-cn" {
4
4
  auth-url "https://platform.minimaxi.com/subscribe/token-plan"
5
5
  instructions "Subscribe to Token Plan and copy your API key"
6
6
  prompt "Paste your MiniMax Token Plan API key" placeholder="sk-..."
7
- validate "chat-completions" base-url="https://api.minimaxi.com/v1" model="MiniMax-M3"
7
+ validate "anthropic-messages" base-url="https://api.minimaxi.com/anthropic" model="MiniMax-M3"
8
8
  }
9
9
  }
@@ -4,6 +4,6 @@ auth "minimax-code" {
4
4
  auth-url "https://platform.minimax.io/subscribe/token-plan"
5
5
  instructions "Subscribe to Token Plan and copy your API key"
6
6
  prompt "Paste your MiniMax Token Plan API key" placeholder="sk-..."
7
- validate "chat-completions" label="MiniMax Token Plan" base-url="https://api.minimax.io/v1" model="MiniMax-M3"
7
+ validate "anthropic-messages" label="MiniMax Token Plan" base-url="https://api.minimax.io/anthropic" model="MiniMax-M3"
8
8
  }
9
9
  }
@@ -9,7 +9,7 @@ auth "openai-codex" {
9
9
  authorize-params {
10
10
  id_token_add_organizations "true"
11
11
  codex_cli_simplified_flow "true"
12
- originator "omp"
12
+ originator "zeta"
13
13
  }
14
14
  instructions "A browser window should open. Complete login to finish."
15
15
  // OpenAI only allowlists this exact URI; a busy port must fail rather than fall back.
@@ -0,0 +1,11 @@
1
+ // Snowflake Cortex REST API. Login runs Snowflake OAuth for local applications
2
+ // (built-in SNOWFLAKE$LOCAL_APPLICATION client, PKCE, loopback); the account
3
+ // host is prompted first, so the flow is a custom hook.
4
+ auth "snowflake" {
5
+ name "Snowflake Cortex"
6
+ login "custom" hook="snowflake"
7
+ refresh hook="snowflake"
8
+ api-key-format "structured"
9
+ callback-port 54551
10
+ paste-code #true
11
+ }
@@ -1,5 +1,5 @@
1
1
  // stencil.so account. Not a model provider: the credential authorizes
2
- // omp-hosted Stencil services such as `omp stream` (live.omp.sh).
2
+ // Zeta-hosted Stencil services such as `zetacode stream` (live.omp.sh).
3
3
  //
4
4
  // Two hosts: the Stencil API at api.stencil.so (`{base}`, STENCIL_BASE_URL)
5
5
  // and the OIDC issuer at auth.stencil.so (`{auth}`, STENCIL_AUTH_URL) which
@@ -1,5 +1,76 @@
1
1
  // Model-lineage compat for "anthropic"; regenerated from the frozen census using class taxonomy selectors.
2
2
 
3
+ // Images bill ⌈w/28⌉·⌈h/28⌉ visual tokens on every host. Claude 4.7+ and
4
+ // Fable/Mythos read up to 2576px and 4,784 tokens; older lines fit 1568px and
5
+ // cap at 1,568 tokens, downscaling past it.
6
+ // https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size
7
+ // The class default is the high-res tier, so ids without a revision
8
+ // (`claude-opus-latest`, `~anthropic/claude-sonnet-latest`) and future lines
9
+ // are never undercounted; only Opus/Sonnet/Haiku revisions known to predate
10
+ // 4.7 take the standard tier. Separator-collapsed revisions parse as two
11
+ // digits (`claude-opus-45` is Opus 4.5 → 45), so 10–46 is standard too.
12
+ // Claude's prompt cache finds an earlier request's entry only within 20 block
13
+ // positions back from a breakpoint, counting the breakpoint; a run of
14
+ // consecutive tool_use or tool_result blocks is one position. Warm-cache
15
+ // tool-result pruning keeps its rewrites inside this window.
16
+ // https://platform.claude.com/docs/en/build-with-claude/prompt-caching
17
+ class "anthropic" {
18
+ prompt-cache-lookback 20
19
+ image-tokenization {
20
+ regime "anthropic-patch"
21
+ max-edge 2576
22
+ max-tokens 4784
23
+ }
24
+ family "opus" {
25
+ revision "<4.7" {
26
+ image-tokenization {
27
+ regime "anthropic-patch"
28
+ max-edge 1568
29
+ max-tokens 1568
30
+ }
31
+ }
32
+ revision ">=10 <47" {
33
+ image-tokenization {
34
+ regime "anthropic-patch"
35
+ max-edge 1568
36
+ max-tokens 1568
37
+ }
38
+ }
39
+ }
40
+ family "sonnet" {
41
+ revision "<4.7" {
42
+ image-tokenization {
43
+ regime "anthropic-patch"
44
+ max-edge 1568
45
+ max-tokens 1568
46
+ }
47
+ }
48
+ revision ">=10 <47" {
49
+ image-tokenization {
50
+ regime "anthropic-patch"
51
+ max-edge 1568
52
+ max-tokens 1568
53
+ }
54
+ }
55
+ }
56
+ family "haiku" {
57
+ revision "<4.7" {
58
+ image-tokenization {
59
+ regime "anthropic-patch"
60
+ max-edge 1568
61
+ max-tokens 1568
62
+ }
63
+ }
64
+ revision ">=10 <47" {
65
+ image-tokenization {
66
+ regime "anthropic-patch"
67
+ max-edge 1568
68
+ max-tokens 1568
69
+ }
70
+ }
71
+ }
72
+ }
73
+
3
74
  class "anthropic" {
4
75
  family "fable" {
5
76
  revision ">=5.1" {
@@ -7,6 +78,46 @@ class "anthropic" {
7
78
  thinking-prefix-binding #true
8
79
  }
9
80
  }
81
+ // Adaptive Claude (Opus 4.7+, Sonnet/Fable/Mythos 5+, Haiku 5.5+) rejects explicit
82
+ // sampling params (`temperature`, `top_p`, `top_k`) with a 400 on every
83
+ // serving host. The `<10` bound keeps whole-number revisions such as
84
+ // `claude-opus-45` (Opus 4.5) out of the range.
85
+ family "opus" {
86
+ revision ">=4.7 <10" {
87
+ supports-sampling-params #false
88
+ }
89
+ }
90
+ family "sonnet" {
91
+ revision ">=5 <10" {
92
+ supports-sampling-params #false
93
+ }
94
+ }
95
+ family "fable" {
96
+ revision ">=5 <10" {
97
+ supports-sampling-params #false
98
+ }
99
+ }
100
+ family "mythos" {
101
+ revision ">=5 <10" {
102
+ supports-sampling-params #false
103
+ }
104
+ }
105
+ family "haiku" {
106
+ revision ">=5.5 <10" {
107
+ supports-sampling-params #false
108
+ }
109
+ // Haiku 5.5 bills every rate 5x for prompts over 100K. Derived from each
110
+ // host's list price so non-Anthropic hosts get the band too; the Claude
111
+ // API and Cursor pin absolute rates, and GitHub Copilot opts out because
112
+ // its long tier is the `-1m` sibling row.
113
+ // https://platform.claude.com/docs/en/models/haiku-5-5/overview#pricing
114
+ revision ">=5.5 <6" {
115
+ long-context-cost {
116
+ input-threshold 100000
117
+ multiplier 5.0
118
+ }
119
+ }
120
+ }
10
121
  // On-demand compaction (compact-2026-09-04) works on the Claude API, Vertex,
11
122
  // and Amazon Bedrock's `/anthropic` routes, not Bedrock Converse.
12
123
  // Foundry / Claude Platform on AWS are first-party Anthropic routes whose
@@ -32,6 +143,11 @@ class "anthropic" {
32
143
  supports-server-compaction #true
33
144
  }
34
145
  }
146
+ family "haiku" {
147
+ revision ">=5.5 <6" {
148
+ supports-server-compaction #true
149
+ }
150
+ }
35
151
  models "claude-mythos-preview" {
36
152
  supports-server-compaction #true
37
153
  }
@@ -84,6 +200,15 @@ class "anthropic" {
84
200
  thinking-prefix-binding #true
85
201
  }
86
202
  }
203
+ // Haiku 5.5 binds signed thinking to the exact preceding conversation like
204
+ // Sonnet 5.5. It accepts a forced `tool_choice` (the response just skips
205
+ // thinking), so it keeps forced tool selection.
206
+ // https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide
207
+ family "haiku" {
208
+ revision ">=5.5 <6" {
209
+ thinking-prefix-binding #true
210
+ }
211
+ }
87
212
  on "anthropic" "cloudflare-ai-gateway" "google-vertex" {
88
213
  family "fable" {
89
214
  revision ">=5" {
@@ -111,6 +236,13 @@ class "anthropic" {
111
236
  supports-turn-scoped-system #true
112
237
  }
113
238
  }
239
+ family "haiku" {
240
+ revision ">=5.5 <6" {
241
+ supports-mid-conversation-system #true
242
+ supports-mid-conversation-tool-changes #true
243
+ supports-turn-scoped-system #true
244
+ }
245
+ }
114
246
  family "opus" {
115
247
  revision ">=4.8" {
116
248
  supports-mid-conversation-system #true
@@ -141,17 +273,30 @@ class "anthropic" {
141
273
  supports-per-message-effort #true
142
274
  }
143
275
  }
276
+ // Haiku 5.5 mirrors Sonnet 5.5; Vertex stays off until verified.
277
+ family "haiku" {
278
+ revision ">=5.5 <6" {
279
+ supports-thinking-binding-controls #true
280
+ supports-per-message-effort #true
281
+ }
282
+ }
144
283
  family "opus" {
145
284
  revision ">=5" {
146
285
  supports-per-message-effort #true
147
286
  }
287
+ // Opus 5.5 is prefix-bound like Sonnet 5.5; without `drop_block` a
288
+ // changed system prompt or tool set fails the replay with a 400.
289
+ // Bounded for the same reason as the forced-tool-choice rule above.
290
+ revision ">=5.5 <6" {
291
+ supports-thinking-binding-controls #true
292
+ }
148
293
  }
149
294
  }
150
295
  on "aimlapi" "gitlab-duo" "kilo" "nanogpt" "venice" {
151
296
  thinking-efforts "minimal" "low" "medium" "high" "xhigh"
152
297
  }
153
298
  on "amazon-bedrock" "anthropic" "cloudflare-ai-gateway" "github-copilot" "gitlab-duo" \
154
- "google-antigravity" "google-vertex" "opencode-zen" "vercel-ai-gateway" "zenmux" {
299
+ "google-antigravity" "google-vertex" "opencode-zen" "snowflake" "vercel-ai-gateway" "zenmux" {
155
300
  family "sonnet" {
156
301
  revision ">=3.7 <4.6" {
157
302
  thinking-mode "budget"
@@ -159,13 +304,21 @@ class "anthropic" {
159
304
  }
160
305
  }
161
306
  on "amazon-bedrock" "anthropic" "cloudflare-ai-gateway" "github-copilot" "gitlab-duo" \
162
- "google-vertex" "opencode-zen" "vercel-ai-gateway" {
307
+ "google-vertex" "opencode-zen" "snowflake" "vercel-ai-gateway" {
163
308
  family "haiku" {
164
309
  thinking-mode "budget"
310
+ // Haiku 5.5 is the first adaptive Haiku: `budget_tokens` is a 400.
311
+ // An omitted `thinking` is adaptive, but unlike Sonnet/Opus 5.5 it
312
+ // accepts `disabled` at effort `high` or below, so Off is explicit.
313
+ // https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5#use-effort-to-control-thinking
314
+ revision ">=5.5 <6" {
315
+ thinking-mode "anthropic-adaptive"
316
+ disabled-thinking "disabled"
317
+ }
165
318
  }
166
319
  }
167
320
  on "amazon-bedrock" "anthropic" "cloudflare-ai-gateway" "github-copilot" "gitlab-duo" \
168
- "google-vertex" "opencode-zen" "vercel-ai-gateway" "zenmux" {
321
+ "google-vertex" "opencode-zen" "snowflake" "vercel-ai-gateway" "zenmux" {
169
322
  family "opus" {
170
323
  revision ">=4.5 <4.6" {
171
324
  thinking-mode "anthropic-budget-effort"
@@ -173,7 +326,7 @@ class "anthropic" {
173
326
  }
174
327
  }
175
328
  on "amazon-bedrock" "anthropic" "cloudflare-ai-gateway" "github-copilot" "google-vertex" \
176
- "opencode-zen" "openrouter" "vercel-ai-gateway" "zenmux" {
329
+ "opencode-zen" "openrouter" "snowflake" "vercel-ai-gateway" "zenmux" {
177
330
  family "opus" {
178
331
  revision ">=4.6 <4.7" {
179
332
  thinking-efforts "low" "medium" "high" "max"
@@ -181,7 +334,7 @@ class "anthropic" {
181
334
  }
182
335
  }
183
336
  on "amazon-bedrock" "anthropic" "cloudflare-ai-gateway" "github-copilot" "google-vertex" \
184
- "opencode-zen" "vercel-ai-gateway" "zenmux" {
337
+ "opencode-zen" "snowflake" "vercel-ai-gateway" "zenmux" {
185
338
  revision ">=4.7 <45.1" {
186
339
  thinking-mode "anthropic-adaptive"
187
340
  }
@@ -212,13 +365,13 @@ class "anthropic" {
212
365
  }
213
366
  }
214
367
  on "anthropic" "cloudflare-ai-gateway" "github-copilot" "google-vertex" "opencode-zen" \
215
- "openrouter" "vercel-ai-gateway" "zenmux" {
368
+ "openrouter" "snowflake" "vercel-ai-gateway" "zenmux" {
216
369
  revision ">=4.7 <45.1" {
217
370
  thinking-efforts "low" "medium" "high" "xhigh" "max"
218
371
  }
219
372
  }
220
373
  on "anthropic" "cloudflare-ai-gateway" "github-copilot" "google-vertex" "opencode-zen" \
221
- "vercel-ai-gateway" "zenmux" {
374
+ "snowflake" "vercel-ai-gateway" "zenmux" {
222
375
  family "sonnet" {
223
376
  revision ">=4.6 <5" {
224
377
  thinking-efforts "low" "medium" "high"
@@ -270,6 +423,34 @@ class "anthropic" {
270
423
  max-tokens 128000
271
424
  }
272
425
  }
426
+ // /v1/models reports neither reasoning, vision, pricing nor limits for
427
+ // Haiku 5.5, so a discovered row would materialize as a text-only,
428
+ // unpriced, non-reasoning model; pin the model card. Prompts over 100K
429
+ // input tokens bill the whole request at the long-context rates.
430
+ // https://platform.claude.com/docs/en/models/haiku-5-5/overview
431
+ family "haiku" {
432
+ revision ">=5.5 <6" {
433
+ thinking-upgrade-neutral #true
434
+ input-modalities "text" "image"
435
+ cost-patch {
436
+ input 0.1
437
+ output 0.5
438
+ cache-read 0.01
439
+ cache-write 0.125
440
+ }
441
+ long-context-cost {
442
+ input-threshold 100000
443
+ input 0.5
444
+ output 2.5
445
+ cache-read 0.05
446
+ cache-write 0.625
447
+ }
448
+ limits-patch {
449
+ context-window 1000000
450
+ max-tokens 128000
451
+ }
452
+ }
453
+ }
273
454
  family "mythos" {
274
455
  cost-patch {
275
456
  input 10.0
@@ -92,8 +92,16 @@ class "deepseek" {
92
92
  models "deepseek-flash" priority=10 {
93
93
  strip-image-input #false
94
94
  }
95
- on "ollama-cloud" "nvidia" "deepseek" "fireworks" "nanogpt" "opencode-go" "openrouter" "litellm" "nous" {
96
- stream-markup-healing-pattern "dsml"
97
- }
95
+ // DSML is the model's own tool-call grammar, not a host quirk: any server
96
+ // running DeepSeek's chat template without (or with a broken) tool parser
97
+ // leaks it into content — hosted gateways, local backends, and custom
98
+ // providers alike. On hosts that parse it the healer sees no markup.
99
+ stream-markup-healing-pattern "dsml"
98
100
  thinking-loop-guard "deepseek"
101
+ // V4 reasoning reaches omp as its plaintext trace on every host, and the
102
+ // revision pins the weights (flash 4.0 / 4.1, pro 4.0). Earlier lineages
103
+ // classify too coarsely to carry: `r1` also matches the R1 distills.
104
+ revision ">=4" {
105
+ portable-reasoning #true
106
+ }
99
107
  }
@@ -118,3 +118,15 @@ class "gemini" {
118
118
  }
119
119
  }
120
120
  }
121
+
122
+ // Gemini 3+ bills a fixed `media_resolution` budget per image regardless of
123
+ // pixels; the default for images is HIGH, 1,120 tokens.
124
+ // https://ai.google.dev/gemini-api/docs/media-resolution
125
+ class "gemini" {
126
+ revision ">=3" {
127
+ image-tokenization {
128
+ regime "fixed"
129
+ tokens 1120
130
+ }
131
+ }
132
+ }