@linxiraos/pi-catalog 1.2.1 → 1.3.1
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 +85 -0
- package/README.md +4 -2
- package/THIRD-PARTY-NOTICES.txt +55 -5
- package/dist/types/build.d.ts +3 -2
- package/dist/types/compat/auth-ids.d.ts +2 -2
- package/dist/types/compat/axes.d.ts +1 -1
- package/dist/types/compat/behavior.d.ts +5 -0
- package/dist/types/compat/catalog-endpoint.d.ts +8 -0
- package/dist/types/compat/image-tokenization.d.ts +9 -1
- package/dist/types/compat/judgment-images.d.ts +25 -0
- package/dist/types/compat/provider-ids.d.ts +1 -1
- package/dist/types/compat/request-compression.d.ts +23 -0
- package/dist/types/compat/request-size.d.ts +12 -3
- package/dist/types/compat/thinking-replay.d.ts +9 -0
- package/dist/types/compat/types.d.ts +4 -0
- package/dist/types/discovery/antigravity.d.ts +7 -0
- package/dist/types/model-cache.d.ts +7 -0
- package/dist/types/model-manager.d.ts +6 -0
- package/dist/types/model-thinking.d.ts +11 -1
- package/dist/types/models.d.ts +16 -1
- package/dist/types/pricing.d.ts +37 -1
- package/dist/types/provider-models/openai-compat.d.ts +18 -46
- package/dist/types/provider-models/special.d.ts +6 -1
- package/dist/types/types.d.ts +63 -12
- package/dist/types/wire/codex.d.ts +2 -0
- package/package.json +5 -5
- package/src/build.d.ts +3 -2
- package/src/build.ts +159 -80
- package/src/compat/auth-ids.ts +2 -0
- package/src/compat/axes.d.ts +1 -1
- package/src/compat/axes.ts +129 -4
- package/src/compat/behavior.d.ts +5 -0
- package/src/compat/behavior.ts +9 -1
- package/src/compat/cascade.ts +4 -1
- package/src/compat/catalog-endpoint.ts +43 -0
- package/src/compat/image-tokenization.ts +28 -10
- package/src/compat/judgment-images.ts +83 -0
- package/src/compat/provider-ids.d.ts +1 -1
- package/src/compat/provider-ids.ts +1 -0
- package/src/compat/request-compression.ts +43 -0
- package/src/compat/request-size.ts +20 -5
- package/src/compat/resolve.ts +90 -53
- package/src/compat/rules/README.md +32 -3
- package/src/compat/rules/auth/_order.kdl +1 -1
- package/src/compat/rules/auth/google-antigravity.kdl +1 -1
- package/src/compat/rules/auth/sambanova.kdl +9 -0
- package/src/compat/rules/auth/stencil.kdl +1 -1
- package/src/compat/rules/classes/anthropic.kdl +42 -2
- package/src/compat/rules/classes/deepseek.kdl +4 -0
- package/src/compat/rules/classes/gemini.kdl +46 -2
- package/src/compat/rules/classes/meta.kdl +7 -0
- package/src/compat/rules/classes/minimax.kdl +11 -1
- package/src/compat/rules/classes/openai.kdl +34 -3
- package/src/compat/rules/classes/xai.kdl +26 -0
- package/src/compat/rules/providers/amazon-bedrock.kdl +1 -0
- package/src/compat/rules/providers/anthropic.kdl +23 -0
- package/src/compat/rules/providers/azure.kdl +2 -0
- package/src/compat/rules/providers/cerebras.kdl +3 -0
- package/src/compat/rules/providers/cline-pass.kdl +16 -0
- package/src/compat/rules/providers/commandcode.kdl +10 -0
- package/src/compat/rules/providers/cursor.kdl +50 -1
- package/src/compat/rules/providers/deepinfra.kdl +3 -1
- package/src/compat/rules/providers/devin.kdl +117 -6
- package/src/compat/rules/providers/factory-droid.kdl +6 -0
- package/src/compat/rules/providers/firepass.kdl +15 -0
- package/src/compat/rules/providers/fireworks.kdl +26 -0
- package/src/compat/rules/providers/github-copilot.kdl +24 -0
- package/src/compat/rules/providers/google-antigravity.kdl +37 -0
- package/src/compat/rules/providers/google-gemini-cli.kdl +1 -0
- package/src/compat/rules/providers/google-vertex.kdl +5 -0
- package/src/compat/rules/providers/google.kdl +1 -0
- package/src/compat/rules/providers/image-tokenization.kdl +2 -1
- package/src/compat/rules/providers/local.kdl +8 -1
- package/src/compat/rules/providers/meta.kdl +16 -0
- package/src/compat/rules/providers/moonshot.kdl +2 -0
- package/src/compat/rules/providers/muse-code.kdl +49 -0
- package/src/compat/rules/providers/native-tools.kdl +3 -0
- package/src/compat/rules/providers/ollama-cloud.kdl +10 -0
- package/src/compat/rules/providers/openai-codex.kdl +29 -5
- package/src/compat/rules/providers/openai.kdl +1 -0
- package/src/compat/rules/providers/opencode-go.kdl +35 -0
- package/src/compat/rules/providers/opencode-zen.kdl +4 -0
- package/src/compat/rules/providers/openrouter.kdl +27 -1
- package/src/compat/rules/providers/sambanova.kdl +60 -0
- package/src/compat/rules/providers/tool-call-names.kdl +37 -0
- package/src/compat/rules/providers/typesafe.kdl +22 -1
- package/src/compat/rules/providers/umans.kdl +7 -0
- package/src/compat/rules/providers/venice.kdl +7 -0
- package/src/compat/rules/providers/web.kdl +7 -0
- package/src/compat/rules/providers/xai-oauth.kdl +16 -6
- package/src/compat/rules/providers/xai.kdl +3 -0
- package/src/compat/rules/providers/zai.kdl +5 -0
- package/src/compat/rules/runtime/behavior.kdl +129 -8
- package/src/compat/rules/taxonomy/_collapse.kdl +11 -0
- package/src/compat/rules/taxonomy/gemma.kdl +1 -0
- package/src/compat/rules/taxonomy/meta.kdl +7 -0
- package/src/compat/rules/taxonomy/openai.kdl +2 -0
- package/src/compat/rules.json +1 -1
- package/src/compat/thinking-replay.ts +33 -0
- package/src/compat/types.d.ts +4 -0
- package/src/compat/types.ts +4 -0
- package/src/discovery/antigravity.d.ts +7 -0
- package/src/discovery/antigravity.ts +13 -0
- package/src/discovery/codex.ts +0 -4
- package/src/discovery/cursor.ts +28 -20
- package/src/discovery/devin.ts +7 -8
- package/src/model-cache.d.ts +7 -0
- package/src/model-cache.ts +8 -0
- package/src/model-manager.d.ts +6 -0
- package/src/model-manager.ts +41 -21
- package/src/model-thinking.d.ts +80 -0
- package/src/model-thinking.ts +13 -1
- package/src/model-tokenizer.ts +7 -1
- package/src/models.d.ts +16 -1
- package/src/models.json +1 -1
- package/src/models.ts +26 -12
- package/src/pricing.d.ts +37 -1
- package/src/pricing.ts +123 -12
- package/src/provider-models/bundled-references.ts +5 -2
- package/src/provider-models/cache-provider-id.ts +1 -1
- package/src/provider-models/descriptors.ts +2 -0
- package/src/provider-models/google.ts +7 -1
- package/src/provider-models/openai-compat.d.ts +18 -46
- package/src/provider-models/openai-compat.ts +188 -104
- package/src/provider-models/special.d.ts +6 -1
- package/src/provider-models/special.ts +15 -9
- package/src/types.d.ts +63 -12
- package/src/types.ts +71 -9
- package/src/wire/codex.d.ts +2 -0
- package/src/wire/codex.ts +17 -0
package/src/models.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { classifyModel } from "./compat/taxonomy";
|
|
2
2
|
import MODELS from "./models.json" with { type: "json" };
|
|
3
|
+
import { dueEffectiveRate } from "./pricing";
|
|
3
4
|
import type {
|
|
4
5
|
Api,
|
|
5
6
|
EffectiveTokenCost,
|
|
@@ -65,22 +66,25 @@ export function getBundledModels(provider: GeneratedProvider): Model<Api>[] {
|
|
|
65
66
|
}
|
|
66
67
|
/** Resolve display semantics without mistaking an absent rate card for a free model. */
|
|
67
68
|
export function getModelPricingStatus(model: Pick<Model<Api>, "cost" | "pricingStatus">): ModelPricingStatus {
|
|
68
|
-
const cost = model.cost;
|
|
69
|
+
const cost = getEffectiveTokenCost(model.cost);
|
|
69
70
|
if (cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0) return "fixed";
|
|
70
71
|
return model.pricingStatus ?? "unknown";
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
/**
|
|
75
|
+
* The base token card in force at `timestamp` (Unix ms, default now): the
|
|
76
|
+
* latest due `timeBased` effective rate, else the row's own legs. Price
|
|
77
|
+
* displays read this rather than the scalar legs, which keep the card current
|
|
78
|
+
* when the row was built while bundles, caches, and long sessions outlive it.
|
|
79
|
+
* Applies no long-context tier or peak/off-peak multiplier.
|
|
80
|
+
*/
|
|
81
|
+
export function getEffectiveTokenCost(cost: ModelCost, timestamp = Date.now()): TokenCost {
|
|
82
|
+
return resolveTokenCost(cost, 0, timestamp);
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
function resolveTokenCost(cost: ModelCost, promptInputTokens: number, timestamp: number | undefined): TokenCost {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (timestamp !== undefined && cost.timeBased?.effectiveRates) {
|
|
77
|
-
for (const candidate of cost.timeBased.effectiveRates) {
|
|
78
|
-
if (candidate.effectiveFrom <= timestamp && candidate.effectiveFrom > effectiveFrom) {
|
|
79
|
-
rates = candidate;
|
|
80
|
-
effectiveFrom = candidate.effectiveFrom;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
86
|
+
const rates: ModelCost | EffectiveTokenCost =
|
|
87
|
+
(timestamp === undefined ? undefined : dueEffectiveRate(cost.timeBased, timestamp)) ?? cost;
|
|
84
88
|
const longContext = rates.longContext;
|
|
85
89
|
if (!longContext) return rates;
|
|
86
90
|
const reachesThreshold =
|
|
@@ -105,10 +109,20 @@ function timeBasedMultiplier(schedule: TimeBasedCost | undefined, timestamp: num
|
|
|
105
109
|
return isPeakPricingPeriod(schedule, timestamp) ? 1 : schedule.offPeakMultiplier;
|
|
106
110
|
}
|
|
107
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Whether a schedule carries a recurring peak/off-peak tariff. A schedule with
|
|
114
|
+
* no peak windows at a 1x off-peak multiplier only carries dated rate cards
|
|
115
|
+
* (`cost-patch`/`cost-fallback` `effective-rates`): its price changes on a
|
|
116
|
+
* date, never by time of day.
|
|
117
|
+
*/
|
|
118
|
+
export function hasRecurringTariff(schedule: TimeBasedCost): boolean {
|
|
119
|
+
return schedule.peakWindows.length > 0 || schedule.offPeakMultiplier !== 1;
|
|
120
|
+
}
|
|
121
|
+
|
|
108
122
|
/** Return the recurring UTC tariff period, independently of its monetary multiplier. */
|
|
109
123
|
export function getTimeBasedPricingPeriod(cost: ModelCost, timestamp?: number): "peak" | "off-peak" | undefined {
|
|
110
124
|
const schedule = cost.timeBased;
|
|
111
|
-
if (!schedule) return undefined;
|
|
125
|
+
if (!schedule || !hasRecurringTariff(schedule)) return undefined;
|
|
112
126
|
return isPeakPricingPeriod(schedule, timestamp ?? Date.now()) ? "peak" : "off-peak";
|
|
113
127
|
}
|
|
114
128
|
|
package/src/pricing.d.ts
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
|
-
import type { TimeBasedCost } from "./types";
|
|
1
|
+
import type { EffectiveTokenCost, ModelCost, TimeBasedCost, TokenCost } from "./types";
|
|
2
2
|
/** Validate serialized schedules before admitting cached model rows. */
|
|
3
3
|
export declare function isTimeBasedCost(value: unknown): value is TimeBasedCost;
|
|
4
4
|
/** KDL object children are named records; normalize them once while constructing the model. */
|
|
5
5
|
export declare function materializeTimeBasedCost(value: unknown): TimeBasedCost;
|
|
6
|
+
/**
|
|
7
|
+
* The latest `effectiveRates` card of a materialized schedule due at
|
|
8
|
+
* `timestamp`, or undefined before the first one (or without a schedule).
|
|
9
|
+
*/
|
|
10
|
+
export declare function dueEffectiveRate(schedule: TimeBasedCost | undefined, timestamp: number): EffectiveTokenCost | undefined;
|
|
11
|
+
/** A `cost-patch`/`cost-fallback` dated card: the legs it overwrites from `effectiveFrom` (Unix ms). */
|
|
12
|
+
export interface DatedCostCard extends Partial<TokenCost> {
|
|
13
|
+
effectiveFrom: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse the compiled `effective-rates` block of a `cost-patch` or
|
|
17
|
+
* `cost-fallback` payload into dated cards, ascending by date. Throws on a
|
|
18
|
+
* malformed card, so a typo in a rule fails the build instead of silently
|
|
19
|
+
* leaving the old price in force.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseDatedCostCards(costAxis: unknown, axis: "cost-patch" | "cost-fallback"): DatedCostCard[];
|
|
22
|
+
/**
|
|
23
|
+
* Earliest instant a rate card can name (the `Date` range minimum). A leading
|
|
24
|
+
* card from here holds the price in force before the first dated change.
|
|
25
|
+
*/
|
|
26
|
+
export declare const EARLIEST_EFFECTIVE_FROM = -8640000000000000;
|
|
27
|
+
/** A schedule of dated rate cards alone: no peak windows, no off-peak discount. */
|
|
28
|
+
export declare const NO_RECURRING_TARIFF: TimeBasedCost;
|
|
29
|
+
/**
|
|
30
|
+
* A flat card plus its dated overrides as a request-time `ModelCost`: the
|
|
31
|
+
* card due at `now` in the scalar legs, and every period (a leading card for
|
|
32
|
+
* the base price, then each dated card over the previous one) in a
|
|
33
|
+
* `timeBased` schedule without a recurring tariff. The plain card when no
|
|
34
|
+
* dated card exists.
|
|
35
|
+
*/
|
|
36
|
+
export declare function datedCost(base: TokenCost, cards: readonly DatedCostCard[], now?: number): ModelCost;
|
|
37
|
+
/**
|
|
38
|
+
* Overwrite `cost` legs with the latest dated card due at `now`. Leaves
|
|
39
|
+
* `cost` unchanged before the first card.
|
|
40
|
+
*/
|
|
41
|
+
export declare function applyDueDatedCostCard(cost: TokenCost, cards: readonly DatedCostCard[], now?: number): void;
|
package/src/pricing.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
EffectiveTokenCost,
|
|
3
|
+
LongContextTokenCost,
|
|
4
|
+
ModelCost,
|
|
5
|
+
PeakPricingWindow,
|
|
6
|
+
TimeBasedCost,
|
|
7
|
+
TokenCost,
|
|
8
|
+
} from "./types";
|
|
2
9
|
import { isRecord } from "./utils";
|
|
3
10
|
|
|
4
11
|
function nonnegative(value: unknown): value is number {
|
|
@@ -86,6 +93,21 @@ function namedEntries(value: unknown, field: string): unknown[] {
|
|
|
86
93
|
return Object.values(value);
|
|
87
94
|
}
|
|
88
95
|
|
|
96
|
+
/** Parse a KDL ISO UTC instant (`YYYY-MM-DDTHH:mm:ssZ`, optional milliseconds) to Unix ms. */
|
|
97
|
+
function parseUtcInstant(date: unknown, axis: string): number {
|
|
98
|
+
if (typeof date !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/.test(date)) {
|
|
99
|
+
throw new Error(`Invalid ${axis} effective-from: expected an ISO UTC timestamp`);
|
|
100
|
+
}
|
|
101
|
+
const instant = Date.parse(date);
|
|
102
|
+
if (
|
|
103
|
+
!Number.isFinite(instant) ||
|
|
104
|
+
new Date(instant).toISOString() !== (date.includes(".") ? date : date.replace("Z", ".000Z"))
|
|
105
|
+
) {
|
|
106
|
+
throw new Error(`Invalid ${axis} effective-from: invalid UTC date`);
|
|
107
|
+
}
|
|
108
|
+
return instant;
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
/** KDL object children are named records; normalize them once while constructing the model. */
|
|
90
112
|
export function materializeTimeBasedCost(value: unknown): TimeBasedCost {
|
|
91
113
|
const source = payload(value, ["offPeakMultiplier", "peakWindows", "effectiveRates"], "schedule");
|
|
@@ -105,17 +127,7 @@ export function materializeTimeBasedCost(value: unknown): TimeBasedCost {
|
|
|
105
127
|
["effectiveFrom", "input", "output", "cacheRead", "cacheWrite", "longContext"],
|
|
106
128
|
"effective-rate",
|
|
107
129
|
);
|
|
108
|
-
const
|
|
109
|
-
if (typeof date !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/.test(date)) {
|
|
110
|
-
throw new Error("Invalid time-based-cost effective-from: expected an ISO UTC timestamp");
|
|
111
|
-
}
|
|
112
|
-
const effectiveFrom = Date.parse(date);
|
|
113
|
-
if (
|
|
114
|
-
!Number.isFinite(effectiveFrom) ||
|
|
115
|
-
new Date(effectiveFrom).toISOString() !== (date.includes(".") ? date : date.replace("Z", ".000Z"))
|
|
116
|
-
) {
|
|
117
|
-
throw new Error("Invalid time-based-cost effective-from: invalid UTC date");
|
|
118
|
-
}
|
|
130
|
+
const effectiveFrom = parseUtcInstant(rate.effectiveFrom, "time-based-cost");
|
|
119
131
|
if (rate.longContext !== undefined) {
|
|
120
132
|
payload(
|
|
121
133
|
rate.longContext,
|
|
@@ -134,3 +146,102 @@ export function materializeTimeBasedCost(value: unknown): TimeBasedCost {
|
|
|
134
146
|
throw new Error("Invalid time-based-cost schedule: invalid windows, rates, or multiplier");
|
|
135
147
|
return schedule;
|
|
136
148
|
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The latest `effectiveRates` card of a materialized schedule due at
|
|
152
|
+
* `timestamp`, or undefined before the first one (or without a schedule).
|
|
153
|
+
*/
|
|
154
|
+
export function dueEffectiveRate(
|
|
155
|
+
schedule: TimeBasedCost | undefined,
|
|
156
|
+
timestamp: number,
|
|
157
|
+
): EffectiveTokenCost | undefined {
|
|
158
|
+
let due: EffectiveTokenCost | undefined;
|
|
159
|
+
for (const candidate of schedule?.effectiveRates ?? []) {
|
|
160
|
+
if (candidate.effectiveFrom <= timestamp && (due === undefined || candidate.effectiveFrom > due.effectiveFrom)) {
|
|
161
|
+
due = candidate;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return due;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const TOKEN_COST_LEGS = ["input", "output", "cacheRead", "cacheWrite"] as const;
|
|
168
|
+
const DATED_CARD_KEYS: readonly string[] = ["effectiveFrom", ...TOKEN_COST_LEGS];
|
|
169
|
+
|
|
170
|
+
/** A `cost-patch`/`cost-fallback` dated card: the legs it overwrites from `effectiveFrom` (Unix ms). */
|
|
171
|
+
export interface DatedCostCard extends Partial<TokenCost> {
|
|
172
|
+
effectiveFrom: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Parse the compiled `effective-rates` block of a `cost-patch` or
|
|
177
|
+
* `cost-fallback` payload into dated cards, ascending by date. Throws on a
|
|
178
|
+
* malformed card, so a typo in a rule fails the build instead of silently
|
|
179
|
+
* leaving the old price in force.
|
|
180
|
+
*/
|
|
181
|
+
export function parseDatedCostCards(costAxis: unknown, axis: "cost-patch" | "cost-fallback"): DatedCostCard[] {
|
|
182
|
+
const effectiveRates = isRecord(costAxis) ? costAxis.effectiveRates : undefined;
|
|
183
|
+
if (effectiveRates === undefined) return [];
|
|
184
|
+
if (!isRecord(effectiveRates)) throw new Error(`Invalid ${axis} effective-rates: expected named objects`);
|
|
185
|
+
const cards = Object.values(effectiveRates).map(entry => {
|
|
186
|
+
if (!isRecord(entry) || Object.keys(entry).some(key => !DATED_CARD_KEYS.includes(key))) {
|
|
187
|
+
throw new Error(`Invalid ${axis} effective-rate: unknown or malformed fields`);
|
|
188
|
+
}
|
|
189
|
+
const card: DatedCostCard = { effectiveFrom: parseUtcInstant(entry.effectiveFrom, axis) };
|
|
190
|
+
for (const leg of TOKEN_COST_LEGS) {
|
|
191
|
+
const value = entry[leg];
|
|
192
|
+
if (value === undefined) continue;
|
|
193
|
+
if (!nonnegative(value))
|
|
194
|
+
throw new Error(`Invalid ${axis} effective-rate ${leg}: expected a nonnegative number`);
|
|
195
|
+
card[leg] = value;
|
|
196
|
+
}
|
|
197
|
+
return card;
|
|
198
|
+
});
|
|
199
|
+
cards.sort((a, b) => a.effectiveFrom - b.effectiveFrom);
|
|
200
|
+
for (let index = 1; index < cards.length; index++) {
|
|
201
|
+
if (cards[index]!.effectiveFrom === cards[index - 1]!.effectiveFrom) {
|
|
202
|
+
throw new Error(`Invalid ${axis} effective-rates: duplicate effective-from`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return cards;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Earliest instant a rate card can name (the `Date` range minimum). A leading
|
|
210
|
+
* card from here holds the price in force before the first dated change.
|
|
211
|
+
*/
|
|
212
|
+
export const EARLIEST_EFFECTIVE_FROM = -8_640_000_000_000_000;
|
|
213
|
+
|
|
214
|
+
/** A schedule of dated rate cards alone: no peak windows, no off-peak discount. */
|
|
215
|
+
export const NO_RECURRING_TARIFF: TimeBasedCost = { offPeakMultiplier: 1, peakWindows: [] };
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* A flat card plus its dated overrides as a request-time `ModelCost`: the
|
|
219
|
+
* card due at `now` in the scalar legs, and every period (a leading card for
|
|
220
|
+
* the base price, then each dated card over the previous one) in a
|
|
221
|
+
* `timeBased` schedule without a recurring tariff. The plain card when no
|
|
222
|
+
* dated card exists.
|
|
223
|
+
*/
|
|
224
|
+
export function datedCost(base: TokenCost, cards: readonly DatedCostCard[], now = Date.now()): ModelCost {
|
|
225
|
+
if (cards.length === 0) return base;
|
|
226
|
+
const effectiveRates: EffectiveTokenCost[] = [{ effectiveFrom: EARLIEST_EFFECTIVE_FROM, ...base }];
|
|
227
|
+
for (const card of cards) effectiveRates.push({ ...effectiveRates.at(-1)!, ...card });
|
|
228
|
+
const timeBased = { ...NO_RECURRING_TARIFF, effectiveRates };
|
|
229
|
+
const { effectiveFrom: _effectiveFrom, ...due } = dueEffectiveRate(timeBased, now)!;
|
|
230
|
+
return { ...due, timeBased };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Overwrite `cost` legs with the latest dated card due at `now`. Leaves
|
|
235
|
+
* `cost` unchanged before the first card.
|
|
236
|
+
*/
|
|
237
|
+
export function applyDueDatedCostCard(cost: TokenCost, cards: readonly DatedCostCard[], now = Date.now()): void {
|
|
238
|
+
let due: DatedCostCard | undefined;
|
|
239
|
+
for (const card of cards) {
|
|
240
|
+
if (card.effectiveFrom <= now) due = card;
|
|
241
|
+
}
|
|
242
|
+
if (due === undefined) return;
|
|
243
|
+
for (const leg of TOKEN_COST_LEGS) {
|
|
244
|
+
const value = due[leg];
|
|
245
|
+
if (value !== undefined) cost[leg] = value;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isBareIdReferenceProvider } from "../compat/behavior";
|
|
2
2
|
import { isZeroCostXaiOAuthReference } from "../identity/reference";
|
|
3
|
+
import { withoutUnverifiedThinking } from "../model-thinking";
|
|
3
4
|
import { getBundledModels, getBundledProviders } from "../models";
|
|
4
5
|
import type { Api, Model, ModelSpec } from "../types";
|
|
5
6
|
|
|
@@ -17,11 +18,13 @@ export function toModelSpec<TApi extends Api>(model: Model<TApi>): ModelSpec<TAp
|
|
|
17
18
|
supportsComputerUseConfig,
|
|
18
19
|
...rest
|
|
19
20
|
} = model;
|
|
20
|
-
|
|
21
|
+
// Unverified thinking is derived output too: references must not carry it to
|
|
22
|
+
// another host as reasoning capability.
|
|
23
|
+
return withoutUnverifiedThinking({
|
|
21
24
|
...rest,
|
|
22
25
|
...(supportsComputerUseConfig !== undefined ? { supportsComputerUse: supportsComputerUseConfig } : {}),
|
|
23
26
|
compat: compatConfig,
|
|
24
|
-
} as ModelSpec<TApi
|
|
27
|
+
} as ModelSpec<TApi>);
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export function createBundledReferenceMap<TApi extends Api>(
|
|
@@ -45,7 +45,7 @@ export function getDefaultModelDiscoveryBaseUrl(providerId: string): string | un
|
|
|
45
45
|
case "litellm":
|
|
46
46
|
return Bun.env.LITELLM_BASE_URL ?? "http://localhost:4000/v1";
|
|
47
47
|
case "opencode-go":
|
|
48
|
-
return "https://opencode.ai/
|
|
48
|
+
return "https://opencode.ai/inference/go/v1";
|
|
49
49
|
case "opencode-zen":
|
|
50
50
|
return "https://opencode.ai/zen/v1";
|
|
51
51
|
case "vllm":
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
qianfanModelManagerOptions,
|
|
60
60
|
qwenPortalModelManagerOptions,
|
|
61
61
|
sakanaModelManagerOptions,
|
|
62
|
+
sambanovaModelManagerOptions,
|
|
62
63
|
siliconflowCnModelManagerOptions,
|
|
63
64
|
siliconflowModelManagerOptions,
|
|
64
65
|
singularityApiDevModelManagerOptions,
|
|
@@ -146,6 +147,7 @@ const MODEL_MANAGER_FACTORIES: Readonly<Partial<Record<KnownProvider, ModelManag
|
|
|
146
147
|
qianfan: config => qianfanModelManagerOptions(config),
|
|
147
148
|
"qwen-portal": config => qwenPortalModelManagerOptions(config),
|
|
148
149
|
sakana: config => sakanaModelManagerOptions(config),
|
|
150
|
+
sambanova: config => sambanovaModelManagerOptions(config),
|
|
149
151
|
siliconflow: config => siliconflowModelManagerOptions(config),
|
|
150
152
|
"siliconflow-cn": config => siliconflowCnModelManagerOptions(config),
|
|
151
153
|
"singularityapi-dev": config => singularityApiDevModelManagerOptions(config),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logger } from "@linxiraos/pi-utils";
|
|
2
|
+
import { isExcludedModel } from "../compat/behavior";
|
|
2
3
|
import { reviewedCollapseTable } from "../compat/collapse";
|
|
3
4
|
import { classifyModel } from "../compat/taxonomy";
|
|
4
5
|
import { providerEntry } from "../compat/providers";
|
|
@@ -127,7 +128,12 @@ export function googleAntigravityModelManagerOptions(
|
|
|
127
128
|
});
|
|
128
129
|
continue;
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
+
// Caches written under older rules fail the compiled-rules hash in
|
|
132
|
+
// the model cache, so filtering fresh rosters covers every source.
|
|
133
|
+
catalogs.push({
|
|
134
|
+
accountKey,
|
|
135
|
+
models: result.models.filter(model => !isExcludedModel("google-antigravity", model.id)),
|
|
136
|
+
});
|
|
131
137
|
}
|
|
132
138
|
if (catalogs.length === 0) return null;
|
|
133
139
|
const tagAccess = catalogs.every(catalog => catalog.accountKey !== undefined);
|
|
@@ -100,6 +100,19 @@ export interface CerebrasModelManagerConfig {
|
|
|
100
100
|
fetch?: FetchImpl;
|
|
101
101
|
}
|
|
102
102
|
export declare function cerebrasModelManagerOptions(config?: CerebrasModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
103
|
+
/** SambaNova discovery inputs: `apiKey` enables the live roster; `baseUrl` defaults to SambaNova Cloud. */
|
|
104
|
+
export interface SambaNovaModelManagerConfig {
|
|
105
|
+
apiKey?: string;
|
|
106
|
+
baseUrl?: string;
|
|
107
|
+
fetch?: FetchImpl;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* SambaNova Cloud's model manager. `/v1/models` requires a key, so a keyless
|
|
111
|
+
* manager serves only the bundled seed; with a key the live roster replaces
|
|
112
|
+
* it. Rows carry pricing and limits but no capability metadata: reasoning,
|
|
113
|
+
* thinking wire format, and image input come from `providers/sambanova.kdl`.
|
|
114
|
+
*/
|
|
115
|
+
export declare function sambanovaModelManagerOptions(config?: SambaNovaModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
103
116
|
export interface HuggingfaceModelManagerConfig {
|
|
104
117
|
apiKey?: string;
|
|
105
118
|
baseUrl?: string;
|
|
@@ -232,52 +245,6 @@ export interface ZhipuCodingPlanModelManagerConfig {
|
|
|
232
245
|
fetch?: FetchImpl;
|
|
233
246
|
}
|
|
234
247
|
export declare function zhipuCodingPlanModelManagerOptions(config?: ZhipuCodingPlanModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
235
|
-
/**
|
|
236
|
-
* Fireworks-published cap for the Kimi K2 family. Fireworks' `/v1/models`
|
|
237
|
-
* envelope generically reports `max_completion_tokens: 65536` for every Kimi
|
|
238
|
-
* deployment, but Kimi K2 (instruct / thinking / turbo) on Fireworks is
|
|
239
|
-
* documented to ship long reasoning traces that should be bounded — capping
|
|
240
|
-
* at 32,768 prevents handing callers a budget the router cannot honor.
|
|
241
|
-
* See https://github.com/can1357/oh-my-pi/issues/1849.
|
|
242
|
-
*/
|
|
243
|
-
export declare const FIREWORKS_KIMI_MAX_TOKENS = 32768;
|
|
244
|
-
/**
|
|
245
|
-
* Fireworks' output ceiling for Kimi K2.7-Code specifically. Its `/v1/models`
|
|
246
|
-
* generic `max_completion_tokens` is 65,536 and Fireworks serves it in full —
|
|
247
|
-
* verified with a single completion emitting 58,971 output tokens and
|
|
248
|
-
* `max_tokens: 200000` accepted without error. Unlike the older K2.5/K2.6
|
|
249
|
-
* family (see {@link FIREWORKS_KIMI_MAX_TOKENS}), K2.7-Code is not clamped to
|
|
250
|
-
* 32,768; that ceiling only truncated it.
|
|
251
|
-
*/
|
|
252
|
-
export declare const FIREWORKS_KIMI_K27_CODE_MAX_TOKENS = 65536;
|
|
253
|
-
/**
|
|
254
|
-
* Returns true for the Kimi K2.5 / K2.6 family served by Fireworks-backed
|
|
255
|
-
* providers (`fireworks` direct, `firepass` router) that share the 32,768
|
|
256
|
-
* `maxTokens` ceiling. Matches both the public catalog id (`kimi-k2.5`,
|
|
257
|
-
* `kimi-k2.6`, `kimi-k2.6-turbo`) and the canonical Fireworks wire id
|
|
258
|
-
* (`accounts/fireworks/{models,routers}/kimi-k2…`).
|
|
259
|
-
*
|
|
260
|
-
* K2.7-Code (incl. `-fast` / `-highspeed`) is deliberately excluded: unlike the
|
|
261
|
-
* earlier K2 family it serves its full context on Fireworks — verified with a
|
|
262
|
-
* single completion emitting 58,971 output tokens and `max_tokens: 200000`
|
|
263
|
-
* accepted without error — so the 32,768 cap would only truncate it. It inherits
|
|
264
|
-
* Fireworks' reported `max_completion_tokens` (65,536) instead.
|
|
265
|
-
*/
|
|
266
|
-
export declare function isFireworksKimiK2ModelId(modelId: string): boolean;
|
|
267
|
-
/**
|
|
268
|
-
* Clamp the Kimi K2 family's `maxTokens` to {@link FIREWORKS_KIMI_MAX_TOKENS}
|
|
269
|
-
* on Fireworks-backed providers, leaving every other model untouched.
|
|
270
|
-
*/
|
|
271
|
-
export declare function clampFireworksKimiMaxTokens(modelId: string, candidate: number): number;
|
|
272
|
-
export declare function clampFireworksKimiMaxTokens(modelId: string, candidate: number | null): number | null;
|
|
273
|
-
/**
|
|
274
|
-
* Kimi K2.7 Code's documented recommended output budget. Some provider
|
|
275
|
-
* discovery rows report the context-sized `max_completion_tokens` instead.
|
|
276
|
-
*/
|
|
277
|
-
export declare const KIMI_K27_CODE_RECOMMENDED_MAX_TOKENS = 32768;
|
|
278
|
-
export declare function isKimiK27CodeModelId(modelId: string): boolean;
|
|
279
|
-
export declare function clampKimiK27CodeMaxTokens(modelId: string, candidate: number): number;
|
|
280
|
-
export declare function clampKimiK27CodeMaxTokens(modelId: string, candidate: number | null): number | null;
|
|
281
248
|
/**
|
|
282
249
|
* Build the Fireworks Fast seed by projecting each base bundled spec into a
|
|
283
250
|
* `<id>-fast` variant. Pushed into the generated catalog (Fast routers never
|
|
@@ -655,6 +622,11 @@ export interface ModelsDevProviderDescriptor {
|
|
|
655
622
|
}
|
|
656
623
|
/** Generic mapper that converts models.dev data using provider descriptors. */
|
|
657
624
|
export declare function mapModelsDevToModels(data: Record<string, unknown>, descriptors: readonly ModelsDevProviderDescriptor[]): ModelSpec<Api>[];
|
|
625
|
+
/**
|
|
626
|
+
* OpenCode Go endpoint for one request API. The model generator re-bases
|
|
627
|
+
* previous-snapshot rows with it so retained rows follow endpoint moves.
|
|
628
|
+
*/
|
|
629
|
+
export declare function openCodeGoBaseUrlForApi(api: Api): string;
|
|
658
630
|
/** Resolves the transport and endpoint for one Z.AI model catalog entry. */
|
|
659
631
|
export declare function resolveZaiApi(modelId: string): {
|
|
660
632
|
api: "anthropic-messages" | "openai-completions";
|