@oh-my-pi/pi-catalog 18.14.0 → 18.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.14.2] - 2026-10-31
6
+
7
+ ### Breaking Changes
8
+
9
+ - Removed `thinkingLoopGuard` from compat records; `thinking-loop-guard` is now a catalog axis that applies on every host, with `"semantic"` for Gemini, DeepSeek, and Grok and `"off"` for Claude
10
+
11
+ ### Fixed
12
+
13
+ - Fixed GitHub Copilot Claude 5.x base models (`claude-opus-5`, `claude-opus-5.5`, `claude-sonnet-5`, `claude-sonnet-5.5`) reporting the 1M window of their `-1m` variants once the model list was read from cache; discovered limits now survive cached reads instead of reverting to bundled values ([#17481](https://github.com/can1357/oh-my-pi/issues/17481))
14
+
15
+ ## [18.14.1] - 2026-10-31
16
+
17
+ ### Changed
18
+
19
+ - Clamping a requested thinking effort now resolves through the model's `effortMap` alias first, so the request lands on the tier the model serves instead of the nearest lower one ([#17395](https://github.com/can1357/oh-my-pi/pull/17395) by [@Maziar123](https://github.com/Maziar123))
20
+ - Long image-heavy conversations on the official Anthropic API now keep up to 120 MB of inline images before evicting older ones, following the Messages API request limit increase from 32 MB to 128 MB
21
+ - The official Anthropic API now records its 128 MB request limit (`request-body-byte-limit`), so the newest message's images can use the 8 MB reserve and long text cannot push images past the limit ([#17492](https://github.com/can1357/oh-my-pi/pull/17492) by [@will-bogusz](https://github.com/will-bogusz))
22
+
23
+ ### Fixed
24
+
25
+ - Fixed Cursor's DeepSeek V4.1 Flash 1017 reporting zero cost; every effort level now bills at Cursor's API rate of $0.30/$1.20 per million tokens, with cache reads at $0.006 ([#17390](https://github.com/can1357/oh-my-pi/pull/17390) by [@eggpeat](https://github.com/eggpeat))
26
+
5
27
  ## [18.14.0] - 2026-10-29
6
28
 
7
29
  ### Breaking Changes
@@ -2514,6 +2514,9 @@ export interface InteractionUpdate extends ProtoMessage {
2514
2514
  } | {
2515
2515
  case: "stepCompleted";
2516
2516
  value: StepCompletedUpdate;
2517
+ } | {
2518
+ case: "toolRequestsListed";
2519
+ value: ToolRequestsListedUpdate;
2517
2520
  };
2518
2521
  }
2519
2522
  export declare const InteractionUpdateSchema: MessageCodec<InteractionUpdate>;
@@ -5318,6 +5321,11 @@ export interface ToolCallStartedUpdate extends ProtoMessage {
5318
5321
  modelCallId: string;
5319
5322
  }
5320
5323
  export declare const ToolCallStartedUpdateSchema: MessageCodec<ToolCallStartedUpdate>;
5324
+ /** Cursor agent message agent.v1.ToolRequestsListedUpdate. */
5325
+ export interface ToolRequestsListedUpdate extends ProtoMessage {
5326
+ callCount: number;
5327
+ }
5328
+ export declare const ToolRequestsListedUpdateSchema: MessageCodec<ToolRequestsListedUpdate>;
5321
5329
  /** Cursor agent message agent.v1.TruncatedToolCall. */
5322
5330
  export interface TruncatedToolCall extends ProtoMessage {
5323
5331
  originalStepBlobId: Uint8Array;
@@ -129,9 +129,19 @@ export declare function createModelManager<TApi extends Api = Api, TModelsDevPay
129
129
  * when at least one configured remote source did not refresh successfully.
130
130
  */
131
131
  export declare function resolveProviderModels<TApi extends Api = Api, TModelsDevPayload = unknown>(options: ModelManagerOptions<TApi, TModelsDevPayload>, strategy?: ModelRefreshStrategy): Promise<ModelResolutionResult<TApi>>;
132
+ /**
133
+ * Merge policy that is part of a cache's identity in
134
+ * {@link fingerprintStaticModels}: `authoritative` when dynamic discovery owns
135
+ * the catalog, `additive` when the shared catalog may only add ids. The flags
136
+ * compose; snapshots written under different policies never match.
137
+ */
138
+ export interface StaticFingerprintPolicy {
139
+ authoritative?: boolean;
140
+ additive?: boolean;
141
+ }
132
142
  /**
133
143
  * Return the versioned content identity for a static provider slice. Callers
134
144
  * may mutate or freeze their arrays, so every call observes current content
135
145
  * and never attaches a stale sidecar fingerprint to caller-owned data.
136
146
  */
137
- export declare function fingerprintStaticModels<TApi extends Api>(models: readonly (ModelSpec<TApi> | Model<TApi>)[], dynamicModelsAuthoritative?: boolean): string;
147
+ export declare function fingerprintStaticModels<TApi extends Api>(models: readonly (ModelSpec<TApi> | Model<TApi>)[], policy?: StaticFingerprintPolicy): string;
@@ -32,6 +32,10 @@ export declare function withoutUnverifiedThinking<T extends {
32
32
  /**
33
33
  * Clamps a requested thinking level against explicit model metadata.
34
34
  *
35
+ * An unserved level first follows `thinking.effortMap` when the map sends it to
36
+ * a served tier that reaches the wire unchanged (a gateway answering `medium`
37
+ * as `high`); otherwise it climbs down to the nearest lower tier.
38
+ *
35
39
  * Non-reasoning models always resolve to `undefined`.
36
40
  */
37
41
  export declare function clampThinkingLevelForModel<TApi extends Api>(model: ApiModel<TApi> | undefined, requested: Effort | undefined): Effort | undefined;
@@ -477,8 +477,6 @@ export interface OpenAICompat {
477
477
  clampOutputToModelMax?: boolean;
478
478
  /** Strip image inputs before encoding (text-only serving of a multimodal id). */
479
479
  stripImageInput?: boolean;
480
- /** Thinking-loop watchdog guard family applied to streamed reasoning. */
481
- thinkingLoopGuard?: "gemini" | "deepseek" | "xai";
482
480
  }
483
481
  /**
484
482
  * Compatibility settings for anthropic-messages API.
@@ -676,8 +674,6 @@ export interface AnthropicCompat {
676
674
  * contract override it. Default: 10485760.
677
675
  */
678
676
  maxImagePayloadBytes?: number;
679
- /** Thinking-loop watchdog guard family applied to streamed reasoning. */
680
- thinkingLoopGuard?: "gemini" | "deepseek" | "xai";
681
677
  /**
682
678
  * Drop the enabled `thinking` config and replayed thinking blocks when the
683
679
  * conversation is not thinking-led (a proxy contract for non-interleaved
@@ -887,8 +883,6 @@ export interface ResolvedOpenAISharedCompat {
887
883
  toolSchemaFlavor?: OpenAICompat["toolSchemaFlavor"];
888
884
  /** Strip image inputs before encoding (text-only serving of a multimodal id). */
889
885
  stripImageInput: boolean;
890
- /** Thinking-loop watchdog guard family applied to streamed reasoning. */
891
- thinkingLoopGuard?: OpenAICompat["thinkingLoopGuard"];
892
886
  /** Flatten/reject leftover root `anyOf`/`oneOf` unions in strict tool schemas (xAI's function-calling validator 400s on them). */
893
887
  rejectRootObjectUnion: boolean;
894
888
  /** Retry without strict tools when the host rejects a strict grammar as too large (OpenRouter-Anthropic compiled-grammar overflow). */
@@ -900,7 +894,7 @@ export interface ResolvedOpenAISharedCompat {
900
894
  * `buildModel`; request handlers read fields and never detect, resolve, or
901
895
  * allocate.
902
896
  */
903
- 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" | "stripThinkingHistory" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "sessionHeader" | "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">> & {
897
+ 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" | "stripThinkingHistory" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "sessionHeader" | "supportsPromptCacheBreakpoints" | "promptCacheBreakpointTtl" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "clampOutputToModelMax" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "streamRevision" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "supportsConfigurationUpdate" | "supportsSteering" | "stripImageInput" | "whenThinking">> & {
904
898
  vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
905
899
  extraBody?: OpenAICompat["extraBody"];
906
900
  cacheControlFormat?: OpenAICompat["cacheControlFormat"];
@@ -992,7 +986,7 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
992
986
  */
993
987
  export type ResolvedOpenRouterCompat = ResolvedOpenAICompat & ResolvedOpenAIResponsesCompat;
994
988
  /** Fully-resolved anthropic-messages compat view (same contract as `ResolvedOpenAICompat`). */
995
- export type ResolvedAnthropicCompat = Required<Omit<AnthropicCompat, "streamIdleTimeoutMs" | "thinkingLoopGuard" | "bedrockMessagesApi" | "effortBeta" | "extendedCacheTtlBeta" | "disabledThinking" | "betweenToolsEffort" | "stripThinkingHistory" | "fastMode" | "maxImageDimension" | "maxImagePayloadBytes">> & {
989
+ export type ResolvedAnthropicCompat = Required<Omit<AnthropicCompat, "streamIdleTimeoutMs" | "bedrockMessagesApi" | "effortBeta" | "extendedCacheTtlBeta" | "disabledThinking" | "betweenToolsEffort" | "stripThinkingHistory" | "fastMode" | "maxImageDimension" | "maxImagePayloadBytes">> & {
996
990
  /** Effort-beta override; undefined keeps the transport's legacy heuristic. */
997
991
  effortBeta?: AnthropicCompat["effortBeta"];
998
992
  /** Extended-cache-ttl beta opt-out; undefined sends it where a 1h breakpoint needs it. */
@@ -1016,8 +1010,6 @@ export type ResolvedAnthropicCompat = Required<Omit<AnthropicCompat, "streamIdle
1016
1010
  * request builder.
1017
1011
  */
1018
1012
  maxImagePayloadBytes?: number;
1019
- /** Thinking-loop watchdog guard family applied to streamed reasoning. */
1020
- thinkingLoopGuard?: AnthropicCompat["thinkingLoopGuard"];
1021
1013
  /**
1022
1014
  * Bedrock's Anthropic Messages API (see {@link AnthropicCompat.bedrockMessagesApi}).
1023
1015
  * `true` when detected or configured; otherwise unset, so rows baked before
@@ -1116,16 +1108,13 @@ export interface GoogleCompat {
1116
1108
  * {@link AnthropicCompat.maxImagePayloadBytes}).
1117
1109
  */
1118
1110
  maxImagePayloadBytes?: number;
1119
- /** Thinking-loop watchdog guard family applied to streamed reasoning. */
1120
- thinkingLoopGuard?: "gemini" | "deepseek" | "xai";
1121
1111
  /** See {@link BedrockCompat.supportsSamplingParams}. */
1122
1112
  supportsSamplingParams?: boolean;
1123
1113
  }
1124
1114
  /** Fully-resolved google-API compat view, materialized once by `buildModel`. */
1125
- export type ResolvedGoogleCompat = Required<Omit<GoogleCompat, "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "thinkingLoopGuard" | "antigravityUsageLabel" | "supportsSamplingParams" | "maxImageDimension" | "maxImagePayloadBytes">> & {
1115
+ export type ResolvedGoogleCompat = Required<Omit<GoogleCompat, "streamFirstEventTimeoutMs" | "streamIdleTimeoutMs" | "antigravityUsageLabel" | "supportsSamplingParams" | "maxImageDimension" | "maxImagePayloadBytes">> & {
1126
1116
  streamFirstEventTimeoutMs?: number;
1127
1117
  streamIdleTimeoutMs?: number;
1128
- thinkingLoopGuard?: GoogleCompat["thinkingLoopGuard"];
1129
1118
  antigravityUsageLabel?: string;
1130
1119
  supportsSamplingParams?: boolean;
1131
1120
  maxImageDimension?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-catalog",
3
- "version": "18.14.0",
3
+ "version": "18.14.2",
4
4
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
5
5
  "keywords": [
6
6
  "ai",
@@ -88,12 +88,12 @@
88
88
  "gen:proto": "bun scripts/generate-protocols.ts"
89
89
  },
90
90
  "dependencies": {
91
- "@oh-my-pi/omptype": "18.14.0",
92
- "@oh-my-pi/pi-utils": "18.14.0"
91
+ "@oh-my-pi/omptype": "18.14.2",
92
+ "@oh-my-pi/pi-utils": "18.14.2"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@bgotink/kdl": "0.4.0",
96
- "@oh-my-pi/pi-ai": "18.14.0",
96
+ "@oh-my-pi/pi-ai": "18.14.2",
97
97
  "@types/bun": "^1.3.14"
98
98
  },
99
99
  "engines": {
@@ -317,11 +317,6 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
317
317
  "strip-image-input": wire("stripImageInput", [...OAI, "anthropic", "google"]),
318
318
  "supports-forced-tool-choice": wire("supportsForcedToolChoice", [...OAI, "anthropic", "bedrock"]),
319
319
  "supports-sampling-params": wire("supportsSamplingParams", [...OAI, "anthropic", "bedrock", "devin", "google"]),
320
- "thinking-loop-guard": wire("thinkingLoopGuard", [...OAI, "anthropic", "google"], "scalar", [
321
- "gemini",
322
- "deepseek",
323
- "xai",
324
- ]),
325
320
 
326
321
  // ── thinking control surface ──
327
322
  "thinking-default-level": { key: "defaultLevel", set: "thinking", shape: "scalar", values: EFFORTS },
@@ -456,6 +451,19 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
456
451
  shape: "scalar",
457
452
  values: ["output", "signature"],
458
453
  },
454
+ /**
455
+ * Stream loop guard for the model line, on every host and API (read
456
+ * through `loopGuardLevel` in pi-ai `utils/thinking-loop`). `semantic`
457
+ * adds near-duplicate and stalled-wording paragraph detection to the
458
+ * exact repeated-cycle check; `off` disables the guard. Unassigned: exact
459
+ * repeated cycles only.
460
+ */
461
+ "thinking-loop-guard": {
462
+ key: "thinkingLoopGuard",
463
+ set: "catalog",
464
+ shape: "scalar",
465
+ values: ["off", "semantic"],
466
+ },
459
467
  "delegation-bias": { key: "delegationBias", set: "catalog", shape: "scalar", values: DELEGATION_BIASES },
460
468
  "discovery-api": { key: "discoveryApi", set: "catalog", shape: "scalar" },
461
469
  "edit-prompt-variant": { key: "editPromptVariant", set: "catalog", shape: "scalar", values: ["full", "compact"] },
@@ -502,8 +510,9 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
502
510
  "image-max-edge": { key: "imageMaxEdge", set: "catalog", shape: "scalar" },
503
511
  "inline-image-byte-budget": { key: "inlineImageByteBudget", set: "catalog", shape: "scalar" },
504
512
  /**
505
- * Largest request body the host accepts. Where set, the inline-image byte clamp keeps the newest user message's
506
- * and newest tool result's images past `inline-image-byte-budget` while they alone fit this limit.
513
+ * Largest request body the host accepts. Where set, the inline-image byte clamp keeps images within what the
514
+ * request's other bytes leave of it, and keeps the newest user message's and newest tool result's images past
515
+ * `inline-image-byte-budget` while they fit that room.
507
516
  */
508
517
  "request-body-byte-limit": { key: "requestBodyByteLimit", set: "catalog", shape: "scalar" },
509
518
  /**
@@ -604,7 +604,6 @@ function detectOpenAICompat(
604
604
  zaiReasoningEffortDialect: false,
605
605
  clampOutputToModelMax: d.isLocalOpenAICompatBackend,
606
606
  stripImageInput: false,
607
- thinkingLoopGuard: undefined,
608
607
  rejectRootObjectUnion: false,
609
608
  retryWithoutStrictOnGrammarError: false,
610
609
  supportsPromptCacheKey: false,
@@ -762,7 +761,6 @@ function resolveOpenAIResponsesPolicy(
762
761
  supportsSteering: false,
763
762
  requiresReasoningOffJuiceInstruction: false,
764
763
  stripImageInput: false,
765
- thinkingLoopGuard: undefined,
766
764
  reasoningEffortMap: {},
767
765
  supportsReasoningParams: true,
768
766
  supportsSamplingParams: true,
@@ -936,7 +934,6 @@ function resolveAnthropicPolicy(
936
934
  // user-authored `compat` block to override them.
937
935
  maxImageDimension: undefined,
938
936
  maxImagePayloadBytes: undefined,
939
- thinkingLoopGuard: undefined,
940
937
  // Present as keys so models.yml `compat` can set them; unset unless a rule assigns them.
941
938
  stripThinkingHistory: undefined,
942
939
  fastMode: undefined,
@@ -227,7 +227,7 @@ One object axis carries a computed form: `long-context-cost` accepts either the
227
227
 
228
228
  `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, and snapcompact gives its archive frames half of it (`frameDataBytesBudget`). The budget applies only while the request reaches the host the rules describe (the Anthropic API, first-party OpenAI, the Codex backend at its default URL, DeepSeek's API, or Factory Droid's own global or EU API host), which callers decide with pi-ai's `reachesBudgetedHost`: `compat.officialEndpoint` for the configured `baseUrl`, for first-party Anthropic models also the `ANTHROPIC_BASE_URL` or Foundry `FOUNDRY_BASE_URL` reroute applied at request time, and for Factory Droid models the `baseUrl` origin. A custom or rerouted endpoint imposes its own body limit.
229
229
 
230
- `request-body-byte-limit` is the largest request body the host accepts (Factory Droid's hosted routes: 4,500,000 bytes), under the same gate. Where it is set, the byte clamp keeps the inline images of the newest user message and then of the newest image-bearing tool result even past `inline-image-byte-budget`, each only while the kept images fit the limit less the request's other serialized bytes, and evicts older images instead; read through `resolveRequestBodyByteLimit`.
230
+ `request-body-byte-limit` is the largest request body the host accepts (Factory Droid's hosted routes: 4,500,000 bytes; Anthropic's Messages API: 128,000,000 bytes), under the same gate. Where it is set, the byte clamp also keeps inline images within what the request's other serialized bytes leave of the limit, and keeps the inline images of the newest user message and then of the newest image-bearing tool result even past `inline-image-byte-budget`, each only while the kept images fit the limit less the request's other serialized bytes, and evicts older images instead; read through `resolveRequestBodyByteLimit`.
231
231
 
232
232
  `catalog-endpoint-budgets #true` makes these host budgets apply whenever a request reaches the provider's own catalog endpoint (an unset `baseUrl`, or an `endpoint-hosts` host; see `isCatalogEndpointUrl`), for a hosted gateway such as Factory Droid whose compat names no official endpoint, or a first-party provider such as DeepSeek whose `openai-completions` compat resolves no `officialEndpoint`. Unassigned, they apply only on the official endpoint.
233
233
 
@@ -29,6 +29,11 @@ class "anthropic" {
29
29
  // back as text (`reasoning_extraction`, issue #6093).
30
30
  classifier-cot-extraction #true
31
31
  thinking-replay-tokens "output"
32
+ // Summarized thinking repeats one progress line verbatim while long hidden
33
+ // reasoning runs ("Still writing the parser..." six-plus times back to
34
+ // back), which reads as an exact cycle. Claude has no runaway-loop failure
35
+ // that warrants the guard, so it never discards a turn here.
36
+ thinking-loop-guard "off"
32
37
  // verified: billing matched this formula on Opus 4.7+ and Fable 5.1.
33
38
  image-tokenization {
34
39
  regime "anthropic-patch"
@@ -102,7 +102,7 @@ class "deepseek" {
102
102
  // leaks it into content — hosted gateways, local backends, and custom
103
103
  // providers alike. On hosts that parse it the healer sees no markup.
104
104
  stream-markup-healing-pattern "dsml"
105
- thinking-loop-guard "deepseek"
105
+ thinking-loop-guard "semantic"
106
106
  // V4 reasoning reaches omp as its plaintext trace on every host, and the
107
107
  // revision pins the weights (flash 4.0 / 4.1, pro 4.0). Earlier lineages
108
108
  // classify too coarsely to carry: `r1` also matches the R1 distills.
@@ -149,7 +149,7 @@ class "gemini" {
149
149
  }
150
150
  }
151
151
 
152
- thinking-loop-guard "gemini"
152
+ thinking-loop-guard "semantic"
153
153
  }
154
154
 
155
155
  // Google Search grounding is a Gemini 2+ lineage capability on every Gemini transport.
@@ -67,7 +67,7 @@ class "xai" {
67
67
  }
68
68
  }
69
69
  }
70
- thinking-loop-guard "xai"
70
+ thinking-loop-guard "semantic"
71
71
  }
72
72
 
73
73
  // Same-provider swap targets for hosted search and image generation.
@@ -78,12 +78,16 @@ provider "anthropic" {
78
78
  // Code's `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` kill switch for gateways
79
79
  // that reject experimental beta fields.
80
80
  honors-claude-code-beta-kill-switch #true
81
- // Messages requests cap at 32 MB. Reserve 8 MB for text, tools, and JSON
82
- // framing when retaining inline base64 images in a long conversation.
83
- // Applied only on the official endpoint; a custom baseUrl has its own limit.
81
+ // Messages requests cap at 128 MB. Reserve 8 MB for text, tools, and JSON
82
+ // framing when retaining inline base64 images in a long conversation; the
83
+ // body limit keeps images within what the other bytes leave, and lets the
84
+ // newest user message's and tool result's images use the reserve.
85
+ // Applied only on the official endpoint; a custom baseUrl has its own limit
86
+ // (Bedrock 20 MB; Vertex, Foundry, and Claude Platform on AWS 30-32 MB).
84
87
  // https://platform.claude.com/docs/en/api/overview#request-size-limits
85
88
  on-api "anthropic-messages" {
86
- inline-image-byte-budget 24000000
89
+ inline-image-byte-budget 120000000
90
+ request-body-byte-limit 128000000
87
91
  }
88
92
  // The official endpoint carries at most 600 images and documents per
89
93
  // request, 100 on models with a 200k-token window: every Claude line before
@@ -387,6 +387,16 @@ provider "cursor" {
387
387
  cache-write 0
388
388
  }
389
389
  }
390
+ // DeepSeek V4.1 Flash 1017: $0.30/$1.20, cache read $0.006, no write fee.
391
+ // The bare id and every reasoning-effort wire id share one card.
392
+ models "deepseek-v41-flash-1017*" {
393
+ cost-patch {
394
+ input 0.3
395
+ output 1.2
396
+ cache-read 0.006
397
+ cache-write 0
398
+ }
399
+ }
390
400
  // Gemini 3 Flash: $0.50/$3.00, cache read $0.05.
391
401
  models "gemini-3-flash" {
392
402
  cost-patch {
@@ -7,8 +7,8 @@ provider "deepseek" {
7
7
 
8
8
  // DeepSeek's vision guide documents 600 images per request and a 48 MiB
9
9
  // request body. OMP reserves 8 MiB for text, tools, and the JSON envelope
10
- // (48 MiB - 8 MiB = 40 MiB); Anthropic's 24,000,000-byte image budget under
11
- // its 32 MB body uses an 8 MB reserve. DeepSeek documents MiB, so this uses
10
+ // (48 MiB - 8 MiB = 40 MiB); Anthropic's 120,000,000-byte image budget under
11
+ // its 128 MB body uses an 8 MB reserve. DeepSeek documents MiB, so this uses
12
12
  // an 8 MiB reserve. The split is OMP's conservative margin, not a
13
13
  // DeepSeek-documented figure. A custom baseUrl keeps the conservative
14
14
  // catalog floor because the gateway's own limits are unknown.
@@ -16,7 +16,7 @@ provider "openai-codex" {
16
16
 
17
17
  // Policy budgets: the Codex backend documents no request-size or image
18
18
  // limit, and requests with several thousand images fail mid-stream at
19
- // random. Inline images keep Anthropic's 24 MB; the official endpoint's
19
+ // random. Inline images keep a 24 MB budget; the official endpoint's
20
20
  // image count stays well below those failures. A custom baseUrl keeps 200.
21
21
  inline-image-byte-budget 24000000
22
22
  image-count-budget 200