@oh-my-pi/pi-catalog 18.8.5 → 18.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.8.7] - 2026-10-09
6
+
7
+ ### Added
8
+
9
+ - Added built-in CoralBricks support with `/login`, live model discovery, per-model reasoning levels and off controls, and bundled offline fallbacks. ([#14146](https://github.com/can1357/oh-my-pi/pull/14146) by [@ryan-brosas](https://github.com/ryan-brosas))
10
+ - Added `gen:models --provider <id>` to update one provider without changing other providers' catalog snapshots. ([#14146](https://github.com/can1357/oh-my-pi/pull/14146) by [@ryan-brosas](https://github.com/ryan-brosas))
11
+
12
+ ### Fixed
13
+
14
+ - Fixed Claude Haiku 5.5 thinking Off to request explicitly disabled thinking on every host serving its adaptive thinking ([#14996](https://github.com/can1357/oh-my-pi/pull/14996) by [@bse-ai](https://github.com/bse-ai)).
15
+
16
+ ## [18.8.6] - 2026-10-08
17
+
18
+ ### Added
19
+
20
+ - Added prompt-cache lookback support for Claude models across all hosts, including the public `prompt-cache-lookback` catalog axis and `resolvePromptCacheLookback` API.
21
+
22
+ ### Fixed
23
+
24
+ - Fixed model discovery when providers publish models before they are recognized by the catalog; unsupported models are now skipped with a warning so other available models remain discoverable.
25
+
5
26
  ## [18.8.5] - 2026-10-08
6
27
 
7
28
  ### Breaking Changes
@@ -1,4 +1,4 @@
1
1
  /** Every provider with an `auth/<id>.kdl` policy. */
2
- export type AuthProviderId = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
2
+ export type AuthProviderId = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
3
3
  /** Providers whose policy declares a `login` flow (the `/login` roster). */
4
- export type LoginProviderId = "abliteration" | "aiand" | "alibaba-coding-plan" | "alibaba-token-plan" | "anthropic" | "baseten" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google-antigravity" | "google-gemini-cli" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "meta" | "minimax-code" | "minimax-code-cn" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
4
+ export type LoginProviderId = "abliteration" | "aiand" | "alibaba-coding-plan" | "alibaba-token-plan" | "anthropic" | "baseten" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google-antigravity" | "google-gemini-cli" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "meta" | "minimax-code" | "minimax-code-cn" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
@@ -0,0 +1,7 @@
1
+ import type { Model } from "../types.js";
2
+ /**
3
+ * Block positions the provider's prompt cache checks back from a breakpoint for
4
+ * an earlier request's entry (`prompt-cache-lookback` axis), or `undefined` when
5
+ * the model has no known lookback bound.
6
+ */
7
+ export declare function resolvePromptCacheLookback(model: Model): number | undefined;
@@ -1,2 +1,2 @@
1
1
  /** Every chat-model provider with a catalog entry (`default-model` in its provider rules). */
2
- export type KnownProvider = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kilo" | "kimi-code" | "litellm" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "opencode-go" | "opencode-zen" | "openrouter" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stepfun" | "synthetic" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zenmux" | "zhipu-coding-plan";
2
+ export type KnownProvider = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kilo" | "kimi-code" | "litellm" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "opencode-go" | "opencode-zen" | "openrouter" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stepfun" | "synthetic" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zenmux" | "zhipu-coding-plan";
@@ -35,6 +35,22 @@ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload =
35
35
  cacheTtlMs?: number;
36
36
  /** When true, a successful dynamic fetch is the complete provider catalog and prunes static-only models. */
37
37
  dynamicModelsAuthoritative?: boolean;
38
+ /**
39
+ * When true, a provider's dynamic rows are the deployment's whole truth
40
+ * for input modality: a live text-only row strips the bundled reference's
41
+ * image support instead of OR-merging it back. Declared by providers whose
42
+ * capability flags are authoritative and whose endpoints reject
43
+ * unsupported content (`github-copilot`, `deepinfra`, `coralbricks`).
44
+ */
45
+ dynamicInputAuthoritative?: boolean;
46
+ /** When true, live reasoning capability replaces the fallback, including an explicit false. */
47
+ dynamicReasoningAuthoritative?: boolean;
48
+ /**
49
+ * When true, a live per-million price replaces the fallback even when it is
50
+ * an explicit `0` (a free model or a dropped cache-write charge). Without it,
51
+ * a zero discovery price is treated as unknown and the bundled rate is kept.
52
+ */
53
+ dynamicCostAuthoritative?: boolean;
38
54
  /**
39
55
  * When true, a fresh cache never satisfies an online-eligible refresh: the
40
56
  * dynamic fetch always runs (an explicit `"offline"` strategy is still
@@ -154,6 +154,19 @@ export interface DeepinfraModelManagerConfig {
154
154
  * model availability at runtime is still gated on credentials by the registry.
155
155
  */
156
156
  export declare function deepinfraModelManagerOptions(config?: DeepinfraModelManagerConfig): ModelManagerOptions<"openai-completions">;
157
+ export declare const CORALBRICKS_BASE_URL = "https://inference.coralbricks.ai/v1";
158
+ /** CoralBricks OpenAI-compatible discovery configuration. */
159
+ export interface CoralbricksModelManagerConfig {
160
+ apiKey?: string;
161
+ baseUrl?: string;
162
+ fetch?: FetchImpl;
163
+ }
164
+ /**
165
+ * Builds CoralBricks' model-discovery manager. `/v1/models` is key-protected
166
+ * (401 without a bearer key), so a keyless config serves only the bundled
167
+ * reviewed seed rows; with a key, live rows are authoritative over the bundle.
168
+ */
169
+ export declare function coralbricksModelManagerOptions(config?: CoralbricksModelManagerConfig): ModelManagerOptions<"openai-completions">;
157
170
  export interface XaiModelManagerConfig {
158
171
  apiKey?: string;
159
172
  baseUrl?: string;
@@ -192,6 +192,8 @@ export interface OpenAICompat {
192
192
  supportsMultipleSystemMessages?: boolean;
193
193
  /** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */
194
194
  supportsReasoningEffort?: boolean;
195
+ /** Do not infer a thinking dial when discovery supplies no explicit thinking configuration. */
196
+ trustExplicitThinkingOnly?: boolean;
195
197
  /** Optional mapping from pi-ai reasoning levels to provider/model-specific `reasoning_effort` values. */
196
198
  reasoningEffortMap?: Partial<Record<Effort, string>>;
197
199
  /** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */
@@ -646,6 +648,8 @@ export interface AnthropicCompat {
646
648
  * deliberately not used to infer these request-shape capabilities.
647
649
  */
648
650
  export interface BedrockCompat {
651
+ /** Explicit disabled-thinking wire form; unset preserves the provider's existing behavior. */
652
+ disabledThinking?: AnthropicCompat["disabledThinking"];
649
653
  /** Whether this endpoint accepts no checkpoints, automatic caching, or explicit cachePoint blocks. */
650
654
  promptCacheMode?: "none" | "automatic" | "explicit";
651
655
  /** Whether this wire may revise already-streamed text (`stream-revision` axis). Unassigned: append-only. */
@@ -684,6 +688,8 @@ export interface BedrockCompat {
684
688
  }
685
689
  /** Fully-resolved Bedrock Converse prompt-cache capabilities, materialized once by `buildModel`. */
686
690
  export interface ResolvedBedrockCompat {
691
+ /** See {@link BedrockCompat.disabledThinking}. */
692
+ disabledThinking?: BedrockCompat["disabledThinking"];
687
693
  promptCacheMode: NonNullable<BedrockCompat["promptCacheMode"]>;
688
694
  /** See {@link BedrockCompat.streamRevision}. */
689
695
  streamRevision?: BedrockCompat["streamRevision"];
@@ -738,6 +744,7 @@ export interface ResolvedOpenAISharedCompat {
738
744
  supportsDeveloperRole: boolean;
739
745
  supportsStrictMode: boolean;
740
746
  supportsReasoningEffort: boolean;
747
+ trustExplicitThinkingOnly?: boolean;
741
748
  reasoningEffortMap: Partial<Record<Effort, string>>;
742
749
  supportsReasoningParams: boolean;
743
750
  supportsSamplingParams: boolean;
@@ -814,7 +821,7 @@ export interface ResolvedOpenAISharedCompat {
814
821
  * `buildModel`; request handlers read fields and never detect, resolve, or
815
822
  * allocate.
816
823
  */
817
- export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "supportsReasoningSummary" | "statefulResponses" | "supportsSamplingParams" | "supportsPenaltyAndStopParams" | "thinkingFormat" | "kimiApiFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "disableReasoningWithTools" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "mistralReasoningContentParts" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "syntheticReasoningContentFallback" | "replayReasoningContent" | "qwenPreserveThinking" | "qwenTemplateReasoningEffort" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "supportsPromptCacheBreakpoints" | "promptCacheBreakpointTtl" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "clampOutputToModelMax" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "streamRevision" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "supportsConfigurationUpdate" | "supportsSteering" | "stripImageInput" | "thinkingLoopGuard" | "whenThinking">> & {
824
+ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "trustExplicitThinkingOnly" | "reasoningEffortMap" | "supportsReasoningParams" | "supportsReasoningSummary" | "statefulResponses" | "supportsSamplingParams" | "supportsPenaltyAndStopParams" | "thinkingFormat" | "kimiApiFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "disableReasoningWithTools" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "mistralReasoningContentParts" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "syntheticReasoningContentFallback" | "replayReasoningContent" | "qwenPreserveThinking" | "qwenTemplateReasoningEffort" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "supportsPromptCacheBreakpoints" | "promptCacheBreakpointTtl" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "clampOutputToModelMax" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "streamRevision" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "supportsConfigurationUpdate" | "supportsSteering" | "stripImageInput" | "thinkingLoopGuard" | "whenThinking">> & {
818
825
  vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
819
826
  extraBody?: OpenAICompat["extraBody"];
820
827
  cacheControlFormat?: OpenAICompat["cacheControlFormat"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-catalog",
3
- "version": "18.8.5",
3
+ "version": "18.8.7",
4
4
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
5
5
  "keywords": [
6
6
  "ai",
@@ -93,12 +93,12 @@
93
93
  "gen:proto": "bun scripts/generate-protocols.ts"
94
94
  },
95
95
  "dependencies": {
96
- "@oh-my-pi/omptype": "18.8.5",
97
- "@oh-my-pi/pi-utils": "18.8.5"
96
+ "@oh-my-pi/omptype": "18.8.7",
97
+ "@oh-my-pi/pi-utils": "18.8.7"
98
98
  },
99
99
  "devDependencies": {
100
100
  "@bgotink/kdl": "0.4.0",
101
- "@oh-my-pi/pi-ai": "18.8.5",
101
+ "@oh-my-pi/pi-ai": "18.8.7",
102
102
  "@types/bun": "^1.3.14"
103
103
  },
104
104
  "engines": {
@@ -18,6 +18,7 @@ export type AuthProviderId =
18
18
  | "cline-pass"
19
19
  | "cloudflare-ai-gateway"
20
20
  | "commandcode"
21
+ | "coralbricks"
21
22
  | "coreweave"
22
23
  | "cursor"
23
24
  | "deepinfra"
@@ -110,6 +111,7 @@ export type LoginProviderId =
110
111
  | "cline-pass"
111
112
  | "cloudflare-ai-gateway"
112
113
  | "commandcode"
114
+ | "coralbricks"
113
115
  | "coreweave"
114
116
  | "cursor"
115
117
  | "deepinfra"
@@ -229,7 +229,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
229
229
  "allow-anthropic-header-overrides": wire("allowAnthropicHeaderOverrides", ["anthropic"]),
230
230
  "disable-adaptive-thinking": wire("disableAdaptiveThinking", ["anthropic"]),
231
231
  "disable-strict-tools": wire("disableStrictTools", ["anthropic"]),
232
- "disabled-thinking": wire("disabledThinking", ["anthropic"], "scalar", ["omit", "disabled", "adaptive"]),
232
+ "disabled-thinking": wire("disabledThinking", ["anthropic", "bedrock"], "scalar", ["omit", "disabled", "adaptive"]),
233
233
  "effort-beta": wire("effortBeta", ["anthropic"]),
234
234
  "escape-builtin-tool-names": wire("escapeBuiltinToolNames", ["anthropic"]),
235
235
  "fast-mode": wire("fastMode", ["anthropic"]),
@@ -261,7 +261,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
261
261
  // ── wire: devin-agent ──
262
262
  "model-router": wire("modelRouter", ["devin"]),
263
263
  "supports-parallel-tool-calls": wire("supportsParallelToolCalls", ["devin"]),
264
- "trust-explicit-thinking-only": wire("trustExplicitThinkingOnly", ["devin"]),
264
+ "trust-explicit-thinking-only": wire("trustExplicitThinkingOnly", [...OAI, "devin"]),
265
265
 
266
266
  // ── wire: google APIs ──
267
267
  "antigravity-claude-tool-mode": wire("antigravityClaudeToolMode", ["google"]),
@@ -399,6 +399,12 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
399
399
  "limits-patch": { key: "limitsPatch", set: "catalog", shape: "object" },
400
400
  "long-context-cost": { key: "longContext", set: "catalog", shape: "object" },
401
401
  "prompt-cache": { key: "promptCache", set: "catalog", shape: "object" },
402
+ /**
403
+ * Prompt-cache lookback in block positions: how far back from a cache
404
+ * breakpoint the provider looks for an earlier request's cache entry.
405
+ * Unassigned: no known lookback bound.
406
+ */
407
+ "prompt-cache-lookback": { key: "promptCacheLookback", set: "catalog", shape: "scalar" },
402
408
  "long-usage-limit-fallback": { key: "longUsageLimitFallback", set: "catalog", shape: "scalar" },
403
409
  "max-context-window": { key: "maxContextWindow", set: "catalog", shape: "scalar" },
404
410
  "pricing-status": {
@@ -0,0 +1,23 @@
1
+ import { toModelSpec } from "../provider-models/bundled-references";
2
+ import type { Model } from "../types";
3
+ import { resolveCatalogAxes } from "./resolve";
4
+
5
+ const lookbackCache = new Map<string, number | null>();
6
+ const LOOKBACK_CACHE_MAX = 8192;
7
+
8
+ /**
9
+ * Block positions the provider's prompt cache checks back from a breakpoint for
10
+ * an earlier request's entry (`prompt-cache-lookback` axis), or `undefined` when
11
+ * the model has no known lookback bound.
12
+ */
13
+ export function resolvePromptCacheLookback(model: Model): number | undefined {
14
+ const key = `${model.provider} ${model.id} ${model.api}`;
15
+ let lookback = lookbackCache.get(key);
16
+ if (lookback === undefined) {
17
+ const value = resolveCatalogAxes(toModelSpec(model)).promptCacheLookback;
18
+ lookback = typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
19
+ if (lookbackCache.size >= LOOKBACK_CACHE_MAX) lookbackCache.clear();
20
+ lookbackCache.set(key, lookback);
21
+ }
22
+ return lookback ?? undefined;
23
+ }
@@ -18,6 +18,7 @@ export type KnownProvider =
18
18
  | "cline-pass"
19
19
  | "cloudflare-ai-gateway"
20
20
  | "commandcode"
21
+ | "coralbricks"
21
22
  | "coreweave"
22
23
  | "cursor"
23
24
  | "deepinfra"
@@ -503,6 +503,7 @@ function detectOpenAICompat(
503
503
  supportsDeveloperRole: isOpenAIHost || isAzureHost,
504
504
  supportsMultipleSystemMessages: supportsMultipleSystemMessagesDefault,
505
505
  supportsReasoningEffort: !isGrok && !d.isXiaomiMimo && (!(d.isZai || d.isZhipu) || supportsZaiReasoningEffort),
506
+ trustExplicitThinkingOnly: undefined,
506
507
  // API-conditional: this completions-only Copilot exclusion cannot be a
507
508
  // provider rule without changing Copilot Responses rows.
508
509
  supportsReasoningParams: provider !== "github-copilot",
@@ -732,6 +733,7 @@ function resolveOpenAIResponsesPolicy(
732
733
  hostMatchesUrl(baseUrl, "openrouter") ||
733
734
  hostMatchesUrl(baseUrl, "deepseekFamily"),
734
735
  supportsReasoningEffort: !isXaiHost,
736
+ trustExplicitThinkingOnly: undefined,
735
737
  supportsLongPromptCacheRetention: isOpenAIUrl,
736
738
  supportsPromptCacheBreakpoints,
737
739
  promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : undefined,
@@ -219,6 +219,8 @@ One object axis carries a computed form: `long-context-cost` accepts either the
219
219
 
220
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
221
 
222
+ `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.
223
+
222
224
  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`.
223
225
 
224
226
  ### Time-based pricing
@@ -10,4 +10,4 @@ login-order "openai-codex" "anthropic" "zai" "zai-coding-plan" "kimi-code" "open
10
10
  "qianfan" "venice" "siliconflow" "siliconflow-cn" "synthetic" "nanogpt" "wafer-serverless" "coreweave" \
11
11
  "vercel-ai-gateway" "cloudflare-ai-gateway" "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,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
+ }
@@ -9,7 +9,13 @@
9
9
  // are never undercounted; only Opus/Sonnet/Haiku revisions known to predate
10
10
  // 4.7 take the standard tier. Separator-collapsed revisions parse as two
11
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
12
17
  class "anthropic" {
18
+ prompt-cache-lookback 20
13
19
  image-tokenization {
14
20
  regime "anthropic-patch"
15
21
  max-edge 2576
@@ -302,8 +308,12 @@ class "anthropic" {
302
308
  family "haiku" {
303
309
  thinking-mode "budget"
304
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
305
314
  revision ">=5.5 <6" {
306
315
  thinking-mode "anthropic-adaptive"
316
+ disabled-thinking "disabled"
307
317
  }
308
318
  }
309
319
  }
@@ -0,0 +1,62 @@
1
+ // CoralBricks inference gateway deployment contract
2
+ // (https://www.coralbricks.ai/docs.md; catalog snapshot 2026-10-08).
3
+ //
4
+ // Coral serves open-weight models behind an OpenAI-compatible wire at
5
+ // https://inference.coralbricks.ai/v1 with a single bearer API key. The
6
+ // key-protected `GET /v1/models` publishes each row's context window,
7
+ // per-million pricing, and capability flags, and Coral documents those
8
+ // flags as authoritative (unsupported content answers
9
+ // `400 unsupported_content_type` rather than being dropped), so live
10
+ // discovery is the deployment truth and same-id rows on other hosts must
11
+ // not backfill capabilities or limits into this provider's rows.
12
+ provider "coralbricks" {
13
+ default-model "glm-5.3-fast"
14
+ // Official docs authenticate via `CORAL_API_KEY`
15
+ // (https://www.coralbricks.ai/docs.md#authentication); `CORALBRICKS_API_KEY`
16
+ // is the alias the Coral pi provider extension shipped with, kept as a
17
+ // compatibility fallback in precedence order.
18
+ env "CORAL_API_KEY" "CORALBRICKS_API_KEY"
19
+ dynamic-models-authoritative #true
20
+ skip-cross-provider-reference-fills #true
21
+ discovery label="CoralBricks"
22
+
23
+ // Reviewed snapshot of the public catalog
24
+ // (https://www.coralbricks.ai/api/public/models). Coral retired GLM 5.3
25
+ // Flash on 2026-10-07 and renamed the remaining slugs (`glm-5.3-fast`,
26
+ // `deepseek-v4.1-flash-fast`). The public rows list input/output rates
27
+ // only; cache-write rates come from Coral's published pricing and cached
28
+ // reads are $0 on every model. `/v1/models` needs a key, so generation
29
+ // without credentials bundles these rows; successful runtime discovery
30
+ // replaces them.
31
+ seed api="openai-completions" base-url="https://inference.coralbricks.ai/v1" bundle="always" {
32
+ model "glm-5.3-fast" name="GLM 5.3" {
33
+ reasoning #true
34
+ input "text"
35
+ cost input=1.12 output=4.4 cache-read=0 cache-write=1.68
36
+ limits context=1048576 max-tokens=131072
37
+ }
38
+ model "deepseek-v4.1-flash-fast" name="DeepSeek V4.1 Flash" {
39
+ reasoning #true
40
+ input "text" "image"
41
+ cost input=0.3 output=1.2 cache-read=0 cache-write=0.09
42
+ limits context=1048576 max-tokens=131072
43
+ }
44
+ }
45
+
46
+ // DeepSeek V4.1 Flash is the one CoralBricks SKU that advertises a genuine
47
+ // off value (`none` in its reasoning-effort vocabulary, per the reasoning
48
+ // table at https://www.coralbricks.ai/docs.md#reasoning), so a
49
+ // thinking-off request disables reasoning instead of clamping to the
50
+ // lowest effort like the GLM SKUs.
51
+ models "deepseek-v4.1-flash-fast" {
52
+ reasoning-disable-mode "none-effort"
53
+ }
54
+ // Gateway request dialect, matching Coral's plain Chat Completions
55
+ // surface ("unchanged from what your existing SDK expects"): output caps
56
+ // ride `max_tokens`, system prompts ride the `system` role, and no
57
+ // `store` field is sent. Coral accepts unknown fields, so acceptance is
58
+ // not evidence the semantics are honored (same call as charm-hyper).
59
+ supports-developer-role #false
60
+ supports-store #false
61
+ max-tokens-field "max_tokens"
62
+ }