@oh-my-pi/pi-catalog 18.2.0 → 18.2.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 +39 -0
- package/dist/types/compat/behavior.d.ts +11 -0
- package/dist/types/compat/cascade.d.ts +10 -0
- package/dist/types/compat/collapse.d.ts +8 -0
- package/dist/types/compat/resolve.d.ts +10 -0
- package/dist/types/compat/types.d.ts +21 -0
- package/dist/types/discovery/antigravity.d.ts +10 -1
- package/dist/types/model-thinking.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +2 -0
- package/dist/types/types.d.ts +36 -1
- package/package.json +4 -4
- package/src/build.ts +59 -0
- package/src/compat/axes.ts +15 -0
- package/src/compat/behavior.ts +22 -2
- package/src/compat/cascade.ts +27 -1
- package/src/compat/collapse.ts +100 -8
- package/src/compat/context-window.ts +11 -1
- package/src/compat/resolve.ts +56 -17
- package/src/compat/rules/README.md +3 -1
- package/src/compat/rules/classes/deepseek.kdl +9 -1
- package/src/compat/rules/classes/kimi.kdl +6 -0
- package/src/compat/rules/providers/alibaba-token-plan.kdl +16 -8
- package/src/compat/rules/providers/amazon-bedrock.kdl +30 -0
- package/src/compat/rules/providers/azure.kdl +6 -0
- package/src/compat/rules/providers/cerebras.kdl +10 -0
- package/src/compat/rules/providers/commandcode.kdl +20 -4
- package/src/compat/rules/providers/cursor.kdl +32 -0
- package/src/compat/rules/providers/deepseek.kdl +5 -5
- package/src/compat/rules/providers/devin.kdl +46 -0
- package/src/compat/rules/providers/google-vertex.kdl +15 -0
- package/src/compat/rules/providers/kimi-code.kdl +48 -0
- package/src/compat/rules/providers/meta.kdl +3 -0
- package/src/compat/rules/providers/muse-code.kdl +3 -0
- package/src/compat/rules/providers/openrouter.kdl +6 -0
- package/src/compat/rules/runtime/behavior.kdl +17 -0
- package/src/compat/rules/taxonomy/deepseek.kdl +5 -0
- package/src/compat/rules.json +1 -1
- package/src/compat/types.ts +23 -0
- package/src/discovery/antigravity.ts +80 -43
- package/src/discovery/devin.ts +22 -4
- package/src/identity/bundled.ts +4 -3
- package/src/model-cache.ts +154 -120
- package/src/model-thinking.ts +10 -7
- package/src/models.json +1 -1
- package/src/provider-models/bundled-references.ts +4 -3
- package/src/provider-models/cache-provider-id.ts +14 -8
- package/src/provider-models/ollama.ts +11 -31
- package/src/provider-models/openai-compat.ts +297 -37
- package/src/types.ts +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.2] - 2026-09-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- OpenAI-compatible model discovery now fills in reasoning-effort tiers for unrecognized models using the shared catalog’s published reasoning options, while preserving explicit discovery metadata and reviewed model rules.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed recovery of corrupted model caches so private backups are preserved and concurrent recovery cannot overwrite a cache that has already been restored.
|
|
14
|
+
- Fixed pricing for Devin (SWE-2, SWE-1.7, and GLM-5.2 High) and Kimi Code models when upstream discovery omits cost information. SWE-2 now reflects its promotional pricing through December 31, 2026, then switches to list pricing on January 1, 2027.
|
|
15
|
+
- Fixed pricing and chat routing for Devin Fusion models so composite models use their own headline rates and supported Fusion lanes connect directly instead of failing through an incompatible routing path.
|
|
16
|
+
|
|
17
|
+
## [18.2.1] - 2026-09-15
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- DeepSeek V4.1 Flash (`deepseek-flash`) now accepts image inputs and resolves its reasoning metadata, name, and effort ladder from upstream instead of shipping as a text-only row without them.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Fixed Cerebras Qwen 3.8 reasoning control by enabling correct effort tiers and disable behavior
|
|
26
|
+
- Fixed Cerebras Qwen models using incorrect reasoning format, enabling proper support for thinking modes
|
|
27
|
+
- Fixed Command Code's `deepseek/deepseek-v4.1-flash` row exposing its documented low/high/max thinking levels and image input, and made live discovery resolve the reasoning contract its rules declare ([#1666](https://github.com/can1357/oh-my-pi/issues/1666), [#11703](https://github.com/can1357/oh-my-pi/pull/11703) by [@aliefe04](https://github.com/aliefe04)).
|
|
28
|
+
- Fixed Meta Model API and Muse Code requests failing with 400 whenever omp forced a tool choice: `api.meta.ai/v1` accepts only `tool_choice: "auto"`, so `none`, `required`, and named choices (subagent final-retry `yield`, forced tools, structured output, compaction handoff) are now omitted instead of sent ([#11635](https://github.com/can1357/oh-my-pi/pull/11635) by [@quantmind-br](https://github.com/quantmind-br)).
|
|
29
|
+
- Bedrock's Qwen rows no longer ask for more output tokens than the model accepts, which Bedrock rejected with a 400. ([#12117](https://github.com/can1357/oh-my-pi/pull/12117) by [@Huang-404-Q](https://github.com/Huang-404-Q))
|
|
30
|
+
- Gemini 2.5 Flash Lite on Vertex AI no longer requests `maxOutputTokens=65536`, which the endpoint rejects with a 400; the output cap is clamped to 65535 ([#10595](https://github.com/can1357/oh-my-pi/pull/10595) by [@WeMingT](https://github.com/WeMingT)).
|
|
31
|
+
- Fixed Meta muse-spark models on OpenRouter wedging every turn with `400 Referenced reasoning item ... was not found or has expired`: replayed Responses reasoning history is now filtered for the muse-spark family, matching the existing Anthropic-on-OpenRouter treatment ([#10675](https://github.com/can1357/oh-my-pi/pull/10675) by [@Giardi77](https://github.com/Giardi77)).
|
|
32
|
+
- Fixed Ollama Cloud model discovery synthesizing a generic `minimal`/`low`/`medium`/`high` effort ladder for every thinking-capable model, which shadowed the per-model compat rules and made `max` unreachable on the DeepSeek V4 line (including the served `deepseek-v4.1-flash`, `deepseek-v4-flash:0731`, and `deepseek-v4-pro:0813` ids): discovery now leaves the ladder to the rule tree, so those models advertise the wire-exact `low`/`high`/`max` and GLM-5.3 exposes `low`/`high`/`max` ([#8334](https://github.com/can1357/oh-my-pi/issues/8334)).
|
|
33
|
+
- Fixed Meta Model API and Muse Code requests failing with 400 whenever omp forced a tool choice: `api.meta.ai/v1` accepts only `tool_choice: "auto"`, so `none`, `required`, and named choices (subagent final-retry `yield`, forced tools, structured output, compaction handoff) are now omitted instead of sent.
|
|
34
|
+
- Fixed Azure GPT-6 Astra Chat Completions policy to disable reasoning with function tools and encode thinking-off as `reasoning_effort: "none"` ([#11052](https://github.com/can1357/oh-my-pi/issues/11052)).
|
|
35
|
+
- Fixed Z.AI and Zhipu timezone-naive quota reset timestamps resolving eight hours late by declaring their UTC+8 reset timezone ([#11014](https://github.com/can1357/oh-my-pi/issues/11014)).
|
|
36
|
+
- Fixed Amazon Bedrock Claude Fable 5.1 effort metadata to expose `xhigh` and `max` instead of the unsupported `minimal` level. ([#10788](https://github.com/can1357/oh-my-pi/pull/10788) by [@voonfoo](https://github.com/voonfoo))
|
|
37
|
+
- LiteLLM discovery no longer exposes known task-specific models, including embedding, media, moderation, reranking, and search models, as coding models.
|
|
38
|
+
- Fixed custom `anthropic-messages` providers whose adaptive effort ladder exposes `minimal` sending `output_config.effort: "minimal"`, which the Anthropic Messages API rejects with `400 level "minimal" not supported`; the adaptive effort mapper now clamps `minimal` to `low` ([#10994](https://github.com/can1357/oh-my-pi/issues/10994)).
|
|
39
|
+
- Qwen 3.8 models on Alibaba Token Plan now send the selected reasoning effort and replay reasoning history across turns.
|
|
40
|
+
- Fixed DeepInfra model cost reporting so promotional pricing is reflected: the `metadata.discount` fraction is now applied to input, output, and cache-read rates ([#10935](https://github.com/can1357/oh-my-pi/issues/10935)).
|
|
41
|
+
- Fixed LiteLLM model discovery leaking ClinePass display names and pricing into models with colliding ids ([#10932](https://github.com/can1357/oh-my-pi/issues/10932)).
|
|
42
|
+
- Raised Cursor context windows to Cursor's documented sizes (Grok 4.5/4.6 256k, default/Auto 256k, Kimi K2.7 Code 262k, GPT-5.6 272k, Claude Opus 5 and Fable 300k by default) so compaction no longer fires too early, without lowering existing 1M Max-mode windows.
|
|
43
|
+
|
|
5
44
|
## [18.2.0] - 2026-09-15
|
|
6
45
|
|
|
7
46
|
### Breaking Changes
|
|
@@ -29,6 +29,8 @@ export declare function cursorModelParameters(model: string): readonly {
|
|
|
29
29
|
* preserve quota semantics for newly discovered ids.
|
|
30
30
|
*/
|
|
31
31
|
export declare function quotaTierFor(provider: string, model: string): string | undefined;
|
|
32
|
+
/** UTC offset for a provider's timezone-naive absolute retry-reset timestamps. */
|
|
33
|
+
export declare function retryResetTimezoneOffsetFor(provider: string): string | undefined;
|
|
32
34
|
/** Whether a provider has catalog-authored model quota scopes. */
|
|
33
35
|
export declare function hasQuotaTierPolicy(provider: string): boolean;
|
|
34
36
|
/** The provider-default wire model for a model-less hosted operation. */
|
|
@@ -55,11 +57,20 @@ export declare function modelLimitsFor(provider: string, model: string): {
|
|
|
55
57
|
} | undefined;
|
|
56
58
|
/** Whether a provider roster entry is a declared non-chat/unsupported SKU. */
|
|
57
59
|
export declare function isExcludedModel(provider: string, model: string): boolean;
|
|
60
|
+
/** Whether an exact upstream discovery mode is excluded from a provider's coding-model roster. */
|
|
61
|
+
export declare function isExcludedDiscoveryMode(provider: string, mode: string): boolean;
|
|
58
62
|
/**
|
|
59
63
|
* Whether a provider is retired: its entire roster is excluded from the
|
|
60
64
|
* generated bundle and must never be resurrected from the previous snapshot.
|
|
61
65
|
*/
|
|
62
66
|
export declare function isRetiredProvider(provider: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Whether a provider's bundled rows may seed cross-provider bare-id enrichment
|
|
69
|
+
* references. Gateway-namespaced providers (ClinePass) are isolated so their
|
|
70
|
+
* limits, pricing, and reasoning controls never contaminate an unrelated proxy
|
|
71
|
+
* model that happens to advertise the same bare id.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isBareIdReferenceProvider(provider: string): boolean;
|
|
63
74
|
/** The declared subscription tier required to use a provider model id, if any. */
|
|
64
75
|
export declare function planRequirementFor(provider: string, model: string): string | undefined;
|
|
65
76
|
/** Cross-provider pricing-peer resolution for one provider model id. */
|
|
@@ -30,3 +30,13 @@ export declare function resolveCascade(target: ResolveTarget): ResolvedAxes;
|
|
|
30
30
|
* mutable rule data. Bundled target lookups use {@link resolveCascade}.
|
|
31
31
|
*/
|
|
32
32
|
export declare function resolveCascadeRules(cascade: CompiledCascade, target: ResolveTarget): ResolvedAxes;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the effort ladder this target resolves to comes from a rule scoped
|
|
35
|
+
* to the model's identity (a recognized class, family, revision, or an explicit
|
|
36
|
+
* model selector), rather than a provider/api-wide or fallback unknown-class
|
|
37
|
+
* rule that any unrecognized id at that provider inherits.
|
|
38
|
+
*
|
|
39
|
+
* Discovery reads this to tell reviewed tiers apart from a blanket default, so
|
|
40
|
+
* catalog-published tiers can correct the latter and never the former.
|
|
41
|
+
*/
|
|
42
|
+
export declare function hasModelScopedEffortsRule(target: ResolveTarget): boolean;
|
|
@@ -124,6 +124,14 @@ export declare function deriveThinkingPairFamilies<TSpec extends VariantSpecLike
|
|
|
124
124
|
* unrelated carriers (GitHub Copilot `-1m` context variants) never match.
|
|
125
125
|
*/
|
|
126
126
|
export declare function isCollapsedVariantSpec(spec: VariantSpecLike): boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Whether a Cursor wire id names an extended tier that upstream serves only in
|
|
129
|
+
* max mode. The compiled taxonomy identifies `xhigh`/`extra-high`/`max`
|
|
130
|
+
* efforts and their optional service lanes. This is an inference, not an
|
|
131
|
+
* upstream marker: it is the only per-tier signal available for bundled rows
|
|
132
|
+
* and for routes live discovery never advertised.
|
|
133
|
+
*/
|
|
134
|
+
export declare function isCursorMaxModeWireId(wireModelId: string): boolean;
|
|
127
135
|
/**
|
|
128
136
|
* Collapse a full mixed-provider list: per provider, the compiled reviewed table, Cursor's
|
|
129
137
|
* conservative live effort-sibling rule, and the automatic `X`/`X-thinking`
|
|
@@ -13,3 +13,13 @@ export interface ResolvedModelPolicy<TApi extends Api = Api> {
|
|
|
13
13
|
* complete compat record, thinking metadata, and catalog-data corrections.
|
|
14
14
|
*/
|
|
15
15
|
export declare function resolveModelPolicy<TApi extends Api>(spec: ModelSpec<TApi>): ResolvedModelPolicy<TApi>;
|
|
16
|
+
/**
|
|
17
|
+
* Whether reviewed rules know THIS model's effort ladder, as opposed to it
|
|
18
|
+
* inheriting a provider-wide default or {@link resolveThinkingPolicy} falling
|
|
19
|
+
* through to the neutral wire ladder.
|
|
20
|
+
*
|
|
21
|
+
* Discovery uses this to tell "omp knows this model's tiers" apart from "omp
|
|
22
|
+
* is guessing them", so catalog-published tiers can correct the guess without
|
|
23
|
+
* ever overriding reviewed knowledge.
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasModelScopedEffortLadder<TApi extends Api>(spec: ModelSpec<TApi>): boolean;
|
|
@@ -272,6 +272,11 @@ export interface CompiledExcludeModels {
|
|
|
272
272
|
provider: string;
|
|
273
273
|
match: CompiledMatchList;
|
|
274
274
|
}
|
|
275
|
+
/** Exact upstream discovery modes excluded from one provider's coding-model roster. */
|
|
276
|
+
export interface CompiledExcludeDiscoveryModes {
|
|
277
|
+
provider: string;
|
|
278
|
+
modes: string[];
|
|
279
|
+
}
|
|
275
280
|
/** Provider plan-requirement tiers keyed by matcher token lists. */
|
|
276
281
|
export interface CompiledPlanRequirement {
|
|
277
282
|
provider: string;
|
|
@@ -289,6 +294,11 @@ export interface CompiledPricingPeer {
|
|
|
289
294
|
peerId: string;
|
|
290
295
|
}[];
|
|
291
296
|
}
|
|
297
|
+
/** Provider timezone assumption for offset-less absolute retry-reset timestamps. */
|
|
298
|
+
export interface CompiledRetryResetTimezone {
|
|
299
|
+
provider: string;
|
|
300
|
+
offset: string;
|
|
301
|
+
}
|
|
292
302
|
/** Compiled runtime behavior vocabulary (`runtime/behavior.kdl`). */
|
|
293
303
|
export interface CompiledBehavior {
|
|
294
304
|
openaiResponsesHeuristic?: CompiledResponsesHeuristic;
|
|
@@ -299,10 +309,13 @@ export interface CompiledBehavior {
|
|
|
299
309
|
hostedDefaults: CompiledHostedDefault[];
|
|
300
310
|
apiRoutes: CompiledApiRoutes[];
|
|
301
311
|
modelLimits: CompiledModelLimits[];
|
|
312
|
+
excludeDiscoveryModes: CompiledExcludeDiscoveryModes[];
|
|
302
313
|
excludeModels: CompiledExcludeModels[];
|
|
303
314
|
planRequirements: CompiledPlanRequirement[];
|
|
304
315
|
pricingPeers: CompiledPricingPeer[];
|
|
316
|
+
retryResetTimezones: CompiledRetryResetTimezone[];
|
|
305
317
|
retiredProviders: string[];
|
|
318
|
+
referenceIsolatedProviders: string[];
|
|
306
319
|
}
|
|
307
320
|
/**
|
|
308
321
|
* A string setting from `auth/*.kdl` that may be overridden by environment
|
|
@@ -647,4 +660,12 @@ export interface ResolvedAxes {
|
|
|
647
660
|
wire: Record<string, unknown>;
|
|
648
661
|
thinking: Record<string, unknown>;
|
|
649
662
|
catalog: Record<string, unknown>;
|
|
663
|
+
/**
|
|
664
|
+
* Reasoning capability after the exact-model effort upgrade: `true` when the
|
|
665
|
+
* target reported reasoning or an exact rule declares a ladder for it (the
|
|
666
|
+
* reviewed correction to metadata-less discovery rows). Compat resolvers
|
|
667
|
+
* read this instead of the raw spec flag, or one id resolves two different
|
|
668
|
+
* wire contracts depending on whether it came from discovery or the bake.
|
|
669
|
+
*/
|
|
670
|
+
reasoning: boolean;
|
|
650
671
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FetchImpl } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import { type VariantCollapseTable } from "../compat/collapse.js";
|
|
2
3
|
import type { ModelSpec } from "../types.js";
|
|
3
4
|
export declare const ANTIGRAVITY_PRIMARY_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
|
|
@@ -37,6 +38,7 @@ export interface AntigravityDiscoveryAgentModelSort {
|
|
|
37
38
|
export interface AntigravityDiscoveryApiResponse {
|
|
38
39
|
models?: Record<string, AntigravityDiscoveryApiModel>;
|
|
39
40
|
agentModelSorts?: AntigravityDiscoveryAgentModelSort[];
|
|
41
|
+
imageGenerationModelIds?: string[];
|
|
40
42
|
}
|
|
41
43
|
/**
|
|
42
44
|
* Options for fetching Antigravity discovery models.
|
|
@@ -53,7 +55,7 @@ export interface FetchAntigravityDiscoveryModelsOptions {
|
|
|
53
55
|
/** Optional abort signal for request cancellation. */
|
|
54
56
|
signal?: AbortSignal;
|
|
55
57
|
/** Optional fetch implementation override for tests. */
|
|
56
|
-
fetcher?:
|
|
58
|
+
fetcher?: FetchImpl;
|
|
57
59
|
/**
|
|
58
60
|
* Hand collapse table to apply to the discovered list. Defaults to the
|
|
59
61
|
* Antigravity (budget-transport) table; `googleGeminiCli` passes the
|
|
@@ -68,3 +70,10 @@ export interface FetchAntigravityDiscoveryModelsOptions {
|
|
|
68
70
|
* Returns `[]` only when the endpoint responds successfully with no usable models.
|
|
69
71
|
*/
|
|
70
72
|
export declare function fetchAntigravityDiscoveryModels(options: FetchAntigravityDiscoveryModelsOptions): Promise<ModelSpec<"google-gemini-cli">[] | null>;
|
|
73
|
+
/** Advertised image model and serving endpoint for one Antigravity account. */
|
|
74
|
+
export interface AntigravityImageModel {
|
|
75
|
+
id: string;
|
|
76
|
+
endpoint: string;
|
|
77
|
+
}
|
|
78
|
+
/** Resolves the first image-generation model advertised by an Antigravity account. */
|
|
79
|
+
export declare function fetchAntigravityImageModel(options: FetchAntigravityDiscoveryModelsOptions): Promise<AntigravityImageModel | null>;
|
|
@@ -35,6 +35,13 @@ export declare function mapEffortToGoogleThinkingLevel<TApi extends Api>(effort:
|
|
|
35
35
|
/**
|
|
36
36
|
* Maps a normalized thinking effort to Anthropic adaptive effort values via
|
|
37
37
|
* the model's baked `thinking.effortMap` (identity for unmapped efforts).
|
|
38
|
+
*
|
|
39
|
+
* The Anthropic adaptive wire vocabulary has no `minimal` tier (valid values:
|
|
40
|
+
* `low`, `medium`, `high`, `xhigh`, `max`); a model ladder that exposes
|
|
41
|
+
* `minimal` — custom `anthropic-messages` providers do, unlike the built-in
|
|
42
|
+
* Claude ladders — would otherwise serialize `output_config.effort: "minimal"`
|
|
43
|
+
* and 400 (`level "minimal" not supported`). Clamp it to the lowest real tier,
|
|
44
|
+
* mirroring {@link mapEffortToGoogleThinkingLevel}'s `minimal` handling.
|
|
38
45
|
*/
|
|
39
46
|
export declare function mapEffortToAnthropicAdaptiveEffort<TApi extends Api>(model: ApiModel<TApi>, effort: Effort): "low" | "medium" | "high" | "xhigh" | "max" | "adaptive";
|
|
40
47
|
/**
|
|
@@ -523,6 +523,8 @@ export interface FetchLiteLLMRichModelsOptions<TApi extends Api> {
|
|
|
523
523
|
}
|
|
524
524
|
export declare const OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW = 128000;
|
|
525
525
|
export declare const OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS = 32768;
|
|
526
|
+
/** Exclude only known non-conversational modes; unknown and non-string modes remain selectable for aliases. */
|
|
527
|
+
export declare function isSelectableLiteLLMModelMode(mode: unknown): boolean;
|
|
526
528
|
export declare function normalizeLiteLLMManagementBaseUrl(baseUrl: string): string;
|
|
527
529
|
export declare function resolveLiteLLMApi(entry: Record<string, unknown> | undefined, id: string, fallbackApi?: Api): Api;
|
|
528
530
|
export declare function fetchLiteLLMRichModels<TApi extends Api>(options: FetchLiteLLMRichModelsOptions<TApi>): Promise<ModelSpec<TApi>[] | null>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -278,6 +278,12 @@ export interface OpenAICompat {
|
|
|
278
278
|
* Default: auto-detected (DeepSeek reasoning models).
|
|
279
279
|
*/
|
|
280
280
|
disableReasoningOnToolChoice?: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Disable reasoning whenever the request advertises function tools.
|
|
283
|
+
* Use for model surfaces that reject every tools-plus-reasoning combination.
|
|
284
|
+
* Default: false.
|
|
285
|
+
*/
|
|
286
|
+
disableReasoningWithTools?: boolean;
|
|
281
287
|
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
|
|
282
288
|
openRouterRouting?: OpenRouterRouting;
|
|
283
289
|
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
|
|
@@ -372,12 +378,24 @@ export interface OpenAICompat {
|
|
|
372
378
|
strictResponsesPairing?: boolean;
|
|
373
379
|
/** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
|
|
374
380
|
supportsImageDetailOriginal?: boolean;
|
|
381
|
+
/**
|
|
382
|
+
* Whether the Responses endpoint accepts `configuration_update` input items
|
|
383
|
+
* that change `reasoning.effort` mid-conversation while the request-level
|
|
384
|
+
* effort stays pinned for prompt caching (GPT-6 Astra). Default:
|
|
385
|
+
* rule-detected (`true` for `gpt-6-astra` on any host, `false` otherwise).
|
|
386
|
+
* Set `false` for custom `openai-responses` / `openai-codex-responses`
|
|
387
|
+
* endpoints that reject the item type with HTTP 400; effort changes are then
|
|
388
|
+
* sent as the top-level `reasoning.effort`.
|
|
389
|
+
*/
|
|
390
|
+
supportsConfigurationUpdate?: boolean;
|
|
375
391
|
/** Whether streamed reasoning deltas for the same field may repeat the full cumulative text snapshot. Default: false. */
|
|
376
392
|
reasoningDeltasMayBeCumulative?: boolean;
|
|
377
393
|
/** Strip leaked DeepSeek chat-template special tokens from visible content deltas. Default: auto-detected. */
|
|
378
394
|
stripDeepseekSpecialTokens?: boolean;
|
|
379
395
|
/** Heal leaked chat-template/tool-call/thinking markup from visible content deltas. Default: auto-detected. */
|
|
380
396
|
streamMarkupHealingPattern?: OpenAIStreamMarkupHealingPattern;
|
|
397
|
+
/** Whether this wire may revise already-streamed text (`stream-revision` axis). Unassigned: append-only. */
|
|
398
|
+
streamRevision?: "none" | "possible";
|
|
381
399
|
/** Treat an empty length-finished stream as a context-window error. Default: auto-detected. */
|
|
382
400
|
emptyLengthFinishIsContextError?: boolean;
|
|
383
401
|
/** Normalize tool call ids to OpenAI's 40-character limit. Default: auto-detected. */
|
|
@@ -548,6 +566,8 @@ export interface AnthropicCompat {
|
|
|
548
566
|
export interface BedrockCompat {
|
|
549
567
|
/** Whether this endpoint accepts no checkpoints, automatic caching, or explicit cachePoint blocks. */
|
|
550
568
|
promptCacheMode?: "none" | "automatic" | "explicit";
|
|
569
|
+
/** Whether this wire may revise already-streamed text (`stream-revision` axis). Unassigned: append-only. */
|
|
570
|
+
streamRevision?: "none" | "possible";
|
|
551
571
|
/** Whether explicit cachePoint blocks accept `ttl: "1h"`; omitted TTL means Bedrock's 5-minute default. */
|
|
552
572
|
supportsLongPromptCacheRetention?: boolean;
|
|
553
573
|
/**
|
|
@@ -571,6 +591,8 @@ export interface BedrockCompat {
|
|
|
571
591
|
/** Fully-resolved Bedrock Converse prompt-cache capabilities, materialized once by `buildModel`. */
|
|
572
592
|
export interface ResolvedBedrockCompat {
|
|
573
593
|
promptCacheMode: NonNullable<BedrockCompat["promptCacheMode"]>;
|
|
594
|
+
/** See {@link BedrockCompat.streamRevision}. */
|
|
595
|
+
streamRevision?: BedrockCompat["streamRevision"];
|
|
574
596
|
supportsLongPromptCacheRetention: boolean;
|
|
575
597
|
promptCacheMinimumTokens: number;
|
|
576
598
|
promptCacheMaximumCheckpoints: number;
|
|
@@ -632,6 +654,7 @@ export interface ResolvedOpenAISharedCompat {
|
|
|
632
654
|
filterReasoningHistory: boolean;
|
|
633
655
|
disableReasoningOnForcedToolChoice: boolean;
|
|
634
656
|
disableReasoningOnToolChoice: boolean;
|
|
657
|
+
disableReasoningWithTools?: boolean;
|
|
635
658
|
supportsToolChoice: boolean;
|
|
636
659
|
supportsForcedToolChoice: boolean;
|
|
637
660
|
supportsNamedToolChoice: boolean;
|
|
@@ -649,6 +672,8 @@ export interface ResolvedOpenAISharedCompat {
|
|
|
649
672
|
requiresAssistantContentForToolCalls: boolean;
|
|
650
673
|
stripDeepseekSpecialTokens: boolean;
|
|
651
674
|
streamMarkupHealingPattern?: OpenAIStreamMarkupHealingPattern;
|
|
675
|
+
/** See {@link OpenAICompat.streamRevision}. */
|
|
676
|
+
streamRevision?: OpenAICompat["streamRevision"];
|
|
652
677
|
/** See {@link OpenAICompat.streamFirstEventTimeoutMs}. */
|
|
653
678
|
streamFirstEventTimeoutMs?: number;
|
|
654
679
|
reasoningDeltasMayBeCumulative: boolean;
|
|
@@ -689,7 +714,7 @@ export interface ResolvedOpenAISharedCompat {
|
|
|
689
714
|
* `buildModel`; request handlers read fields and never detect, resolve, or
|
|
690
715
|
* allocate.
|
|
691
716
|
*/
|
|
692
|
-
export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "supportsReasoningSummary" | "supportsSamplingParams" | "supportsPenaltyAndStopParams" | "thinkingFormat" | "kimiApiFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "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" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "stripImageInput" | "thinkingLoopGuard" | "whenThinking">> & {
|
|
717
|
+
export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "supportsReasoningSummary" | "supportsSamplingParams" | "supportsPenaltyAndStopParams" | "thinkingFormat" | "kimiApiFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "disableReasoningWithTools" | "supportsToolChoice" | "supportsForcedToolChoice" | "supportsNamedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "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" | "stripImageInput" | "thinkingLoopGuard" | "whenThinking">> & {
|
|
693
718
|
vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
|
|
694
719
|
extraBody?: OpenAICompat["extraBody"];
|
|
695
720
|
cacheControlFormat?: OpenAICompat["cacheControlFormat"];
|
|
@@ -988,6 +1013,16 @@ export interface Model<TApi extends Api = Api> {
|
|
|
988
1013
|
gitlabDuoWorkflowRootNamespaceId?: string;
|
|
989
1014
|
/** Cursor `max_mode` request flag returned by `GetUsableModels` for premium models that require max mode. */
|
|
990
1015
|
cursorMaxMode?: boolean;
|
|
1016
|
+
/**
|
|
1017
|
+
* Per-wire-id `max_mode` markers for the members a collapsed Cursor row
|
|
1018
|
+
* routes to, recorded by `collapseVariants` from live `GetUsableModels`
|
|
1019
|
+
* rows. {@link cursorMaxMode} on a collapsed row is an OR across members,
|
|
1020
|
+
* so it cannot tell a `-low` route that needs no max mode from an Opus
|
|
1021
|
+
* `-fast` route that does; transports look the routed wire id up here
|
|
1022
|
+
* first. Absent on raw rows (their own `cursorMaxMode` already describes
|
|
1023
|
+
* their single wire id) and on bundled snapshots that predate discovery.
|
|
1024
|
+
*/
|
|
1025
|
+
cursorMaxModeRoutes?: Readonly<Record<string, boolean>>;
|
|
991
1026
|
cost: ModelCost;
|
|
992
1027
|
/** Premium Copilot requests charged per user-initiated request (defaults to 1). */
|
|
993
1028
|
premiumMultiplier?: number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-catalog",
|
|
4
|
-
"version": "18.2.
|
|
4
|
+
"version": "18.2.2",
|
|
5
5
|
"description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Stencil Labs, Inc.",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"gen:proto": "bun scripts/generate-protocols.ts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@oh-my-pi/omptype": "18.2.
|
|
39
|
-
"@oh-my-pi/pi-utils": "18.2.
|
|
38
|
+
"@oh-my-pi/omptype": "18.2.2",
|
|
39
|
+
"@oh-my-pi/pi-utils": "18.2.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@bgotink/kdl": "0.4.0",
|
|
43
|
-
"@oh-my-pi/pi-ai": "18.2.
|
|
43
|
+
"@oh-my-pi/pi-ai": "18.2.2",
|
|
44
44
|
"@types/bun": "^1.3.14"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
package/src/build.ts
CHANGED
|
@@ -24,6 +24,41 @@ function objectPayload(value: unknown): object | undefined {
|
|
|
24
24
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Overwrite seeded fallback rates with the latest dated card whose
|
|
29
|
+
* `effectiveFrom` is already due. Leaves the seed unchanged when no card
|
|
30
|
+
* has started, and never attaches a `timeBased` tariff.
|
|
31
|
+
*/
|
|
32
|
+
function applyEffectiveFallbackRates(
|
|
33
|
+
cost: { input: number; output: number; cacheRead: number; cacheWrite: number },
|
|
34
|
+
effectiveRates: unknown,
|
|
35
|
+
now = Date.now(),
|
|
36
|
+
): void {
|
|
37
|
+
const rates = objectPayload(effectiveRates);
|
|
38
|
+
if (rates === undefined) return;
|
|
39
|
+
let latestFrom = Number.NEGATIVE_INFINITY;
|
|
40
|
+
let latest: object | undefined;
|
|
41
|
+
for (const entry of Object.values(rates)) {
|
|
42
|
+
const payload = objectPayload(entry);
|
|
43
|
+
if (payload === undefined) continue;
|
|
44
|
+
const date = Reflect.get(payload, "effectiveFrom");
|
|
45
|
+
if (typeof date !== "string") continue;
|
|
46
|
+
const from = Date.parse(date);
|
|
47
|
+
if (!Number.isFinite(from) || from > now || from < latestFrom) continue;
|
|
48
|
+
latestFrom = from;
|
|
49
|
+
latest = payload;
|
|
50
|
+
}
|
|
51
|
+
if (latest === undefined) return;
|
|
52
|
+
const input = numberField(latest, "input");
|
|
53
|
+
if (input !== undefined) cost.input = input;
|
|
54
|
+
const output = numberField(latest, "output");
|
|
55
|
+
if (output !== undefined) cost.output = output;
|
|
56
|
+
const cacheRead = numberField(latest, "cacheRead");
|
|
57
|
+
if (cacheRead !== undefined) cost.cacheRead = cacheRead;
|
|
58
|
+
const cacheWrite = numberField(latest, "cacheWrite");
|
|
59
|
+
if (cacheWrite !== undefined) cost.cacheWrite = cacheWrite;
|
|
60
|
+
}
|
|
61
|
+
|
|
27
62
|
/** Narrow a compiled `input-modalities` axis value to the model input union. */
|
|
28
63
|
function isInputModalities(value: unknown): value is ("text" | "image")[] {
|
|
29
64
|
return Array.isArray(value) && value.every(entry => entry === "text" || entry === "image");
|
|
@@ -139,6 +174,30 @@ export function applyCatalogCorrections(
|
|
|
139
174
|
const cacheWrite = numberField(patch, "cacheWrite");
|
|
140
175
|
if (cacheWrite !== undefined) model.cost.cacheWrite = cacheWrite;
|
|
141
176
|
}
|
|
177
|
+
const fallback = objectPayload(catalog.costFallback);
|
|
178
|
+
if (fallback !== undefined) {
|
|
179
|
+
const base = model.cost;
|
|
180
|
+
const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
|
|
181
|
+
if (!hasTokenPrice) {
|
|
182
|
+
// Upstream reported no token price (plan-included or promo-free
|
|
183
|
+
// rows): seed the reviewed list price instead of overwriting real
|
|
184
|
+
// discovery data the way `cost-patch` would.
|
|
185
|
+
model.cost = { ...model.cost };
|
|
186
|
+
const input = numberField(fallback, "input");
|
|
187
|
+
if (input !== undefined) model.cost.input = input;
|
|
188
|
+
const output = numberField(fallback, "output");
|
|
189
|
+
if (output !== undefined) model.cost.output = output;
|
|
190
|
+
const cacheRead = numberField(fallback, "cacheRead");
|
|
191
|
+
if (cacheRead !== undefined) model.cost.cacheRead = cacheRead;
|
|
192
|
+
const cacheWrite = numberField(fallback, "cacheWrite");
|
|
193
|
+
if (cacheWrite !== undefined) model.cost.cacheWrite = cacheWrite;
|
|
194
|
+
// Dated fallback rates overwrite the seeded numbers when they have
|
|
195
|
+
// already taken effect. They are not a recurring tariff: wrapping
|
|
196
|
+
// them in `timeBased` with empty peak windows would report
|
|
197
|
+
// permanent off-peak and never wake at the dated boundary.
|
|
198
|
+
applyEffectiveFallbackRates(model.cost, Reflect.get(fallback, "effectiveRates"));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
142
201
|
if (catalog.timeBased !== undefined) {
|
|
143
202
|
model.cost = { ...model.cost, timeBased: materializeTimeBasedCost(catalog.timeBased) };
|
|
144
203
|
}
|
package/src/compat/axes.ts
CHANGED
|
@@ -93,6 +93,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
93
93
|
"clamp-output-to-model-max": wire("clampOutputToModelMax", OAI),
|
|
94
94
|
"disable-reasoning-on-forced-tool-choice": wire("disableReasoningOnForcedToolChoice", OAI),
|
|
95
95
|
"disable-reasoning-on-tool-choice": wire("disableReasoningOnToolChoice", OAI),
|
|
96
|
+
"disable-reasoning-with-tools": wire("disableReasoningWithTools", ["openai"]),
|
|
96
97
|
"drop-thinking-when-reasoning-effort": wire("dropThinkingWhenReasoningEffort", ["openai"]),
|
|
97
98
|
"empty-length-finish-is-context-error": wire("emptyLengthFinishIsContextError", OAI),
|
|
98
99
|
"extra-body": { ...wire("extraBody", ["openai"], "object"), verbatimKeys: true },
|
|
@@ -235,6 +236,19 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
235
236
|
"supports-function-part-id": wire("supportsFunctionPartId", ["google"]),
|
|
236
237
|
|
|
237
238
|
// ── wire: shared across surfaces ──
|
|
239
|
+
/**
|
|
240
|
+
* Whether this wire may revise text it has already streamed: bytes
|
|
241
|
+
* reclassified out of the visible channel (a leaned-on thinking opener),
|
|
242
|
+
* carved into a tool call, reordered by content-block index, or replaced
|
|
243
|
+
* wholesale by an authoritative final payload. Unassigned means the wire
|
|
244
|
+
* only appends, so the transcript may retire finished lines into native
|
|
245
|
+
* scrollback while the turn is still streaming (see
|
|
246
|
+
* `AssistantMessageComponent`). Declare `possible` only with a citable
|
|
247
|
+
* mechanism: the renderer also verifies published rows every frame and stops
|
|
248
|
+
* retiring the block on the first mismatch, so this axis decides where
|
|
249
|
+
* mid-stream retirement is attempted, not whether it is safe.
|
|
250
|
+
*/
|
|
251
|
+
"stream-revision": wire("streamRevision", [...OAI, "bedrock"], "scalar", ["none", "possible"]),
|
|
238
252
|
"stream-first-event-timeout-ms": wire("streamFirstEventTimeoutMs", [...OAI, "google"]),
|
|
239
253
|
"stream-idle-timeout-ms": wire("streamIdleTimeoutMs", [...OAI, "anthropic", "bedrock", "google"]),
|
|
240
254
|
"strip-image-input": wire("stripImageInput", [...OAI, "anthropic", "google"]),
|
|
@@ -274,6 +288,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
274
288
|
"context-promotion-target": { key: "contextPromotionTarget", set: "catalog", shape: "scalar" },
|
|
275
289
|
"context-window-floor": { key: "contextWindowFloor", set: "catalog", shape: "scalar" },
|
|
276
290
|
"cost-patch": { key: "costPatch", set: "catalog", shape: "object" },
|
|
291
|
+
"cost-fallback": { key: "costFallback", set: "catalog", shape: "object" },
|
|
277
292
|
"delegation-bias": { key: "delegationBias", set: "catalog", shape: "scalar", values: DELEGATION_BIASES },
|
|
278
293
|
"edit-prompt-variant": { key: "editPromptVariant", set: "catalog", shape: "scalar", values: ["full", "compact"] },
|
|
279
294
|
"edit-revision": { key: "editRevision", set: "catalog", shape: "scalar" },
|
package/src/compat/behavior.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Typed accessors over the compiled runtime-behavior vocabulary
|
|
3
3
|
* (`rules/runtime/behavior.kdl`): provider/model heuristics that run before
|
|
4
4
|
* or outside exact bundled-model lookup — responses routing, API routing,
|
|
5
|
-
* quota tiers, plan requirements, model limits, roster
|
|
6
|
-
* defaults, and pricing peers.
|
|
5
|
+
* quota tiers, plan requirements, model limits, roster and discovery-mode
|
|
6
|
+
* exclusions, hosted defaults, and pricing peers.
|
|
7
7
|
*/
|
|
8
8
|
import { globMatch } from "./cascade";
|
|
9
9
|
import rules from "./rules.json";
|
|
@@ -103,6 +103,11 @@ export function quotaTierFor(provider: string, model: string): string | undefine
|
|
|
103
103
|
return undefined;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/** UTC offset for a provider's timezone-naive absolute retry-reset timestamps. */
|
|
107
|
+
export function retryResetTimezoneOffsetFor(provider: string): string | undefined {
|
|
108
|
+
return behavior.retryResetTimezones.find(rule => rule.provider === provider)?.offset;
|
|
109
|
+
}
|
|
110
|
+
|
|
106
111
|
/** Whether a provider has catalog-authored model quota scopes. */
|
|
107
112
|
export function hasQuotaTierPolicy(provider: string): boolean {
|
|
108
113
|
return behavior.quotaTiers.some(rule => rule.provider === provider);
|
|
@@ -176,6 +181,11 @@ export function isExcludedModel(provider: string, model: string): boolean {
|
|
|
176
181
|
return behavior.excludeModels.some(rule => rule.provider === provider && matchesList(rule.match, lower, lower));
|
|
177
182
|
}
|
|
178
183
|
|
|
184
|
+
/** Whether an exact upstream discovery mode is excluded from a provider's coding-model roster. */
|
|
185
|
+
export function isExcludedDiscoveryMode(provider: string, mode: string): boolean {
|
|
186
|
+
return behavior.excludeDiscoveryModes.some(rule => rule.provider === provider && rule.modes.includes(mode));
|
|
187
|
+
}
|
|
188
|
+
|
|
179
189
|
/**
|
|
180
190
|
* Whether a provider is retired: its entire roster is excluded from the
|
|
181
191
|
* generated bundle and must never be resurrected from the previous snapshot.
|
|
@@ -184,6 +194,16 @@ export function isRetiredProvider(provider: string): boolean {
|
|
|
184
194
|
return behavior.retiredProviders.includes(provider);
|
|
185
195
|
}
|
|
186
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Whether a provider's bundled rows may seed cross-provider bare-id enrichment
|
|
199
|
+
* references. Gateway-namespaced providers (ClinePass) are isolated so their
|
|
200
|
+
* limits, pricing, and reasoning controls never contaminate an unrelated proxy
|
|
201
|
+
* model that happens to advertise the same bare id.
|
|
202
|
+
*/
|
|
203
|
+
export function isBareIdReferenceProvider(provider: string): boolean {
|
|
204
|
+
return !behavior.referenceIsolatedProviders.includes(provider);
|
|
205
|
+
}
|
|
206
|
+
|
|
187
207
|
/** The declared subscription tier required to use a provider model id, if any. */
|
|
188
208
|
export function planRequirementFor(provider: string, model: string): string | undefined {
|
|
189
209
|
const rule = behavior.planRequirements.find(candidate => candidate.provider === provider);
|
package/src/compat/cascade.ts
CHANGED
|
@@ -293,6 +293,7 @@ function cloneAxes(axes: ResolvedAxes): ResolvedAxes {
|
|
|
293
293
|
wire: cloneAxisRecord(axes.wire),
|
|
294
294
|
thinking: cloneAxisRecord(axes.thinking),
|
|
295
295
|
catalog: cloneAxisRecord(axes.catalog),
|
|
296
|
+
reasoning: axes.reasoning,
|
|
296
297
|
};
|
|
297
298
|
}
|
|
298
299
|
|
|
@@ -324,9 +325,33 @@ export function resolveCascadeRules(cascade: CompiledCascade, target: ResolveTar
|
|
|
324
325
|
return cloneAxes(resolveOverIndex(buildRuleIndex(cascade), target));
|
|
325
326
|
}
|
|
326
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Whether the effort ladder this target resolves to comes from a rule scoped
|
|
330
|
+
* to the model's identity (a recognized class, family, revision, or an explicit
|
|
331
|
+
* model selector), rather than a provider/api-wide or fallback unknown-class
|
|
332
|
+
* rule that any unrecognized id at that provider inherits.
|
|
333
|
+
*
|
|
334
|
+
* Discovery reads this to tell reviewed tiers apart from a blanket default, so
|
|
335
|
+
* catalog-published tiers can correct the latter and never the former.
|
|
336
|
+
*/
|
|
337
|
+
export function hasModelScopedEffortsRule(target: ResolveTarget): boolean {
|
|
338
|
+
const winners: WinnerTable = {};
|
|
339
|
+
for (const { rule, rank } of rankRelevantRules(getRuleIndex(), prepareTarget(target))) {
|
|
340
|
+
contest(winners, rule.compiled.thinking, rank, rule, target);
|
|
341
|
+
}
|
|
342
|
+
const winner = winners.efforts?.rule.compiled;
|
|
343
|
+
if (winner === undefined) return false;
|
|
344
|
+
return (
|
|
345
|
+
(winner.class !== undefined && winner.class !== "unknown") ||
|
|
346
|
+
winner.family !== undefined ||
|
|
347
|
+
winner.revision !== undefined ||
|
|
348
|
+
winner.models !== undefined
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
327
352
|
function resolveOverIndex(index: RuleIndex, target: ResolveTarget): ResolvedAxes {
|
|
328
353
|
const ranked = rankRelevantRules(index, prepareTarget(target));
|
|
329
|
-
let reasoning = target.reasoning;
|
|
354
|
+
let reasoning = target.reasoning === true;
|
|
330
355
|
if (!reasoning) {
|
|
331
356
|
for (const { rule, rank } of ranked) {
|
|
332
357
|
if (rule.hasExactEffortsRule && rank[0] === 2) {
|
|
@@ -347,5 +372,6 @@ function resolveOverIndex(index: RuleIndex, target: ResolveTarget): ResolvedAxes
|
|
|
347
372
|
wire: collect(wire, rule => rule.wire),
|
|
348
373
|
thinking: collect(thinking, rule => rule.thinking),
|
|
349
374
|
catalog: collect(catalog, rule => rule.catalog),
|
|
375
|
+
reasoning,
|
|
350
376
|
};
|
|
351
377
|
}
|