@oh-my-pi/pi-catalog 18.10.3 → 18.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/README.md +4 -2
- package/dist/types/build.d.ts +3 -2
- package/dist/types/compat/auth-ids.d.ts +2 -2
- package/dist/types/compat/provider-ids.d.ts +1 -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 -0
- package/dist/types/types.d.ts +0 -2
- package/package.json +4 -4
- package/src/build.ts +138 -78
- package/src/compat/auth-ids.ts +2 -0
- package/src/compat/axes.ts +21 -0
- package/src/compat/provider-ids.ts +1 -0
- package/src/compat/resolve.ts +15 -2
- package/src/compat/rules/README.md +5 -1
- package/src/compat/rules/auth/_order.kdl +1 -1
- package/src/compat/rules/auth/sambanova.kdl +9 -0
- package/src/compat/rules/classes/anthropic.kdl +3 -0
- package/src/compat/rules/classes/gemini.kdl +28 -0
- package/src/compat/rules/classes/meta.kdl +4 -2
- package/src/compat/rules/classes/minimax.kdl +1 -1
- package/src/compat/rules/providers/cursor.kdl +20 -0
- package/src/compat/rules/providers/devin.kdl +110 -5
- package/src/compat/rules/providers/local.kdl +8 -1
- package/src/compat/rules/providers/muse-code.kdl +40 -0
- package/src/compat/rules/providers/opencode-go.kdl +31 -0
- package/src/compat/rules/providers/sambanova.kdl +60 -0
- package/src/compat/rules/runtime/behavior.kdl +4 -0
- 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 +4 -0
- package/src/compat/rules.json +1 -1
- package/src/discovery/codex.ts +0 -4
- package/src/discovery/cursor.ts +25 -11
- package/src/discovery/devin.ts +5 -3
- package/src/models.json +1 -1
- package/src/models.ts +26 -12
- package/src/pricing.ts +123 -12
- package/src/provider-models/cache-provider-id.ts +1 -1
- package/src/provider-models/descriptors.ts +2 -0
- package/src/provider-models/openai-compat.ts +169 -8
- package/src/types.ts +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.11.0] - 2026-10-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `local/nemotron-streaming-en-0.6b` for local streaming English dictation ([#15759](https://github.com/can1357/oh-my-pi/pull/15759) by [@daaximus](https://github.com/daaximus)).
|
|
10
|
+
- Added SambaNova Cloud (`sambanova`) as a provider: `/login sambanova` with an API key, and the live `/v1/models` roster with its prices, reasoning models, and Gemma 4 image input ([#14986](https://github.com/can1357/oh-my-pi/pull/14986) by [@rjuez00](https://github.com/rjuez00))
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- OpenCode Go requests now go to the current `https://opencode.ai/inference/go/v1` endpoint instead of the legacy `/zen/go` one ([#15722](https://github.com/can1357/oh-my-pi/issues/15722))
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Fixed OpenCode Go's `deepseek-flash` alias showing $0, unknown limits, and no reasoning instead of the V4.1 Flash rate card and capabilities ([#15357](https://github.com/can1357/oh-my-pi/issues/15357))
|
|
19
|
+
- Fixed OpenCode Go's Gemini 4 Argon Contributor failing with an unsupported protocol and thinking level; it now uses the native Gemini endpoint ([#15722](https://github.com/can1357/oh-my-pi/issues/15722))
|
|
20
|
+
|
|
21
|
+
## [18.10.4] - 2026-10-13
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Added Muse Code's subscription-only Muse Wonder Full and Wonder contributor tiers with the `max` effort, recording API-equivalent cost instead of $0: Wonder Full at Muse Wonder's $4 input / $0.20 cached / $20 output per 1M tokens, contributor tiers at the measured $1.60 / $0.08 / $8 ([#15522](https://github.com/can1357/oh-my-pi/pull/15522) by [@eggpeat](https://github.com/eggpeat))
|
|
26
|
+
- Added the `classifier-cot-extraction` rule axis, set for Claude, marking models whose classifier refuses earlier reasoning quoted back into their input ([#15436](https://github.com/can1357/oh-my-pi/pull/15436) by [@will-bogusz](https://github.com/will-bogusz))
|
|
27
|
+
- Added Gemini 4 Argon pricing on Cursor ($2 input / $0.10 cached / $10 output per 1M tokens) and Google Antigravity, which now uses Google's first-party rate instead of showing $0 ([#15620](https://github.com/can1357/oh-my-pi/pull/15620) by [@eggpeat](https://github.com/eggpeat))
|
|
28
|
+
- Added scheduled list-price changes to `cost-patch`, as `cost-fallback` already allowed: a dated `effective-rates` card sets the price from its date, and each request is priced at the card in force when it was made, even on models loaded before the change, on rebuilt models, and on Cursor lanes priced from a sibling's card. A malformed dated card now fails the model build instead of silently keeping the old price. `getEffectiveTokenCost` returns that card for price displays, and `hasRecurringTariff` tells these dated-only schedules apart from peak/off-peak tariffs, which alone show a status-line arrow ([#15620](https://github.com/can1357/oh-my-pi/pull/15620) by [@eggpeat](https://github.com/eggpeat))
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Devin models with a long-context price tier (GPT-5.4 through 5.6 standard lanes, GPT-6 through 6.1, Gemini Pro, and Grok 4.5 through 4.7) now default to a 272K or 200K context window, where that pricing starts; run `/extended-context on` to use the full window at long-context rates ([#14891](https://github.com/can1357/oh-my-pi/pull/14891) by [@eggpeat](https://github.com/eggpeat)).
|
|
33
|
+
- Devin SWE-2, SWE-1.7, and GLM-5.2 fallback pricing no longer charges cache writes at the input rate, since Devin publishes no cache-write rate for them ([#14891](https://github.com/can1357/oh-my-pi/pull/14891) by [@eggpeat](https://github.com/eggpeat)).
|
|
34
|
+
- Google Antigravity now lists Gemini 4 Argon once, with selectable low, medium, and high thinking levels, instead of a separate entry per thinking tier ([#15620](https://github.com/can1357/oh-my-pi/pull/15620) by [@eggpeat](https://github.com/eggpeat))
|
|
35
|
+
- Gemini 4 Argon on Google, Vertex, Google Antigravity, and Cursor moves to Google's $4 input / $0.20 cached / $20 output list price on 2026-12-01 (midnight US Pacific), including requests on models loaded before then, without a catalog update ([#15620](https://github.com/can1357/oh-my-pi/pull/15620) by [@eggpeat](https://github.com/eggpeat))
|
|
36
|
+
- Devin SWE-2's promotional fallback price now ends on 2027-01-01 for requests on models loaded before then too ([#15620](https://github.com/can1357/oh-my-pi/pull/15620) by [@eggpeat](https://github.com/eggpeat))
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Fixed Devin Claude and GPT-5.6 through GPT-6 models pricing prompt-cache writes at $0; they now use Devin's published rate of 1.25x input, and Adaptive uses its input rate ([#14891](https://github.com/can1357/oh-my-pi/pull/14891) by [@eggpeat](https://github.com/eggpeat)).
|
|
41
|
+
- Fixed Devin GPT-5.4 through GPT-6.1, Gemini Pro, and Grok 4.5 through 4.7 models missing the long-context price tiers Devin publishes above 272K and 200K prompt tokens ([#14891](https://github.com/can1357/oh-my-pi/pull/14891) by [@eggpeat](https://github.com/eggpeat)).
|
|
42
|
+
- Fixed Devin Fusion pairings ignoring their lead model's rules, including its cache-write rate and long-context tier ([#14891](https://github.com/can1357/oh-my-pi/pull/14891) by [@eggpeat](https://github.com/eggpeat)).
|
|
43
|
+
- Fixed Kilo and NanoGPT models showing stale or missing prices (for example Gemini 4 Argon at $4/$20 instead of $2/$10, and many models at $0); prices now come from each gateway's live model list ([#15623](https://github.com/can1357/oh-my-pi/pull/15623) by [@eggpeat](https://github.com/eggpeat))
|
|
44
|
+
- Fixed NanoGPT models showing their raw id as the name and no context window (disabling auto-compaction) when the bundled catalog lacked them; names, context windows and output limits now come from NanoGPT's live model list ([#15623](https://github.com/can1357/oh-my-pi/pull/15623) by [@eggpeat](https://github.com/eggpeat))
|
|
45
|
+
|
|
46
|
+
### Removed
|
|
47
|
+
|
|
48
|
+
- Removed the Codex `toolMode` model field (`code_mode_only`); Codex discovery no longer maps `tool_mode`
|
|
49
|
+
|
|
5
50
|
## [18.10.3] - 2026-10-12
|
|
6
51
|
|
|
7
52
|
### Breaking Changes
|
package/README.md
CHANGED
|
@@ -47,12 +47,14 @@ The `models` subpath (also exported from the root) provides timestamp-aware pric
|
|
|
47
47
|
| `calculateCost(model, usage, timestamp?)` | Updates and returns `usage.cost` using `model.cost`. |
|
|
48
48
|
| `calculateUsageCost(cost, usage, timestamp?)` | Updates and returns `usage.cost` using a `ModelCost`. |
|
|
49
49
|
| `calculateUncachedInputCost(cost, promptInputTokens, timestamp?)` | Returns the cost of a fully uncached prompt. |
|
|
50
|
-
| `
|
|
50
|
+
| `getEffectiveTokenCost(cost, timestamp?)` | Returns the base card in force: the latest due effective rate, else the row's own legs. |
|
|
51
|
+
| `getTimeBasedPricingPeriod(cost, timestamp?)` | Returns `"peak"`, `"off-peak"`, or `undefined` without a recurring tariff. |
|
|
52
|
+
| `hasRecurringTariff(schedule)` | Whether a `TimeBasedCost` carries a peak/off-peak tariff rather than only dated rate cards. |
|
|
51
53
|
| `getNextTimeBasedPricingTransition(cost, timestamp?)` | Returns the next actual peak/off-peak change strictly after the timestamp, or `undefined` if none exists. |
|
|
52
54
|
|
|
53
55
|
Timestamps are Unix milliseconds; omitted timestamps use the current time for scheduled pricing. Flat token prices are unaffected. Pricing selects the latest applicable effective rate card, then its long-context tier, then the peak/off-peak multiplier. A transition query concerns the recurring tariff, not dated rate-card changes.
|
|
54
56
|
|
|
55
|
-
`ModelCost.timeBased` is optional typed metadata (`TimeBasedCost`): `offPeakMultiplier`, `peakWindows` (UTC `weekdays`, Sunday = 0, and start-inclusive/end-exclusive `startMinute`/`endMinute`), and optional `effectiveRates`. Each effective rate is a complete `TokenCost` with an `effectiveFrom` Unix-millisecond timestamp and optional `longContext` tier, replacing the base card from that instant.
|
|
57
|
+
`ModelCost.timeBased` is optional typed metadata (`TimeBasedCost`): `offPeakMultiplier`, `peakWindows` (UTC `weekdays`, Sunday = 0, and start-inclusive/end-exclusive `startMinute`/`endMinute`), and optional `effectiveRates`. Each effective rate is a complete `TokenCost` with an `effectiveFrom` Unix-millisecond timestamp and optional `longContext` tier, replacing the base card from that instant. A schedule with no peak windows at a 1x off-peak multiplier has no recurring tariff, only dated rate cards: `cost-patch`/`cost-fallback` `effective-rates` compile to one, so a row built before a scheduled price change still prices later requests at the new card.
|
|
56
58
|
|
|
57
59
|
Pass the request-start timestamp when estimating request usage, then preserve the resulting monetary amounts rather than repricing history at display time. OMP does this using the assistant message timestamp; it is an estimation convention, not a claim about server billing across boundaries. Prefer monetary costs reported by a provider when available.
|
|
58
60
|
|
package/dist/types/build.d.ts
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
import { type Api, type Model, type ModelSpec } from "./types.js";
|
|
10
10
|
/**
|
|
11
11
|
* Applies reviewed catalog-data value corrections (`cost-patch`,
|
|
12
|
-
* `cache-read-at-input-rate`, `
|
|
13
|
-
* `context-window-floor`, `input-modalities`) onto an
|
|
12
|
+
* `cache-read-at-input-rate`, `cache-write-rate`, `limits-patch`,
|
|
13
|
+
* `long-context-cost`, `context-window-floor`, `input-modalities`) onto an
|
|
14
|
+
* upstream-sourced spec. Applied by
|
|
14
15
|
* `buildModel` to every upstream-sourced spec; user-authored overrides are
|
|
15
16
|
* recomposed after building by the override applicators, so explicit user
|
|
16
17
|
* limits and pricing still win.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Every provider with an `auth/<id>.kdl` policy. */
|
|
2
|
-
export type AuthProviderId = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
|
|
2
|
+
export type AuthProviderId = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "sambanova" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
|
|
3
3
|
/** Providers whose policy declares a `login` flow (the `/login` roster). */
|
|
4
|
-
export type LoginProviderId = "abliteration" | "aiand" | "alibaba-coding-plan" | "alibaba-token-plan" | "anthropic" | "baseten" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google-antigravity" | "google-gemini-cli" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "meta" | "minimax-code" | "minimax-code-cn" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
|
|
4
|
+
export type LoginProviderId = "abliteration" | "aiand" | "alibaba-coding-plan" | "alibaba-token-plan" | "anthropic" | "baseten" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google-antigravity" | "google-gemini-cli" | "helmcode" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "meta" | "minimax-code" | "minimax-code-cn" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sakana" | "sambanova" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stencil" | "stepfun" | "synthetic" | "tavily" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zai-coding-plan" | "zenmux" | "zhipu-coding-plan";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Every chat-model provider with a catalog entry (`default-model` in its provider rules). */
|
|
2
|
-
export type KnownProvider = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kilo" | "kimi-code" | "litellm" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "opencode-go" | "opencode-zen" | "openrouter" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stepfun" | "synthetic" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zenmux" | "zhipu-coding-plan";
|
|
2
|
+
export type KnownProvider = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kilo" | "kimi-code" | "litellm" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "opencode-go" | "opencode-zen" | "openrouter" | "qianfan" | "qwen-portal" | "sakana" | "sambanova" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stepfun" | "synthetic" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zenmux" | "zhipu-coding-plan";
|
package/dist/types/models.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import MODELS from "./models.json";
|
|
2
|
-
import type { Api, KnownProvider, Model, ModelCost, ModelPricingStatus, Usage } from "./types.js";
|
|
2
|
+
import type { Api, KnownProvider, Model, ModelCost, ModelPricingStatus, TimeBasedCost, TokenCost, Usage } from "./types.js";
|
|
3
3
|
export type GeneratedProvider = keyof typeof MODELS;
|
|
4
4
|
/** Whether `provider` has bundled rows in models.json (e.g. a provider id authored in KDL). */
|
|
5
5
|
export declare function isGeneratedProvider(provider: string): provider is GeneratedProvider;
|
|
@@ -8,6 +8,21 @@ export declare function getBundledProviders(): KnownProvider[];
|
|
|
8
8
|
export declare function getBundledModels(provider: GeneratedProvider): Model<Api>[];
|
|
9
9
|
/** Resolve display semantics without mistaking an absent rate card for a free model. */
|
|
10
10
|
export declare function getModelPricingStatus(model: Pick<Model<Api>, "cost" | "pricingStatus">): ModelPricingStatus;
|
|
11
|
+
/**
|
|
12
|
+
* The base token card in force at `timestamp` (Unix ms, default now): the
|
|
13
|
+
* latest due `timeBased` effective rate, else the row's own legs. Price
|
|
14
|
+
* displays read this rather than the scalar legs, which keep the card current
|
|
15
|
+
* when the row was built while bundles, caches, and long sessions outlive it.
|
|
16
|
+
* Applies no long-context tier or peak/off-peak multiplier.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getEffectiveTokenCost(cost: ModelCost, timestamp?: number): TokenCost;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a schedule carries a recurring peak/off-peak tariff. A schedule with
|
|
21
|
+
* no peak windows at a 1x off-peak multiplier only carries dated rate cards
|
|
22
|
+
* (`cost-patch`/`cost-fallback` `effective-rates`): its price changes on a
|
|
23
|
+
* date, never by time of day.
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasRecurringTariff(schedule: TimeBasedCost): boolean;
|
|
11
26
|
/** Return the recurring UTC tariff period, independently of its monetary multiplier. */
|
|
12
27
|
export declare function getTimeBasedPricingPeriod(cost: ModelCost, timestamp?: number): "peak" | "off-peak" | undefined;
|
|
13
28
|
/** Return the next actual peak/off-peak change strictly after the Unix-ms timestamp. */
|
package/dist/types/pricing.d.ts
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
|
-
import type { TimeBasedCost } from "./types.js";
|
|
1
|
+
import type { EffectiveTokenCost, ModelCost, TimeBasedCost, TokenCost } from "./types.js";
|
|
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;
|
|
@@ -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;
|
|
@@ -655,6 +668,11 @@ export interface ModelsDevProviderDescriptor {
|
|
|
655
668
|
}
|
|
656
669
|
/** Generic mapper that converts models.dev data using provider descriptors. */
|
|
657
670
|
export declare function mapModelsDevToModels(data: Record<string, unknown>, descriptors: readonly ModelsDevProviderDescriptor[]): ModelSpec<Api>[];
|
|
671
|
+
/**
|
|
672
|
+
* OpenCode Go endpoint for one request API. The model generator re-bases
|
|
673
|
+
* previous-snapshot rows with it so retained rows follow endpoint moves.
|
|
674
|
+
*/
|
|
675
|
+
export declare function openCodeGoBaseUrlForApi(api: Api): string;
|
|
658
676
|
/** Resolves the transport and endpoint for one Z.AI model catalog entry. */
|
|
659
677
|
export declare function resolveZaiApi(modelId: string): {
|
|
660
678
|
api: "anthropic-messages" | "openai-completions";
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1401,8 +1401,6 @@ export interface Model<TApi extends Api = Api> {
|
|
|
1401
1401
|
preferWebsockets?: boolean;
|
|
1402
1402
|
/** Codex Responses Lite transport: send the lite marker and carry instructions/tools as input items (mirrors codex-rs `use_responses_lite`). */
|
|
1403
1403
|
useResponsesLite?: boolean;
|
|
1404
|
-
/** Codex Code Mode restriction: model expects tools routed through a programmatic exec surface (mirrors codex-rs `tool_mode`). */
|
|
1405
|
-
toolMode?: "code_mode_only";
|
|
1406
1404
|
/**
|
|
1407
1405
|
* Service-tier ids the provider advertises for this model (Codex discovery
|
|
1408
1406
|
* `service_tiers[].id`, e.g. `priority`, `ultrafast`). Absent when the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-catalog",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.11.0",
|
|
4
4
|
"description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -93,12 +93,12 @@
|
|
|
93
93
|
"gen:proto": "bun scripts/generate-protocols.ts"
|
|
94
94
|
},
|
|
95
95
|
"dependencies": {
|
|
96
|
-
"@oh-my-pi/omptype": "18.
|
|
97
|
-
"@oh-my-pi/pi-utils": "18.
|
|
96
|
+
"@oh-my-pi/omptype": "18.11.0",
|
|
97
|
+
"@oh-my-pi/pi-utils": "18.11.0"
|
|
98
98
|
},
|
|
99
99
|
"devDependencies": {
|
|
100
100
|
"@bgotink/kdl": "0.4.0",
|
|
101
|
-
"@oh-my-pi/pi-ai": "18.
|
|
101
|
+
"@oh-my-pi/pi-ai": "18.11.0",
|
|
102
102
|
"@types/bun": "^1.3.14"
|
|
103
103
|
},
|
|
104
104
|
"engines": {
|
package/src/build.ts
CHANGED
|
@@ -10,8 +10,16 @@
|
|
|
10
10
|
import { resolveDiscoveryApi, resolveModelPolicy } from "./compat/resolve";
|
|
11
11
|
import type { ModelIdentity } from "./compat/types";
|
|
12
12
|
import { resolveModelTokenizer } from "./model-tokenizer";
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import {
|
|
14
|
+
applyDueDatedCostCard,
|
|
15
|
+
type DatedCostCard,
|
|
16
|
+
dueEffectiveRate,
|
|
17
|
+
EARLIEST_EFFECTIVE_FROM,
|
|
18
|
+
materializeTimeBasedCost,
|
|
19
|
+
NO_RECURRING_TARIFF,
|
|
20
|
+
parseDatedCostCards,
|
|
21
|
+
} from "./pricing";
|
|
22
|
+
import { type Api, type EffectiveTokenCost, MODEL_KINDS, type Model, type ModelCost, type ModelSpec } from "./types";
|
|
15
23
|
import { cleanModelName } from "./utils";
|
|
16
24
|
|
|
17
25
|
function numberField(source: object, key: string): number | undefined {
|
|
@@ -24,41 +32,6 @@ function objectPayload(value: unknown): object | undefined {
|
|
|
24
32
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
25
33
|
}
|
|
26
34
|
|
|
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
|
-
|
|
62
35
|
/** Narrow a compiled `input-modalities` axis value to the model input union. */
|
|
63
36
|
function isInputModalities(value: unknown): value is ("text" | "image")[] {
|
|
64
37
|
return Array.isArray(value) && value.every(entry => entry === "text" || entry === "image");
|
|
@@ -164,52 +137,65 @@ function applyCatalogAssignments<TApi extends Api>(model: Model<TApi>, catalog:
|
|
|
164
137
|
}
|
|
165
138
|
}
|
|
166
139
|
|
|
140
|
+
/** The parsed dated cards of a row's `cost-patch` and `cost-fallback`. */
|
|
141
|
+
interface DatedCostCards {
|
|
142
|
+
patch: readonly DatedCostCard[];
|
|
143
|
+
fallback: readonly DatedCostCard[];
|
|
144
|
+
}
|
|
145
|
+
|
|
167
146
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* `buildModel` to every upstream-sourced spec; user-authored overrides are
|
|
172
|
-
* recomposed after building by the override applicators, so explicit user
|
|
173
|
-
* limits and pricing still win.
|
|
147
|
+
* The row's corrected price card at `now`: `cost-patch`, then `cost-fallback`
|
|
148
|
+
* (each with its dated card due at `now`), then the long-context tier and
|
|
149
|
+
* cache-rate derivations, all from the upstream card.
|
|
174
150
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
151
|
+
function correctedCost(
|
|
152
|
+
upstream: ModelCost,
|
|
177
153
|
catalog: Record<string, unknown>,
|
|
178
|
-
|
|
154
|
+
cards: DatedCostCards,
|
|
155
|
+
now: number,
|
|
156
|
+
): ModelCost {
|
|
157
|
+
let cost: ModelCost = { ...upstream };
|
|
158
|
+
const upstreamCard =
|
|
159
|
+
upstream.timeBased?.effectiveRates?.[0]?.effectiveFrom === EARLIEST_EFFECTIVE_FROM
|
|
160
|
+
? dueEffectiveRate(upstream.timeBased, now)
|
|
161
|
+
: undefined;
|
|
162
|
+
if (upstreamCard !== undefined) {
|
|
163
|
+
// A row rebuilt from an already built one (dynamic merges, overrides)
|
|
164
|
+
// carries the dated schedule compiled below. Its leading card covers all
|
|
165
|
+
// history, so the scalar legs only ever held the card due at the first
|
|
166
|
+
// build; start from the card due now instead.
|
|
167
|
+
const { effectiveFrom: _effectiveFrom, ...card } = upstreamCard;
|
|
168
|
+
const { longContext: _longContext, ...base } = cost;
|
|
169
|
+
cost = { ...base, ...card };
|
|
170
|
+
}
|
|
179
171
|
const patch = objectPayload(catalog.costPatch);
|
|
180
172
|
if (patch !== undefined) {
|
|
181
|
-
model.cost = { ...model.cost };
|
|
182
173
|
const input = numberField(patch, "input");
|
|
183
|
-
if (input !== undefined)
|
|
174
|
+
if (input !== undefined) cost.input = input;
|
|
184
175
|
const output = numberField(patch, "output");
|
|
185
|
-
if (output !== undefined)
|
|
176
|
+
if (output !== undefined) cost.output = output;
|
|
186
177
|
const cacheRead = numberField(patch, "cacheRead");
|
|
187
|
-
if (cacheRead !== undefined)
|
|
178
|
+
if (cacheRead !== undefined) cost.cacheRead = cacheRead;
|
|
188
179
|
const cacheWrite = numberField(patch, "cacheWrite");
|
|
189
|
-
if (cacheWrite !== undefined)
|
|
180
|
+
if (cacheWrite !== undefined) cost.cacheWrite = cacheWrite;
|
|
181
|
+
applyDueDatedCostCard(cost, cards.patch, now);
|
|
190
182
|
}
|
|
191
183
|
const fallback = objectPayload(catalog.costFallback);
|
|
192
184
|
if (fallback !== undefined) {
|
|
193
|
-
const
|
|
194
|
-
const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
|
|
185
|
+
const hasTokenPrice = cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0;
|
|
195
186
|
if (!hasTokenPrice) {
|
|
196
187
|
// Upstream reported no token price (plan-included or promo-free
|
|
197
188
|
// rows): seed the reviewed list price instead of overwriting real
|
|
198
189
|
// discovery data the way `cost-patch` would.
|
|
199
|
-
model.cost = { ...model.cost };
|
|
200
190
|
const input = numberField(fallback, "input");
|
|
201
|
-
if (input !== undefined)
|
|
191
|
+
if (input !== undefined) cost.input = input;
|
|
202
192
|
const output = numberField(fallback, "output");
|
|
203
|
-
if (output !== undefined)
|
|
193
|
+
if (output !== undefined) cost.output = output;
|
|
204
194
|
const cacheRead = numberField(fallback, "cacheRead");
|
|
205
|
-
if (cacheRead !== undefined)
|
|
195
|
+
if (cacheRead !== undefined) cost.cacheRead = cacheRead;
|
|
206
196
|
const cacheWrite = numberField(fallback, "cacheWrite");
|
|
207
|
-
if (cacheWrite !== undefined)
|
|
208
|
-
|
|
209
|
-
// already taken effect. They are not a recurring tariff: wrapping
|
|
210
|
-
// them in `timeBased` with empty peak windows would report
|
|
211
|
-
// permanent off-peak and never wake at the dated boundary.
|
|
212
|
-
applyEffectiveFallbackRates(model.cost, Reflect.get(fallback, "effectiveRates"));
|
|
197
|
+
if (cacheWrite !== undefined) cost.cacheWrite = cacheWrite;
|
|
198
|
+
applyDueDatedCostCard(cost, cards.fallback, now);
|
|
213
199
|
}
|
|
214
200
|
}
|
|
215
201
|
const longContext = objectPayload(catalog.longContext);
|
|
@@ -221,20 +207,19 @@ export function applyCatalogCorrections(
|
|
|
221
207
|
const output = numberField(longContext, "output");
|
|
222
208
|
const cacheRead = numberField(longContext, "cacheRead");
|
|
223
209
|
const cacheWrite = numberField(longContext, "cacheWrite");
|
|
224
|
-
const
|
|
225
|
-
const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
|
|
210
|
+
const hasTokenPrice = cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0;
|
|
226
211
|
if (inputThreshold !== undefined && multiplier !== undefined && hasTokenPrice) {
|
|
227
212
|
// Multiplier form: tier rates derive from the row's final base card,
|
|
228
213
|
// after `cost-patch`/`cost-fallback` corrected the live list price.
|
|
229
|
-
|
|
230
|
-
...
|
|
214
|
+
cost = {
|
|
215
|
+
...cost,
|
|
231
216
|
longContext: {
|
|
232
217
|
inputThreshold,
|
|
233
218
|
...(inclusive && { inputThresholdInclusive: true }),
|
|
234
|
-
input:
|
|
235
|
-
output:
|
|
236
|
-
cacheRead:
|
|
237
|
-
cacheWrite:
|
|
219
|
+
input: cost.input * multiplier,
|
|
220
|
+
output: cost.output * (numberField(longContext, "outputMultiplier") ?? multiplier),
|
|
221
|
+
cacheRead: cost.cacheRead * multiplier,
|
|
222
|
+
cacheWrite: cost.cacheWrite * multiplier,
|
|
238
223
|
},
|
|
239
224
|
};
|
|
240
225
|
} else if (
|
|
@@ -244,19 +229,94 @@ export function applyCatalogCorrections(
|
|
|
244
229
|
cacheRead !== undefined &&
|
|
245
230
|
cacheWrite !== undefined
|
|
246
231
|
) {
|
|
247
|
-
|
|
232
|
+
cost = { ...cost, longContext: { inputThreshold, input, output, cacheRead, cacheWrite } };
|
|
248
233
|
}
|
|
249
234
|
}
|
|
250
235
|
if (catalog.cacheReadAtInputRate === true) {
|
|
251
|
-
const { longContext } =
|
|
252
|
-
|
|
253
|
-
...
|
|
254
|
-
cacheRead:
|
|
236
|
+
const { longContext } = cost;
|
|
237
|
+
cost = {
|
|
238
|
+
...cost,
|
|
239
|
+
cacheRead: cost.input,
|
|
255
240
|
...(longContext && { longContext: { ...longContext, cacheRead: longContext.input } }),
|
|
256
241
|
};
|
|
257
242
|
}
|
|
258
|
-
|
|
259
|
-
|
|
243
|
+
const cacheWriteRate = catalog.cacheWriteRate;
|
|
244
|
+
if (typeof cacheWriteRate === "number") {
|
|
245
|
+
const { longContext } = cost;
|
|
246
|
+
cost = {
|
|
247
|
+
...cost,
|
|
248
|
+
cacheWrite: cost.input * cacheWriteRate,
|
|
249
|
+
...(longContext && { longContext: { ...longContext, cacheWrite: longContext.input * cacheWriteRate } }),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
return cost;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Every price period the dated `cost-patch`/`cost-fallback` cards define, for
|
|
257
|
+
* request-time selection (`calculateUsageCost`): a row built before a change
|
|
258
|
+
* still bills requests after it at the new price, and a leading card keeps
|
|
259
|
+
* earlier requests at the old one on rows built after it. Undefined when no
|
|
260
|
+
* card changes the price (no cards, or a fallback the upstream price outranks).
|
|
261
|
+
*/
|
|
262
|
+
function scheduledRates(
|
|
263
|
+
upstream: ModelCost,
|
|
264
|
+
catalog: Record<string, unknown>,
|
|
265
|
+
cards: DatedCostCards,
|
|
266
|
+
): EffectiveTokenCost[] | undefined {
|
|
267
|
+
const dates = [...cards.patch, ...cards.fallback].map(card => card.effectiveFrom).sort((a, b) => a - b);
|
|
268
|
+
if (dates.length === 0) return undefined;
|
|
269
|
+
const periods: EffectiveTokenCost[] = [];
|
|
270
|
+
let previousPrice: string | undefined;
|
|
271
|
+
for (const effectiveFrom of [EARLIEST_EFFECTIVE_FROM, ...dates]) {
|
|
272
|
+
const { input, output, cacheRead, cacheWrite, longContext } = correctedCost(
|
|
273
|
+
upstream,
|
|
274
|
+
catalog,
|
|
275
|
+
cards,
|
|
276
|
+
effectiveFrom,
|
|
277
|
+
);
|
|
278
|
+
const price = { input, output, cacheRead, cacheWrite, ...(longContext && { longContext }) };
|
|
279
|
+
const key = JSON.stringify(price);
|
|
280
|
+
if (key === previousPrice) continue;
|
|
281
|
+
previousPrice = key;
|
|
282
|
+
periods.push({ effectiveFrom, ...price });
|
|
283
|
+
}
|
|
284
|
+
return periods.length > 1 ? periods : undefined;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Applies reviewed catalog-data value corrections (`cost-patch`,
|
|
289
|
+
* `cache-read-at-input-rate`, `cache-write-rate`, `limits-patch`,
|
|
290
|
+
* `long-context-cost`, `context-window-floor`, `input-modalities`) onto an
|
|
291
|
+
* upstream-sourced spec. Applied by
|
|
292
|
+
* `buildModel` to every upstream-sourced spec; user-authored overrides are
|
|
293
|
+
* recomposed after building by the override applicators, so explicit user
|
|
294
|
+
* limits and pricing still win.
|
|
295
|
+
*/
|
|
296
|
+
export function applyCatalogCorrections(
|
|
297
|
+
model: Pick<ModelSpec<Api>, "cost" | "contextWindow" | "maxTokens" | "input">,
|
|
298
|
+
catalog: Record<string, unknown>,
|
|
299
|
+
): void {
|
|
300
|
+
const upstream = model.cost;
|
|
301
|
+
const cards: DatedCostCards = {
|
|
302
|
+
patch: parseDatedCostCards(catalog.costPatch, "cost-patch"),
|
|
303
|
+
fallback: parseDatedCostCards(catalog.costFallback, "cost-fallback"),
|
|
304
|
+
};
|
|
305
|
+
// The card due now is the row's displayed price; the dated schedule rides
|
|
306
|
+
// along so rows reused past a change (bundles, caches, long sessions) still
|
|
307
|
+
// bill each request at the card in force when it was made.
|
|
308
|
+
model.cost = correctedCost(upstream, catalog, cards, Date.now());
|
|
309
|
+
const recurring = catalog.timeBased === undefined ? undefined : materializeTimeBasedCost(catalog.timeBased);
|
|
310
|
+
const dated = scheduledRates(upstream, catalog, cards);
|
|
311
|
+
if (dated !== undefined) {
|
|
312
|
+
if (recurring?.effectiveRates !== undefined) {
|
|
313
|
+
throw new Error(
|
|
314
|
+
"Dated cost-patch/cost-fallback effective-rates cannot combine with time-based-cost effective-rates",
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
model.cost = { ...model.cost, timeBased: { ...(recurring ?? NO_RECURRING_TARIFF), effectiveRates: dated } };
|
|
318
|
+
} else if (recurring !== undefined) {
|
|
319
|
+
model.cost = { ...model.cost, timeBased: recurring };
|
|
260
320
|
}
|
|
261
321
|
const limitsPatch = objectPayload(catalog.limitsPatch);
|
|
262
322
|
if (limitsPatch !== undefined) {
|
package/src/compat/auth-ids.ts
CHANGED
|
@@ -70,6 +70,7 @@ export type AuthProviderId =
|
|
|
70
70
|
| "qianfan"
|
|
71
71
|
| "qwen-portal"
|
|
72
72
|
| "sakana"
|
|
73
|
+
| "sambanova"
|
|
73
74
|
| "siliconflow"
|
|
74
75
|
| "siliconflow-cn"
|
|
75
76
|
| "singularityapi-dev"
|
|
@@ -157,6 +158,7 @@ export type LoginProviderId =
|
|
|
157
158
|
| "qianfan"
|
|
158
159
|
| "qwen-portal"
|
|
159
160
|
| "sakana"
|
|
161
|
+
| "sambanova"
|
|
160
162
|
| "siliconflow"
|
|
161
163
|
| "siliconflow-cn"
|
|
162
164
|
| "singularityapi-dev"
|
package/src/compat/axes.ts
CHANGED
|
@@ -370,6 +370,19 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
370
370
|
shape: "scalar",
|
|
371
371
|
values: [true, false],
|
|
372
372
|
},
|
|
373
|
+
/**
|
|
374
|
+
* The model's input classifier refuses requests that reproduce assistant
|
|
375
|
+
* reasoning as quoted text (`reasoning_extraction`), so reasoning must not
|
|
376
|
+
* be replayed as text into its input: compaction archives, summarizer
|
|
377
|
+
* transcripts and demoted interrupted turns leave it out. Declared per class
|
|
378
|
+
* in `classes/*.kdl`.
|
|
379
|
+
*/
|
|
380
|
+
"classifier-cot-extraction": {
|
|
381
|
+
key: "classifierCotExtraction",
|
|
382
|
+
set: "catalog",
|
|
383
|
+
shape: "scalar",
|
|
384
|
+
values: [true, false],
|
|
385
|
+
},
|
|
373
386
|
"clamp-context-override": { key: "clampContextOverride", set: "catalog", shape: "scalar" },
|
|
374
387
|
"context-promotion-target": { key: "contextPromotionTarget", set: "catalog", shape: "scalar" },
|
|
375
388
|
"context-window-floor": { key: "contextWindowFloor", set: "catalog", shape: "scalar" },
|
|
@@ -391,6 +404,14 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
391
404
|
shape: "scalar",
|
|
392
405
|
values: [true, false],
|
|
393
406
|
},
|
|
407
|
+
/**
|
|
408
|
+
* The host bills cache writes at this multiple of the row's live `input`
|
|
409
|
+
* price, for hosts whose discovery reports cache-write tokens but no
|
|
410
|
+
* cache-write rate. It replaces any `cacheWrite` the row carries, including
|
|
411
|
+
* a `cost-patch`/`cost-fallback` value and an absolute long-context tier's
|
|
412
|
+
* `cacheWrite` (rebased on the tier's `input`).
|
|
413
|
+
*/
|
|
414
|
+
"cache-write-rate": { key: "cacheWriteRate", set: "catalog", shape: "scalar" },
|
|
394
415
|
/**
|
|
395
416
|
* How the model line bills a replayed signed thinking block as input:
|
|
396
417
|
* `output` bills the reasoning its signature carries, at the size the turn
|